@openinary/core 1.1.0
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/LICENSE +661 -0
- package/dist/config/deps.d.ts +14 -0
- package/dist/config/deps.d.ts.map +1 -0
- package/dist/config/deps.js +2 -0
- package/dist/config/deps.js.map +1 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +28 -0
- package/dist/index.js.map +1 -0
- package/dist/routes/authenticated.d.ts +4 -0
- package/dist/routes/authenticated.d.ts.map +1 -0
- package/dist/routes/authenticated.js +130 -0
- package/dist/routes/authenticated.js.map +1 -0
- package/dist/routes/download-folder.d.ts +4 -0
- package/dist/routes/download-folder.d.ts.map +1 -0
- package/dist/routes/download-folder.js +101 -0
- package/dist/routes/download-folder.js.map +1 -0
- package/dist/routes/download-zip.d.ts +15 -0
- package/dist/routes/download-zip.d.ts.map +1 -0
- package/dist/routes/download-zip.js +147 -0
- package/dist/routes/download-zip.js.map +1 -0
- package/dist/routes/download.d.ts +4 -0
- package/dist/routes/download.d.ts.map +1 -0
- package/dist/routes/download.js +83 -0
- package/dist/routes/download.js.map +1 -0
- package/dist/routes/invalidate.d.ts +4 -0
- package/dist/routes/invalidate.d.ts.map +1 -0
- package/dist/routes/invalidate.js +114 -0
- package/dist/routes/invalidate.js.map +1 -0
- package/dist/routes/queue-events.d.ts +4 -0
- package/dist/routes/queue-events.d.ts.map +1 -0
- package/dist/routes/queue-events.js +125 -0
- package/dist/routes/queue-events.js.map +1 -0
- package/dist/routes/queue.d.ts +4 -0
- package/dist/routes/queue.d.ts.map +1 -0
- package/dist/routes/queue.js +130 -0
- package/dist/routes/queue.js.map +1 -0
- package/dist/routes/storage.d.ts +4 -0
- package/dist/routes/storage.d.ts.map +1 -0
- package/dist/routes/storage.js +694 -0
- package/dist/routes/storage.js.map +1 -0
- package/dist/routes/transform-helpers.d.ts +62 -0
- package/dist/routes/transform-helpers.d.ts.map +1 -0
- package/dist/routes/transform-helpers.js +372 -0
- package/dist/routes/transform-helpers.js.map +1 -0
- package/dist/routes/transform.d.ts +4 -0
- package/dist/routes/transform.d.ts.map +1 -0
- package/dist/routes/transform.js +65 -0
- package/dist/routes/transform.js.map +1 -0
- package/dist/routes/video-status.d.ts +4 -0
- package/dist/routes/video-status.d.ts.map +1 -0
- package/dist/routes/video-status.js +208 -0
- package/dist/routes/video-status.js.map +1 -0
- package/dist/services/transform.service.d.ts +71 -0
- package/dist/services/transform.service.d.ts.map +1 -0
- package/dist/services/transform.service.js +362 -0
- package/dist/services/transform.service.js.map +1 -0
- package/dist/types.d.ts +82 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/asset-deletion.d.ts +16 -0
- package/dist/utils/asset-deletion.d.ts.map +1 -0
- package/dist/utils/asset-deletion.js +131 -0
- package/dist/utils/asset-deletion.js.map +1 -0
- package/dist/utils/cache.d.ts +44 -0
- package/dist/utils/cache.d.ts.map +1 -0
- package/dist/utils/cache.js +248 -0
- package/dist/utils/cache.js.map +1 -0
- package/dist/utils/get-unique-file-path.d.ts +8 -0
- package/dist/utils/get-unique-file-path.d.ts.map +1 -0
- package/dist/utils/get-unique-file-path.js +26 -0
- package/dist/utils/get-unique-file-path.js.map +1 -0
- package/dist/utils/image/aspect-ratio.d.ts +7 -0
- package/dist/utils/image/aspect-ratio.d.ts.map +1 -0
- package/dist/utils/image/aspect-ratio.js +40 -0
- package/dist/utils/image/aspect-ratio.js.map +1 -0
- package/dist/utils/image/background.d.ts +6 -0
- package/dist/utils/image/background.d.ts.map +1 -0
- package/dist/utils/image/background.js +22 -0
- package/dist/utils/image/background.js.map +1 -0
- package/dist/utils/image/compression.d.ts +44 -0
- package/dist/utils/image/compression.d.ts.map +1 -0
- package/dist/utils/image/compression.js +345 -0
- package/dist/utils/image/compression.js.map +1 -0
- package/dist/utils/image/gravity.d.ts +6 -0
- package/dist/utils/image/gravity.d.ts.map +1 -0
- package/dist/utils/image/gravity.js +24 -0
- package/dist/utils/image/gravity.js.map +1 -0
- package/dist/utils/image/index.d.ts +8 -0
- package/dist/utils/image/index.d.ts.map +1 -0
- package/dist/utils/image/index.js +77 -0
- package/dist/utils/image/index.js.map +1 -0
- package/dist/utils/image/param-registry.d.ts +63 -0
- package/dist/utils/image/param-registry.d.ts.map +1 -0
- package/dist/utils/image/param-registry.js +196 -0
- package/dist/utils/image/param-registry.js.map +1 -0
- package/dist/utils/image/quality.d.ts +8 -0
- package/dist/utils/image/quality.d.ts.map +1 -0
- package/dist/utils/image/quality.js +9 -0
- package/dist/utils/image/quality.js.map +1 -0
- package/dist/utils/image/resize.d.ts +7 -0
- package/dist/utils/image/resize.d.ts.map +1 -0
- package/dist/utils/image/resize.js +62 -0
- package/dist/utils/image/resize.js.map +1 -0
- package/dist/utils/image/rotation.d.ts +6 -0
- package/dist/utils/image/rotation.d.ts.map +1 -0
- package/dist/utils/image/rotation.js +20 -0
- package/dist/utils/image/rotation.js.map +1 -0
- package/dist/utils/image/round-corners.d.ts +12 -0
- package/dist/utils/image/round-corners.d.ts.map +1 -0
- package/dist/utils/image/round-corners.js +102 -0
- package/dist/utils/image/round-corners.js.map +1 -0
- package/dist/utils/image/types.d.ts +2 -0
- package/dist/utils/image/types.d.ts.map +1 -0
- package/dist/utils/image/types.js +2 -0
- package/dist/utils/image/types.js.map +1 -0
- package/dist/utils/logger.d.ts +21 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +82 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/parser.d.ts +8 -0
- package/dist/utils/parser.d.ts.map +1 -0
- package/dist/utils/parser.js +226 -0
- package/dist/utils/parser.js.map +1 -0
- package/dist/utils/signature.d.ts +35 -0
- package/dist/utils/signature.d.ts.map +1 -0
- package/dist/utils/signature.js +100 -0
- package/dist/utils/signature.js.map +1 -0
- package/dist/utils/storage/cache.d.ts +41 -0
- package/dist/utils/storage/cache.d.ts.map +1 -0
- package/dist/utils/storage/cache.js +90 -0
- package/dist/utils/storage/cache.js.map +1 -0
- package/dist/utils/storage/cloud-storage.d.ts +188 -0
- package/dist/utils/storage/cloud-storage.d.ts.map +1 -0
- package/dist/utils/storage/cloud-storage.js +514 -0
- package/dist/utils/storage/cloud-storage.js.map +1 -0
- package/dist/utils/storage/factory.d.ts +10 -0
- package/dist/utils/storage/factory.d.ts.map +1 -0
- package/dist/utils/storage/factory.js +17 -0
- package/dist/utils/storage/factory.js.map +1 -0
- package/dist/utils/storage/index.d.ts +7 -0
- package/dist/utils/storage/index.d.ts.map +1 -0
- package/dist/utils/storage/index.js +8 -0
- package/dist/utils/storage/index.js.map +1 -0
- package/dist/utils/storage/key-generator.d.ts +11 -0
- package/dist/utils/storage/key-generator.d.ts.map +1 -0
- package/dist/utils/storage/key-generator.js +23 -0
- package/dist/utils/storage/key-generator.js.map +1 -0
- package/dist/utils/storage/listing-cache.d.ts +14 -0
- package/dist/utils/storage/listing-cache.d.ts.map +1 -0
- package/dist/utils/storage/listing-cache.js +29 -0
- package/dist/utils/storage/listing-cache.js.map +1 -0
- package/dist/utils/storage/s3-client.d.ts +97 -0
- package/dist/utils/storage/s3-client.d.ts.map +1 -0
- package/dist/utils/storage/s3-client.js +297 -0
- package/dist/utils/storage/s3-client.js.map +1 -0
- package/dist/utils/storage/stats-tracker.d.ts +45 -0
- package/dist/utils/storage/stats-tracker.d.ts.map +1 -0
- package/dist/utils/storage/stats-tracker.js +97 -0
- package/dist/utils/storage/stats-tracker.js.map +1 -0
- package/dist/utils/storage/types.d.ts +2 -0
- package/dist/utils/storage/types.d.ts.map +1 -0
- package/dist/utils/storage/types.js +2 -0
- package/dist/utils/storage/types.js.map +1 -0
- package/dist/utils/storage-level.d.ts +66 -0
- package/dist/utils/storage-level.d.ts.map +1 -0
- package/dist/utils/storage-level.js +106 -0
- package/dist/utils/storage-level.js.map +1 -0
- package/dist/utils/storage-tree.d.ts +30 -0
- package/dist/utils/storage-tree.d.ts.map +1 -0
- package/dist/utils/storage-tree.js +81 -0
- package/dist/utils/storage-tree.js.map +1 -0
- package/dist/utils/upload-signature.d.ts +25 -0
- package/dist/utils/upload-signature.d.ts.map +1 -0
- package/dist/utils/upload-signature.js +56 -0
- package/dist/utils/upload-signature.js.map +1 -0
- package/dist/utils/video/auto-downscale.d.ts +12 -0
- package/dist/utils/video/auto-downscale.d.ts.map +1 -0
- package/dist/utils/video/auto-downscale.js +29 -0
- package/dist/utils/video/auto-downscale.js.map +1 -0
- package/dist/utils/video/command-builder.d.ts +22 -0
- package/dist/utils/video/command-builder.d.ts.map +1 -0
- package/dist/utils/video/command-builder.js +79 -0
- package/dist/utils/video/command-builder.js.map +1 -0
- package/dist/utils/video/config.d.ts +51 -0
- package/dist/utils/video/config.d.ts.map +1 -0
- package/dist/utils/video/config.js +170 -0
- package/dist/utils/video/config.js.map +1 -0
- package/dist/utils/video/format.d.ts +22 -0
- package/dist/utils/video/format.d.ts.map +1 -0
- package/dist/utils/video/format.js +64 -0
- package/dist/utils/video/format.js.map +1 -0
- package/dist/utils/video/index.d.ts +25 -0
- package/dist/utils/video/index.d.ts.map +1 -0
- package/dist/utils/video/index.js +104 -0
- package/dist/utils/video/index.js.map +1 -0
- package/dist/utils/video/param-registry.d.ts +64 -0
- package/dist/utils/video/param-registry.d.ts.map +1 -0
- package/dist/utils/video/param-registry.js +201 -0
- package/dist/utils/video/param-registry.js.map +1 -0
- package/dist/utils/video/quality.d.ts +12 -0
- package/dist/utils/video/quality.d.ts.map +1 -0
- package/dist/utils/video/quality.js +45 -0
- package/dist/utils/video/quality.js.map +1 -0
- package/dist/utils/video/queue-store.d.ts +51 -0
- package/dist/utils/video/queue-store.d.ts.map +1 -0
- package/dist/utils/video/queue-store.js +2 -0
- package/dist/utils/video/queue-store.js.map +1 -0
- package/dist/utils/video/resize.d.ts +7 -0
- package/dist/utils/video/resize.d.ts.map +1 -0
- package/dist/utils/video/resize.js +40 -0
- package/dist/utils/video/resize.js.map +1 -0
- package/dist/utils/video/sqlite-video-job-store.d.ts +29 -0
- package/dist/utils/video/sqlite-video-job-store.d.ts.map +1 -0
- package/dist/utils/video/sqlite-video-job-store.js +320 -0
- package/dist/utils/video/sqlite-video-job-store.js.map +1 -0
- package/dist/utils/video/thumbnail.d.ts +7 -0
- package/dist/utils/video/thumbnail.d.ts.map +1 -0
- package/dist/utils/video/thumbnail.js +22 -0
- package/dist/utils/video/thumbnail.js.map +1 -0
- package/dist/utils/video/trim.d.ts +7 -0
- package/dist/utils/video/trim.d.ts.map +1 -0
- package/dist/utils/video/trim.js +36 -0
- package/dist/utils/video/trim.js.map +1 -0
- package/dist/utils/video/types.d.ts +19 -0
- package/dist/utils/video/types.d.ts.map +1 -0
- package/dist/utils/video/types.js +2 -0
- package/dist/utils/video/types.js.map +1 -0
- package/dist/utils/video/video-info.d.ts +25 -0
- package/dist/utils/video/video-info.d.ts.map +1 -0
- package/dist/utils/video/video-info.js +58 -0
- package/dist/utils/video/video-info.js.map +1 -0
- package/dist/utils/video/video-worker.d.ts +52 -0
- package/dist/utils/video/video-worker.d.ts.map +1 -0
- package/dist/utils/video/video-worker.js +192 -0
- package/dist/utils/video/video-worker.js.map +1 -0
- package/dist/utils/video-job-queue.d.ts +62 -0
- package/dist/utils/video-job-queue.d.ts.map +1 -0
- package/dist/utils/video-job-queue.js +122 -0
- package/dist/utils/video-job-queue.js.map +1 -0
- package/package.json +51 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"listing-cache.d.ts","sourceRoot":"","sources":["../../../src/utils/storage/listing-cache.ts"],"names":[],"mappings":"AAAA,KAAK,YAAY,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,IAAI,CAAA;CAAE,CAAC;AASxE;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,MAAM,OAAO,CAAC,YAAY,EAAE,CAAC,GACrC,OAAO,CAAC,YAAY,EAAE,CAAC,CAkBzB;AAED,wBAAgB,sBAAsB,IAAI,IAAI,CAE7C"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
const LISTING_CACHE_TTL = 60 * 1000;
|
|
2
|
+
// Module-level singleton: storage.ts and upload.ts each create their own
|
|
3
|
+
// CloudStorage instance, so the shared listing cache cannot live on the class
|
|
4
|
+
let entry = null;
|
|
5
|
+
/**
|
|
6
|
+
* Returns the cached full bucket listing, fetching it at most once per TTL.
|
|
7
|
+
* The promise itself is cached so concurrent callers (e.g. GET /storage and
|
|
8
|
+
* GET /storage/stats firing together on dashboard load) share one S3 fan-out.
|
|
9
|
+
*/
|
|
10
|
+
export function getCachedFullListing(fetcher) {
|
|
11
|
+
if (entry && Date.now() - entry.timestamp < LISTING_CACHE_TTL) {
|
|
12
|
+
return entry.promise;
|
|
13
|
+
}
|
|
14
|
+
const current = {
|
|
15
|
+
promise: fetcher(),
|
|
16
|
+
timestamp: Date.now(),
|
|
17
|
+
};
|
|
18
|
+
entry = current;
|
|
19
|
+
current.promise.catch(() => {
|
|
20
|
+
if (entry === current) {
|
|
21
|
+
entry = null;
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
return current.promise;
|
|
25
|
+
}
|
|
26
|
+
export function invalidateListingCache() {
|
|
27
|
+
entry = null;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=listing-cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"listing-cache.js","sourceRoot":"","sources":["../../../src/utils/storage/listing-cache.ts"],"names":[],"mappings":"AAEA,MAAM,iBAAiB,GAAG,EAAE,GAAG,IAAI,CAAC;AAEpC,yEAAyE;AACzE,8EAA8E;AAC9E,IAAI,KAAK,GACP,IAAI,CAAC;AAEP;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAClC,OAAsC;IAEtC,IAAI,KAAK,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,SAAS,GAAG,iBAAiB,EAAE,CAAC;QAC9D,OAAO,KAAK,CAAC,OAAO,CAAC;IACvB,CAAC;IAED,MAAM,OAAO,GAA4D;QACvE,OAAO,EAAE,OAAO,EAAE;QAClB,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;KACtB,CAAC;IACF,KAAK,GAAG,OAAO,CAAC;IAEhB,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,EAAE;QACzB,IAAI,KAAK,KAAK,OAAO,EAAE,CAAC;YACtB,KAAK,GAAG,IAAI,CAAC;QACf,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,OAAO,CAAC,OAAO,CAAC;AACzB,CAAC;AAED,MAAM,UAAU,sBAAsB;IACpC,KAAK,GAAG,IAAI,CAAC;AACf,CAAC"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { StorageConfig, StorageClientOptions } from "./types";
|
|
2
|
+
export declare class S3ClientWrapper {
|
|
3
|
+
private s3Client;
|
|
4
|
+
private config;
|
|
5
|
+
constructor(config: StorageConfig, clientOptions?: StorageClientOptions);
|
|
6
|
+
/**
|
|
7
|
+
* Checks if an object exists in the bucket
|
|
8
|
+
*/
|
|
9
|
+
objectExists(key: string): Promise<boolean>;
|
|
10
|
+
/**
|
|
11
|
+
* Downloads an object from the bucket
|
|
12
|
+
*/
|
|
13
|
+
downloadObject(key: string): Promise<Buffer>;
|
|
14
|
+
/**
|
|
15
|
+
* Downloads an object as a stream, without buffering it in memory.
|
|
16
|
+
* Used to serve large files (e.g. original videos) directly to clients.
|
|
17
|
+
*/
|
|
18
|
+
downloadObjectStream(key: string): Promise<{
|
|
19
|
+
stream: ReadableStream<Uint8Array>;
|
|
20
|
+
contentLength?: number;
|
|
21
|
+
contentType?: string;
|
|
22
|
+
}>;
|
|
23
|
+
/**
|
|
24
|
+
* Lists objects under an optional prefix
|
|
25
|
+
*/
|
|
26
|
+
listObjects(prefix?: string, maxKeys?: number): Promise<{
|
|
27
|
+
key: string;
|
|
28
|
+
size?: number;
|
|
29
|
+
lastModified?: Date;
|
|
30
|
+
}[]>;
|
|
31
|
+
/**
|
|
32
|
+
* Lists a single page of one directory level using Delimiter: "/"
|
|
33
|
+
* Returns direct child prefixes (CommonPrefixes) and direct child objects
|
|
34
|
+
*/
|
|
35
|
+
listDelimitedPage(prefix: string, maxKeys?: number, continuationToken?: string): Promise<{
|
|
36
|
+
prefixes: string[];
|
|
37
|
+
objects: {
|
|
38
|
+
key: string;
|
|
39
|
+
size?: number;
|
|
40
|
+
lastModified?: Date;
|
|
41
|
+
}[];
|
|
42
|
+
isTruncated: boolean;
|
|
43
|
+
nextToken?: string;
|
|
44
|
+
}>;
|
|
45
|
+
/**
|
|
46
|
+
* Lists one full directory level (all pages) using Delimiter: "/"
|
|
47
|
+
*/
|
|
48
|
+
listDelimited(prefix: string): Promise<{
|
|
49
|
+
prefixes: string[];
|
|
50
|
+
objects: {
|
|
51
|
+
key: string;
|
|
52
|
+
size?: number;
|
|
53
|
+
lastModified?: Date;
|
|
54
|
+
}[];
|
|
55
|
+
}>;
|
|
56
|
+
/**
|
|
57
|
+
* Uploads an object to the bucket
|
|
58
|
+
*/
|
|
59
|
+
uploadObject(key: string, buffer: Buffer, contentType: string, metadata?: Record<string, string>): Promise<void>;
|
|
60
|
+
/**
|
|
61
|
+
* Creates a zero-byte object to represent a folder in S3-compatible storage
|
|
62
|
+
*/
|
|
63
|
+
createFolderMarker(key: string): Promise<void>;
|
|
64
|
+
/**
|
|
65
|
+
* Generates a signed URL for temporary access
|
|
66
|
+
*/
|
|
67
|
+
getSignedUrl(key: string, expiresIn?: number): Promise<string>;
|
|
68
|
+
/**
|
|
69
|
+
* Generates public URL for the object
|
|
70
|
+
*/
|
|
71
|
+
getPublicUrl(key: string): string;
|
|
72
|
+
/**
|
|
73
|
+
* Copies an object within the bucket to a new key
|
|
74
|
+
*/
|
|
75
|
+
copyObject(sourceKey: string, destKey: string): Promise<void>;
|
|
76
|
+
/**
|
|
77
|
+
* Deletes an object from the bucket
|
|
78
|
+
*/
|
|
79
|
+
deleteObject(key: string): Promise<void>;
|
|
80
|
+
/**
|
|
81
|
+
* Gets object metadata (size, lastModified) without downloading the file
|
|
82
|
+
*/
|
|
83
|
+
getObjectMetadata(key: string): Promise<{
|
|
84
|
+
size: number;
|
|
85
|
+
lastModified: Date;
|
|
86
|
+
metadata?: Record<string, string>;
|
|
87
|
+
} | null>;
|
|
88
|
+
/**
|
|
89
|
+
* Deletes multiple objects from the bucket (up to 1000 at once)
|
|
90
|
+
*/
|
|
91
|
+
deleteObjects(keys: string[]): Promise<number>;
|
|
92
|
+
/**
|
|
93
|
+
* Gets the bucket name
|
|
94
|
+
*/
|
|
95
|
+
get bucketName(): string;
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=s3-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"s3-client.d.ts","sourceRoot":"","sources":["../../../src/utils/storage/s3-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
import { S3Client, PutObjectCommand, GetObjectCommand, HeadObjectCommand, ListObjectsV2Command, DeleteObjectCommand, DeleteObjectsCommand, CopyObjectCommand, } from "@aws-sdk/client-s3";
|
|
2
|
+
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
|
|
3
|
+
import https from "https";
|
|
4
|
+
export class S3ClientWrapper {
|
|
5
|
+
s3Client;
|
|
6
|
+
config;
|
|
7
|
+
constructor(config, clientOptions = {}) {
|
|
8
|
+
this.config = config;
|
|
9
|
+
// Configure HTTP handler with socket settings (caller resolves these,
|
|
10
|
+
// e.g. from environment variables in self-hosted mode)
|
|
11
|
+
const maxSockets = clientOptions.maxSockets ?? 50;
|
|
12
|
+
const connectionTimeout = clientOptions.connectionTimeout ?? 0;
|
|
13
|
+
const requestTimeout = clientOptions.requestTimeout ?? 0;
|
|
14
|
+
const socketTimeout = clientOptions.socketTimeout ?? 0;
|
|
15
|
+
const clientConfig = {
|
|
16
|
+
region: config.region,
|
|
17
|
+
credentials: {
|
|
18
|
+
accessKeyId: config.accessKeyId,
|
|
19
|
+
secretAccessKey: config.secretAccessKey,
|
|
20
|
+
},
|
|
21
|
+
...(config.endpoint && {
|
|
22
|
+
endpoint: config.endpoint,
|
|
23
|
+
forcePathStyle: true, // Required for most S3-compatible providers
|
|
24
|
+
}),
|
|
25
|
+
requestHandler: {
|
|
26
|
+
httpsAgent: new https.Agent({
|
|
27
|
+
keepAlive: true,
|
|
28
|
+
maxSockets,
|
|
29
|
+
}),
|
|
30
|
+
...(connectionTimeout > 0 && { connectionTimeout }),
|
|
31
|
+
...(requestTimeout > 0 && { requestTimeout }),
|
|
32
|
+
...(socketTimeout > 0 && { socketTimeout }),
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
this.s3Client = new S3Client(clientConfig);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Checks if an object exists in the bucket
|
|
39
|
+
*/
|
|
40
|
+
async objectExists(key) {
|
|
41
|
+
try {
|
|
42
|
+
await this.s3Client.send(new HeadObjectCommand({
|
|
43
|
+
Bucket: this.config.bucketName,
|
|
44
|
+
Key: key,
|
|
45
|
+
}));
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Downloads an object from the bucket
|
|
54
|
+
*/
|
|
55
|
+
async downloadObject(key) {
|
|
56
|
+
const response = await this.s3Client.send(new GetObjectCommand({
|
|
57
|
+
Bucket: this.config.bucketName,
|
|
58
|
+
Key: key,
|
|
59
|
+
}));
|
|
60
|
+
if (!response.Body) {
|
|
61
|
+
throw new Error("File not found");
|
|
62
|
+
}
|
|
63
|
+
// Converts the stream to buffer
|
|
64
|
+
const chunks = [];
|
|
65
|
+
const reader = response.Body.transformToWebStream().getReader();
|
|
66
|
+
while (true) {
|
|
67
|
+
const { done, value } = await reader.read();
|
|
68
|
+
if (done)
|
|
69
|
+
break;
|
|
70
|
+
chunks.push(value);
|
|
71
|
+
}
|
|
72
|
+
return Buffer.concat(chunks);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Downloads an object as a stream, without buffering it in memory.
|
|
76
|
+
* Used to serve large files (e.g. original videos) directly to clients.
|
|
77
|
+
*/
|
|
78
|
+
async downloadObjectStream(key) {
|
|
79
|
+
const response = await this.s3Client.send(new GetObjectCommand({
|
|
80
|
+
Bucket: this.config.bucketName,
|
|
81
|
+
Key: key,
|
|
82
|
+
}));
|
|
83
|
+
if (!response.Body) {
|
|
84
|
+
throw new Error("File not found");
|
|
85
|
+
}
|
|
86
|
+
return {
|
|
87
|
+
stream: response.Body.transformToWebStream(),
|
|
88
|
+
contentLength: response.ContentLength,
|
|
89
|
+
contentType: response.ContentType,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Lists objects under an optional prefix
|
|
94
|
+
*/
|
|
95
|
+
async listObjects(prefix, maxKeys) {
|
|
96
|
+
const results = [];
|
|
97
|
+
let continuationToken;
|
|
98
|
+
do {
|
|
99
|
+
const response = await this.s3Client.send(new ListObjectsV2Command({
|
|
100
|
+
Bucket: this.config.bucketName,
|
|
101
|
+
Prefix: prefix,
|
|
102
|
+
MaxKeys: maxKeys,
|
|
103
|
+
ContinuationToken: continuationToken,
|
|
104
|
+
}));
|
|
105
|
+
if (response.Contents) {
|
|
106
|
+
for (const object of response.Contents) {
|
|
107
|
+
if (object.Key) {
|
|
108
|
+
results.push({
|
|
109
|
+
key: object.Key,
|
|
110
|
+
size: object.Size,
|
|
111
|
+
lastModified: object.LastModified,
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
continuationToken =
|
|
117
|
+
response.IsTruncated && (!maxKeys || results.length < maxKeys)
|
|
118
|
+
? response.NextContinuationToken
|
|
119
|
+
: undefined;
|
|
120
|
+
} while (continuationToken);
|
|
121
|
+
return results;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Lists a single page of one directory level using Delimiter: "/"
|
|
125
|
+
* Returns direct child prefixes (CommonPrefixes) and direct child objects
|
|
126
|
+
*/
|
|
127
|
+
async listDelimitedPage(prefix, maxKeys = 1000, continuationToken) {
|
|
128
|
+
const response = await this.s3Client.send(new ListObjectsV2Command({
|
|
129
|
+
Bucket: this.config.bucketName,
|
|
130
|
+
Prefix: prefix,
|
|
131
|
+
Delimiter: "/",
|
|
132
|
+
MaxKeys: maxKeys,
|
|
133
|
+
ContinuationToken: continuationToken,
|
|
134
|
+
}));
|
|
135
|
+
const prefixes = [];
|
|
136
|
+
for (const commonPrefix of response.CommonPrefixes ?? []) {
|
|
137
|
+
if (commonPrefix.Prefix) {
|
|
138
|
+
prefixes.push(commonPrefix.Prefix);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
const objects = [];
|
|
142
|
+
for (const object of response.Contents ?? []) {
|
|
143
|
+
if (object.Key) {
|
|
144
|
+
objects.push({
|
|
145
|
+
key: object.Key,
|
|
146
|
+
size: object.Size,
|
|
147
|
+
lastModified: object.LastModified,
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return {
|
|
152
|
+
prefixes,
|
|
153
|
+
objects,
|
|
154
|
+
isTruncated: response.IsTruncated ?? false,
|
|
155
|
+
nextToken: response.NextContinuationToken,
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Lists one full directory level (all pages) using Delimiter: "/"
|
|
160
|
+
*/
|
|
161
|
+
async listDelimited(prefix) {
|
|
162
|
+
// Some S3-compatible providers repeat CommonPrefixes across pages
|
|
163
|
+
const prefixes = new Set();
|
|
164
|
+
const objects = [];
|
|
165
|
+
let continuationToken;
|
|
166
|
+
do {
|
|
167
|
+
const page = await this.listDelimitedPage(prefix, 1000, continuationToken);
|
|
168
|
+
for (const p of page.prefixes) {
|
|
169
|
+
prefixes.add(p);
|
|
170
|
+
}
|
|
171
|
+
objects.push(...page.objects);
|
|
172
|
+
continuationToken = page.isTruncated ? page.nextToken : undefined;
|
|
173
|
+
} while (continuationToken);
|
|
174
|
+
return { prefixes: [...prefixes], objects };
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Uploads an object to the bucket
|
|
178
|
+
*/
|
|
179
|
+
async uploadObject(key, buffer, contentType, metadata) {
|
|
180
|
+
await this.s3Client.send(new PutObjectCommand({
|
|
181
|
+
Bucket: this.config.bucketName,
|
|
182
|
+
Key: key,
|
|
183
|
+
Body: buffer,
|
|
184
|
+
ContentType: contentType,
|
|
185
|
+
CacheControl: "public, max-age=31536000", // Cache 1 year
|
|
186
|
+
Metadata: metadata,
|
|
187
|
+
}));
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Creates a zero-byte object to represent a folder in S3-compatible storage
|
|
191
|
+
*/
|
|
192
|
+
async createFolderMarker(key) {
|
|
193
|
+
await this.s3Client.send(new PutObjectCommand({
|
|
194
|
+
Bucket: this.config.bucketName,
|
|
195
|
+
Key: key,
|
|
196
|
+
Body: "",
|
|
197
|
+
ContentType: "application/x-directory",
|
|
198
|
+
}));
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Generates a signed URL for temporary access
|
|
202
|
+
*/
|
|
203
|
+
async getSignedUrl(key, expiresIn = 3600) {
|
|
204
|
+
return await getSignedUrl(this.s3Client, new GetObjectCommand({
|
|
205
|
+
Bucket: this.config.bucketName,
|
|
206
|
+
Key: key,
|
|
207
|
+
}), { expiresIn });
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Generates public URL for the object
|
|
211
|
+
*/
|
|
212
|
+
getPublicUrl(key) {
|
|
213
|
+
if (this.config.publicUrl) {
|
|
214
|
+
return `${this.config.publicUrl}/${key}`;
|
|
215
|
+
}
|
|
216
|
+
// For custom endpoints, construct URL from endpoint
|
|
217
|
+
if (this.config.endpoint) {
|
|
218
|
+
const endpointUrl = this.config.endpoint.replace(/\/$/, "");
|
|
219
|
+
return `${endpointUrl}/${this.config.bucketName}/${key}`;
|
|
220
|
+
}
|
|
221
|
+
// Default AWS S3 URL format
|
|
222
|
+
return `https://${this.config.bucketName}.s3.${this.config.region}.amazonaws.com/${key}`;
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Copies an object within the bucket to a new key
|
|
226
|
+
*/
|
|
227
|
+
async copyObject(sourceKey, destKey) {
|
|
228
|
+
await this.s3Client.send(new CopyObjectCommand({
|
|
229
|
+
Bucket: this.config.bucketName,
|
|
230
|
+
CopySource: `${this.config.bucketName}/${sourceKey
|
|
231
|
+
.split("/")
|
|
232
|
+
.map(encodeURIComponent)
|
|
233
|
+
.join("/")}`,
|
|
234
|
+
Key: destKey,
|
|
235
|
+
}));
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Deletes an object from the bucket
|
|
239
|
+
*/
|
|
240
|
+
async deleteObject(key) {
|
|
241
|
+
await this.s3Client.send(new DeleteObjectCommand({
|
|
242
|
+
Bucket: this.config.bucketName,
|
|
243
|
+
Key: key,
|
|
244
|
+
}));
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Gets object metadata (size, lastModified) without downloading the file
|
|
248
|
+
*/
|
|
249
|
+
async getObjectMetadata(key) {
|
|
250
|
+
try {
|
|
251
|
+
const response = await this.s3Client.send(new HeadObjectCommand({
|
|
252
|
+
Bucket: this.config.bucketName,
|
|
253
|
+
Key: key,
|
|
254
|
+
}));
|
|
255
|
+
return {
|
|
256
|
+
size: response.ContentLength ?? 0,
|
|
257
|
+
lastModified: response.LastModified ?? new Date(),
|
|
258
|
+
metadata: response.Metadata,
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
catch {
|
|
262
|
+
return null;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Deletes multiple objects from the bucket (up to 1000 at once)
|
|
267
|
+
*/
|
|
268
|
+
async deleteObjects(keys) {
|
|
269
|
+
if (keys.length === 0) {
|
|
270
|
+
return 0;
|
|
271
|
+
}
|
|
272
|
+
// S3 DeleteObjects can delete up to 1000 objects at once
|
|
273
|
+
const batches = [];
|
|
274
|
+
for (let i = 0; i < keys.length; i += 1000) {
|
|
275
|
+
batches.push(keys.slice(i, i + 1000));
|
|
276
|
+
}
|
|
277
|
+
let totalDeleted = 0;
|
|
278
|
+
for (const batch of batches) {
|
|
279
|
+
const response = await this.s3Client.send(new DeleteObjectsCommand({
|
|
280
|
+
Bucket: this.config.bucketName,
|
|
281
|
+
Delete: {
|
|
282
|
+
Objects: batch.map((key) => ({ Key: key })),
|
|
283
|
+
Quiet: true,
|
|
284
|
+
},
|
|
285
|
+
}));
|
|
286
|
+
totalDeleted += batch.length - (response.Errors?.length ?? 0);
|
|
287
|
+
}
|
|
288
|
+
return totalDeleted;
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Gets the bucket name
|
|
292
|
+
*/
|
|
293
|
+
get bucketName() {
|
|
294
|
+
return this.config.bucketName;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
//# sourceMappingURL=s3-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"s3-client.js","sourceRoot":"","sources":["../../../src/utils/storage/s3-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export type AggregateStats = {
|
|
2
|
+
size: number;
|
|
3
|
+
fileCount: number;
|
|
4
|
+
};
|
|
5
|
+
export type BucketStats = {
|
|
6
|
+
storage: AggregateStats;
|
|
7
|
+
cache: AggregateStats;
|
|
8
|
+
updatedAt: string;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Persistence and reconciliation operations the tracker delegates to the
|
|
12
|
+
* storage layer (implemented by CloudStorage)
|
|
13
|
+
*/
|
|
14
|
+
export type StatsBackend = {
|
|
15
|
+
loadPersistedStats(): Promise<BucketStats | null>;
|
|
16
|
+
persistStats(stats: BucketStats): Promise<void>;
|
|
17
|
+
computeBucketStats(): Promise<{
|
|
18
|
+
storage: AggregateStats;
|
|
19
|
+
cache: AggregateStats;
|
|
20
|
+
}>;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Returns the tracked aggregate stats, loading them from the persisted
|
|
24
|
+
* bucket object on first call. Falls back to a one-time full recomputation
|
|
25
|
+
* (recursive listing) when no persisted stats exist yet.
|
|
26
|
+
*/
|
|
27
|
+
export declare function getBucketStats(backend: StatsBackend): Promise<BucketStats>;
|
|
28
|
+
/**
|
|
29
|
+
* Forces a full recomputation from bucket listings and persists the result.
|
|
30
|
+
* Reconciles any drift accumulated by the incremental adjustments (e.g.
|
|
31
|
+
* objects modified outside the app, or a crash before a persist flush).
|
|
32
|
+
* Keeps the previous stats when the recomputation fails.
|
|
33
|
+
*/
|
|
34
|
+
export declare function recalculateBucketStats(backend: StatsBackend): Promise<BucketStats>;
|
|
35
|
+
/**
|
|
36
|
+
* Applies an incremental delta to the tracked stats after a bucket mutation
|
|
37
|
+
* (upload, delete, ...). Fire-and-forget: callers never wait on it and it
|
|
38
|
+
* never throws, so stats tracking cannot break the mutation itself.
|
|
39
|
+
*/
|
|
40
|
+
export declare function adjustBucketStats(backend: StatsBackend, target: "storage" | "cache", delta: {
|
|
41
|
+
size: number;
|
|
42
|
+
fileCount: number;
|
|
43
|
+
}): void;
|
|
44
|
+
export declare function resetBucketStatsTracker(): void;
|
|
45
|
+
//# sourceMappingURL=stats-tracker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stats-tracker.d.ts","sourceRoot":"","sources":["../../../src/utils/storage/stats-tracker.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,cAAc,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC;AAEjE,MAAM,MAAM,WAAW,GAAG;IACxB,OAAO,EAAE,cAAc,CAAC;IACxB,KAAK,EAAE,cAAc,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB,kBAAkB,IAAI,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAClD,YAAY,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChD,kBAAkB,IAAI,OAAO,CAAC;QAC5B,OAAO,EAAE,cAAc,CAAC;QACxB,KAAK,EAAE,cAAc,CAAC;KACvB,CAAC,CAAC;CACJ,CAAC;AAoBF;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,CAc1E;AAED;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,YAAY,GACpB,OAAO,CAAC,WAAW,CAAC,CAItB;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,YAAY,EACrB,MAAM,EAAE,SAAS,GAAG,OAAO,EAC3B,KAAK,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GACzC,IAAI,CAeN;AA8BD,wBAAgB,uBAAuB,IAAI,IAAI,CAM9C"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import logger, { serializeError } from "../logger.js";
|
|
2
|
+
const PERSIST_THROTTLE_MS = 5_000;
|
|
3
|
+
// Module-level singleton: storage.ts and upload.ts each create their own
|
|
4
|
+
// CloudStorage instance, so the shared aggregate cannot live on the class
|
|
5
|
+
let statsPromise = null;
|
|
6
|
+
let persistTimer = null;
|
|
7
|
+
async function recompute(backend) {
|
|
8
|
+
const { storage, cache } = await backend.computeBucketStats();
|
|
9
|
+
const stats = {
|
|
10
|
+
storage,
|
|
11
|
+
cache,
|
|
12
|
+
updatedAt: new Date().toISOString(),
|
|
13
|
+
};
|
|
14
|
+
await backend.persistStats(stats);
|
|
15
|
+
return stats;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Returns the tracked aggregate stats, loading them from the persisted
|
|
19
|
+
* bucket object on first call. Falls back to a one-time full recomputation
|
|
20
|
+
* (recursive listing) when no persisted stats exist yet.
|
|
21
|
+
*/
|
|
22
|
+
export function getBucketStats(backend) {
|
|
23
|
+
if (!statsPromise) {
|
|
24
|
+
const promise = (async () => {
|
|
25
|
+
const persisted = await backend.loadPersistedStats();
|
|
26
|
+
return persisted ?? (await recompute(backend));
|
|
27
|
+
})();
|
|
28
|
+
promise.catch(() => {
|
|
29
|
+
if (statsPromise === promise) {
|
|
30
|
+
statsPromise = null;
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
statsPromise = promise;
|
|
34
|
+
}
|
|
35
|
+
return statsPromise;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Forces a full recomputation from bucket listings and persists the result.
|
|
39
|
+
* Reconciles any drift accumulated by the incremental adjustments (e.g.
|
|
40
|
+
* objects modified outside the app, or a crash before a persist flush).
|
|
41
|
+
* Keeps the previous stats when the recomputation fails.
|
|
42
|
+
*/
|
|
43
|
+
export async function recalculateBucketStats(backend) {
|
|
44
|
+
const stats = await recompute(backend);
|
|
45
|
+
statsPromise = Promise.resolve(stats);
|
|
46
|
+
return stats;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Applies an incremental delta to the tracked stats after a bucket mutation
|
|
50
|
+
* (upload, delete, ...). Fire-and-forget: callers never wait on it and it
|
|
51
|
+
* never throws, so stats tracking cannot break the mutation itself.
|
|
52
|
+
*/
|
|
53
|
+
export function adjustBucketStats(backend, target, delta) {
|
|
54
|
+
void getBucketStats(backend)
|
|
55
|
+
.then((stats) => {
|
|
56
|
+
const aggregate = stats[target];
|
|
57
|
+
aggregate.size = Math.max(0, aggregate.size + delta.size);
|
|
58
|
+
aggregate.fileCount = Math.max(0, aggregate.fileCount + delta.fileCount);
|
|
59
|
+
stats.updatedAt = new Date().toISOString();
|
|
60
|
+
schedulePersist(backend);
|
|
61
|
+
})
|
|
62
|
+
.catch((error) => {
|
|
63
|
+
logger.warn({ error: serializeError(error), target, delta }, "Failed to adjust bucket stats");
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Throttled persistence: bursts of mutations (bulk uploads/deletes) produce
|
|
68
|
+
* at most one stats write per window instead of one per object
|
|
69
|
+
*/
|
|
70
|
+
function schedulePersist(backend) {
|
|
71
|
+
if (persistTimer) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
persistTimer = setTimeout(() => {
|
|
75
|
+
persistTimer = null;
|
|
76
|
+
const current = statsPromise;
|
|
77
|
+
if (!current) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
void current
|
|
81
|
+
.then((stats) => backend.persistStats(stats))
|
|
82
|
+
.catch((error) => {
|
|
83
|
+
logger.warn({ error: serializeError(error) }, "Failed to persist bucket stats");
|
|
84
|
+
});
|
|
85
|
+
}, PERSIST_THROTTLE_MS);
|
|
86
|
+
// Don't keep the process alive just to flush stats; reconciliation
|
|
87
|
+
// covers any write lost to a shutdown
|
|
88
|
+
persistTimer.unref?.();
|
|
89
|
+
}
|
|
90
|
+
export function resetBucketStatsTracker() {
|
|
91
|
+
statsPromise = null;
|
|
92
|
+
if (persistTimer) {
|
|
93
|
+
clearTimeout(persistTimer);
|
|
94
|
+
persistTimer = null;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=stats-tracker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stats-tracker.js","sourceRoot":"","sources":["../../../src/utils/storage/stats-tracker.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/utils/storage/types.ts"],"names":[],"mappings":"AACA,YAAY,EACV,aAAa,EACb,oBAAoB,EACpB,UAAU,EACX,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/utils/storage/types.ts"],"names":[],"mappings":""}
|