@visulima/storage 1.0.0-alpha.1 → 1.0.0-alpha.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +30 -0
- package/README.md +33 -14
- package/dist/adapter/nuxt/module.d.ts +39 -0
- package/dist/adapter/nuxt/module.js +93 -0
- package/dist/adapter/nuxt/package.json +20 -0
- package/dist/handler/base/base-handler-core.d.ts +91 -0
- package/dist/handler/base/base-handler-fetch.d.ts +76 -0
- package/dist/handler/base/base-handler-node.d.ts +137 -0
- package/dist/handler/http/fetch/index.d.ts +4 -0
- package/dist/handler/http/fetch/index.js +4 -0
- package/dist/handler/http/hono/index.d.ts +67 -0
- package/dist/handler/http/hono/index.js +65 -0
- package/dist/handler/http/nextjs/index.d.ts +61 -0
- package/dist/handler/http/nextjs/index.js +37 -0
- package/dist/handler/http/node/index.d.ts +4 -0
- package/dist/handler/http/node/index.js +4 -0
- package/dist/handler/http/solid-start/index.d.ts +60 -0
- package/dist/handler/http/solid-start/index.js +44 -0
- package/dist/handler/multipart/multipart-base.d.ts +84 -0
- package/dist/handler/multipart/multipart-fetch.d.ts +64 -0
- package/dist/handler/multipart/multipart.d.ts +49 -0
- package/dist/handler/rest/rest-base.d.ts +106 -0
- package/dist/handler/rest/rest-fetch.d.ts +88 -0
- package/dist/handler/rest/rest.d.ts +93 -0
- package/dist/handler/tus/tus-base.d.ts +152 -0
- package/dist/handler/tus/tus-fetch.d.ts +72 -0
- package/dist/handler/tus/tus.d.ts +78 -0
- package/dist/handler/types.d.ts +53 -0
- package/dist/handler/utils/request-parser.d.ts +72 -0
- package/dist/handler/utils/response-builder.d.ts +83 -0
- package/dist/handler/utils/storage-utils.d.ts +10 -0
- package/dist/handler/utils/stream-utils.d.ts +29 -0
- package/dist/handler/utils/upload-handlers.d.ts +76 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +13 -0
- package/dist/metrics/index.d.ts +2 -0
- package/dist/metrics/no-op-metrics.d.ts +15 -0
- package/dist/metrics/opentelemetry-metrics.d.ts +55 -0
- package/dist/openapi/index.d.ts +5 -0
- package/dist/openapi/index.js +5 -0
- package/dist/openapi/rest.d.ts +7 -0
- package/dist/openapi/shared.d.ts +13 -0
- package/dist/openapi/transform.d.ts +3 -0
- package/dist/openapi/tus.d.ts +7 -0
- package/dist/openapi/xhr.d.ts +7 -0
- package/dist/packem_shared/AwsLightFile-tTneXZgG.js +11 -0
- package/dist/packem_shared/AwsLightMetaStorage-BWSOtVaN.js +4 -0
- package/dist/packem_shared/AwsLightStorage-Blv-GP4v.js +133 -0
- package/dist/packem_shared/AzureFile-CesgFzps.js +8 -0
- package/dist/packem_shared/AzureSMetaStorage-CFs-OYJT.js +88 -0
- package/dist/packem_shared/AzureStorage-B0v048hG.js +357 -0
- package/dist/packem_shared/BaseTransformer-C2gLib6v.js +82 -0
- package/dist/packem_shared/DiskStorage-BlltBst6.js +12 -0
- package/dist/packem_shared/DiskStorageWithChecksum-BJTmMklc.js +238 -0
- package/dist/packem_shared/ERRORS-D0apMqnc.js +97 -0
- package/dist/packem_shared/File-Bb3P23dr.js +69 -0
- package/dist/packem_shared/GCSConfig-vPP22kN6.js +11 -0
- package/dist/packem_shared/GCSFile-BIEunhAN.js +8 -0
- package/dist/packem_shared/GCSMetaStorage-BMFEdzJ7.js +7 -0
- package/dist/packem_shared/GCStorage-DnhiwaS9.js +406 -0
- package/dist/packem_shared/LocalMetaStorage-CZHhKkMd.js +7 -0
- package/dist/packem_shared/MediaTransformer-D6658DL1.js +1197 -0
- package/dist/packem_shared/MetaStorage-pECeFOad.js +46 -0
- package/dist/packem_shared/Metadata-DRLXeJ0F.js +89 -0
- package/dist/packem_shared/Multipart-CNFK_Okz.js +163 -0
- package/dist/packem_shared/Multipart-CtUL7BQw.js +128 -0
- package/dist/packem_shared/NetlifyBlobFile-CXzyjqrD.js +14 -0
- package/dist/packem_shared/NetlifyBlobMetaStorage-DxZ5aDvD.js +9 -0
- package/dist/packem_shared/NetlifyBlobStorage-CLPtjHqd.js +376 -0
- package/dist/packem_shared/NoOpMetrics-DhAk5rXc.js +10 -0
- package/dist/packem_shared/OpenTelemetryMetrics-BnxhqIaH.js +67 -0
- package/dist/packem_shared/Rest-CAOAEkOj.js +267 -0
- package/dist/packem_shared/Rest-DNuLwBrK.js +228 -0
- package/dist/packem_shared/S3File-DZiyk9Qt.js +11 -0
- package/dist/packem_shared/S3MetaStorage-Dz9aDabA.js +76 -0
- package/dist/packem_shared/S3Storage-DHmTk-hU.js +316 -0
- package/dist/packem_shared/TUS_RESUMABLE-GJzZ9R-f.js +434 -0
- package/dist/packem_shared/Tus-B8PmlMgR.js +200 -0
- package/dist/packem_shared/Tus-C4F1aYOl.js +195 -0
- package/dist/packem_shared/ValidationError-BfF1aE4h.js +26 -0
- package/dist/packem_shared/VercelBlobFile-BCg4aTEq.js +18 -0
- package/dist/packem_shared/VercelBlobMetaStorage-Bd9F-VFm.js +9 -0
- package/dist/packem_shared/VercelBlobStorage-DD9LMOS6.js +261 -0
- package/dist/packem_shared/_commonjsHelpers-B85MJLTf.js +5 -0
- package/dist/packem_shared/aws-light-meta-storage-DKJBgbR6.js +446 -0
- package/dist/packem_shared/backblaze-BlMnIcBC.js +20 -0
- package/dist/packem_shared/base-handler-core-BKuf4YLT.js +303 -0
- package/dist/packem_shared/base-handler-fetch-Cr0hLiqg.js +291 -0
- package/dist/packem_shared/base-handler-node-gk5aN9Cx.js +730 -0
- package/dist/packem_shared/cache-B88MXQ_2.js +18 -0
- package/dist/packem_shared/cloudflare-Bi1q8wXE.js +21 -0
- package/dist/packem_shared/defaultCloudStorageFileNameValidation-DUuacjWv.js +11 -0
- package/dist/packem_shared/digitalOcean-CWQRJM3L.js +21 -0
- package/dist/packem_shared/disk-storage-Bh2wy3YW.js +810 -0
- package/dist/packem_shared/gcs-meta-storage-0tgMNnPO.js +158 -0
- package/dist/packem_shared/has-content-CY66ehMK.js +3 -0
- package/dist/packem_shared/headers-DoS5nwM-.js +3220 -0
- package/dist/packem_shared/is-expired-CTThU1q5.js +8 -0
- package/dist/packem_shared/isRetryableError-Dycp7127.js +82 -0
- package/dist/packem_shared/isValidMediaType-BeDgiObq.js +35 -0
- package/dist/packem_shared/local-meta-storage-By-3SNBI.js +649 -0
- package/dist/packem_shared/minio-C2YBZQOw.js +22 -0
- package/dist/packem_shared/multipart-base-B3i67SSX.js +102 -0
- package/dist/packem_shared/part-match-BMNqHDYD.js +96 -0
- package/dist/packem_shared/path-CR6YkPXX-7R1-9CMk.js +161 -0
- package/dist/packem_shared/response-builder-BtnRiBUI.js +45 -0
- package/dist/packem_shared/rest-base-GRCcnan7.js +457 -0
- package/dist/packem_shared/restOpenApiSpec-CwcHHY2C.js +800 -0
- package/dist/packem_shared/s3-base-storage-C1DIHTYY.js +510 -0
- package/dist/packem_shared/sharedGet-Cpo7QUyu.js +1019 -0
- package/dist/packem_shared/storage-C6NSXb8h.js +1175 -0
- package/dist/packem_shared/tigris-Hac8TKnX.js +21 -0
- package/dist/packem_shared/transformOpenApiSpec-DWM5WtnN.js +975 -0
- package/dist/packem_shared/tusOpenApiSpec-6ohiToBy.js +740 -0
- package/dist/packem_shared/update-size-CCGm6i1J.js +8 -0
- package/dist/packem_shared/validator-BeX_lJet.js +78 -0
- package/dist/packem_shared/waitForStorage-Cscw85sx.js +18 -0
- package/dist/packem_shared/wasabi-DIyflHSd.js +21 -0
- package/dist/packem_shared/xhrOpenApiSpec-DS17brnx.js +264 -0
- package/dist/storage/aws/clients/backblaze.d.ts +12 -0
- package/dist/storage/aws/clients/cloudflare.d.ts +13 -0
- package/dist/storage/aws/clients/digital-ocean.d.ts +12 -0
- package/dist/storage/aws/clients/index.d.ts +6 -0
- package/dist/storage/aws/clients/index.js +6 -0
- package/dist/storage/aws/clients/minio.d.ts +13 -0
- package/dist/storage/aws/clients/tigris.d.ts +12 -0
- package/dist/storage/aws/clients/types.d.ts +95 -0
- package/dist/storage/aws/clients/wasabi.d.ts +12 -0
- package/dist/storage/aws/index.d.ts +4 -0
- package/dist/storage/aws/index.js +3 -0
- package/dist/storage/aws/s3-base-storage.d.ts +248 -0
- package/dist/storage/aws/s3-client-adapter.d.ts +110 -0
- package/dist/storage/aws/s3-file.d.ts +10 -0
- package/dist/storage/aws/s3-meta-storage.d.ts +15 -0
- package/dist/storage/aws/s3-storage.d.ts +70 -0
- package/dist/storage/aws/types.d.ts +119 -0
- package/dist/storage/aws-light/aws-light-api-adapter.d.ts +130 -0
- package/dist/storage/aws-light/aws-light-file.d.ts +10 -0
- package/dist/storage/aws-light/aws-light-meta-storage.d.ts +19 -0
- package/dist/storage/aws-light/aws-light-storage.d.ts +65 -0
- package/dist/storage/aws-light/index.d.ts +4 -0
- package/dist/storage/aws-light/index.js +3 -0
- package/dist/storage/aws-light/types.d.ts +37 -0
- package/dist/storage/azure/azure-file.d.ts +6 -0
- package/dist/storage/azure/azure-meta-storage.d.ts +15 -0
- package/dist/storage/azure/azure-storage.d.ts +69 -0
- package/dist/storage/azure/index.d.ts +4 -0
- package/dist/storage/azure/index.js +3 -0
- package/dist/storage/azure/types.d.ts +62 -0
- package/dist/storage/gcs/fetch-error.d.ts +11 -0
- package/dist/storage/gcs/gcs-config.d.ts +2 -0
- package/dist/storage/gcs/gcs-file.d.ts +6 -0
- package/dist/storage/gcs/gcs-meta-storage.d.ts +27 -0
- package/dist/storage/gcs/gcs-storage.d.ts +91 -0
- package/dist/storage/gcs/index.d.ts +5 -0
- package/dist/storage/gcs/index.js +4 -0
- package/dist/storage/gcs/types.d.ts +55 -0
- package/dist/storage/gcs/utils.d.ts +7 -0
- package/dist/storage/local/disk-storage-with-checksum.d.ts +15 -0
- package/dist/storage/local/disk-storage.d.ts +135 -0
- package/dist/storage/local/index.d.ts +4 -0
- package/dist/storage/local/index.js +3 -0
- package/dist/storage/local/local-meta-storage.d.ts +32 -0
- package/dist/storage/meta-storage.d.ts +30 -0
- package/dist/storage/netlify-blob/index.d.ts +4 -0
- package/dist/storage/netlify-blob/index.js +3 -0
- package/dist/storage/netlify-blob/netlify-blob-file.d.ts +12 -0
- package/dist/storage/netlify-blob/netlify-blob-meta-storage.d.ts +7 -0
- package/dist/storage/netlify-blob/netlify-blob-storage.d.ts +93 -0
- package/dist/storage/netlify-blob/types.d.ts +30 -0
- package/dist/storage/storage.d.ts +353 -0
- package/dist/storage/types.d.ts +221 -0
- package/dist/storage/utils/file/file.d.ts +25 -0
- package/dist/storage/utils/file/get-file-status.d.ts +9 -0
- package/dist/storage/utils/file/has-content.d.ts +9 -0
- package/dist/storage/utils/file/index.d.ts +10 -0
- package/dist/storage/utils/file/is-expired.d.ts +8 -0
- package/dist/storage/utils/file/metadata.d.ts +18 -0
- package/dist/storage/utils/file/part-match.d.ts +11 -0
- package/dist/storage/utils/file/types.d.ts +37 -0
- package/dist/storage/utils/file/update-metadata.d.ts +10 -0
- package/dist/storage/utils/file/update-size.d.ts +10 -0
- package/dist/storage/vercel-blob/index.d.ts +4 -0
- package/dist/storage/vercel-blob/index.js +3 -0
- package/dist/storage/vercel-blob/types.d.ts +32 -0
- package/dist/storage/vercel-blob/vercel-blob-file.d.ts +16 -0
- package/dist/storage/vercel-blob/vercel-blob-meta-storage.d.ts +7 -0
- package/dist/storage/vercel-blob/vercel-blob-storage.d.ts +76 -0
- package/dist/transformer/audio-transformer.d.ts +128 -0
- package/dist/transformer/audio-transformer.js +278 -0
- package/dist/transformer/base-transformer.d.ts +63 -0
- package/dist/transformer/image-transformer.d.ts +571 -0
- package/dist/transformer/image-transformer.js +1100 -0
- package/dist/transformer/index.d.ts +5 -0
- package/dist/transformer/index.js +4 -0
- package/dist/transformer/media-transformer.d.ts +332 -0
- package/dist/transformer/types.d.ts +652 -0
- package/dist/transformer/utils.d.ts +33 -0
- package/dist/transformer/validation-error.d.ts +23 -0
- package/dist/transformer/video-transformer.d.ts +145 -0
- package/dist/transformer/video-transformer.js +310 -0
- package/dist/utils/cache.d.ts +32 -0
- package/dist/utils/chunked-upload.d.ts +65 -0
- package/dist/utils/detect-file-type.d.ts +28 -0
- package/dist/utils/errors.d.ts +74 -0
- package/dist/utils/file-path-url-matcher.d.ts +18 -0
- package/dist/utils/headers.d.ts +111 -0
- package/dist/utils/http.d.ts +92 -0
- package/dist/utils/locker.d.ts +26 -0
- package/dist/utils/pipes/stream-checksum.d.ts +47 -0
- package/dist/utils/pipes/stream-length.d.ts +22 -0
- package/dist/utils/primitives/get-last-one.d.ts +3 -0
- package/dist/utils/primitives/is-record.d.ts +2 -0
- package/dist/utils/primitives/map-values.d.ts +9 -0
- package/dist/utils/primitives/pick.d.ts +2 -0
- package/dist/utils/primitives/to-milliseconds.d.ts +12 -0
- package/dist/utils/primitives/to-seconds.d.ts +12 -0
- package/dist/utils/range-checksum.d.ts +33 -0
- package/dist/utils/range-hasher.d.ts +46 -0
- package/dist/utils/retry.d.ts +64 -0
- package/dist/utils/types.d.ts +108 -0
- package/dist/utils/validation-error.d.ts +22 -0
- package/dist/utils/validator.d.ts +36 -0
- package/package.json +5 -5
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { Readable } from "node:stream";
|
|
2
|
+
import type { Metadata } from "./metadata.d.ts";
|
|
3
|
+
export interface FileInit {
|
|
4
|
+
contentType?: string;
|
|
5
|
+
expiredAt?: Date | number | string;
|
|
6
|
+
metadata: Metadata;
|
|
7
|
+
originalName?: string;
|
|
8
|
+
size?: number | string;
|
|
9
|
+
storageClass?: string;
|
|
10
|
+
ttl?: number | string;
|
|
11
|
+
}
|
|
12
|
+
export interface FileReturn extends Omit<Required<FileInit>, "storageClass" | "ttl" | "expiredAt"> {
|
|
13
|
+
content: Buffer;
|
|
14
|
+
ETag?: string;
|
|
15
|
+
expiredAt?: Date | number | string;
|
|
16
|
+
id: string;
|
|
17
|
+
modifiedAt?: Date | number | string;
|
|
18
|
+
name: string;
|
|
19
|
+
storageClass?: string;
|
|
20
|
+
}
|
|
21
|
+
type UploadEventTypeValue = "completed" | "created" | "deleted" | "part" | "updated";
|
|
22
|
+
export type UploadEventType = UploadEventTypeValue;
|
|
23
|
+
export interface FileQuery {
|
|
24
|
+
id: string;
|
|
25
|
+
name?: string;
|
|
26
|
+
size?: number;
|
|
27
|
+
}
|
|
28
|
+
export interface Checksum {
|
|
29
|
+
checksum?: string;
|
|
30
|
+
checksumAlgorithm?: string;
|
|
31
|
+
}
|
|
32
|
+
export interface FilePart extends Checksum, FileQuery {
|
|
33
|
+
body: Readable;
|
|
34
|
+
contentLength?: number;
|
|
35
|
+
start: number;
|
|
36
|
+
}
|
|
37
|
+
export {};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type File from "./file.d.ts";
|
|
2
|
+
/**
|
|
3
|
+
* Updates a file object with new metadata using deep merge.
|
|
4
|
+
* Also updates the originalName based on the merged metadata.
|
|
5
|
+
* @param file File object to update
|
|
6
|
+
* @param metadata Partial metadata to merge into the file
|
|
7
|
+
* @template T - File type extending base File class
|
|
8
|
+
*/
|
|
9
|
+
declare const updateMetadata: <T extends File>(file: T, metadata: Partial<T>) => void;
|
|
10
|
+
export default updateMetadata;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type File from "./file.d.ts";
|
|
2
|
+
/**
|
|
3
|
+
* Updates a file's size, but only if the new size is smaller than the current size.
|
|
4
|
+
* This prevents accidental size increases that could indicate data corruption.
|
|
5
|
+
* @param file File object to update
|
|
6
|
+
* @param size New size value
|
|
7
|
+
* @returns The updated file object
|
|
8
|
+
*/
|
|
9
|
+
declare const updateSize: (file: File, size: number) => File;
|
|
10
|
+
export default updateSize;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export type { VercelBlobStorageOptions } from "./types.d.ts";
|
|
2
|
+
export { default as VercelBlobFile } from "./vercel-blob-file.d.ts";
|
|
3
|
+
export { default as VercelBlobMetaStorage } from "./vercel-blob-meta-storage.d.ts";
|
|
4
|
+
export { default as VercelBlobStorage } from "./vercel-blob-storage.d.ts";
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { default as VercelBlobFile } from '../../packem_shared/VercelBlobFile-BCg4aTEq.js';
|
|
2
|
+
export { default as VercelBlobMetaStorage } from '../../packem_shared/VercelBlobMetaStorage-Bd9F-VFm.js';
|
|
3
|
+
export { default as VercelBlobStorage } from '../../packem_shared/VercelBlobStorage-DD9LMOS6.js';
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { LocalMetaStorageOptions } from "../local/local-meta-storage.d.ts";
|
|
2
|
+
import type { BaseStorageOptions } from "../types.d.ts";
|
|
3
|
+
import type VercelBlobFile from "./vercel-blob-file.d.ts";
|
|
4
|
+
export interface VercelBlobStorageOptions extends BaseStorageOptions<VercelBlobFile> {
|
|
5
|
+
/**
|
|
6
|
+
* Configure metafiles storage
|
|
7
|
+
* @example
|
|
8
|
+
* Using local metafiles
|
|
9
|
+
* ```ts
|
|
10
|
+
* const storage = new VercelBlobStorage({
|
|
11
|
+
* token: process.env.BLOB_READ_WRITE_TOKEN,
|
|
12
|
+
* metaStorageConfig: { directory: '/tmp/upload-metafiles' }
|
|
13
|
+
* })
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
metaStorageConfig?: LocalMetaStorageOptions;
|
|
17
|
+
/**
|
|
18
|
+
* Enable multipart uploads for large files
|
|
19
|
+
* Can be a boolean to always use multipart, or a number (in bytes) as threshold
|
|
20
|
+
* @default false
|
|
21
|
+
* @example
|
|
22
|
+
* // Always use multipart uploads
|
|
23
|
+
* multipart: true
|
|
24
|
+
* // Use multipart for files larger than 100MB
|
|
25
|
+
* multipart: 100 * 1024 * 1024
|
|
26
|
+
*/
|
|
27
|
+
multipart?: boolean | number;
|
|
28
|
+
/**
|
|
29
|
+
* Vercel Blob read-write token
|
|
30
|
+
*/
|
|
31
|
+
token?: string;
|
|
32
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { File } from "../utils/index.d.ts";
|
|
2
|
+
declare class VercelBlobFile extends File {
|
|
3
|
+
/**
|
|
4
|
+
* The blob's public URL
|
|
5
|
+
*/
|
|
6
|
+
url?: string;
|
|
7
|
+
/**
|
|
8
|
+
* The blob's download URL (may be different from url for private blobs)
|
|
9
|
+
*/
|
|
10
|
+
downloadUrl?: string;
|
|
11
|
+
/**
|
|
12
|
+
* The blob's pathname within the store
|
|
13
|
+
*/
|
|
14
|
+
pathname?: string;
|
|
15
|
+
}
|
|
16
|
+
export default VercelBlobFile;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { LocalMetaStorageOptions } from "../local/local-meta-storage.d.ts";
|
|
2
|
+
import LocalMetaStorage from "../local/local-meta-storage.d.ts";
|
|
3
|
+
import type VercelBlobFile from "./vercel-blob-file.d.ts";
|
|
4
|
+
declare class VercelBlobMetaStorage extends LocalMetaStorage<VercelBlobFile> {
|
|
5
|
+
constructor(config?: LocalMetaStorageOptions);
|
|
6
|
+
}
|
|
7
|
+
export default VercelBlobMetaStorage;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import type MetaStorage from "../meta-storage.d.ts";
|
|
2
|
+
import { BaseStorage } from "../storage.d.ts";
|
|
3
|
+
import type { FileInit, FilePart, FileQuery, FileReturn } from "../utils/index.d.ts";
|
|
4
|
+
import type { VercelBlobStorageOptions } from "./types.d.ts";
|
|
5
|
+
import VercelBlobFile from "./vercel-blob-file.d.ts";
|
|
6
|
+
/**
|
|
7
|
+
* Vercel Blob storage based backend.
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* const storage = new VercelBlobStorage({
|
|
11
|
+
* token: process.env.BLOB_READ_WRITE_TOKEN,
|
|
12
|
+
* metaStorageConfig: { directory: '/tmp/upload-metafiles' }
|
|
13
|
+
* });
|
|
14
|
+
* ```
|
|
15
|
+
* @remarks
|
|
16
|
+
* ## Supported Operations
|
|
17
|
+
* - ✅ create, write, delete, get, copy, move
|
|
18
|
+
* - ✅ Batch operations: deleteBatch, copyBatch, moveBatch (inherited from BaseStorage)
|
|
19
|
+
* - ✅ exists: Implemented (checks metadata and Vercel Blob)
|
|
20
|
+
* - ❌ getStream: Not implemented (use get() for file retrieval)
|
|
21
|
+
* - ❌ list: Not implemented (Vercel Blob API doesn't support listing)
|
|
22
|
+
* - ❌ update: Not implemented (Vercel Blob API doesn't support metadata updates)
|
|
23
|
+
* - ❌ getUrl: Not implemented (Vercel Blob URLs available via Vercel Blob API)
|
|
24
|
+
* - ❌ getUploadUrl: Not implemented (Vercel Blob upload URLs handled internally)
|
|
25
|
+
*/
|
|
26
|
+
declare class VercelBlobStorage extends BaseStorage<VercelBlobFile, FileReturn> {
|
|
27
|
+
static readonly name: string;
|
|
28
|
+
checksumTypes: string[];
|
|
29
|
+
protected meta: MetaStorage<VercelBlobFile>;
|
|
30
|
+
private readonly token;
|
|
31
|
+
private readonly multipart;
|
|
32
|
+
constructor(config: VercelBlobStorageOptions);
|
|
33
|
+
create(config: FileInit): Promise<VercelBlobFile>;
|
|
34
|
+
write(part: FilePart | FileQuery | VercelBlobFile): Promise<VercelBlobFile>;
|
|
35
|
+
/**
|
|
36
|
+
* Deletes an upload and its metadata.
|
|
37
|
+
* @param query File query containing the file ID to delete.
|
|
38
|
+
* @param query.id File ID to delete.
|
|
39
|
+
* @returns Promise resolving to the deleted file object with status: "deleted".
|
|
40
|
+
* @throws {UploadError} If the file metadata cannot be found.
|
|
41
|
+
*/
|
|
42
|
+
delete({ id }: FileQuery): Promise<VercelBlobFile>;
|
|
43
|
+
/**
|
|
44
|
+
* Checks if a file exists by verifying both metadata and the actual Vercel Blob.
|
|
45
|
+
* Returns true only if both the metadata and the blob exist.
|
|
46
|
+
* @param query File query containing the file ID to check.
|
|
47
|
+
* @returns Promise resolving to true if both metadata and blob exist, false otherwise.
|
|
48
|
+
*/
|
|
49
|
+
exists({ id }: FileQuery): Promise<boolean>;
|
|
50
|
+
get({ id }: FileQuery): Promise<FileReturn>;
|
|
51
|
+
/**
|
|
52
|
+
* Copies an upload file to a new location.
|
|
53
|
+
* @param name Source file name/ID.
|
|
54
|
+
* @param destination Destination file name/ID.
|
|
55
|
+
* @returns Promise resolving to the copied file object.
|
|
56
|
+
* @throws {UploadError} If the source file cannot be found.
|
|
57
|
+
*/
|
|
58
|
+
copy(name: string, destination: string): Promise<VercelBlobFile>;
|
|
59
|
+
/**
|
|
60
|
+
* Moves an upload file to a new location.
|
|
61
|
+
* @param name Source file name/ID.
|
|
62
|
+
* @param destination Destination file name/ID.
|
|
63
|
+
* @returns Promise resolving to the moved file object.
|
|
64
|
+
* @throws {UploadError} If the source file cannot be found.
|
|
65
|
+
*/
|
|
66
|
+
move(name: string, destination: string): Promise<VercelBlobFile>;
|
|
67
|
+
list(limit?: number): Promise<VercelBlobFile[]>;
|
|
68
|
+
private internalOnComplete;
|
|
69
|
+
/**
|
|
70
|
+
* Determines if multipart upload should be used for the given file.
|
|
71
|
+
* @param file File object to check.
|
|
72
|
+
* @returns True if multipart upload should be used, false otherwise.
|
|
73
|
+
*/
|
|
74
|
+
private shouldUseMultipart;
|
|
75
|
+
}
|
|
76
|
+
export default VercelBlobStorage;
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import type { BaseStorage } from "../storage/storage.d.ts";
|
|
2
|
+
import type { File, FileReturn } from "../storage/utils/index.d.ts";
|
|
3
|
+
import BaseTransformer from "./base-transformer.d.ts";
|
|
4
|
+
import type { AudioChannelMixOptions, AudioResampleOptions, AudioTransformationStep, AudioTransformerConfig, AudioTransformOptions, AudioTransformResult } from "./types.d.ts";
|
|
5
|
+
/**
|
|
6
|
+
* Audio transformer that uses storage backends and Mediabunny to retrieve and transform audio files
|
|
7
|
+
*
|
|
8
|
+
* Supports audio transformations with query parameters for on-demand audio processing.
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* const transformer = new AudioTransformer(storage, {
|
|
12
|
+
* maxAudioSize: 50 * 1024 * 1024, // 50MB
|
|
13
|
+
* cache: new Map()
|
|
14
|
+
* });
|
|
15
|
+
*
|
|
16
|
+
* // Programmatic usage - resample audio
|
|
17
|
+
* const result = await transformer.resample('audio-id', {
|
|
18
|
+
* sampleRate: 44100
|
|
19
|
+
* });
|
|
20
|
+
*
|
|
21
|
+
* // URL-based transformations
|
|
22
|
+
* // GET /files/audio-id?sampleRate=48000&codec=aac&bitrate=128000
|
|
23
|
+
* // GET /files/audio-id?numberOfChannels=1&format=mp3
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* ## Supported Query Parameters
|
|
27
|
+
*
|
|
28
|
+
* - `sampleRate`: Sample rate in Hz (Number)
|
|
29
|
+
* - `numberOfChannels`: Number of channels (Number)
|
|
30
|
+
* - `codec`: Audio codec - aac/opus/mp3/vorbis/flac
|
|
31
|
+
* - `bitrate`: Audio bitrate in bits per second (Number)
|
|
32
|
+
* - `format`: Output format - mp3/wav/ogg/aac/flac
|
|
33
|
+
*/
|
|
34
|
+
declare class AudioTransformer<TFile extends File = File, TFileReturn extends FileReturn = FileReturn> extends BaseTransformer<AudioTransformerConfig, AudioTransformResult<TFileReturn>, TFile, TFileReturn> {
|
|
35
|
+
/**
|
|
36
|
+
* Creates a new AudioTransformer instance.
|
|
37
|
+
* @param storage The storage backend for retrieving and storing audio files.
|
|
38
|
+
* @param config Configuration options for audio transformation including cache settings, codec defaults, and size limits.
|
|
39
|
+
*/
|
|
40
|
+
constructor(storage: BaseStorage<TFile, TFileReturn>, config?: AudioTransformerConfig);
|
|
41
|
+
/**
|
|
42
|
+
* Resamples audio to different sample rate.
|
|
43
|
+
* @param fileId Unique identifier of the audio file to resample.
|
|
44
|
+
* @param options Resample options including target sample rate.
|
|
45
|
+
* @returns Promise resolving to transformed audio result.
|
|
46
|
+
*/
|
|
47
|
+
resample(fileId: string, options: AudioResampleOptions): Promise<AudioTransformResult<TFileReturn>>;
|
|
48
|
+
/**
|
|
49
|
+
* Changes number of channels (up/downmixing).
|
|
50
|
+
* @param fileId Unique identifier of the audio file to process.
|
|
51
|
+
* @param options Channel mix options including target number of channels.
|
|
52
|
+
* @returns Promise resolving to transformed audio result.
|
|
53
|
+
*/
|
|
54
|
+
mixChannels(fileId: string, options: AudioChannelMixOptions): Promise<AudioTransformResult<TFileReturn>>;
|
|
55
|
+
/**
|
|
56
|
+
* Converts audio format or codec.
|
|
57
|
+
* @param fileId Unique identifier of the audio file to convert.
|
|
58
|
+
* @param format Target audio format (e.g., "mp3", "wav", "ogg").
|
|
59
|
+
* @param options Additional transform options.
|
|
60
|
+
* @returns Promise resolving to transformed audio result.
|
|
61
|
+
*/
|
|
62
|
+
convertFormat(fileId: string, format: string, options?: AudioTransformOptions): Promise<AudioTransformResult<TFileReturn>>;
|
|
63
|
+
/**
|
|
64
|
+
* Transcodes audio to different codec.
|
|
65
|
+
* @param fileId Unique identifier of the audio file to transcode.
|
|
66
|
+
* @param codec Target audio codec (e.g., "aac", "opus", "mp3").
|
|
67
|
+
* @param options Additional transform options.
|
|
68
|
+
* @returns Promise resolving to transformed audio result.
|
|
69
|
+
*/
|
|
70
|
+
transcode(fileId: string, codec: AudioTransformOptions["codec"], options?: Omit<AudioTransformOptions, "codec">): Promise<AudioTransformResult<TFileReturn>>;
|
|
71
|
+
/**
|
|
72
|
+
* Applies a custom transformation pipeline to an audio file.
|
|
73
|
+
* @param fileId Unique identifier of the audio file to transform.
|
|
74
|
+
* @param steps Array of transformation steps to apply in sequence.
|
|
75
|
+
* @returns Promise resolving to transformed audio result.
|
|
76
|
+
*/
|
|
77
|
+
transform(fileId: string, steps: AudioTransformationStep[]): Promise<AudioTransformResult<TFileReturn>>;
|
|
78
|
+
/**
|
|
79
|
+
* Apply multiple transformations in sequence using Mediabunny
|
|
80
|
+
*/
|
|
81
|
+
private applyTransformations;
|
|
82
|
+
/**
|
|
83
|
+
* Convert transformation steps to Mediabunny audio options
|
|
84
|
+
* @param steps Array of audio transformation steps to convert
|
|
85
|
+
* @returns Mediabunny audio options object for conversion
|
|
86
|
+
* @private
|
|
87
|
+
*/
|
|
88
|
+
private stepsToAudioOptions;
|
|
89
|
+
/**
|
|
90
|
+
* Determine output format based on transformation steps
|
|
91
|
+
* @param steps Array of audio transformation steps
|
|
92
|
+
* @returns Mediabunny output format instance (defaults to MP3)
|
|
93
|
+
* @private
|
|
94
|
+
*/
|
|
95
|
+
private determineOutputFormat;
|
|
96
|
+
/**
|
|
97
|
+
* Convert format string to Mediabunny output format
|
|
98
|
+
* @param format Audio format string (aac, flac, mp3, ogg, wav)
|
|
99
|
+
* @returns Mediabunny output format instance
|
|
100
|
+
* @private
|
|
101
|
+
*/
|
|
102
|
+
private formatStringToOutputFormat;
|
|
103
|
+
/**
|
|
104
|
+
* Validate that the file is a supported audio file
|
|
105
|
+
* @param file The file to validate
|
|
106
|
+
* @returns Promise that resolves if validation passes
|
|
107
|
+
* @throws Error if file size exceeds limits, wrong content type, unsupported format, or invalid audio
|
|
108
|
+
* @private
|
|
109
|
+
*/
|
|
110
|
+
private validateAudio;
|
|
111
|
+
/**
|
|
112
|
+
* Create transformation result with metadata
|
|
113
|
+
* @param buffer The transformed audio buffer
|
|
114
|
+
* @param originalFile The original file information
|
|
115
|
+
* @returns Audio transformation result with metadata
|
|
116
|
+
* @private
|
|
117
|
+
*/
|
|
118
|
+
private createTransformResult;
|
|
119
|
+
/**
|
|
120
|
+
* Generate cache key for transformation
|
|
121
|
+
* @param fileId The file identifier
|
|
122
|
+
* @param steps Array of transformation steps
|
|
123
|
+
* @returns Unique cache key string
|
|
124
|
+
* @private
|
|
125
|
+
*/
|
|
126
|
+
private generateCacheKey;
|
|
127
|
+
}
|
|
128
|
+
export default AudioTransformer;
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
import { Input, BufferSource, ALL_FORMATS, Output, BufferTarget, Conversion, Mp3OutputFormat, WavOutputFormat, OggOutputFormat, FlacOutputFormat, AdtsOutputFormat } from 'mediabunny';
|
|
2
|
+
import BaseTransformer from '../packem_shared/BaseTransformer-C2gLib6v.js';
|
|
3
|
+
import { isValidMediaType, getFormatFromContentType } from '../packem_shared/isValidMediaType-BeDgiObq.js';
|
|
4
|
+
|
|
5
|
+
class AudioTransformer extends BaseTransformer {
|
|
6
|
+
/**
|
|
7
|
+
* Creates a new AudioTransformer instance.
|
|
8
|
+
* @param storage The storage backend for retrieving and storing audio files.
|
|
9
|
+
* @param config Configuration options for audio transformation including cache settings, codec defaults, and size limits.
|
|
10
|
+
*/
|
|
11
|
+
constructor(storage, config = {}) {
|
|
12
|
+
const logger = config.logger || storage.logger;
|
|
13
|
+
const transformerConfig = {
|
|
14
|
+
cacheTtl: 3600,
|
|
15
|
+
// 1 hour
|
|
16
|
+
defaultBitrate: 128e3,
|
|
17
|
+
// 128 kbps
|
|
18
|
+
defaultCodec: "aac",
|
|
19
|
+
maxAudioSize: 100 * 1024 * 1024,
|
|
20
|
+
// 100MB
|
|
21
|
+
maxCacheSize: 100,
|
|
22
|
+
// Max 100 transformed audio files in cache
|
|
23
|
+
supportedFormats: ["mp3", "wav", "ogg", "aac", "flac", "m4a", "wma", "aiff"],
|
|
24
|
+
...config
|
|
25
|
+
};
|
|
26
|
+
super(storage, transformerConfig, logger);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Resamples audio to different sample rate.
|
|
30
|
+
* @param fileId Unique identifier of the audio file to resample.
|
|
31
|
+
* @param options Resample options including target sample rate.
|
|
32
|
+
* @returns Promise resolving to transformed audio result.
|
|
33
|
+
*/
|
|
34
|
+
async resample(fileId, options) {
|
|
35
|
+
return this.transform(fileId, [{ options, type: "resample" }]);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Changes number of channels (up/downmixing).
|
|
39
|
+
* @param fileId Unique identifier of the audio file to process.
|
|
40
|
+
* @param options Channel mix options including target number of channels.
|
|
41
|
+
* @returns Promise resolving to transformed audio result.
|
|
42
|
+
*/
|
|
43
|
+
async mixChannels(fileId, options) {
|
|
44
|
+
return this.transform(fileId, [{ options, type: "channels" }]);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Converts audio format or codec.
|
|
48
|
+
* @param fileId Unique identifier of the audio file to convert.
|
|
49
|
+
* @param format Target audio format (e.g., "mp3", "wav", "ogg").
|
|
50
|
+
* @param options Additional transform options.
|
|
51
|
+
* @returns Promise resolving to transformed audio result.
|
|
52
|
+
*/
|
|
53
|
+
async convertFormat(fileId, format, options = {}) {
|
|
54
|
+
return this.transform(fileId, [{ options: { ...options, format }, type: "format" }]);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Transcodes audio to different codec.
|
|
58
|
+
* @param fileId Unique identifier of the audio file to transcode.
|
|
59
|
+
* @param codec Target audio codec (e.g., "aac", "opus", "mp3").
|
|
60
|
+
* @param options Additional transform options.
|
|
61
|
+
* @returns Promise resolving to transformed audio result.
|
|
62
|
+
*/
|
|
63
|
+
async transcode(fileId, codec, options = {}) {
|
|
64
|
+
return this.transform(fileId, [{ options: { ...options, codec }, type: "codec" }]);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Applies a custom transformation pipeline to an audio file.
|
|
68
|
+
* @param fileId Unique identifier of the audio file to transform.
|
|
69
|
+
* @param steps Array of transformation steps to apply in sequence.
|
|
70
|
+
* @returns Promise resolving to transformed audio result.
|
|
71
|
+
*/
|
|
72
|
+
async transform(fileId, steps) {
|
|
73
|
+
const fileQuery = { id: fileId };
|
|
74
|
+
const cacheKey = this.generateCacheKey(fileId, steps);
|
|
75
|
+
if (this.cache) {
|
|
76
|
+
const cached = await Promise.resolve(this.cache.get(cacheKey));
|
|
77
|
+
if (cached) {
|
|
78
|
+
this.logger?.debug("Returning cached transformed audio for %s", fileId);
|
|
79
|
+
return cached;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
const originalFile = await this.storage.get(fileQuery);
|
|
83
|
+
await this.validateAudio(originalFile);
|
|
84
|
+
const transformedBuffer = await this.applyTransformations(originalFile.content, steps);
|
|
85
|
+
const result = await this.createTransformResult(transformedBuffer, originalFile);
|
|
86
|
+
if (this.cache) {
|
|
87
|
+
this.cache.set(cacheKey, result);
|
|
88
|
+
}
|
|
89
|
+
return result;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Apply multiple transformations in sequence using Mediabunny
|
|
93
|
+
*/
|
|
94
|
+
async applyTransformations(buffer, steps) {
|
|
95
|
+
const input = new Input({
|
|
96
|
+
formats: ALL_FORMATS,
|
|
97
|
+
source: new BufferSource(buffer)
|
|
98
|
+
});
|
|
99
|
+
const outputFormat = this.determineOutputFormat(steps);
|
|
100
|
+
const output = new Output({
|
|
101
|
+
format: outputFormat,
|
|
102
|
+
target: new BufferTarget()
|
|
103
|
+
});
|
|
104
|
+
const audioOptions = this.stepsToAudioOptions(steps);
|
|
105
|
+
const conversion = await Conversion.init({
|
|
106
|
+
audio: audioOptions,
|
|
107
|
+
input,
|
|
108
|
+
output
|
|
109
|
+
});
|
|
110
|
+
if (!conversion.isValid) {
|
|
111
|
+
const reasons = conversion.discardedTracks.map((track) => track.reason).join(", ");
|
|
112
|
+
throw new Error(`Audio transformation failed: ${reasons}`);
|
|
113
|
+
}
|
|
114
|
+
await conversion.execute();
|
|
115
|
+
return Buffer.from(output.target.buffer);
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Convert transformation steps to Mediabunny audio options
|
|
119
|
+
* @param steps Array of audio transformation steps to convert
|
|
120
|
+
* @returns Mediabunny audio options object for conversion
|
|
121
|
+
* @private
|
|
122
|
+
*/
|
|
123
|
+
// eslint-disable-next-line class-methods-use-this
|
|
124
|
+
stepsToAudioOptions(steps) {
|
|
125
|
+
const options = {};
|
|
126
|
+
for (const step of steps) {
|
|
127
|
+
switch (step.type) {
|
|
128
|
+
case "bitrate": {
|
|
129
|
+
const bitrateOptions = step.options;
|
|
130
|
+
if (bitrateOptions.bitrate) {
|
|
131
|
+
options.bitrate = bitrateOptions.bitrate;
|
|
132
|
+
}
|
|
133
|
+
break;
|
|
134
|
+
}
|
|
135
|
+
case "channels": {
|
|
136
|
+
const channelOptions = step.options;
|
|
137
|
+
if (channelOptions.numberOfChannels) {
|
|
138
|
+
options.numberOfChannels = channelOptions.numberOfChannels;
|
|
139
|
+
}
|
|
140
|
+
break;
|
|
141
|
+
}
|
|
142
|
+
case "codec": {
|
|
143
|
+
const codecOptions = step.options;
|
|
144
|
+
if (codecOptions.codec) {
|
|
145
|
+
options.codec = codecOptions.codec;
|
|
146
|
+
}
|
|
147
|
+
if (codecOptions.bitrate) {
|
|
148
|
+
options.bitrate = codecOptions.bitrate;
|
|
149
|
+
}
|
|
150
|
+
break;
|
|
151
|
+
}
|
|
152
|
+
case "resample": {
|
|
153
|
+
const resampleOptions = step.options;
|
|
154
|
+
if (resampleOptions.sampleRate) {
|
|
155
|
+
options.sampleRate = resampleOptions.sampleRate;
|
|
156
|
+
}
|
|
157
|
+
break;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return options;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Determine output format based on transformation steps
|
|
165
|
+
* @param steps Array of audio transformation steps
|
|
166
|
+
* @returns Mediabunny output format instance (defaults to MP3)
|
|
167
|
+
* @private
|
|
168
|
+
*/
|
|
169
|
+
determineOutputFormat(steps) {
|
|
170
|
+
for (const step of steps) {
|
|
171
|
+
if (step.type === "format" && step.options.format) {
|
|
172
|
+
return this.formatStringToOutputFormat(step.options.format);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return new Mp3OutputFormat();
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Convert format string to Mediabunny output format
|
|
179
|
+
* @param format Audio format string (aac, flac, mp3, ogg, wav)
|
|
180
|
+
* @returns Mediabunny output format instance
|
|
181
|
+
* @private
|
|
182
|
+
*/
|
|
183
|
+
// eslint-disable-next-line class-methods-use-this
|
|
184
|
+
formatStringToOutputFormat(format) {
|
|
185
|
+
switch (format.toLowerCase()) {
|
|
186
|
+
case "aac": {
|
|
187
|
+
return new AdtsOutputFormat();
|
|
188
|
+
}
|
|
189
|
+
case "flac": {
|
|
190
|
+
return new FlacOutputFormat();
|
|
191
|
+
}
|
|
192
|
+
case "mp3": {
|
|
193
|
+
return new Mp3OutputFormat();
|
|
194
|
+
}
|
|
195
|
+
case "ogg": {
|
|
196
|
+
return new OggOutputFormat();
|
|
197
|
+
}
|
|
198
|
+
case "wav": {
|
|
199
|
+
return new WavOutputFormat();
|
|
200
|
+
}
|
|
201
|
+
default: {
|
|
202
|
+
return new Mp3OutputFormat();
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Validate that the file is a supported audio file
|
|
208
|
+
* @param file The file to validate
|
|
209
|
+
* @returns Promise that resolves if validation passes
|
|
210
|
+
* @throws Error if file size exceeds limits, wrong content type, unsupported format, or invalid audio
|
|
211
|
+
* @private
|
|
212
|
+
*/
|
|
213
|
+
async validateAudio(file) {
|
|
214
|
+
const fileSize = typeof file.size === "string" ? Number.parseInt(file.size, 10) : file.size;
|
|
215
|
+
if (this.config?.maxAudioSize && fileSize > this.config.maxAudioSize) {
|
|
216
|
+
throw new Error(`Audio size ${fileSize} exceeds maximum allowed size ${this.config.maxAudioSize}`);
|
|
217
|
+
}
|
|
218
|
+
if (!isValidMediaType(file.contentType, "audio")) {
|
|
219
|
+
throw new Error(`File is not audio: ${file.contentType}`);
|
|
220
|
+
}
|
|
221
|
+
const format = getFormatFromContentType(file.contentType);
|
|
222
|
+
if (this.config?.supportedFormats && format && !this.config.supportedFormats.includes(format)) {
|
|
223
|
+
throw new Error(`Unsupported audio format: ${format}`);
|
|
224
|
+
}
|
|
225
|
+
try {
|
|
226
|
+
const input = new Input({
|
|
227
|
+
formats: ALL_FORMATS,
|
|
228
|
+
source: new BufferSource(file.content)
|
|
229
|
+
});
|
|
230
|
+
const primaryTrack = await input.getPrimaryAudioTrack();
|
|
231
|
+
if (!primaryTrack) {
|
|
232
|
+
throw new Error("No audio track found");
|
|
233
|
+
}
|
|
234
|
+
} catch (error) {
|
|
235
|
+
throw new Error(`Invalid audio file: ${error}`);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Create transformation result with metadata
|
|
240
|
+
* @param buffer The transformed audio buffer
|
|
241
|
+
* @param originalFile The original file information
|
|
242
|
+
* @returns Audio transformation result with metadata
|
|
243
|
+
* @private
|
|
244
|
+
*/
|
|
245
|
+
async createTransformResult(buffer, originalFile) {
|
|
246
|
+
const input = new Input({
|
|
247
|
+
formats: ALL_FORMATS,
|
|
248
|
+
source: new BufferSource(buffer)
|
|
249
|
+
});
|
|
250
|
+
const audioTrack = await input.getPrimaryAudioTrack();
|
|
251
|
+
const duration = await input.computeDuration();
|
|
252
|
+
return {
|
|
253
|
+
bitrate: this.config.defaultBitrate,
|
|
254
|
+
buffer,
|
|
255
|
+
duration,
|
|
256
|
+
format: "mp3",
|
|
257
|
+
// Default, would need to detect actual format
|
|
258
|
+
numberOfChannels: audioTrack?.numberOfChannels || 2,
|
|
259
|
+
originalFile,
|
|
260
|
+
sampleRate: audioTrack?.sampleRate || 44100,
|
|
261
|
+
size: buffer.length
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Generate cache key for transformation
|
|
266
|
+
* @param fileId The file identifier
|
|
267
|
+
* @param steps Array of transformation steps
|
|
268
|
+
* @returns Unique cache key string
|
|
269
|
+
* @private
|
|
270
|
+
*/
|
|
271
|
+
// eslint-disable-next-line class-methods-use-this
|
|
272
|
+
generateCacheKey(fileId, steps) {
|
|
273
|
+
const stepsKey = steps.map((step) => `${step.type}:${JSON.stringify(step.options)}`).join("|");
|
|
274
|
+
return `${fileId}:${stepsKey}`;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
export { AudioTransformer as default };
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { Readable } from "node:stream";
|
|
2
|
+
import type { BaseStorage } from "../storage/storage.d.ts";
|
|
3
|
+
import type { File, FileReturn } from "../storage/utils/index.d.ts";
|
|
4
|
+
import type { Cache } from "../utils/cache.d.ts";
|
|
5
|
+
import type { BaseTransformerConfig } from "./types.d.ts";
|
|
6
|
+
/**
|
|
7
|
+
* Abstract base class for all media transformers.
|
|
8
|
+
*
|
|
9
|
+
* Provides a common interface and shared functionality for image, video, and audio transformers.
|
|
10
|
+
* All transformers must implement the abstract methods defined here.
|
|
11
|
+
*/
|
|
12
|
+
declare abstract class BaseTransformer<Config extends BaseTransformerConfig, CacheValue extends object, TFile extends File = File, TFileReturn extends FileReturn = FileReturn> {
|
|
13
|
+
protected readonly storage: BaseStorage<TFile, TFileReturn>;
|
|
14
|
+
protected config: Config;
|
|
15
|
+
protected logger?: Console;
|
|
16
|
+
protected cache?: Cache<string, CacheValue>;
|
|
17
|
+
/**
|
|
18
|
+
* Creates a new BaseTransformer instance with common functionality.
|
|
19
|
+
* @param storage The storage backend for retrieving and storing files.
|
|
20
|
+
* @param config Configuration options for the transformer.
|
|
21
|
+
* @param logger Optional logger instance for logging operations.
|
|
22
|
+
* @protected
|
|
23
|
+
*/
|
|
24
|
+
protected constructor(storage: BaseStorage<TFile, TFileReturn>, config: Config, logger?: Console);
|
|
25
|
+
/**
|
|
26
|
+
* Transforms a file with the given steps.
|
|
27
|
+
* @param fileId Unique identifier of the file to transform.
|
|
28
|
+
* @param steps Array of transformation steps to apply.
|
|
29
|
+
* @returns Promise resolving to transformation result.
|
|
30
|
+
*/
|
|
31
|
+
abstract transform(fileId: string, steps: any[]): Promise<any>;
|
|
32
|
+
/**
|
|
33
|
+
* Streams transform of a file with the given steps (for large files).
|
|
34
|
+
* @param fileId Unique identifier of the file to transform.
|
|
35
|
+
* @param steps Array of transformation steps to apply.
|
|
36
|
+
* @returns Promise resolving to streaming result with headers, size, and stream.
|
|
37
|
+
*/
|
|
38
|
+
transformStream?(fileId: string, steps: any[]): Promise<{
|
|
39
|
+
headers?: Record<string, string>;
|
|
40
|
+
size?: number;
|
|
41
|
+
stream: Readable;
|
|
42
|
+
}>;
|
|
43
|
+
/**
|
|
44
|
+
* Clears cache for a specific file or all files.
|
|
45
|
+
* @param fileId Optional file identifier to clear cache for specific file.
|
|
46
|
+
*/
|
|
47
|
+
clearCache(fileId?: string): void;
|
|
48
|
+
/**
|
|
49
|
+
* Gets cache statistics.
|
|
50
|
+
* @returns Cache statistics including max size and current size.
|
|
51
|
+
*/
|
|
52
|
+
getCacheStats(): {
|
|
53
|
+
maxSize: number;
|
|
54
|
+
size: number;
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* Gets content type from transformation result based on format.
|
|
58
|
+
* @param result Transformation result object containing format information.
|
|
59
|
+
* @returns Content type string (MIME type).
|
|
60
|
+
*/
|
|
61
|
+
protected getContentTypeFromResult(result: any): string;
|
|
62
|
+
}
|
|
63
|
+
export default BaseTransformer;
|