@critical-path/core 0.30.0 → 0.32.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/CHANGELOG.md +28 -0
- package/README.md +10 -1
- package/dist/engine/authorization.test.js +8 -4
- package/dist/engine/authorization.test.js.map +1 -1
- package/dist/engine/config.test.d.ts +2 -0
- package/dist/engine/config.test.d.ts.map +1 -0
- package/dist/engine/config.test.js +46 -0
- package/dist/engine/config.test.js.map +1 -0
- package/dist/engine/index.d.ts +22 -3
- package/dist/engine/index.d.ts.map +1 -1
- package/dist/engine/index.js +60 -16
- package/dist/engine/index.js.map +1 -1
- package/dist/schemas/index.d.ts +9 -11
- package/dist/schemas/index.d.ts.map +1 -1
- package/dist/schemas/index.js +3 -3
- package/dist/schemas/index.js.map +1 -1
- package/dist/storage/file-storage.d.ts +10 -0
- package/dist/storage/file-storage.d.ts.map +1 -1
- package/dist/storage/file-storage.js +40 -4
- package/dist/storage/file-storage.js.map +1 -1
- package/dist/storage/firebase-storage.d.ts.map +1 -1
- package/dist/storage/firebase-storage.js +10 -13
- package/dist/storage/firebase-storage.js.map +1 -1
- package/dist/storage/s3.d.ts +46 -18
- package/dist/storage/s3.d.ts.map +1 -1
- package/dist/storage/s3.js +59 -89
- package/dist/storage/s3.js.map +1 -1
- package/dist/storage/storage.test.js +88 -27
- package/dist/storage/storage.test.js.map +1 -1
- package/dist/types/index.d.ts +12 -1
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/engine/authorization.test.ts +13 -5
- package/src/engine/config.test.ts +51 -0
- package/src/engine/index.ts +67 -18
- package/src/schemas/index.ts +3 -3
- package/src/storage/file-storage.ts +44 -4
- package/src/storage/firebase-storage.ts +10 -13
- package/src/storage/s3.ts +98 -101
- package/src/storage/storage.test.ts +86 -28
- package/src/types/index.ts +12 -1
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -1,3 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builds a storage key `<prefix>/<timestamp>_<random>_<filename>`. The prefix is validated (no
|
|
3
|
+
* `.`/`..` segments, no leading slash, safe characters only) so callers cannot write outside it.
|
|
4
|
+
*/
|
|
5
|
+
export function buildStorageKey(pathPrefix, filename) {
|
|
6
|
+
let prefix = '';
|
|
7
|
+
if (pathPrefix) {
|
|
8
|
+
const trimmed = pathPrefix.replace(/\/+$/, '');
|
|
9
|
+
const segments = trimmed.split('/');
|
|
10
|
+
if (trimmed.startsWith('/') ||
|
|
11
|
+
segments.some((segment) => segment === '' || segment === '.' || segment === '..' || !/^[A-Za-z0-9._-]+$/.test(segment))) {
|
|
12
|
+
throw new Error(`Invalid storage path prefix "${pathPrefix}".`);
|
|
13
|
+
}
|
|
14
|
+
prefix = `${trimmed}/`;
|
|
15
|
+
}
|
|
16
|
+
const random = Array.from(crypto.getRandomValues(new Uint8Array(6)), (b) => b.toString(16).padStart(2, '0')).join('');
|
|
17
|
+
const safeName = filename.replace(/[^a-zA-Z0-9._-]/g, '_').replace(/^\.+/, '_') || 'file';
|
|
18
|
+
return `${prefix}${Date.now()}_${random}_${safeName}`;
|
|
19
|
+
}
|
|
20
|
+
/** Content types a browser would execute or render as a page if opened from the storage host. */
|
|
21
|
+
const ACTIVE_CONTENT_TYPES = new Set([
|
|
22
|
+
'text/html',
|
|
23
|
+
'application/xhtml+xml',
|
|
24
|
+
'image/svg+xml',
|
|
25
|
+
'text/javascript',
|
|
26
|
+
'application/javascript',
|
|
27
|
+
'text/xml',
|
|
28
|
+
'application/xml'
|
|
29
|
+
]);
|
|
30
|
+
/**
|
|
31
|
+
* `Content-Disposition` for stored files: active content (HTML, SVG, scripts) is forced to
|
|
32
|
+
* download so a stored file cannot run script on the storage origin.
|
|
33
|
+
*/
|
|
34
|
+
export function contentDispositionFor(mimeType, filename) {
|
|
35
|
+
const base = mimeType.split(';')[0].trim().toLowerCase();
|
|
36
|
+
if (!ACTIVE_CONTENT_TYPES.has(base))
|
|
37
|
+
return undefined;
|
|
38
|
+
return `attachment; filename="${filename.replace(/["\\\r\n]/g, '_')}"`;
|
|
39
|
+
}
|
|
1
40
|
export function normalizeUploadData(data, encoding, mimeType) {
|
|
2
41
|
if (data instanceof Uint8Array) {
|
|
3
42
|
return data;
|
|
@@ -65,10 +104,7 @@ export class InMemoryFileStore {
|
|
|
65
104
|
this.publicBaseUrl = options.publicUrlBase || options.publicBaseUrl || 'memory://attachments';
|
|
66
105
|
}
|
|
67
106
|
async upload(input) {
|
|
68
|
-
const
|
|
69
|
-
const randomId = Math.random().toString(36).substring(2, 9);
|
|
70
|
-
const sanitizedFilename = input.filename.replace(/[^a-zA-Z0-9._-]/g, '_');
|
|
71
|
-
const storageKey = `${prefix}${Date.now()}_${randomId}_${sanitizedFilename}`;
|
|
107
|
+
const storageKey = buildStorageKey(input.pathPrefix, input.filename);
|
|
72
108
|
const buffer = normalizeUploadData(input.data, input.encoding, input.mimeType);
|
|
73
109
|
const mimeType = input.mimeType || 'application/octet-stream';
|
|
74
110
|
const sizeBytes = buffer.byteLength;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-storage.js","sourceRoot":"","sources":["../../src/storage/file-storage.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"file-storage.js","sourceRoot":"","sources":["../../src/storage/file-storage.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"firebase-storage.d.ts","sourceRoot":"","sources":["../../src/storage/firebase-storage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,kBAAkB,EAClB,eAAe,EACf,gBAAgB,EAChB,mBAAmB,EACnB,qBAAqB,EACtB,MAAM,mBAAmB,CAAC;AAG3B,MAAM,WAAW,8BAA8B;IAC7C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG;QAClB,IAAI,CACF,IAAI,EAAE,UAAU,GAAG,MAAM,GAAG,MAAM,EAClC,OAAO,CAAC,EAAE;YAAE,QAAQ,CAAC,EAAE;gBAAE,WAAW,CAAC,EAAE,MAAM,CAAC;gBAAC,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;aAAE,CAAC;YAAC,SAAS,CAAC,EAAE,OAAO,CAAA;SAAE,GACzF,OAAO,CAAC,IAAI,CAAC,CAAC;QACjB,MAAM,CAAC,OAAO,CAAC,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;QACpC,YAAY,CAAC,CAAC,MAAM,EAAE;YAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;YAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;YAAC,WAAW,CAAC,EAAE,MAAM,CAAA;SAAE,GAAG,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;QAC9H,SAAS,CAAC,IAAI,MAAM,CAAC;KACtB,CAAC;CACH;AAED,qBAAa,2BAA4B,YAAW,8BAA8B;IAChF,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,KAAK,CAAgF;gBAEjF,IAAI,GAAE,MAA+B;IAIjD,IAAI,CAAC,IAAI,EAAE,MAAM;mBAII,UAAU,GAAG,MAAM,GAAG,MAAM,YAAY,GAAG;;oBAoB1C,OAAO,CAAC,CAAC,UAAU,CAAC,CAAC;uBAKlB,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC;6BASR,GAAG,GAAG,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC;;;CAUvD;AAED,MAAM,WAAW,qBAAqB;IACpC,MAAM,CAAC,EAAE,8BAA8B,CAAC;IACxC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,qBAAa,sBAAuB,YAAW,kBAAkB;IAC/D,OAAO,CAAC,MAAM,CAAiC;IAC/C,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,aAAa,CAAC,CAAS;gBAEnB,MAAM,GAAE,qBAA0B;
|
|
1
|
+
{"version":3,"file":"firebase-storage.d.ts","sourceRoot":"","sources":["../../src/storage/firebase-storage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,kBAAkB,EAClB,eAAe,EACf,gBAAgB,EAChB,mBAAmB,EACnB,qBAAqB,EACtB,MAAM,mBAAmB,CAAC;AAG3B,MAAM,WAAW,8BAA8B;IAC7C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG;QAClB,IAAI,CACF,IAAI,EAAE,UAAU,GAAG,MAAM,GAAG,MAAM,EAClC,OAAO,CAAC,EAAE;YAAE,QAAQ,CAAC,EAAE;gBAAE,WAAW,CAAC,EAAE,MAAM,CAAC;gBAAC,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;aAAE,CAAC;YAAC,SAAS,CAAC,EAAE,OAAO,CAAA;SAAE,GACzF,OAAO,CAAC,IAAI,CAAC,CAAC;QACjB,MAAM,CAAC,OAAO,CAAC,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;QACpC,YAAY,CAAC,CAAC,MAAM,EAAE;YAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;YAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;YAAC,WAAW,CAAC,EAAE,MAAM,CAAA;SAAE,GAAG,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;QAC9H,SAAS,CAAC,IAAI,MAAM,CAAC;KACtB,CAAC;CACH;AAED,qBAAa,2BAA4B,YAAW,8BAA8B;IAChF,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,KAAK,CAAgF;gBAEjF,IAAI,GAAE,MAA+B;IAIjD,IAAI,CAAC,IAAI,EAAE,MAAM;mBAII,UAAU,GAAG,MAAM,GAAG,MAAM,YAAY,GAAG;;oBAoB1C,OAAO,CAAC,CAAC,UAAU,CAAC,CAAC;uBAKlB,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC;6BASR,GAAG,GAAG,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC;;;CAUvD;AAED,MAAM,WAAW,qBAAqB;IACpC,MAAM,CAAC,EAAE,8BAA8B,CAAC;IACxC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,qBAAa,sBAAuB,YAAW,kBAAkB;IAC/D,OAAO,CAAC,MAAM,CAAiC;IAC/C,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,aAAa,CAAC,CAAS;gBAEnB,MAAM,GAAE,qBAA0B;IAa9C,OAAO,CAAC,YAAY;IAQd,MAAM,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAiCzD,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAU5C,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,UAAU,CAAC;IAe1D,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAcnD,qBAAqB,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,qBAAqB,CAAC;CAwB1F"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { normalizeUploadData } from './file-storage.js';
|
|
1
|
+
import { buildStorageKey, contentDispositionFor, normalizeUploadData } from './file-storage.js';
|
|
2
2
|
export class InMemoryFirebaseStorageMock {
|
|
3
3
|
name;
|
|
4
4
|
files = new Map();
|
|
@@ -63,7 +63,11 @@ export class FirebaseStorageAdapter {
|
|
|
63
63
|
bucketName;
|
|
64
64
|
publicUrlBase;
|
|
65
65
|
constructor(config = {}) {
|
|
66
|
-
|
|
66
|
+
if (!config.bucket) {
|
|
67
|
+
// Never fall back to an in-memory mock silently: files would vanish on restart.
|
|
68
|
+
throw new Error('FirebaseStorageAdapter requires a "bucket" (e.g. getStorage().bucket()). Use InMemoryFirebaseStorageMock in tests.');
|
|
69
|
+
}
|
|
70
|
+
this.bucket = config.bucket;
|
|
67
71
|
this.bucketName = config.bucketName || this.bucket.name || 'default-bucket';
|
|
68
72
|
if (this.bucket && config.bucketName && this.bucket.name !== config.bucketName) {
|
|
69
73
|
this.bucket.name = config.bucketName;
|
|
@@ -78,10 +82,7 @@ export class FirebaseStorageAdapter {
|
|
|
78
82
|
return `https://firebasestorage.googleapis.com/v0/b/${encodeURIComponent(this.bucketName)}/o/${encodeURIComponent(storageKey)}?alt=media${tokenParam}`;
|
|
79
83
|
}
|
|
80
84
|
async upload(input) {
|
|
81
|
-
const
|
|
82
|
-
const randomId = Math.random().toString(36).substring(2, 9);
|
|
83
|
-
const sanitizedFilename = input.filename.replace(/[^a-zA-Z0-9._-]/g, '_');
|
|
84
|
-
const storageKey = `${prefix}${Date.now()}_${randomId}_${sanitizedFilename}`;
|
|
85
|
+
const storageKey = buildStorageKey(input.pathPrefix, input.filename);
|
|
85
86
|
const bodyData = normalizeUploadData(input.data, input.encoding, input.mimeType);
|
|
86
87
|
const mimeType = input.mimeType || 'application/octet-stream';
|
|
87
88
|
const sizeBytes = bodyData.byteLength;
|
|
@@ -92,6 +93,7 @@ export class FirebaseStorageAdapter {
|
|
|
92
93
|
await fileRef.save(bodyData, {
|
|
93
94
|
metadata: {
|
|
94
95
|
contentType: mimeType,
|
|
96
|
+
...(contentDispositionFor(mimeType, input.filename) ? { contentDisposition: contentDispositionFor(mimeType, input.filename) } : {}),
|
|
95
97
|
metadata: {
|
|
96
98
|
firebaseStorageDownloadTokens: downloadToken
|
|
97
99
|
}
|
|
@@ -162,13 +164,8 @@ export class FirebaseStorageAdapter {
|
|
|
162
164
|
headers: options.contentType ? { 'Content-Type': options.contentType } : {}
|
|
163
165
|
};
|
|
164
166
|
}
|
|
165
|
-
//
|
|
166
|
-
|
|
167
|
-
uploadUrl: this.getPublicUrl(storageKey),
|
|
168
|
-
storageKey,
|
|
169
|
-
method: 'PUT',
|
|
170
|
-
headers: options.contentType ? { 'Content-Type': options.contentType } : {}
|
|
171
|
-
};
|
|
167
|
+
// A public URL is not an upload credential; refuse rather than hand out a URL that cannot work.
|
|
168
|
+
throw new Error('FirebaseStorageAdapter cannot presign uploads: the bucket does not support getSignedUrl.');
|
|
172
169
|
}
|
|
173
170
|
}
|
|
174
171
|
//# sourceMappingURL=firebase-storage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"firebase-storage.js","sourceRoot":"","sources":["../../src/storage/firebase-storage.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"firebase-storage.js","sourceRoot":"","sources":["../../src/storage/firebase-storage.ts"],"names":[],"mappings":"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"}
|
package/dist/storage/s3.d.ts
CHANGED
|
@@ -1,36 +1,64 @@
|
|
|
1
1
|
import type { FileStorageAdapter, UploadFileInput, UploadFileResult, PresignedUrlOptions, PresignedUploadResult } from '../types/index.js';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
/** The subset of the AWS SDK v3 `S3Client` the adapter uses. */
|
|
3
|
+
export interface S3ClientLike {
|
|
4
|
+
send(command: unknown): Promise<unknown>;
|
|
5
|
+
}
|
|
6
|
+
type CommandClass = new (input: Record<string, unknown>) => unknown;
|
|
7
|
+
/**
|
|
8
|
+
* Command classes from `@aws-sdk/client-s3`, passed in so `@critical-path/core` has no AWS
|
|
9
|
+
* dependency: `{ PutObjectCommand, DeleteObjectCommand, GetObjectCommand }`.
|
|
10
|
+
*/
|
|
11
|
+
export interface S3Commands {
|
|
12
|
+
PutObjectCommand: CommandClass;
|
|
13
|
+
DeleteObjectCommand: CommandClass;
|
|
14
|
+
/** Needed for signed download URLs (private buckets). */
|
|
15
|
+
GetObjectCommand?: CommandClass;
|
|
7
16
|
}
|
|
8
17
|
export interface S3StorageConfig {
|
|
9
18
|
bucket: string;
|
|
10
19
|
region?: string;
|
|
20
|
+
/** Custom endpoint for S3-compatible services (MinIO, R2, LocalStack). */
|
|
11
21
|
endpoint?: string;
|
|
12
|
-
|
|
13
|
-
secretAccessKey?: string;
|
|
14
|
-
sessionToken?: string;
|
|
22
|
+
/** Base URL for public object links (e.g. a CDN). */
|
|
15
23
|
publicUrlBase?: string;
|
|
16
24
|
forcePathStyle?: boolean;
|
|
17
|
-
|
|
25
|
+
/** An AWS SDK v3 `S3Client` (or compatible). Required for uploads and deletes. */
|
|
26
|
+
client?: S3ClientLike;
|
|
27
|
+
commands?: S3Commands;
|
|
28
|
+
/**
|
|
29
|
+
* Signs a command into a URL, typically
|
|
30
|
+
* `(command, { expiresIn }) => getSignedUrl(client, command, { expiresIn })` from
|
|
31
|
+
* `@aws-sdk/s3-request-presigner`. Required for presigned uploads and signed downloads.
|
|
32
|
+
*/
|
|
33
|
+
presign?: (command: unknown, options: {
|
|
34
|
+
expiresIn: number;
|
|
35
|
+
}) => Promise<string>;
|
|
36
|
+
/**
|
|
37
|
+
* Serve downloads through signed URLs instead of public object URLs (for private buckets).
|
|
38
|
+
* Requires `presign` and `commands.GetObjectCommand`. Default `false`.
|
|
39
|
+
*/
|
|
40
|
+
signedDownloads?: boolean;
|
|
41
|
+
/** Lifetime of signed download URLs in seconds. Default 3600. */
|
|
42
|
+
downloadUrlExpiresIn?: number;
|
|
18
43
|
}
|
|
44
|
+
/**
|
|
45
|
+
* Stores attachments in Amazon S3 (or an S3-compatible service) using the AWS SDK v3 client
|
|
46
|
+
* you provide. Errors from S3 propagate; nothing is reported as stored unless S3 accepted it.
|
|
47
|
+
*/
|
|
19
48
|
export declare class S3StorageAdapter implements FileStorageAdapter {
|
|
20
|
-
private bucket;
|
|
21
|
-
private
|
|
22
|
-
private
|
|
23
|
-
private
|
|
24
|
-
private
|
|
25
|
-
private sessionToken?;
|
|
26
|
-
private publicUrlBase?;
|
|
27
|
-
private forcePathStyle;
|
|
28
|
-
private s3Client?;
|
|
49
|
+
private readonly bucket;
|
|
50
|
+
private readonly endpoint;
|
|
51
|
+
private readonly publicUrlBase?;
|
|
52
|
+
private readonly forcePathStyle;
|
|
53
|
+
private readonly config;
|
|
29
54
|
constructor(config: S3StorageConfig);
|
|
55
|
+
private requireClient;
|
|
30
56
|
private getObjectUrl;
|
|
31
57
|
upload(input: UploadFileInput): Promise<UploadFileResult>;
|
|
58
|
+
/** Deletes an object. S3 deletes are idempotent, so a missing object still returns `true`. */
|
|
32
59
|
delete(storageKey: string): Promise<boolean>;
|
|
33
60
|
getDownloadUrl(storageKey: string): Promise<string>;
|
|
34
61
|
getPresignedUploadUrl(options: PresignedUrlOptions): Promise<PresignedUploadResult>;
|
|
35
62
|
}
|
|
63
|
+
export {};
|
|
36
64
|
//# sourceMappingURL=s3.d.ts.map
|
package/dist/storage/s3.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"s3.d.ts","sourceRoot":"","sources":["../../src/storage/s3.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,kBAAkB,EAClB,eAAe,EACf,gBAAgB,EAChB,mBAAmB,EACnB,qBAAqB,EACtB,MAAM,mBAAmB,CAAC;AAG3B,MAAM,WAAW,
|
|
1
|
+
{"version":3,"file":"s3.d.ts","sourceRoot":"","sources":["../../src/storage/s3.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,kBAAkB,EAClB,eAAe,EACf,gBAAgB,EAChB,mBAAmB,EACnB,qBAAqB,EACtB,MAAM,mBAAmB,CAAC;AAG3B,gEAAgE;AAChE,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC1C;AAED,KAAK,YAAY,GAAG,KAAK,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC;AAEpE;;;GAGG;AACH,MAAM,WAAW,UAAU;IACzB,gBAAgB,EAAE,YAAY,CAAC;IAC/B,mBAAmB,EAAE,YAAY,CAAC;IAClC,yDAAyD;IACzD,gBAAgB,CAAC,EAAE,YAAY,CAAC;CACjC;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,qDAAqD;IACrD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,kFAAkF;IAClF,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,QAAQ,CAAC,EAAE,UAAU,CAAC;IACtB;;;;OAIG;IACH,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAChF;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,iEAAiE;IACjE,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED;;;GAGG;AACH,qBAAa,gBAAiB,YAAW,kBAAkB;IACzD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAS;IACxC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAU;IACzC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkB;gBAE7B,MAAM,EAAE,eAAe;IAmBnC,OAAO,CAAC,aAAa;IAOrB,OAAO,CAAC,YAAY;IAOd,MAAM,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAoB/D,8FAA8F;IACxF,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAM5C,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAQnD,qBAAqB,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,qBAAqB,CAAC;CAkB1F"}
|
package/dist/storage/s3.js
CHANGED
|
@@ -1,120 +1,90 @@
|
|
|
1
|
-
import { normalizeUploadData } from './file-storage.js';
|
|
1
|
+
import { buildStorageKey, contentDispositionFor, normalizeUploadData } from './file-storage.js';
|
|
2
|
+
/**
|
|
3
|
+
* Stores attachments in Amazon S3 (or an S3-compatible service) using the AWS SDK v3 client
|
|
4
|
+
* you provide. Errors from S3 propagate; nothing is reported as stored unless S3 accepted it.
|
|
5
|
+
*/
|
|
2
6
|
export class S3StorageAdapter {
|
|
3
7
|
bucket;
|
|
4
|
-
region;
|
|
5
8
|
endpoint;
|
|
6
|
-
accessKeyId;
|
|
7
|
-
secretAccessKey;
|
|
8
|
-
sessionToken;
|
|
9
9
|
publicUrlBase;
|
|
10
10
|
forcePathStyle;
|
|
11
|
-
|
|
11
|
+
config;
|
|
12
12
|
constructor(config) {
|
|
13
13
|
if (!config.bucket) {
|
|
14
14
|
throw new Error('S3StorageAdapter requires a "bucket" name in its config.');
|
|
15
15
|
}
|
|
16
|
+
if (config.client && !config.commands) {
|
|
17
|
+
throw new Error('S3StorageAdapter needs "commands" ({ PutObjectCommand, DeleteObjectCommand }) from @aws-sdk/client-s3 when a client is given.');
|
|
18
|
+
}
|
|
19
|
+
if (config.signedDownloads && (!config.presign || !config.commands?.GetObjectCommand)) {
|
|
20
|
+
throw new Error('S3StorageAdapter signedDownloads requires "presign" and "commands.GetObjectCommand".');
|
|
21
|
+
}
|
|
22
|
+
this.config = config;
|
|
16
23
|
this.bucket = config.bucket;
|
|
17
|
-
|
|
18
|
-
this.endpoint = (config.endpoint || `https://s3.${
|
|
19
|
-
this.accessKeyId = config.accessKeyId;
|
|
20
|
-
this.secretAccessKey = config.secretAccessKey;
|
|
21
|
-
this.sessionToken = config.sessionToken;
|
|
24
|
+
const region = config.region || 'us-east-1';
|
|
25
|
+
this.endpoint = (config.endpoint || `https://s3.${region}.amazonaws.com`).replace(/\/+$/, '');
|
|
22
26
|
this.publicUrlBase = config.publicUrlBase?.replace(/\/+$/, '');
|
|
23
|
-
this.forcePathStyle =
|
|
24
|
-
|
|
27
|
+
this.forcePathStyle =
|
|
28
|
+
config.forcePathStyle ?? (this.endpoint.includes('localhost') || this.endpoint.includes('127.0.0.1'));
|
|
25
29
|
}
|
|
26
|
-
|
|
27
|
-
if (this.
|
|
28
|
-
|
|
30
|
+
requireClient(operation) {
|
|
31
|
+
if (!this.config.client || !this.config.commands) {
|
|
32
|
+
throw new Error(`S3StorageAdapter cannot ${operation}: configure "client" and "commands".`);
|
|
29
33
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
const
|
|
34
|
-
|
|
34
|
+
return { client: this.config.client, commands: this.config.commands };
|
|
35
|
+
}
|
|
36
|
+
getObjectUrl(storageKey) {
|
|
37
|
+
const path = encodeURIComponent(storageKey).replace(/%2F/g, '/');
|
|
38
|
+
if (this.publicUrlBase)
|
|
39
|
+
return `${this.publicUrlBase}/${path}`;
|
|
40
|
+
if (this.forcePathStyle)
|
|
41
|
+
return `${this.endpoint}/${this.bucket}/${path}`;
|
|
42
|
+
return `${this.endpoint.replace('://', `://${this.bucket}.`)}/${path}`;
|
|
35
43
|
}
|
|
36
44
|
async upload(input) {
|
|
37
|
-
const
|
|
38
|
-
const
|
|
39
|
-
const
|
|
40
|
-
const storageKey = `${prefix}${Date.now()}_${randomId}_${sanitizedFilename}`;
|
|
41
|
-
const bodyData = normalizeUploadData(input.data, input.encoding, input.mimeType);
|
|
45
|
+
const { client, commands } = this.requireClient('upload');
|
|
46
|
+
const storageKey = buildStorageKey(input.pathPrefix, input.filename);
|
|
47
|
+
const body = normalizeUploadData(input.data, input.encoding, input.mimeType);
|
|
42
48
|
const mimeType = input.mimeType || 'application/octet-stream';
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
Body: bodyData,
|
|
53
|
-
ContentType: mimeType
|
|
54
|
-
}
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
else if (typeof this.s3Client.putObject === 'function') {
|
|
58
|
-
await this.s3Client.putObject({
|
|
59
|
-
Bucket: this.bucket,
|
|
60
|
-
Key: storageKey,
|
|
61
|
-
Body: bodyData,
|
|
62
|
-
ContentType: mimeType
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
catch {
|
|
67
|
-
// Fallback
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
return {
|
|
71
|
-
storageKey,
|
|
72
|
-
url,
|
|
73
|
-
sizeBytes,
|
|
74
|
-
mimeType
|
|
75
|
-
};
|
|
49
|
+
const disposition = contentDispositionFor(mimeType, input.filename);
|
|
50
|
+
await client.send(new commands.PutObjectCommand({
|
|
51
|
+
Bucket: this.bucket,
|
|
52
|
+
Key: storageKey,
|
|
53
|
+
Body: body,
|
|
54
|
+
ContentType: mimeType,
|
|
55
|
+
...(disposition ? { ContentDisposition: disposition } : {})
|
|
56
|
+
}));
|
|
57
|
+
return { storageKey, url: await this.getDownloadUrl(storageKey), sizeBytes: body.byteLength, mimeType };
|
|
76
58
|
}
|
|
59
|
+
/** Deletes an object. S3 deletes are idempotent, so a missing object still returns `true`. */
|
|
77
60
|
async delete(storageKey) {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
if (typeof this.s3Client.send === 'function') {
|
|
81
|
-
await this.s3Client.send({
|
|
82
|
-
input: {
|
|
83
|
-
Bucket: this.bucket,
|
|
84
|
-
Key: storageKey
|
|
85
|
-
}
|
|
86
|
-
});
|
|
87
|
-
return true;
|
|
88
|
-
}
|
|
89
|
-
else if (typeof this.s3Client.deleteObject === 'function') {
|
|
90
|
-
await this.s3Client.deleteObject({
|
|
91
|
-
Bucket: this.bucket,
|
|
92
|
-
Key: storageKey
|
|
93
|
-
});
|
|
94
|
-
return true;
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
catch {
|
|
98
|
-
return false;
|
|
99
|
-
}
|
|
100
|
-
}
|
|
61
|
+
const { client, commands } = this.requireClient('delete');
|
|
62
|
+
await client.send(new commands.DeleteObjectCommand({ Bucket: this.bucket, Key: storageKey }));
|
|
101
63
|
return true;
|
|
102
64
|
}
|
|
103
65
|
async getDownloadUrl(storageKey) {
|
|
66
|
+
if (this.config.signedDownloads) {
|
|
67
|
+
const command = new this.config.commands.GetObjectCommand({ Bucket: this.bucket, Key: storageKey });
|
|
68
|
+
return this.config.presign(command, { expiresIn: this.config.downloadUrlExpiresIn ?? 3600 });
|
|
69
|
+
}
|
|
104
70
|
return this.getObjectUrl(storageKey);
|
|
105
71
|
}
|
|
106
72
|
async getPresignedUploadUrl(options) {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
const headers = {};
|
|
110
|
-
if (options.contentType) {
|
|
111
|
-
headers['Content-Type'] = options.contentType;
|
|
73
|
+
if (!this.config.presign || !this.config.commands) {
|
|
74
|
+
throw new Error('S3StorageAdapter cannot presign uploads: configure "presign" and "commands".');
|
|
112
75
|
}
|
|
76
|
+
const command = new this.config.commands.PutObjectCommand({
|
|
77
|
+
Bucket: this.bucket,
|
|
78
|
+
Key: options.storageKey,
|
|
79
|
+
...(options.contentType ? { ContentType: options.contentType } : {})
|
|
80
|
+
});
|
|
81
|
+
const uploadUrl = await this.config.presign(command, { expiresIn: options.expiresInSeconds ?? 900 });
|
|
113
82
|
return {
|
|
114
83
|
uploadUrl,
|
|
115
|
-
storageKey,
|
|
84
|
+
storageKey: options.storageKey,
|
|
116
85
|
method: 'PUT',
|
|
117
|
-
|
|
86
|
+
// The signature covers Content-Type, so the uploader must send exactly this header.
|
|
87
|
+
headers: options.contentType ? { 'Content-Type': options.contentType } : {}
|
|
118
88
|
};
|
|
119
89
|
}
|
|
120
90
|
}
|
package/dist/storage/s3.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"s3.js","sourceRoot":"","sources":["../../src/storage/s3.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"s3.js","sourceRoot":"","sources":["../../src/storage/s3.ts"],"names":[],"mappings":"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"}
|