Compare commits

..

8 Commits

10 changed files with 4373 additions and 2240 deletions

View File

@ -1,5 +1,35 @@
# Changelog
## 2024-11-18 - 3.1.0 - feat(file)
Added functionality to retrieve magic bytes from files and detect file types using magic bytes.
- Introduced method `getMagicBytes` in `File` and `Bucket` classes to retrieve a specific number of bytes from a file.
- Enhanced file type detection by utilizing magic bytes in `MetaData` class.
- Updated dependencies for better performance and compatibility.
## 2024-11-18 - 3.0.24 - fix(metadata)
Fix metadata handling to address type assertion and data retrieval.
- Fixed type assertion issues in `MetaData` class properties with type non-null assertions.
- Corrected the handling of JSON data retrieval in `MetaData.storeCustomMetaData` function.
## 2024-10-16 - 3.0.23 - fix(dependencies)
Update package dependencies for improved functionality and security.
- Updated @aws-sdk/client-s3 to version ^3.670.0 for enhanced S3 client capabilities.
- Updated @push.rocks/smartstream to version ^3.2.4.
- Updated the dev dependency @push.rocks/tapbundle to version ^5.3.0.
## 2024-07-28 - 3.0.22 - fix(dependencies)
Update dependencies and improve bucket retrieval logging
- Updated @aws-sdk/client-s3 to ^3.620.0
- Updated @git.zone/tsbuild to ^2.1.84
- Updated @git.zone/tsrun to ^1.2.49
- Updated @push.rocks/smartpromise to ^4.0.4
- Updated @tsclass/tsclass to ^4.1.2
- Added a log for when a bucket is not found by name in getBucketByName method
## 2024-07-04 - 3.0.21 - fix(test)
Update endpoint configuration in tests to use environment variable

4
package-lock.json generated
View File

@ -1,12 +1,12 @@
{
"name": "@push.rocks/smartbucket",
"version": "3.0.21",
"version": "3.1.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@push.rocks/smartbucket",
"version": "3.0.21",
"version": "3.1.0",
"license": "UNLICENSED",
"dependencies": {
"@push.rocks/smartpath": "^5.0.18",

View File

@ -1,6 +1,6 @@
{
"name": "@push.rocks/smartbucket",
"version": "3.0.21",
"version": "3.1.0",
"description": "A TypeScript library offering simple and cloud-agnostic object storage with advanced features like bucket creation, file and directory management, and data streaming.",
"main": "dist_ts/index.js",
"typings": "dist_ts/index.d.ts",
@ -12,22 +12,22 @@
"build": "(tsbuild --web --allowimplicitany)"
},
"devDependencies": {
"@git.zone/tsbuild": "^2.1.80",
"@git.zone/tsrun": "^1.2.46",
"@git.zone/tsbuild": "^2.1.84",
"@git.zone/tsrun": "^1.2.49",
"@git.zone/tstest": "^1.0.90",
"@push.rocks/qenv": "^6.0.5",
"@push.rocks/tapbundle": "^5.0.23"
"@push.rocks/tapbundle": "^5.3.0"
},
"dependencies": {
"@aws-sdk/client-s3": "^3.600.0",
"@push.rocks/smartmime": "^2.0.2",
"@aws-sdk/client-s3": "^3.693.0",
"@push.rocks/smartmime": "^2.0.4",
"@push.rocks/smartpath": "^5.0.18",
"@push.rocks/smartpromise": "^4.0.3",
"@push.rocks/smartpromise": "^4.0.4",
"@push.rocks/smartrx": "^3.0.7",
"@push.rocks/smartstream": "^3.0.44",
"@push.rocks/smartstream": "^3.2.4",
"@push.rocks/smartstring": "^4.0.15",
"@push.rocks/smartunique": "^3.0.9",
"@tsclass/tsclass": "^4.0.60"
"@tsclass/tsclass": "^4.1.2"
},
"private": false,
"files": [

6485
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@ -21,4 +21,8 @@ tap.test('should create a valid smartbucket', async () => {
expect(myBucket.name).toEqual('testzone');
});
tap.test('', async () => {
})
export default tap.start();

View File

@ -3,6 +3,6 @@
*/
export const commitinfo = {
name: '@push.rocks/smartbucket',
version: '3.0.21',
version: '3.1.0',
description: 'A TypeScript library offering simple and cloud-agnostic object storage with advanced features like bucket creation, file and directory management, and data streaming.'
}

View File

@ -24,6 +24,7 @@ export class Bucket {
console.log(`Taking this as base for new Bucket instance`);
return new this(smartbucketRef, bucketNameArg);
} else {
console.log(`did not find bucket by name: ${bucketNameArg}`);
return null;
}
}
@ -231,6 +232,7 @@ export class Bucket {
if (typeArg === 'webstream') {
return (await duplexStream.getWebStreams()).readable;
}
throw new Error('unknown typeArg');
}
/**
@ -436,4 +438,28 @@ export class Bucket {
const response = await this.smartbucketRef.s3Client.send(command);
return response.Contents.length > 0;
}
public async getMagicBytes(optionsArg: { path: string; length: number }): Promise<Buffer> {
try {
const command = new plugins.s3.GetObjectCommand({
Bucket: this.name,
Key: optionsArg.path,
Range: `bytes=0-${optionsArg.length - 1}`,
});
const response = await this.smartbucketRef.s3Client.send(command);
const chunks = [];
const stream = response.Body as any; // SdkStreamMixin includes readable stream
for await (const chunk of stream) {
chunks.push(chunk);
}
return Buffer.concat(chunks);
} catch (error) {
console.error(
`Error retrieving magic bytes from object at path '${optionsArg.path}' in bucket '${this.name}':`,
error
);
throw error;
}
}
}

View File

@ -50,6 +50,10 @@ export class File {
public parentDirectoryRef: Directory;
public name: string;
/**
* get the full path to the file
* @returns the full path to the file
*/
public getBasePath(): string {
return plugins.path.join(this.parentDirectoryRef.getBasePath(), this.name);
}
@ -188,7 +192,7 @@ export class File {
if (isDirectory) {
moveToPath = await helpers.reducePathDescriptorToPath({
...pathDescriptorArg,
path: plugins.path.join(pathDescriptorArg.path, this.name),
path: plugins.path.join(pathDescriptorArg.path!, this.name),
});
}
// lets move the file
@ -230,4 +234,11 @@ export class File {
contents: JSON.stringify(dataArg),
});
}
public async getMagicBytes(optionsArg: { length: number }): Promise<Buffer> {
return this.parentDirectoryRef.bucketRef.getMagicBytes({
path: this.getBasePath(),
length: optionsArg.length
})
}
}

