@adonis-agora/media 0.8.2 → 0.10.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.
Files changed (110) hide show
  1. package/CHANGELOG.md +88 -0
  2. package/README.md +2 -2
  3. package/dist/providers/media_provider.d.ts.map +1 -1
  4. package/dist/providers/media_provider.js +138 -0
  5. package/dist/providers/media_provider.js.map +1 -1
  6. package/dist/src/content_type.d.ts +6 -1
  7. package/dist/src/content_type.d.ts.map +1 -1
  8. package/dist/src/content_type.js +102 -7
  9. package/dist/src/content_type.js.map +1 -1
  10. package/dist/src/define_config.d.ts +104 -5
  11. package/dist/src/define_config.d.ts.map +1 -1
  12. package/dist/src/define_config.js +7 -2
  13. package/dist/src/define_config.js.map +1 -1
  14. package/dist/src/diagnostics.d.ts +7 -0
  15. package/dist/src/diagnostics.d.ts.map +1 -1
  16. package/dist/src/diagnostics.js +20 -0
  17. package/dist/src/diagnostics.js.map +1 -1
  18. package/dist/src/direct_upload.d.ts +177 -0
  19. package/dist/src/direct_upload.d.ts.map +1 -0
  20. package/dist/src/direct_upload.js +299 -0
  21. package/dist/src/direct_upload.js.map +1 -0
  22. package/dist/src/direct_upload_handler.d.ts +117 -0
  23. package/dist/src/direct_upload_handler.d.ts.map +1 -0
  24. package/dist/src/direct_upload_handler.js +277 -0
  25. package/dist/src/direct_upload_handler.js.map +1 -0
  26. package/dist/src/disks/factory.d.ts +11 -3
  27. package/dist/src/disks/factory.d.ts.map +1 -1
  28. package/dist/src/disks/factory.js +5 -3
  29. package/dist/src/disks/factory.js.map +1 -1
  30. package/dist/src/disks/s3.d.ts +10 -0
  31. package/dist/src/disks/s3.d.ts.map +1 -1
  32. package/dist/src/disks/s3.js +96 -22
  33. package/dist/src/disks/s3.js.map +1 -1
  34. package/dist/src/disks/sigv4.d.ts +58 -0
  35. package/dist/src/disks/sigv4.d.ts.map +1 -0
  36. package/dist/src/disks/sigv4.js +87 -0
  37. package/dist/src/disks/sigv4.js.map +1 -0
  38. package/dist/src/disks/xml_fallback.d.ts +3 -3
  39. package/dist/src/disks/xml_fallback.js +3 -3
  40. package/dist/src/errors.d.ts +104 -0
  41. package/dist/src/errors.d.ts.map +1 -1
  42. package/dist/src/errors.js +145 -0
  43. package/dist/src/errors.js.map +1 -1
  44. package/dist/src/hls/delivery.d.ts +112 -0
  45. package/dist/src/hls/delivery.d.ts.map +1 -0
  46. package/dist/src/hls/delivery.js +118 -0
  47. package/dist/src/hls/delivery.js.map +1 -0
  48. package/dist/src/hls/playlist.d.ts +67 -0
  49. package/dist/src/hls/playlist.d.ts.map +1 -0
  50. package/dist/src/hls/playlist.js +126 -0
  51. package/dist/src/hls/playlist.js.map +1 -0
  52. package/dist/src/index.d.ts +19 -4
  53. package/dist/src/index.d.ts.map +1 -1
  54. package/dist/src/index.js +13 -2
  55. package/dist/src/index.js.map +1 -1
  56. package/dist/src/media_collection.d.ts +8 -1
  57. package/dist/src/media_collection.d.ts.map +1 -1
  58. package/dist/src/media_collection.js +23 -1
  59. package/dist/src/media_collection.js.map +1 -1
  60. package/dist/src/media_library.d.ts +32 -2
  61. package/dist/src/media_library.d.ts.map +1 -1
  62. package/dist/src/media_library.js +218 -11
  63. package/dist/src/media_library.js.map +1 -1
  64. package/dist/src/media_manager.d.ts +37 -2
  65. package/dist/src/media_manager.d.ts.map +1 -1
  66. package/dist/src/media_manager.js +54 -1
  67. package/dist/src/media_manager.js.map +1 -1
  68. package/dist/src/media_record.d.ts +22 -2
  69. package/dist/src/media_record.d.ts.map +1 -1
  70. package/dist/src/testing/fake_transformer.d.ts +32 -0
  71. package/dist/src/testing/fake_transformer.d.ts.map +1 -0
  72. package/dist/src/testing/fake_transformer.js +32 -0
  73. package/dist/src/testing/fake_transformer.js.map +1 -0
  74. package/dist/src/testing/index.d.ts +2 -0
  75. package/dist/src/testing/index.d.ts.map +1 -1
  76. package/dist/src/testing/index.js +1 -0
  77. package/dist/src/testing/index.js.map +1 -1
  78. package/dist/src/transformer.d.ts +111 -0
  79. package/dist/src/transformer.d.ts.map +1 -0
  80. package/dist/src/transformer.js +2 -0
  81. package/dist/src/transformer.js.map +1 -0
  82. package/dist/src/transformers/factory.d.ts +30 -0
  83. package/dist/src/transformers/factory.d.ts.map +1 -0
  84. package/dist/src/transformers/factory.js +34 -0
  85. package/dist/src/transformers/factory.js.map +1 -0
  86. package/dist/src/transformers/hls.d.ts +110 -0
  87. package/dist/src/transformers/hls.d.ts.map +1 -0
  88. package/dist/src/transformers/hls.js +111 -0
  89. package/dist/src/transformers/hls.js.map +1 -0
  90. package/dist/src/transformers/mediabunny.d.ts +5 -0
  91. package/dist/src/transformers/mediabunny.d.ts.map +1 -0
  92. package/dist/src/transformers/mediabunny.js +150 -0
  93. package/dist/src/transformers/mediabunny.js.map +1 -0
  94. package/dist/src/transformers/mediabunny_loader.d.ts +15 -0
  95. package/dist/src/transformers/mediabunny_loader.d.ts.map +1 -0
  96. package/dist/src/transformers/mediabunny_loader.js +21 -0
  97. package/dist/src/transformers/mediabunny_loader.js.map +1 -0
  98. package/dist/src/transformers/probe.d.ts +56 -0
  99. package/dist/src/transformers/probe.d.ts.map +1 -0
  100. package/dist/src/transformers/probe.js +32 -0
  101. package/dist/src/transformers/probe.js.map +1 -0
  102. package/dist/src/transformers/source_file.d.ts +20 -0
  103. package/dist/src/transformers/source_file.d.ts.map +1 -0
  104. package/dist/src/transformers/source_file.js +30 -0
  105. package/dist/src/transformers/source_file.js.map +1 -0
  106. package/dist/src/types.d.ts +80 -0
  107. package/dist/src/types.d.ts.map +1 -1
  108. package/dist/stubs/config/media.stub +12 -0
  109. package/package.json +11 -7
  110. package/LICENSE +0 -21
