@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,299 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { publishMedia } from './diagnostics.js';
3
+ import { MimeNotAllowedError, UploadNotSupportedError, UploadPartOutOfRangeError, UploadPartSizeError, UploadPartsIncompleteError, UploadSessionExpiredError, UploadSessionNotFoundError, } from './errors.js';
4
+ import { isMultipartCapable } from './multipart.js';
5
+ /**
6
+ * Default part size: 20 MiB. Between S3's 5 MiB minimum and a reasonable payload per browser `PUT`;
7
+ * with S3's 10,000-part cap it covers files up to ~195 GiB. Larger than the proxy default (8 MiB)
8
+ * on purpose — direct parts don't occupy app memory, so the only cost of a bigger part is a bigger
9
+ * retry unit.
10
+ */
11
+ export const DEFAULT_DIRECT_PART_SIZE = 20 * 1024 * 1024;
12
+ /** S3's minimum part size (every part but the last). Enforced at `initiate` — see {@link UploadPartSizeError}. */
13
+ export const MIN_DIRECT_PART_SIZE = 5 * 1024 * 1024;
14
+ /** S3's cap on parts per multipart upload. */
15
+ export const MAX_DIRECT_PARTS = 10_000;
16
+ /**
17
+ * Default presigned part-URL lifetime (1 hour). Deliberately not sized to "the whole upload on a
18
+ * slow connection": {@link DirectUploadManager.status} re-issues fresh URLs for whatever is still
19
+ * pending, so an expired URL costs one status round-trip, not the upload.
20
+ */
21
+ const DEFAULT_PRESIGN_TTL_SECONDS = 3600;
22
+ /** Session-metadata key marking a session as a direct upload and carrying its agreed part size. */
23
+ const PART_SIZE_METADATA_KEY = 'direct:partSize';
24
+ /**
25
+ * Session-backed direct-to-S3 multipart uploads: the browser `PUT`s every byte straight to storage
26
+ * through presigned part URLs, and the app only coordinates — open, presign, collect ETags, close.
27
+ * The app's bandwidth cost is a handful of JSON round-trips regardless of file size, which is the
28
+ * entire point for video-sized files: the TUS path streams every chunk THROUGH the app (2× the
29
+ * bytes: client→app, app→S3), where this path streams none.
30
+ *
31
+ * What this adds over the raw primitives on {@link UploadManager} (`initiateDirect` & friends) is
32
+ * the **persisted session**: `uploadId`, the agreed `partSize` and every confirmed part ETag live
33
+ * in an {@link UploadSessionStore} — the same SPI the TUS engine persists its offsets in — instead
34
+ * of in the client's memory. A page reload no longer orphans the upload: the client asks
35
+ * {@link status} and gets back the confirmed ETags plus fresh URLs for what is missing.
36
+ *
37
+ * Framework-free, like {@link ResumableUploadManager}: the `DirectUploadHandler` maps it onto HTTP
38
+ * and the AdonisJS provider mounts that. `MediaManager.completeDirectUploadToLibrary` bridges a
39
+ * finished session into the media library through `attachExisting` — where the collection's
40
+ * whitelist checks the REAL bytes, exactly like every other upload path.
41
+ */
42
+ export class DirectUploadManager {
43
+ storage;
44
+ sessions;
45
+ collections;
46
+ partSize;
47
+ presignTtlSeconds;
48
+ ttlSeconds;
49
+ newId;
50
+ now;
51
+ emitDiagnostics;
52
+ constructor(options) {
53
+ this.storage = options.storage;
54
+ this.sessions = options.sessions;
55
+ this.collections = options.collections;
56
+ this.partSize = options.partSize ?? DEFAULT_DIRECT_PART_SIZE;
57
+ this.presignTtlSeconds = options.presignTtlSeconds ?? DEFAULT_PRESIGN_TTL_SECONDS;
58
+ this.ttlSeconds = options.sessionTtlSeconds;
59
+ this.newId = options.idGenerator ?? (() => randomUUID());
60
+ this.now = options.clock ?? (() => new Date());
61
+ this.emitDiagnostics = options.emitDiagnostics ?? true;
62
+ }
63
+ /**
64
+ * Open a direct upload: validate everything that can be validated without bytes, start the native
65
+ * multipart upload, persist the session, and presign every part URL in one batch (presigning is
66
+ * local computation — see `sigv4.ts` — so a 10,000-part batch costs no S3 round-trips).
67
+ */
68
+ async initiate(input) {
69
+ const diskName = input.disk ?? this.storage.defaultDisk;
70
+ const disk = this.storage.disk(diskName);
71
+ if (!isMultipartCapable(disk))
72
+ throw new UploadNotSupportedError(diskName);
73
+ if (typeof this.sessions.addPart !== 'function' ||
74
+ typeof this.sessions.listParts !== 'function') {
75
+ throw new UploadNotSupportedError(diskName, 'direct upload part recording');
76
+ }
77
+ if (!Number.isInteger(input.size) || input.size <= 0) {
78
+ throw new RangeError(`Direct upload size must be a positive integer, got ${input.size}`);
79
+ }
80
+ const partSize = input.partSize ?? this.partSize;
81
+ if (!Number.isInteger(partSize) || partSize < MIN_DIRECT_PART_SIZE) {
82
+ throw new UploadPartSizeError(`${partSize} bytes is below S3's ${MIN_DIRECT_PART_SIZE}-byte minimum`);
83
+ }
84
+ const totalParts = Math.max(1, Math.ceil(input.size / partSize));
85
+ if (totalParts > MAX_DIRECT_PARTS) {
86
+ throw new UploadPartSizeError(`${input.size} bytes at ${partSize} bytes/part needs ${totalParts} parts, over S3's cap of ${MAX_DIRECT_PARTS} — increase partSize`);
87
+ }
88
+ // The cheapest possible rejection, before the multipart upload even opens. Only the DECLARED
89
+ // type can be checked here (there are no bytes yet); the collection config stays the single
90
+ // source of truth, and attach-time validation of the real content remains the final barrier.
91
+ if (input.collection !== undefined && this.collections !== undefined) {
92
+ const accepts = this.collections.get(input.collection).acceptsMimeTypes;
93
+ if (accepts && input.contentType !== undefined && !accepts.includes(input.contentType)) {
94
+ throw new MimeNotAllowedError(input.collection, input.contentType);
95
+ }
96
+ }
97
+ const putOptions = input.contentType !== undefined || input.visibility !== undefined
98
+ ? {
99
+ ...(input.contentType !== undefined ? { contentType: input.contentType } : {}),
100
+ ...(input.visibility !== undefined ? { visibility: input.visibility } : {}),
101
+ }
102
+ : undefined;
103
+ const { uploadId } = await disk.createMultipartUpload(input.key, putOptions);
104
+ const createdAt = this.now();
105
+ const session = await this.sessions.create({
106
+ id: this.newId(),
107
+ disk: diskName,
108
+ key: input.key,
109
+ contentType: input.contentType,
110
+ size: input.size,
111
+ offset: 0,
112
+ parts: 0,
113
+ multipartUploadId: uploadId,
114
+ createdAt,
115
+ ...(this.ttlSeconds !== undefined
116
+ ? { expiresAt: new Date(createdAt.getTime() + this.ttlSeconds * 1000) }
117
+ : {}),
118
+ metadata: { ...input.metadata, [PART_SIZE_METADATA_KEY]: String(partSize) },
119
+ });
120
+ const parts = await this.#presignParts(disk, session, Array.from({ length: totalParts }, (_, index) => index + 1));
121
+ this.emit('upload.start', {
122
+ id: session.id,
123
+ disk: diskName,
124
+ key: input.key,
125
+ mode: 'direct',
126
+ size: input.size,
127
+ contentType: input.contentType,
128
+ });
129
+ return {
130
+ id: session.id,
131
+ key: session.key,
132
+ disk: diskName,
133
+ partSize,
134
+ size: input.size,
135
+ totalParts,
136
+ parts,
137
+ expiresAt: session.expiresAt,
138
+ };
139
+ }
140
+ /**
141
+ * Record one part the client finished `PUT`ing (its S3 `ETag` response header). This is what makes
142
+ * the session resumable: an ETag the server holds survives any client-side loss of state. Safe to
143
+ * retry — confirming the same part again overwrites its ETag.
144
+ */
145
+ async confirmPart(id, part) {
146
+ const session = await this.#require(id);
147
+ const { partSize, totalParts } = this.#geometry(session);
148
+ if (!Number.isInteger(part.partNumber) || part.partNumber < 1 || part.partNumber > totalParts) {
149
+ throw new UploadPartOutOfRangeError(part.partNumber, totalParts);
150
+ }
151
+ await this.sessions.addPart?.(id, { partNumber: part.partNumber, etag: part.etag });
152
+ // Recompute progress from what is actually recorded (parts confirm in any order and in
153
+ // parallel), so offset means "bytes safely on S3" rather than a linear cursor.
154
+ const confirmed = (await this.sessions.listParts?.(id)) ?? [];
155
+ session.parts = confirmed.length;
156
+ session.offset = confirmed.reduce((sum, recorded) => sum + this.#partBytes(session, partSize, totalParts, recorded.partNumber), 0);
157
+ await this.sessions.update(session);
158
+ this.emit('upload.progress', {
159
+ id: session.id,
160
+ offset: session.offset,
161
+ parts: session.parts,
162
+ size: session.size,
163
+ });
164
+ return { offset: session.offset, completedParts: confirmed.length };
165
+ }
166
+ /**
167
+ * Where the upload stands, framed for resumption: the ETags already confirmed and a FRESH
168
+ * presigned URL for every part still missing. After a page reload the client calls this, slices
169
+ * the file with the returned `partSize`, uploads only `pendingParts`, and completes.
170
+ */
171
+ async status(id) {
172
+ const session = await this.#require(id);
173
+ const disk = this.storage.disk(session.disk);
174
+ if (!isMultipartCapable(disk))
175
+ throw new UploadNotSupportedError(session.disk);
176
+ const { partSize, totalParts } = this.#geometry(session);
177
+ const completedParts = [...((await this.sessions.listParts?.(id)) ?? [])].sort((a, b) => a.partNumber - b.partNumber);
178
+ const confirmedNumbers = new Set(completedParts.map((part) => part.partNumber));
179
+ const pendingNumbers = Array.from({ length: totalParts }, (_, index) => index + 1).filter((partNumber) => !confirmedNumbers.has(partNumber));
180
+ return {
181
+ id: session.id,
182
+ key: session.key,
183
+ disk: session.disk,
184
+ partSize,
185
+ size: session.size,
186
+ totalParts,
187
+ contentType: session.contentType,
188
+ completedParts,
189
+ pendingParts: await this.#presignParts(disk, session, pendingNumbers),
190
+ expiresAt: session.expiresAt,
191
+ };
192
+ }
193
+ /**
194
+ * Assemble the parts into the final object and close the session. `parts` supplements what the
195
+ * session already holds (a client may hand over ETags it never got to confirm — e.g. it raced
196
+ * completion against its last confirms); on overlap the caller's ETag wins. Every part number in
197
+ * `1..totalParts` must be accounted for, or this throws {@link UploadPartsIncompleteError} naming
198
+ * the gaps — BEFORE the S3 round-trip that would report an opaque `InvalidPart`.
199
+ *
200
+ * This is the raw primitive (the object exists, no media record). To land in the library, use
201
+ * `MediaManager.completeDirectUploadToLibrary`, which chains `attachExisting` — collection
202
+ * whitelist against the real bytes included.
203
+ */
204
+ async complete(id, parts = []) {
205
+ const session = await this.#require(id);
206
+ const disk = this.storage.disk(session.disk);
207
+ if (!isMultipartCapable(disk))
208
+ throw new UploadNotSupportedError(session.disk);
209
+ const { totalParts } = this.#geometry(session);
210
+ const byNumber = new Map();
211
+ for (const recorded of (await this.sessions.listParts?.(id)) ?? []) {
212
+ byNumber.set(recorded.partNumber, recorded);
213
+ }
214
+ for (const given of parts)
215
+ byNumber.set(given.partNumber, given);
216
+ const missing = Array.from({ length: totalParts }, (_, index) => index + 1).filter((partNumber) => !byNumber.has(partNumber));
217
+ if (missing.length > 0)
218
+ throw new UploadPartsIncompleteError(id, missing);
219
+ const assembled = [...byNumber.values()].sort((a, b) => a.partNumber - b.partNumber);
220
+ await disk.completeMultipartUpload(session.key, session.multipartUploadId, assembled);
221
+ await this.sessions.delete(id);
222
+ this.emit('upload.complete', { id: session.id, disk: session.disk, key: session.key });
223
+ return { key: session.key, disk: session.disk, size: session.size };
224
+ }
225
+ /**
226
+ * Discard an in-flight upload: abort the native multipart upload (S3 frees the stored parts and
227
+ * stops charging for them) and drop the session. The S3 abort is best-effort — a bucket lifecycle
228
+ * rule may have already reaped the upload (`NoSuchUpload`), and a session that can no longer be
229
+ * aborted remotely must still be deletable locally.
230
+ */
231
+ async abort(id) {
232
+ const session = await this.sessions.get(id);
233
+ if (!session)
234
+ return;
235
+ const disk = this.storage.disk(session.disk);
236
+ if (session.multipartUploadId && isMultipartCapable(disk)) {
237
+ await disk.abortMultipartUpload(session.key, session.multipartUploadId).catch(() => { });
238
+ }
239
+ await this.sessions.delete(id);
240
+ this.emit('upload.abort', { id: session.id, disk: session.disk, key: session.key });
241
+ }
242
+ /** In-progress direct sessions, optionally filtered. Empty when the store cannot enumerate. */
243
+ async list(filter) {
244
+ const sessions = (await this.sessions.list?.(filter)) ?? [];
245
+ return sessions.filter((session) => session.metadata?.[PART_SIZE_METADATA_KEY] !== undefined);
246
+ }
247
+ /** Presign a `PUT` URL for each given part number, in one local batch. */
248
+ async #presignParts(disk, session, partNumbers) {
249
+ const urls = [];
250
+ for (const partNumber of partNumbers) {
251
+ urls.push({
252
+ partNumber,
253
+ url: await disk.presignUploadPart(session.key, session.multipartUploadId, partNumber, this.presignTtlSeconds),
254
+ });
255
+ }
256
+ return urls;
257
+ }
258
+ /** The agreed slicing for a session, recovered from its persisted metadata. */
259
+ #geometry(session) {
260
+ const partSize = Number(session.metadata?.[PART_SIZE_METADATA_KEY]);
261
+ const size = session.size;
262
+ return { partSize, totalParts: Math.max(1, Math.ceil(size / partSize)) };
263
+ }
264
+ /** Byte length of one part: `partSize`, except the last part which takes the remainder. */
265
+ #partBytes(session, partSize, totalParts, partNumber) {
266
+ const size = session.size;
267
+ return partNumber === totalParts ? size - (totalParts - 1) * partSize : partSize;
268
+ }
269
+ /**
270
+ * Load a session, requiring it to be a DIRECT one: the store may be shared with the TUS engine
271
+ * (the Lucid driver even shares tables), so a session lacking the direct part-size marker — or a
272
+ * declared size, or a native upload id — is "not found" here, never misinterpreted. An expired
273
+ * session is treated as gone: native upload aborted, record deleted,
274
+ * {@link UploadSessionExpiredError} thrown.
275
+ */
276
+ async #require(id) {
277
+ const session = await this.sessions.get(id);
278
+ if (!session ||
279
+ session.multipartUploadId === undefined ||
280
+ session.size === undefined ||
281
+ !Number.isFinite(Number(session.metadata?.[PART_SIZE_METADATA_KEY]))) {
282
+ throw new UploadSessionNotFoundError(id);
283
+ }
284
+ if (session.expiresAt && session.expiresAt.getTime() <= this.now().getTime()) {
285
+ const disk = this.storage.disk(session.disk);
286
+ if (isMultipartCapable(disk)) {
287
+ await disk.abortMultipartUpload(session.key, session.multipartUploadId).catch(() => { });
288
+ }
289
+ await this.sessions.delete(id);
290
+ throw new UploadSessionExpiredError(id);
291
+ }
292
+ return session;
293
+ }
294
+ emit(event, payload) {
295
+ if (this.emitDiagnostics)
296
+ publishMedia(event, payload);
297
+ }
298
+ }
299
+ //# sourceMappingURL=direct_upload.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"direct_upload.js","sourceRoot":"","sources":["../../src/direct_upload.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EACL,mBAAmB,EACnB,uBAAuB,EACvB,yBAAyB,EACzB,mBAAmB,EACnB,0BAA0B,EAC1B,yBAAyB,EACzB,0BAA0B,GAC3B,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AASpD;;;;;GAKG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC;AACzD,kHAAkH;AAClH,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC;AACpD,8CAA8C;AAC9C,MAAM,CAAC,MAAM,gBAAgB,GAAG,MAAM,CAAC;AACvC;;;;GAIG;AACH,MAAM,2BAA2B,GAAG,IAAI,CAAC;AAEzC,mGAAmG;AACnG,MAAM,sBAAsB,GAAG,iBAAiB,CAAC;AA0FjD;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,OAAO,mBAAmB;IACb,OAAO,CAAiB;IACxB,QAAQ,CAAqB;IAC7B,WAAW,CAAsC;IACjD,QAAQ,CAAS;IACjB,iBAAiB,CAAS;IAC1B,UAAU,CAAqB;IAC/B,KAAK,CAAe;IACpB,GAAG,CAAa;IAChB,eAAe,CAAU;IAE1C,YAAY,OAAmC;QAC7C,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;QAC/B,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;QACjC,IAAI,CAAC,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;QACvC,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,wBAAwB,CAAC;QAC7D,IAAI,CAAC,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,IAAI,2BAA2B,CAAC;QAClF,IAAI,CAAC,UAAU,GAAG,OAAO,CAAC,iBAAiB,CAAC;QAC5C,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,WAAW,IAAI,CAAC,GAAG,EAAE,CAAC,UAAU,EAAE,CAAC,CAAC;QACzD,IAAI,CAAC,GAAG,GAAG,OAAO,CAAC,KAAK,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;QAC/C,IAAI,CAAC,eAAe,GAAG,OAAO,CAAC,eAAe,IAAI,IAAI,CAAC;IACzD,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,QAAQ,CAAC,KAAgC;QAC7C,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,IAAI,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC;QACxD,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACzC,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC;YAAE,MAAM,IAAI,uBAAuB,CAAC,QAAQ,CAAC,CAAC;QAC3E,IACE,OAAO,IAAI,CAAC,QAAQ,CAAC,OAAO,KAAK,UAAU;YAC3C,OAAO,IAAI,CAAC,QAAQ,CAAC,SAAS,KAAK,UAAU,EAC7C,CAAC;YACD,MAAM,IAAI,uBAAuB,CAAC,QAAQ,EAAE,8BAA8B,CAAC,CAAC;QAC9E,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,IAAI,IAAI,CAAC,EAAE,CAAC;YACrD,MAAM,IAAI,UAAU,CAAC,sDAAsD,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;QAC3F,CAAC;QAED,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,IAAI,IAAI,CAAC,QAAQ,CAAC;QACjD,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,QAAQ,GAAG,oBAAoB,EAAE,CAAC;YACnE,MAAM,IAAI,mBAAmB,CAC3B,GAAG,QAAQ,wBAAwB,oBAAoB,eAAe,CACvE,CAAC;QACJ,CAAC;QACD,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,QAAQ,CAAC,CAAC,CAAC;QACjE,IAAI,UAAU,GAAG,gBAAgB,EAAE,CAAC;YAClC,MAAM,IAAI,mBAAmB,CAC3B,GAAG,KAAK,CAAC,IAAI,aAAa,QAAQ,qBAAqB,UAAU,4BAA4B,gBAAgB,sBAAsB,CACpI,CAAC;QACJ,CAAC;QAED,6FAA6F;QAC7F,4FAA4F;QAC5F,6FAA6F;QAC7F,IAAI,KAAK,CAAC,UAAU,KAAK,SAAS,IAAI,IAAI,CAAC,WAAW,KAAK,SAAS,EAAE,CAAC;YACrE,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,gBAAgB,CAAC;YACxE,IAAI,OAAO,IAAI,KAAK,CAAC,WAAW,KAAK,SAAS,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC;gBACvF,MAAM,IAAI,mBAAmB,CAAC,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,WAAW,CAAC,CAAC;YACrE,CAAC;QACH,CAAC;QAED,MAAM,UAAU,GACd,KAAK,CAAC,WAAW,KAAK,SAAS,IAAI,KAAK,CAAC,UAAU,KAAK,SAAS;YAC/D,CAAC,CAAC;gBACE,GAAG,CAAC,KAAK,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC9E,GAAG,CAAC,KAAK,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,KAAK,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAC5E;YACH,CAAC,CAAC,SAAS,CAAC;QAChB,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,IAAI,CAAC,qBAAqB,CAAC,KAAK,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;QAE7E,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC7B,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;YACzC,EAAE,EAAE,IAAI,CAAC,KAAK,EAAE;YAChB,IAAI,EAAE,QAAQ;YACd,GAAG,EAAE,KAAK,CAAC,GAAG;YACd,WAAW,EAAE,KAAK,CAAC,WAAW;YAC9B,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,MAAM,EAAE,CAAC;YACT,KAAK,EAAE,CAAC;YACR,iBAAiB,EAAE,QAAQ;YAC3B,SAAS;YACT,GAAG,CAAC,IAAI,CAAC,UAAU,KAAK,SAAS;gBAC/B,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,EAAE;gBACvE,CAAC,CAAC,EAAE,CAAC;YACP,QAAQ,EAAE,EAAE,GAAG,KAAK,CAAC,QAAQ,EAAE,CAAC,sBAAsB,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC,EAAE;SAC5E,CAAC,CAAC;QAEH,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,aAAa,CACpC,IAAI,EACJ,OAAO,EACP,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,GAAG,CAAC,CAAC,CAC5D,CAAC;QAEF,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE;YACxB,EAAE,EAAE,OAAO,CAAC,EAAE;YACd,IAAI,EAAE,QAAQ;YACd,GAAG,EAAE,KAAK,CAAC,GAAG;YACd,IAAI,EAAE,QAAQ;YACd,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,WAAW,EAAE,KAAK,CAAC,WAAW;SAC/B,CAAC,CAAC;QAEH,OAAO;YACL,EAAE,EAAE,OAAO,CAAC,EAAE;YACd,GAAG,EAAE,OAAO,CAAC,GAAG;YAChB,IAAI,EAAE,QAAQ;YACd,QAAQ;YACR,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,UAAU;YACV,KAAK;YACL,SAAS,EAAE,OAAO,CAAC,SAAS;SAC7B,CAAC;IACJ,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,WAAW,CACf,EAAU,EACV,IAAmB;QAEnB,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QACxC,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QACzD,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,IAAI,CAAC,UAAU,GAAG,CAAC,IAAI,IAAI,CAAC,UAAU,GAAG,UAAU,EAAE,CAAC;YAC9F,MAAM,IAAI,yBAAyB,CAAC,IAAI,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;QACnE,CAAC;QAED,MAAM,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC,EAAE,EAAE,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QAEpF,uFAAuF;QACvF,+EAA+E;QAC/E,MAAM,SAAS,GAAG,CAAC,MAAM,IAAI,CAAC,QAAQ,CAAC,SAAS,EAAE,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QAC9D,OAAO,CAAC,KAAK,GAAG,SAAS,CAAC,MAAM,CAAC;QACjC,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,MAAM,CAC/B,CAAC,GAAG,EAAE,QAAQ,EAAE,EAAE,CAAC,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,CAAC,UAAU,CAAC,EAC5F,CAAC,CACF,CAAC;QACF,MAAM,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAEpC,IAAI,CAAC,IAAI,CAAC,iBAAiB,EAAE;YAC3B,EAAE,EAAE,OAAO,CAAC,EAAE;YACd,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,IAAI,EAAE,OAAO,CAAC,IAAI;SACnB,CAAC,CAAC;QACH,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,cAAc,EAAE,SAAS,CAAC,MAAM,EAAE,CAAC;IACtE,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,MAAM,CAAC,EAAU;QACrB,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QACxC,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC7C,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC;YAAE,MAAM,IAAI,uBAAuB,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC/E,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QAEzD,MAAM,cAAc,GAAG,CAAC,GAAG,CAAC,CAAC,MAAM,IAAI,CAAC,QAAQ,CAAC,SAAS,EAAE,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAC5E,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,UAAU,CACtC,CAAC;QACF,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;QAChF,MAAM,cAAc,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,MAAM,CACvF,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,gBAAgB,CAAC,GAAG,CAAC,UAAU,CAAC,CAClD,CAAC;QAEF,OAAO;YACL,EAAE,EAAE,OAAO,CAAC,EAAE;YACd,GAAG,EAAE,OAAO,CAAC,GAAG;YAChB,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,QAAQ;YACR,IAAI,EAAE,OAAO,CAAC,IAAc;YAC5B,UAAU;YACV,WAAW,EAAE,OAAO,CAAC,WAAW;YAChC,cAAc;YACd,YAAY,EAAE,MAAM,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE,OAAO,EAAE,cAAc,CAAC;YACrE,SAAS,EAAE,OAAO,CAAC,SAAS;SAC7B,CAAC;IACJ,CAAC;IAED;;;;;;;;;;OAUG;IACH,KAAK,CAAC,QAAQ,CACZ,EAAU,EACV,QAAyB,EAAE;QAE3B,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QACxC,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC7C,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC;YAAE,MAAM,IAAI,uBAAuB,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC/E,MAAM,EAAE,UAAU,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QAE/C,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAyB,CAAC;QAClD,KAAK,MAAM,QAAQ,IAAI,CAAC,MAAM,IAAI,CAAC,QAAQ,CAAC,SAAS,EAAE,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;YACnE,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;QAC9C,CAAC;QACD,KAAK,MAAM,KAAK,IAAI,KAAK;YAAE,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;QAEjE,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,MAAM,CAChF,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC,CAC1C,CAAC;QACF,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC;YAAE,MAAM,IAAI,0BAA0B,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;QAE1E,MAAM,SAAS,GAAG,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC;QACrF,MAAM,IAAI,CAAC,uBAAuB,CAAC,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,iBAA2B,EAAE,SAAS,CAAC,CAAC;QAChG,MAAM,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAE/B,IAAI,CAAC,IAAI,CAAC,iBAAiB,EAAE,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;QACvF,OAAO,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,IAAc,EAAE,CAAC;IAChF,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,KAAK,CAAC,EAAU;QACpB,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC5C,IAAI,CAAC,OAAO;YAAE,OAAO;QACrB,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC7C,IAAI,OAAO,CAAC,iBAAiB,IAAI,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAAC;YAC1D,MAAM,IAAI,CAAC,oBAAoB,CAAC,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,iBAAiB,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QAC1F,CAAC;QACD,MAAM,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAC/B,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IACtF,CAAC;IAED,+FAA+F;IAC/F,KAAK,CAAC,IAAI,CAAC,MAAgC;QACzC,MAAM,QAAQ,GAAG,CAAC,MAAM,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;QAC5D,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,sBAAsB,CAAC,KAAK,SAAS,CAAC,CAAC;IAChG,CAAC;IAED,0EAA0E;IAC1E,KAAK,CAAC,aAAa,CACjB,IAAyB,EACzB,OAAsB,EACtB,WAAqB;QAErB,MAAM,IAAI,GAA0B,EAAE,CAAC;QACvC,KAAK,MAAM,UAAU,IAAI,WAAW,EAAE,CAAC;YACrC,IAAI,CAAC,IAAI,CAAC;gBACR,UAAU;gBACV,GAAG,EAAE,MAAM,IAAI,CAAC,iBAAiB,CAC/B,OAAO,CAAC,GAAG,EACX,OAAO,CAAC,iBAA2B,EACnC,UAAU,EACV,IAAI,CAAC,iBAAiB,CACvB;aACF,CAAC,CAAC;QACL,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,+EAA+E;IAC/E,SAAS,CAAC,OAAsB;QAC9B,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,sBAAsB,CAAC,CAAC,CAAC;QACpE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAc,CAAC;QACpC,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,QAAQ,CAAC,CAAC,EAAE,CAAC;IAC3E,CAAC;IAED,2FAA2F;IAC3F,UAAU,CACR,OAAsB,EACtB,QAAgB,EAChB,UAAkB,EAClB,UAAkB;QAElB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAc,CAAC;QACpC,OAAO,UAAU,KAAK,UAAU,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,UAAU,GAAG,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC;IACnF,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,QAAQ,CAAC,EAAU;QACvB,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC5C,IACE,CAAC,OAAO;YACR,OAAO,CAAC,iBAAiB,KAAK,SAAS;YACvC,OAAO,CAAC,IAAI,KAAK,SAAS;YAC1B,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,sBAAsB,CAAC,CAAC,CAAC,EACpE,CAAC;YACD,MAAM,IAAI,0BAA0B,CAAC,EAAE,CAAC,CAAC;QAC3C,CAAC;QACD,IAAI,OAAO,CAAC,SAAS,IAAI,OAAO,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC;YAC7E,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YAC7C,IAAI,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC7B,MAAM,IAAI,CAAC,oBAAoB,CAAC,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,iBAAiB,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;YAC1F,CAAC;YACD,MAAM,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YAC/B,MAAM,IAAI,yBAAyB,CAAC,EAAE,CAAC,CAAC;QAC1C,CAAC;QACD,OAAO,OAAO,CAAC;IACjB,CAAC;IAEO,IAAI,CACV,KAAQ,EACR,OAA8C;QAE9C,IAAI,IAAI,CAAC,eAAe;YAAE,YAAY,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IACzD,CAAC;CACF"}
@@ -0,0 +1,117 @@
1
+ import type { DirectUploadManager } from './direct_upload.js';
2
+ import type { AttachExistingInput } from './media_library.js';
3
+ import type { MediaRecord } from './media_record.js';
4
+ import type { DirectUploadPolicy, MultipartPart } from './types.js';
5
+ /**
6
+ * A web-framework-neutral direct-upload request, one variant per lifecycle step (the provider maps
7
+ * an AdonisJS `HttpContext` to this; any other framework maps its own request the same way).
8
+ */
9
+ export type DirectUploadRequest = {
10
+ action: 'initiate';
11
+ /** Name of the file being uploaded — feeds `keyFor`, never used as a key verbatim. */
12
+ fileName: string;
13
+ /** Total size in bytes. */
14
+ size: number;
15
+ contentType?: string | undefined;
16
+ /** Extra metadata persisted on the session. */
17
+ metadata?: Record<string, string> | undefined;
18
+ } | {
19
+ action: 'status';
20
+ uploadId: string;
21
+ } | {
22
+ action: 'confirm-part';
23
+ uploadId: string;
24
+ partNumber: number;
25
+ etag: string;
26
+ } | {
27
+ action: 'complete';
28
+ uploadId: string;
29
+ parts?: MultipartPart[] | undefined;
30
+ } | {
31
+ action: 'abort';
32
+ uploadId: string;
33
+ };
34
+ /** A web-framework-neutral response: a status code and a JSON-serializable body. */
35
+ export interface DirectUploadResponse {
36
+ status: number;
37
+ body?: unknown;
38
+ }
39
+ export interface DirectUploadHandlerOptions {
40
+ manager: DirectUploadManager;
41
+ /** Disk uploads land on. Defaults to the manager's default disk. */
42
+ disk?: string | undefined;
43
+ /**
44
+ * Collection this endpoint uploads into. Forwarded to the manager's `initiate`, whose MIME gate
45
+ * (against the registry the manager holds) rejects a wrong declared type with `415` before the
46
+ * multipart upload opens. The collection config stays the single source of truth.
47
+ */
48
+ collection?: string | undefined;
49
+ /** Reject initiations whose `size` exceeds this many bytes (`413`). */
50
+ maxSize?: number | undefined;
51
+ /** Compute the final object key. Default: `uploads/<token>/<fileName>`. */
52
+ keyFor?: ((fileName: string, token: string, metadata: Record<string, string>) => string) | undefined;
53
+ idGenerator?: (() => string) | undefined;
54
+ /**
55
+ * App-injected strategy that owns the variant decisions (key resolution, what the upload becomes
56
+ * on completion, error→HTTP mapping). When present, `initiate`/`complete`/`abort` route through
57
+ * it; when absent, the handler keeps its built-in key/complete behavior. See {@link DirectUploadPolicy}.
58
+ */
59
+ policy?: DirectUploadPolicy<unknown, unknown> | undefined;
60
+ /**
61
+ * Adopt an assembled object into the media library — wired to `MediaManager.completeDirectUploadToLibrary`
62
+ * by the provider. The policy's `complete` path calls it with the resolution's `sessionId`/`target`
63
+ * (plus the caller-supplied parts) and returns the resulting record. Unused without a {@link policy}.
64
+ */
65
+ adopt?: ((sessionId: string, target: Omit<AttachExistingInput, 'key' | 'disk' | 'size'>, parts?: MultipartPart[] | undefined) => Promise<MediaRecord>) | undefined;
66
+ }
67
+ /**
68
+ * HTTP half of the session-backed direct upload flow, mirroring {@link TusUploadHandler}: the core
69
+ * ({@link DirectUploadManager}) never sees HTTP, this class never sees a framework, and a thin
70
+ * AdonisJS route adapter maps `HttpContext` to {@link DirectUploadRequest}/{@link DirectUploadResponse}.
71
+ *
72
+ * The endpoint surface it expects to be mounted on (see the provider's `uploads.direct.routes`):
73
+ *
74
+ * - `POST /` → `initiate` — `201` + session id, part size, presigned URLs
75
+ * - `GET /:id` → `status` — confirmed ETags + fresh URLs for pending parts
76
+ * - `POST /:id/parts/:partNumber` → `confirm-part` — record one uploaded part's ETag
77
+ * - `POST /:id/complete` → `complete` — assemble; `409` names any missing parts
78
+ * - `DELETE /:id` → `abort`
79
+ *
80
+ * **This handler performs NO authorization** — the same split as `TusUploadHandler` and
81
+ * `MediaDeliveryHandler`. Who may upload, and into whose namespace the key resolves, are questions
82
+ * only the app can answer: guard the route, and resolve the key server-side via {@link keyFor}
83
+ * (the client sends a `fileName`, never a key).
84
+ */
85
+ export declare class DirectUploadHandler {
86
+ private readonly manager;
87
+ private readonly disk;
88
+ private readonly collection;
89
+ private readonly maxSize;
90
+ private readonly keyFor;
91
+ private readonly newId;
92
+ private readonly policy;
93
+ private readonly adopt;
94
+ constructor(options: DirectUploadHandlerOptions);
95
+ handle(req: DirectUploadRequest, ctx?: unknown): Promise<DirectUploadResponse>;
96
+ /** The `201` body for a created session — shared by the built-in and policy initiate paths. */
97
+ private initiateBody;
98
+ /**
99
+ * Policy-driven `initiate`: the policy decides the key/collection/metadata (and may attach a
100
+ * `response` merged onto the `201`), the manager opens the upload. If anything throws after the
101
+ * decision, the decision's `rollback` runs and the policy's `mapError` gets first refusal on the
102
+ * HTTP mapping (with the decision in the info); an unmapped error falls through to {@link mapError}.
103
+ */
104
+ private initiatePolicy;
105
+ /**
106
+ * Policy-driven `complete`: `resolveComplete` maps the session onto a library `target`, `adopt`
107
+ * assembles + adopts the object, and the `200` body is whatever `onComplete` returns. Parts-shape
108
+ * validation is deliberately skipped — the policy owns what a completion means. `mapError` (with
109
+ * the resolution in the info) gets first refusal on failures; else {@link mapError}.
110
+ */
111
+ private completePolicy;
112
+ /** Policy-driven `abort`: the policy cleans up app-side state, then the session is dropped. */
113
+ private abortPolicy;
114
+ /** Map manager errors onto HTTP statuses; anything unexpected keeps propagating. */
115
+ private mapError;
116
+ }
117
+ //# sourceMappingURL=direct_upload_handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"direct_upload_handler.d.ts","sourceRoot":"","sources":["../../src/direct_upload_handler.ts"],"names":[],"mappings":"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"}