View File

@ -21,20 +21,34 @@ export class MetaData {
/**
* the file that contains the metadata
*/
metadataFile: File;
metadataFile!: File;
/**
* the file that the metadata is for
*/
fileRef: File;
fileRef!: File;
public async getFileType(optionsArg?: {
useFileExtension?: boolean;
useMagicBytes?: boolean;
}): Promise<string> {
if ((optionsArg && optionsArg.useFileExtension) || optionsArg.useFileExtension === undefined) {
return plugins.path.extname(this.fileRef.name);
}): Promise<plugins.smartmime.IFileTypeResult | undefined> {
if ((optionsArg && optionsArg.useFileExtension) || !optionsArg) {
const fileType = await plugins.smartmime.detectMimeType({
path: this.fileRef.name,
});
return fileType;
}
if (optionsArg && optionsArg.useMagicBytes) {
const fileType = await plugins.smartmime.detectMimeType({
buffer: await this.fileRef.getMagicBytes({
length: 100,
})
});
return fileType;
}
throw new Error('optionsArg.useFileExtension and optionsArg.useMagicBytes cannot both be false');
}
/**
@ -44,13 +58,13 @@ export class MetaData {
const stat = await this.fileRef.parentDirectoryRef.bucketRef.fastStat({
path: this.fileRef.getBasePath(),
});
return stat.ContentLength;
return stat.ContentLength!;
}
private prefixCustomMetaData = 'custom_';
public async storeCustomMetaData<T = any>(optionsArg: { key: string; value: T }) {
const data = await this.metadataFile.getContentsAsString();
const data = await this.metadataFile.getJsonData();
data[this.prefixCustomMetaData + optionsArg.key] = optionsArg.value;
await this.metadataFile.writeJsonData(data);
}

View File

@ -6,7 +6,8 @@
"module": "NodeNext",
"moduleResolution": "NodeNext",
"esModuleInterop": true,
"verbatimModuleSyntax": true
"verbatimModuleSyntax": true,
"strict": true
},
"exclude": [
"dist_*/**/*.d.ts"