@@ -0,0 +1,277 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { traceMedia } from './diagnostics.js';
3
+ import { MimeNotAllowedError, UploadNotSupportedError, UploadPartOutOfRangeError, UploadPartSizeError, UploadPartsIncompleteError, UploadSessionExpiredError, UploadSessionNotFoundError, } from './errors.js';
4
+ /**
5
+ * HTTP half of the session-backed direct upload flow, mirroring {@link TusUploadHandler}: the core
6
+ * ({@link DirectUploadManager}) never sees HTTP, this class never sees a framework, and a thin
7
+ * AdonisJS route adapter maps `HttpContext` to {@link DirectUploadRequest}/{@link DirectUploadResponse}.
8
+ *
9
+ * The endpoint surface it expects to be mounted on (see the provider's `uploads.direct.routes`):
10
+ *
11
+ * - `POST /` → `initiate` — `201` + session id, part size, presigned URLs
12
+ * - `GET /:id` → `status` — confirmed ETags + fresh URLs for pending parts
13
+ * - `POST /:id/parts/:partNumber` → `confirm-part` — record one uploaded part's ETag
14
+ * - `POST /:id/complete` → `complete` — assemble; `409` names any missing parts
15
+ * - `DELETE /:id` → `abort`
16
+ *
17
+ * **This handler performs NO authorization** — the same split as `TusUploadHandler` and
18
+ * `MediaDeliveryHandler`. Who may upload, and into whose namespace the key resolves, are questions
19
+ * only the app can answer: guard the route, and resolve the key server-side via {@link keyFor}
20
+ * (the client sends a `fileName`, never a key).
21
+ */
22
+ export class DirectUploadHandler {
23
+ manager;
24
+ disk;
25
+ collection;
26
+ maxSize;
27
+ keyFor;
28
+ newId;
29
+ policy;
30
+ adopt;
31
+ constructor(options) {
32
+ this.manager = options.manager;
33
+ this.disk = options.disk;
34
+ this.collection = options.collection;
35
+ this.maxSize = options.maxSize;
36
+ this.keyFor = options.keyFor ?? ((fileName, token) => `uploads/${token}/${fileName}`);
37
+ this.newId = options.idGenerator ?? (() => randomUUID());
38
+ this.policy = options.policy;
39
+ this.adopt = options.adopt;
40
+ if (this.policy && !this.adopt) {
41
+ throw new TypeError('DirectUploadHandler: "adopt" is required when a "policy" is configured');
42
+ }
43
+ }
44
+ async handle(req, ctx) {
45
+ switch (req.action) {
46
+ case 'initiate': {
47
+ if (typeof req.fileName !== 'string' || req.fileName.length === 0) {
48
+ return { status: 400, body: { error: 'fileName is required' } };
49
+ }
50
+ if (!Number.isInteger(req.size) || req.size <= 0) {
51
+ return { status: 400, body: { error: 'size must be a positive integer' } };
52
+ }
53
+ if (this.maxSize !== undefined && req.size > this.maxSize) {
54
+ return {
55
+ status: 413,
56
+ body: { error: `Upload exceeds the maximum size of ${this.maxSize} bytes` },
57
+ };
58
+ }
59
+ if (this.policy)
60
+ return this.initiatePolicy(req, ctx);
61
+ const metadata = req.metadata ?? {};
62
+ try {
63
+ const created = await this.manager.initiate({
64
+ key: this.keyFor(req.fileName, this.newId(), metadata),
65
+ size: req.size,
66
+ contentType: req.contentType,
67
+ metadata,
68
+ ...(this.disk !== undefined ? { disk: this.disk } : {}),
69
+ ...(this.collection !== undefined ? { collection: this.collection } : {}),
70
+ });
71
+ return { status: 201, body: this.initiateBody(created) };
72
+ }
73
+ catch (err) {
74
+ return this.mapError(err);
75
+ }
76
+ }
77
+ case 'status': {
78
+ try {
79
+ const status = await this.manager.status(req.uploadId);
80
+ return {
81
+ status: 200,
82
+ body: {
83
+ id: status.id,
84
+ key: status.key,
85
+ disk: status.disk,
86
+ partSize: status.partSize,
87
+ size: status.size,
88
+ totalParts: status.totalParts,
89
+ ...(status.contentType !== undefined ? { contentType: status.contentType } : {}),
90
+ completedParts: status.completedParts,
91
+ pendingParts: status.pendingParts,
92
+ ...(status.expiresAt !== undefined
93
+ ? { expiresAt: status.expiresAt.toISOString() }
94
+ : {}),
95
+ },
96
+ };
97
+ }
98
+ catch (err) {
99
+ return this.mapError(err);
100
+ }
101
+ }
102
+ case 'confirm-part': {
103
+ if (!Number.isInteger(req.partNumber) || req.partNumber < 1) {
104
+ return { status: 400, body: { error: 'partNumber must be a positive integer' } };
105
+ }
106
+ if (typeof req.etag !== 'string' || req.etag.length === 0) {
107
+ return { status: 400, body: { error: 'etag is required' } };
108
+ }
109
+ try {
110
+ const progress = await this.manager.confirmPart(req.uploadId, {
111
+ partNumber: req.partNumber,
112
+ etag: req.etag,
113
+ });
114
+ return { status: 200, body: progress };
115
+ }
116
+ catch (err) {
117
+ return this.mapError(err);
118
+ }
119
+ }
120
+ case 'complete': {
121
+ if (this.policy)
122
+ return this.completePolicy(req, ctx);
123
+ const parts = req.parts ?? [];
124
+ if (!Array.isArray(parts) ||
125
+ parts.some((part) => !Number.isInteger(part?.partNumber) ||
126
+ part.partNumber < 1 ||
127
+ typeof part?.etag !== 'string' ||
128
+ part.etag.length === 0)) {
129
+ return {
130
+ status: 400,
131
+ body: { error: 'parts must be an array of { partNumber, etag }' },
132
+ };
133
+ }
134
+ try {
135
+ const done = await this.manager.complete(req.uploadId, parts);
136
+ return { status: 200, body: done };
137
+ }
138
+ catch (err) {
139
+ return this.mapError(err);
140
+ }
141
+ }
142
+ case 'abort': {
143
+ if (this.policy)
144
+ return this.abortPolicy(req, ctx);
145
+ await this.manager.abort(req.uploadId);
146
+ return { status: 204 };
147
+ }
148
+ default:
149
+ return { status: 400, body: { error: 'Unknown action' } };
150
+ }
151
+ }
152
+ /** The `201` body for a created session — shared by the built-in and policy initiate paths. */
153
+ initiateBody(created) {
154
+ return {
155
+ id: created.id,
156
+ key: created.key,
157
+ disk: created.disk,
158
+ partSize: created.partSize,
159
+ size: created.size,
160
+ totalParts: created.totalParts,
161
+ parts: created.parts,
162
+ ...(created.expiresAt !== undefined ? { expiresAt: created.expiresAt.toISOString() } : {}),
163
+ };
164
+ }
165
+ /**
166
+ * Policy-driven `initiate`: the policy decides the key/collection/metadata (and may attach a
167
+ * `response` merged onto the `201`), the manager opens the upload. If anything throws after the
168
+ * decision, the decision's `rollback` runs and the policy's `mapError` gets first refusal on the
169
+ * HTTP mapping (with the decision in the info); an unmapped error falls through to {@link mapError}.
170
+ */
171
+ async initiatePolicy(req, ctx) {
172
+ const policy = this.policy;
173
+ let decision;
174
+ try {
175
+ decision = await traceMedia('upload.policy.on_initiate', () => policy.onInitiate(ctx, {
176
+ fileName: req.fileName,
177
+ size: req.size,
178
+ contentType: req.contentType,
179
+ metadata: req.metadata,
180
+ }));
181
+ const disk = decision.disk ?? this.disk;
182
+ const collection = decision.collection ?? this.collection;
183
+ const session = await this.manager.initiate({
184
+ key: decision.key,
185
+ size: req.size,
186
+ contentType: req.contentType,
187
+ metadata: decision.metadata ?? {},
188
+ ...(disk !== undefined ? { disk } : {}),
189
+ ...(collection !== undefined ? { collection } : {}),
190
+ ...(decision.visibility !== undefined ? { visibility: decision.visibility } : {}),
191
+ ...(decision.partSize !== undefined ? { partSize: decision.partSize } : {}),
192
+ });
193
+ await traceMedia('upload.policy.on_initiated', () => policy.onInitiated?.(ctx, { decision: decision, session }));
194
+ return {
195
+ status: 201,
196
+ body: { ...this.initiateBody(session), ...(decision.response ?? {}) },
197
+ };
198
+ }
199
+ catch (err) {
200
+ try {
201
+ await decision?.rollback?.();
202
+ }
203
+ catch {
204
+ // a failing rollback must not mask the primary error or preempt mapError
205
+ }
206
+ const mapped = await policy.mapError?.(ctx, err, { phase: 'initiate', decision });
207
+ if (mapped !== undefined)
208
+ return mapped;
209
+ return this.mapError(err);
210
+ }
211
+ }
212
+ /**
213
+ * Policy-driven `complete`: `resolveComplete` maps the session onto a library `target`, `adopt`
214
+ * assembles + adopts the object, and the `200` body is whatever `onComplete` returns. Parts-shape
215
+ * validation is deliberately skipped — the policy owns what a completion means. `mapError` (with
216
+ * the resolution in the info) gets first refusal on failures; else {@link mapError}.
217
+ */
218
+ async completePolicy(req, ctx) {
219
+ const policy = this.policy;
220
+ let resolution;
221
+ try {
222
+ resolution = await traceMedia('upload.policy.resolve_complete', () => policy.resolveComplete(ctx, { id: req.uploadId, parts: req.parts }));
223
+ const record = await this.adopt(resolution.sessionId, resolution.target, req.parts);
224
+ const body = await traceMedia('upload.policy.on_complete', () => policy.onComplete(ctx, { record, resolution: resolution }));
225
+ return { status: 200, body };
226
+ }
227
+ catch (err) {
228
+ const mapped = await policy.mapError?.(ctx, err, { phase: 'complete', resolution });
229
+ if (mapped !== undefined)
230
+ return mapped;
231
+ return this.mapError(err);
232
+ }
233
+ }
234
+ /** Policy-driven `abort`: the policy cleans up app-side state, then the session is dropped. */
235
+ async abortPolicy(req, ctx) {
236
+ const policy = this.policy;
237
+ try {
238
+ await traceMedia('upload.policy.on_abort', () => policy.onAbort?.(ctx, { id: req.uploadId }));
239
+ await this.manager.abort(req.uploadId);
240
+ return { status: 204 };
241
+ }
242
+ catch (err) {
243
+ const mapped = await policy.mapError?.(ctx, err, { phase: 'abort' });
244
+ if (mapped !== undefined)
245
+ return mapped;
246
+ return this.mapError(err);
247
+ }
248
+ }
249
+ /** Map manager errors onto HTTP statuses; anything unexpected keeps propagating. */
250
+ mapError(err) {
251
+ if (err instanceof UploadSessionNotFoundError) {
252
+ return { status: 404, body: { error: err.message, code: err.code } };
253
+ }
254
+ if (err instanceof UploadSessionExpiredError) {
255
+ return { status: 410, body: { error: err.message, code: err.code } };
256
+ }
257
+ if (err instanceof MimeNotAllowedError) {
258
+ return { status: 415, body: { error: err.message, code: err.code } };
259
+ }
260
+ // Not-yet-uploaded parts are client state out of sync with the session, not a bad request.
261
+ if (err instanceof UploadPartsIncompleteError) {
262
+ return {
263
+ status: 409,
264
+ body: { error: err.message, code: err.code, missingParts: [...err.missingParts] },
265
+ };
266
+ }
267
+ if (err instanceof UploadPartOutOfRangeError ||
268
+ err instanceof UploadPartSizeError ||
269
+ err instanceof UploadNotSupportedError ||
270
+ err instanceof RangeError) {
271
+ const code = err.code;
272
+ return { status: 400, body: { error: err.message, ...(code ? { code } : {}) } };
273
+ }
274
+ throw err;
275
+ }
276
+ }
277
+ //# sourceMappingURL=direct_upload_handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"direct_upload_handler.js","sourceRoot":"","sources":["../../src/direct_upload_handler.ts"],"names":[],"mappings":"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"}
@@ -24,6 +24,13 @@ export interface S3DiskConfig {
24
24
  credentials?: S3Credentials;
25
25
  /** Custom endpoint for S3-compatible services (MinIO, R2, DigitalOcean Spaces, …). */
26
26
  endpoint?: string;
27
+ /**
28
+ * Endpoint presigned URLs are signed against, when it differs from `endpoint`. Presigned URLs are
29
+ * consumed by the BROWSER (direct-upload part `PUT`s, signed `GET`s) and SigV4 bakes the host into
30
+ * the signature — so when `endpoint` is an internal FQDN the internet cannot resolve (MinIO on a
31
+ * private network), set the public one here. Server-side operations keep using `endpoint`.
32
+ */
33
+ publicEndpoint?: string;
27
34
  /** Use path-style addressing (`endpoint/bucket/key`) — required by most S3-compatible services. */
28
35
  forcePathStyle?: boolean;
29
36
  /** Prefix prepended to every key (e.g. `uploads`). */
@@ -51,11 +58,12 @@ export interface S3DiskConfig {
51
58
  * ```
52
59
  *
53
60
  * Each factory returns a {@link DiskFactory} — a lazy thunk. Calling it in the config file costs
54
- * nothing; `@aws-sdk/client-s3` (and `@aws-sdk/s3-request-presigner`) are only imported when the
55
- * provider builds the selected disk at boot, keeping the AWS SDK an optional peer.
61
+ * nothing; `@aws-sdk/client-s3` is only imported when the provider builds the selected disk at
62
+ * boot, keeping the AWS SDK an optional peer. (Presigning needs no SDK at all — it is hand-rolled
63
+ * SigV4, see `sigv4.ts`.)
56
64
  */
57
65
  export declare const disks: {
58
- /** S3 (or S3-compatible) disk — needs the optional `@aws-sdk/client-s3` + `@aws-sdk/s3-request-presigner` peers. */
66
+ /** S3 (or S3-compatible) disk — needs the optional `@aws-sdk/client-s3` peer. */
59
67
  s3(config: S3DiskConfig): DiskFactory;
60
68
  };
61
69
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../../src/disks/factory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAExC;;;;GAIG;AACH,MAAM,MAAM,WAAW,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;AAE9C,yGAAyG;AACzG,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,sGAAsG;AACtG,MAAM,WAAW,YAAY;IAC3B,gCAAgC;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,oCAAoC;IACpC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,WAAW,CAAC,EAAE,aAAa,CAAC;IAC5B,sFAAsF;IACtF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mGAAmG;IACnG,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,sDAAsD;IACtD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uFAAuF;IACvF,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,UAAU,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;CACnC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,KAAK;IAChB,oHAAoH;eACzG,YAAY,GAAG,WAAW;CAsBtC,CAAC;AAEF;;;;GAIG;AACH,wBAAsB,sBAAsB,CAC1C,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,GAAG,SAAS,GACjD,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAQ/B"}
1
+ {"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../../src/disks/factory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAExC;;;;GAIG;AACH,MAAM,MAAM,WAAW,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;AAE9C,yGAAyG;AACzG,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,sGAAsG;AACtG,MAAM,WAAW,YAAY;IAC3B,gCAAgC;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,oCAAoC;IACpC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,WAAW,CAAC,EAAE,aAAa,CAAC;IAC5B,sFAAsF;IACtF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;;OAKG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,mGAAmG;IACnG,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,sDAAsD;IACtD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uFAAuF;IACvF,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,UAAU,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;CACnC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,KAAK;IAChB,iFAAiF;eACtE,YAAY,GAAG,WAAW;CAuBtC,CAAC;AAEF;;;;GAIG;AACH,wBAAsB,sBAAsB,CAC1C,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,GAAG,SAAS,GACjD,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAQ/B"}
@@ -13,11 +13,12 @@
13
13
  * ```
14
14
  *
15
15
  * Each factory returns a {@link DiskFactory} — a lazy thunk. Calling it in the config file costs
16
- * nothing; `@aws-sdk/client-s3` (and `@aws-sdk/s3-request-presigner`) are only imported when the
17
- * provider builds the selected disk at boot, keeping the AWS SDK an optional peer.
16
+ * nothing; `@aws-sdk/client-s3` is only imported when the provider builds the selected disk at
17
+ * boot, keeping the AWS SDK an optional peer. (Presigning needs no SDK at all — it is hand-rolled
18
+ * SigV4, see `sigv4.ts`.)
18
19
  */
19
20
  export const disks = {
20
- /** S3 (or S3-compatible) disk — needs the optional `@aws-sdk/client-s3` + `@aws-sdk/s3-request-presigner` peers. */
21
+ /** S3 (or S3-compatible) disk — needs the optional `@aws-sdk/client-s3` peer. */
21
22
  s3(config) {
22
23
  return async () => {
23
24
  const { S3Client } = await import('@aws-sdk/client-s3');
@@ -35,6 +36,7 @@ export const disks = {
35
36
  ...(config.publicBaseUrl !== undefined ? { publicBaseUrl: config.publicBaseUrl } : {}),
36
37
  ...(config.region !== undefined ? { region: config.region } : {}),
37
38
  ...(config.endpoint !== undefined ? { endpoint: config.endpoint } : {}),
39
+ ...(config.publicEndpoint !== undefined ? { publicEndpoint: config.publicEndpoint } : {}),
38
40
  ...(config.forcePathStyle !== undefined ? { forcePathStyle: config.forcePathStyle } : {}),
39
41
  ...(config.visibility !== undefined ? { visibility: config.visibility } : {}),
40
42
  });
@@ -1 +1 @@
1
- {"version":3,"file":"factory.js","sourceRoot":"","sources":["../../../src/disks/factory.ts"],"names":[],"mappings":"AA0CA;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,MAAM,KAAK,GAAG;IACnB,oHAAoH;IACpH,EAAE,CAAC,MAAoB;QACrB,OAAO,KAAK,IAAI,EAAE;YAChB,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,oBAAoB,CAAC,CAAC;YACxD,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,CAAC;YAC3C,MAAM,MAAM,GAAG,IAAI,QAAQ,CAAC;gBAC1B,GAAG,CAAC,MAAM,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACjE,GAAG,CAAC,MAAM,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAChF,GAAG,CAAC,MAAM,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACvE,GAAG,CAAC,MAAM,CAAC,cAAc,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,MAAM,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAC1F,CAAC,CAAC;YACH,OAAO,IAAI,MAAM,CAAC;gBAChB,MAAM;gBACN,MAAM,EAAE,MAAM,CAAC,MAAM;gBACrB,GAAG,CAAC,MAAM,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC1E,GAAG,CAAC,MAAM,CAAC,aAAa,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,MAAM,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACtF,GAAG,CAAC,MAAM,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACjE,GAAG,CAAC,MAAM,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACvE,GAAG,CAAC,MAAM,CAAC,cAAc,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,MAAM,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACzF,GAAG,CAAC,MAAM,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAC9E,CAAC,CAAC;QACL,CAAC,CAAC;IACJ,CAAC;CACF,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,SAAkD;IAElD,MAAM,KAAK,GAAyB,EAAE,CAAC;IACvC,IAAI,SAAS,EAAE,CAAC;QACd,KAAK,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;YACxD,KAAK,CAAC,IAAI,CAAC,GAAG,MAAM,OAAO,EAAE,CAAC;QAChC,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
1
+ {"version":3,"file":"factory.js","sourceRoot":"","sources":["../../../src/disks/factory.ts"],"names":[],"mappings":"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"}
@@ -19,6 +19,14 @@ export interface S3DiskOptions {
19
19
  region?: string;
20
20
  /** Custom endpoint (S3-compatible services). Used for URL synthesis when no `publicBaseUrl` is set. */
21
21
  endpoint?: string;
22
+ /**
23
+ * Endpoint presigned URLs are signed against, when it differs from `endpoint`. SigV4 embeds the
24
+ * `Host` in the signature, and presigned URLs are consumed by the BROWSER (a part `PUT` during a
25
+ * direct upload, a `GET` while streaming) — so when the app reaches storage through an internal
26
+ * FQDN the internet cannot resolve (MinIO behind a private network), set this to the public one.
27
+ * Server-side operations keep using `endpoint`; only what leaves the server is signed for here.
28
+ */
29
+ publicEndpoint?: string;
22
30
  /** Emit path-style URLs (`endpoint/bucket/key`) instead of virtual-hosted-style. */
23
31
  forcePathStyle?: boolean;
24
32
  /**
@@ -39,6 +47,7 @@ export interface S3DiskOptions {
39
47
  * plus a {@link DiskCapabilities} descriptor), detected structurally via `isExtendedDisk`.
40
48
  */
41
49
  export declare class S3Disk implements Disk, MultipartUploadDisk, ExtendedDisk {
50
+ #private;
42
51
  /** Coarse feature descriptor — S3 supports presign, native multipart, and prefix listing. */
43
52
  readonly capabilities: DiskCapabilities;
44
53
  private readonly client;
@@ -47,6 +56,7 @@ export declare class S3Disk implements Disk, MultipartUploadDisk, ExtendedDisk {
47
56
  private readonly publicBaseUrl;
48
57
  private readonly region;
49
58
  private readonly endpoint;
59
+ private readonly publicEndpoint;
50
60
  private readonly forcePathStyle;
51
61
  private readonly visibility;
52
62
  constructor(options: S3DiskOptions);
@@ -1 +1 @@
1
- {"version":3,"file":"s3.d.ts","sourceRoot":"","sources":["../../../src/disks/s3.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"s3.d.ts","sourceRoot":"","sources":["../../../src/disks/s3.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { AbortMultipartUploadCommand, CompleteMultipartUploadCommand, CopyObjectCommand, CreateMultipartUploadCommand, DeleteObjectCommand, DeleteObjectsCommand, GetObjectCommand, HeadObjectCommand, ListObjectsV2Command, PutObjectCommand, UploadPartCommand, } from '@aws-sdk/client-s3';
2
- import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
3
2
  import { hardenBodyStream } from './harden_body_stream.js';
3
+ import { presignS3Url } from './sigv4.js';
4
4
  import { extractListObjectsV2FromXml, isXmlEntityDeserializationError } from './xml_fallback.js';
5
5
  /** Default presigned-URL lifetime when a caller passes no `expiresIn` (30 minutes). */
6
6
  const DEFAULT_SIGNED_URL_TTL_SECONDS = 1800;
@@ -48,6 +48,7 @@ export class S3Disk {
48
48
  publicBaseUrl;
49
49
  region;
50
50
  endpoint;
51
+ publicEndpoint;
51
52
  forcePathStyle;
52
53
  visibility;
53
54
  constructor(options) {
@@ -57,6 +58,7 @@ export class S3Disk {
57
58
  this.publicBaseUrl = options.publicBaseUrl;
58
59
  this.region = options.region;
59
60
  this.endpoint = options.endpoint;
61
+ this.publicEndpoint = options.publicEndpoint;
60
62
  this.forcePathStyle = options.forcePathStyle ?? false;
61
63
  this.visibility = options.visibility ?? 'private';
62
64
  this.capabilities = {
@@ -165,12 +167,80 @@ export class S3Disk {
165
167
  return this.visibility;
166
168
  }
167
169
  async getSignedUrl(key, options) {
168
- return getSignedUrl(this.client, new GetObjectCommand({
169
- Bucket: this.bucket,
170
- Key: this.key(key),
171
- ResponseContentType: options?.contentType,
172
- ResponseContentDisposition: options?.contentDisposition,
173
- }), { expiresIn: toExpiresInSeconds(options?.expiresIn) });
170
+ const query = {};
171
+ if (options?.contentType !== undefined)
172
+ query['response-content-type'] = options.contentType;
173
+ if (options?.contentDisposition !== undefined) {
174
+ query['response-content-disposition'] = options.contentDisposition;
175
+ }
176
+ return this.#presign('GET', this.key(key), query, toExpiresInSeconds(options?.expiresIn), {
177
+ browserFacing: true,
178
+ });
179
+ }
180
+ // --- Hand-rolled SigV4 presigning ---------------------------------------------------------
181
+ /**
182
+ * Credentials + region for signing, resolved from the SDK client's own config so every credential
183
+ * source the client supports (static, env, shared config, IAM role) keeps working. Only the
184
+ * *signature computation* is hand-rolled — see {@link presignS3Url} for why (it is pure local
185
+ * crypto, and owning it is what lets a URL be signed for {@link S3DiskOptions.publicEndpoint}
186
+ * without constructing a second client per endpoint).
187
+ */
188
+ async #signingContext() {
189
+ const config = this.client.config;
190
+ const credentials = typeof config.credentials === 'function' ? await config.credentials() : config.credentials;
191
+ let region = this.region;
192
+ if (region === undefined) {
193
+ try {
194
+ region = typeof config.region === 'function' ? await config.region() : config.region;
195
+ }
196
+ catch {
197
+ // A client constructed without a region (S3-compatible services often don't need one).
198
+ }
199
+ }
200
+ return { credentials, region: region ?? 'us-east-1' };
201
+ }
202
+ /**
203
+ * The scheme/host/path a presigned URL is computed for. `browserFacing` URLs prefer
204
+ * {@link S3DiskOptions.publicEndpoint}: the signature bakes the `Host` in, and these URLs are
205
+ * consumed outside the server's network. Server-side presigns (the list XML fallback) always
206
+ * target the internal endpoint.
207
+ */
208
+ #presignTarget(fullKey, options) {
209
+ const bucket = options.bucket ?? this.bucket;
210
+ const base = (options.browserFacing ? this.publicEndpoint : undefined) ?? this.endpoint;
211
+ if (base !== undefined) {
212
+ const url = new URL(base);
213
+ const basePath = url.pathname.replace(/\/+$/, '');
214
+ const protocol = url.protocol === 'http:' ? 'http:' : 'https:';
215
+ if (this.forcePathStyle) {
216
+ return {
217
+ protocol,
218
+ host: url.host,
219
+ path: `${basePath}/${bucket}${fullKey ? `/${fullKey}` : ''}`,
220
+ };
221
+ }
222
+ return { protocol, host: `${bucket}.${url.host}`, path: `${basePath}/${fullKey}` };
223
+ }
224
+ return {
225
+ protocol: 'https:',
226
+ host: `${bucket}.s3.${options.region}.amazonaws.com`,
227
+ path: `/${fullKey}`,
228
+ };
229
+ }
230
+ /** Presign one request against this disk. `fullKey` is already prefixed; `''` targets the bucket. */
231
+ async #presign(method, fullKey, query, expiresInSeconds, options) {
232
+ const { credentials, region } = await this.#signingContext();
233
+ const target = this.#presignTarget(fullKey, { ...options, region });
234
+ return presignS3Url({
235
+ method,
236
+ protocol: target.protocol,
237
+ host: target.host,
238
+ path: target.path,
239
+ query,
240
+ credentials,
241
+ region,
242
+ expiresInSeconds,
243
+ });
174
244
  }
175
245
  async getMetaData(key) {
176
246
  try {
@@ -282,15 +352,22 @@ export class S3Disk {
282
352
  if (!isXmlEntityDeserializationError(err))
283
353
  throw err;
284
354
  // fast-xml-parser rejected valid entity refs in the ListObjectsV2 XML — presign the same
285
- // request and fetch the raw body, then parse it by hand into the same shape. The presigner is
286
- // already bundled with this disk, so the fallback adds no new dependency (see xml_fallback.ts).
287
- const signedUrl = await getSignedUrl(this.client, new ListObjectsV2Command({
288
- Bucket: bucket,
289
- Prefix: fullPrefix,
290
- Delimiter: options?.delimiter ?? '/',
291
- MaxKeys: options?.limit,
292
- ContinuationToken: options?.cursor,
293
- }), { expiresIn: 60 });
355
+ // request (hand-rolled SigV4, see sigv4.ts) and fetch the raw body, then parse it by hand
356
+ // into the same shape. This is a SERVER-side fetch, so it deliberately targets the internal
357
+ // endpoint even when a `publicEndpoint` is configured (see xml_fallback.ts).
358
+ const listQuery = {
359
+ 'list-type': '2',
360
+ prefix: fullPrefix,
361
+ delimiter: options?.delimiter ?? '/',
362
+ };
363
+ if (options?.limit !== undefined)
364
+ listQuery['max-keys'] = String(options.limit);
365
+ if (options?.cursor !== undefined)
366
+ listQuery['continuation-token'] = options.cursor;
367
+ const signedUrl = await this.#presign('GET', '', listQuery, 60, {
368
+ browserFacing: false,
369
+ bucket,
370
+ });
294
371
  const response = await fetch(signedUrl);
295
372
  if (!response.ok) {
296
373
  throw new Error(`S3Disk: signed list fallback failed: HTTP ${response.status} ${response.statusText}`);
@@ -337,12 +414,9 @@ export class S3Disk {
337
414
  return { partNumber, etag: out.ETag };
338
415
  }
339
416
  async presignUploadPart(key, uploadId, partNumber, expiresInSeconds) {
340
- return getSignedUrl(this.client, new UploadPartCommand({
341
- Bucket: this.bucket,
342
- Key: this.key(key),
343
- UploadId: uploadId,
344
- PartNumber: partNumber,
345
- }), { expiresIn: Math.max(1, Math.round(expiresInSeconds)) });
417
+ // Browser-facing: the client PUTs the part bytes to this URL, so it is signed against the
418
+ // public endpoint when one is configured.
419
+ return this.#presign('PUT', this.key(key), { uploadId, partNumber: String(partNumber) }, expiresInSeconds, { browserFacing: true });
346
420
  }
347
421
  async completeMultipartUpload(key, uploadId, parts) {
348
422
  await this.client.send(new CompleteMultipartUploadCommand({