@adonis-agora/media 0.8.1 → 0.9.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 +121 -0
- package/README.md +206 -0
- package/dist/providers/media_provider.d.ts +3 -13
- package/dist/providers/media_provider.d.ts.map +1 -1
- package/dist/providers/media_provider.js +151 -4
- package/dist/providers/media_provider.js.map +1 -1
- package/dist/src/content_type.d.ts +6 -1
- package/dist/src/content_type.d.ts.map +1 -1
- package/dist/src/content_type.js +102 -7
- package/dist/src/content_type.js.map +1 -1
- package/dist/src/define_config.d.ts +88 -5
- package/dist/src/define_config.d.ts.map +1 -1
- package/dist/src/define_config.js +7 -2
- package/dist/src/define_config.js.map +1 -1
- package/dist/src/direct_upload.d.ts +177 -0
- package/dist/src/direct_upload.d.ts.map +1 -0
- package/dist/src/direct_upload.js +299 -0
- package/dist/src/direct_upload.js.map +1 -0
- package/dist/src/direct_upload_handler.d.ts +83 -0
- package/dist/src/direct_upload_handler.d.ts.map +1 -0
- package/dist/src/direct_upload_handler.js +180 -0
- package/dist/src/direct_upload_handler.js.map +1 -0
- package/dist/src/disks/factory.d.ts +11 -3
- package/dist/src/disks/factory.d.ts.map +1 -1
- package/dist/src/disks/factory.js +5 -3
- package/dist/src/disks/factory.js.map +1 -1
- package/dist/src/disks/s3.d.ts +10 -0
- package/dist/src/disks/s3.d.ts.map +1 -1
- package/dist/src/disks/s3.js +96 -22
- package/dist/src/disks/s3.js.map +1 -1
- package/dist/src/disks/sigv4.d.ts +58 -0
- package/dist/src/disks/sigv4.d.ts.map +1 -0
- package/dist/src/disks/sigv4.js +87 -0
- package/dist/src/disks/sigv4.js.map +1 -0
- package/dist/src/disks/xml_fallback.d.ts +3 -3
- package/dist/src/disks/xml_fallback.js +3 -3
- package/dist/src/errors.d.ts +104 -0
- package/dist/src/errors.d.ts.map +1 -1
- package/dist/src/errors.js +145 -0
- package/dist/src/errors.js.map +1 -1
- package/dist/src/hls/delivery.d.ts +112 -0
- package/dist/src/hls/delivery.d.ts.map +1 -0
- package/dist/src/hls/delivery.js +118 -0
- package/dist/src/hls/delivery.js.map +1 -0
- package/dist/src/hls/playlist.d.ts +67 -0
- package/dist/src/hls/playlist.d.ts.map +1 -0
- package/dist/src/hls/playlist.js +126 -0
- package/dist/src/hls/playlist.js.map +1 -0
- package/dist/src/index.d.ts +18 -3
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +13 -2
- package/dist/src/index.js.map +1 -1
- package/dist/src/media_collection.d.ts +8 -1
- package/dist/src/media_collection.d.ts.map +1 -1
- package/dist/src/media_collection.js +23 -1
- package/dist/src/media_collection.js.map +1 -1
- package/dist/src/media_library.d.ts +32 -2
- package/dist/src/media_library.d.ts.map +1 -1
- package/dist/src/media_library.js +218 -11
- package/dist/src/media_library.js.map +1 -1
- package/dist/src/media_manager.d.ts +37 -2
- package/dist/src/media_manager.d.ts.map +1 -1
- package/dist/src/media_manager.js +54 -1
- package/dist/src/media_manager.js.map +1 -1
- package/dist/src/media_record.d.ts +22 -2
- package/dist/src/media_record.d.ts.map +1 -1
- package/dist/src/services/booted_app.d.ts +9 -0
- package/dist/src/services/booted_app.d.ts.map +1 -0
- package/dist/src/services/booted_app.js +33 -0
- package/dist/src/services/booted_app.js.map +1 -0
- package/dist/src/services/main.d.ts +12 -0
- package/dist/src/services/main.d.ts.map +1 -1
- package/dist/src/services/main.js +15 -3
- package/dist/src/services/main.js.map +1 -1
- package/dist/src/single_file_store.d.ts +4 -0
- package/dist/src/single_file_store.d.ts.map +1 -1
- package/dist/src/single_file_store.js +8 -4
- package/dist/src/single_file_store.js.map +1 -1
- package/dist/src/testing/fake_transformer.d.ts +32 -0
- package/dist/src/testing/fake_transformer.d.ts.map +1 -0
- package/dist/src/testing/fake_transformer.js +32 -0
- package/dist/src/testing/fake_transformer.js.map +1 -0
- package/dist/src/testing/index.d.ts +2 -0
- package/dist/src/testing/index.d.ts.map +1 -1
- package/dist/src/testing/index.js +1 -0
- package/dist/src/testing/index.js.map +1 -1
- package/dist/src/transformer.d.ts +111 -0
- package/dist/src/transformer.d.ts.map +1 -0
- package/dist/src/transformer.js +2 -0
- package/dist/src/transformer.js.map +1 -0
- package/dist/src/transformers/factory.d.ts +30 -0
- package/dist/src/transformers/factory.d.ts.map +1 -0
- package/dist/src/transformers/factory.js +34 -0
- package/dist/src/transformers/factory.js.map +1 -0
- package/dist/src/transformers/hls.d.ts +110 -0
- package/dist/src/transformers/hls.d.ts.map +1 -0
- package/dist/src/transformers/hls.js +111 -0
- package/dist/src/transformers/hls.js.map +1 -0
- package/dist/src/transformers/mediabunny.d.ts +5 -0
- package/dist/src/transformers/mediabunny.d.ts.map +1 -0
- package/dist/src/transformers/mediabunny.js +150 -0
- package/dist/src/transformers/mediabunny.js.map +1 -0
- package/dist/src/transformers/mediabunny_loader.d.ts +15 -0
- package/dist/src/transformers/mediabunny_loader.d.ts.map +1 -0
- package/dist/src/transformers/mediabunny_loader.js +21 -0
- package/dist/src/transformers/mediabunny_loader.js.map +1 -0
- package/dist/src/transformers/probe.d.ts +56 -0
- package/dist/src/transformers/probe.d.ts.map +1 -0
- package/dist/src/transformers/probe.js +32 -0
- package/dist/src/transformers/probe.js.map +1 -0
- package/dist/src/transformers/source_file.d.ts +20 -0
- package/dist/src/transformers/source_file.d.ts.map +1 -0
- package/dist/src/transformers/source_file.js +30 -0
- package/dist/src/transformers/source_file.js.map +1 -0
- package/dist/stubs/config/media.stub +12 -0
- package/package.json +11 -7
- package/LICENSE +0 -21
package/dist/src/errors.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,mBAAoB,SAAQ,KAAK;IAC5C,QAAQ,CAAC,IAAI,8BAA8B;gBAC/B,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;CAIjD;AAED;;;;;;GAMG;AACH,qBAAa,wBAAyB,SAAQ,KAAK;IAG/C,QAAQ,CAAC,UAAU,EAAE,MAAM;IAC3B,QAAQ,CAAC,gBAAgB,EAAE,MAAM;IACjC,QAAQ,CAAC,gBAAgB,EAAE,MAAM;IAJnC,QAAQ,CAAC,IAAI,mCAAmC;gBAErC,UAAU,EAAE,MAAM,EAClB,gBAAgB,EAAE,MAAM,EACxB,gBAAgB,EAAE,MAAM,EACjC,QAAQ,EAAE,SAAS,MAAM,EAAE;CAO9B;AAED;;;;;;;;;GASG;AACH,qBAAa,iCAAkC,SAAQ,KAAK;IAGxD,QAAQ,CAAC,UAAU,EAAE,MAAM;IAC3B,QAAQ,CAAC,gBAAgB,EAAE,MAAM,GAAG,SAAS;IAC7C,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE;IAJtC,QAAQ,CAAC,IAAI,4CAA4C;gBAE9C,UAAU,EAAE,MAAM,EAClB,gBAAgB,EAAE,MAAM,GAAG,SAAS,EACpC,QAAQ,EAAE,SAAS,MAAM,EAAE;CASvC;AAED;;;;;GAKG;AACH,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,QAAQ,CAAC,IAAI,6BAA6B;gBAC9B,IAAI,EAAE,MAAM;CAMzB;AAED,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,QAAQ,CAAC,IAAI,8BAA8B;gBAC/B,EAAE,EAAE,MAAM;CAIvB;AAED,qBAAa,uBAAwB,SAAQ,KAAK;IAChD,QAAQ,CAAC,IAAI,4BAA4B;gBAC7B,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM;CAMtC;AAED,qBAAa,yBAA0B,SAAQ,KAAK;IAClD,QAAQ,CAAC,IAAI,oCAAoC;gBACrC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM;CAInD;AAED,qBAAa,0BAA2B,SAAQ,KAAK;IACnD,QAAQ,CAAC,IAAI,qCAAqC;;CAKnD;AAED,qBAAa,oBAAqB,SAAQ,KAAK;IAC7C,QAAQ,CAAC,IAAI,+BAA+B;gBAChC,OAAO,EAAE,MAAM;CAI5B;AAED,qBAAa,uBAAwB,SAAQ,KAAK;IAChD,QAAQ,CAAC,IAAI,kCAAkC;gBACnC,IAAI,EAAE,MAAM,EAAE,SAAS,SAA4B;CAMhE;AAED,qBAAa,0BAA2B,SAAQ,KAAK;IACnD,QAAQ,CAAC,IAAI,sCAAsC;gBACvC,EAAE,EAAE,MAAM;CAIvB;AAED,qBAAa,yBAA0B,SAAQ,KAAK;IAGhD,QAAQ,CAAC,QAAQ,EAAE,MAAM;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM;IAH3B,QAAQ,CAAC,IAAI,oCAAoC;gBAEtC,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM;CAK5B;AAED,qBAAa,yBAA0B,SAAQ,KAAK;IAClD,QAAQ,CAAC,IAAI,oCAAoC;gBACrC,EAAE,EAAE,MAAM;CAIvB;AAED,qBAAa,kCAAmC,SAAQ,KAAK;IAC3D,QAAQ,CAAC,IAAI,sCAAsC;;CAOpD;AAED,qBAAa,uBAAwB,SAAQ,KAAK;IAChD,QAAQ,CAAC,IAAI,kCAAkC;gBACnC,IAAI,EAAE,MAAM;CAMzB;AAED,qBAAa,oCAAqC,SAAQ,KAAK;IAC7D,QAAQ,CAAC,IAAI,iDAAiD;gBAClD,IAAI,EAAE,MAAM;CAMzB"}
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/errors.ts"],"names":[],"mappings":"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"}
|
package/dist/src/errors.js
CHANGED
|
@@ -82,6 +82,102 @@ export class ConversionNotDefinedError extends Error {
|
|
|
82
82
|
this.name = 'ConversionNotDefinedError';
|
|
83
83
|
}
|
|
84
84
|
}
|
|
85
|
+
/**
|
|
86
|
+
* A conversion was requested by a name that names neither an image preset nor a transformer of the
|
|
87
|
+
* record's collection — the transformer counterpart of {@link ConversionNotDefinedError}, raised by
|
|
88
|
+
* `MediaLibrary.transform`.
|
|
89
|
+
*/
|
|
90
|
+
export class TransformerNotDefinedError extends Error {
|
|
91
|
+
code = 'E_MEDIA_TRANSFORMER_NOT_DEFINED';
|
|
92
|
+
constructor(collection, transformer) {
|
|
93
|
+
super(`Transformer "${transformer}" is not defined for collection "${collection}"`);
|
|
94
|
+
this.name = 'TransformerNotDefinedError';
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* A transformer-produced conversion was read (`url` / `deliver` / HLS delivery) before it was
|
|
99
|
+
* generated. Deliberately NOT generated lazily on read like image conversions: a transform is
|
|
100
|
+
* assumed heavy (a video remux takes minutes), and a read path is the wrong place to pay that.
|
|
101
|
+
* Generate it explicitly — `media.library.transform(id, name)` from a job — then read again.
|
|
102
|
+
*/
|
|
103
|
+
export class TransformNotReadyError extends Error {
|
|
104
|
+
mediaId;
|
|
105
|
+
transformer;
|
|
106
|
+
code = 'E_MEDIA_TRANSFORM_NOT_READY';
|
|
107
|
+
constructor(mediaId, transformer) {
|
|
108
|
+
super(`Conversion "${transformer}" of media "${mediaId}" has not been generated yet. Transformer conversions are never generated inside a read path — run \`media.library.transform('${mediaId}', '${transformer}')\` (idempotent; call it from a job) and retry.`);
|
|
109
|
+
this.mediaId = mediaId;
|
|
110
|
+
this.transformer = transformer;
|
|
111
|
+
this.name = 'TransformNotReadyError';
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Two derivatives of one collection claim the same name. Presets and transformers persist into the
|
|
116
|
+
* same `record.conversions` map, so the namespace is shared; raised at registry construction (boot),
|
|
117
|
+
* not on first attach.
|
|
118
|
+
*/
|
|
119
|
+
export class TransformerConflictError extends Error {
|
|
120
|
+
code = 'E_MEDIA_TRANSFORMER_CONFLICT';
|
|
121
|
+
constructor(collection, name) {
|
|
122
|
+
super(`Collection "${collection}" defines more than one conversion or transformer named "${name}". Preset and transformer names share the \`record.conversions\` namespace, so each name may appear once per collection.`);
|
|
123
|
+
this.name = 'TransformerConflictError';
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* A transformer needs a runtime capability the host doesn't provide — an optional peer that isn't
|
|
128
|
+
* installed (`mediabunny`), or an API the runtime lacks (WebCodecs in Node). Thrown by the built-in
|
|
129
|
+
* transformers and available for custom ones, so "this environment can't do that" always surfaces
|
|
130
|
+
* as one clear, typed error instead of a deep import/undefined crash.
|
|
131
|
+
*/
|
|
132
|
+
export class TransformerRuntimeMissingError extends Error {
|
|
133
|
+
transformer;
|
|
134
|
+
requirement;
|
|
135
|
+
code = 'E_MEDIA_TRANSFORMER_RUNTIME_MISSING';
|
|
136
|
+
constructor(transformer, requirement, hint) {
|
|
137
|
+
super(`Transformer "${transformer}" requires ${requirement}, which is not available in this runtime.${hint ? ` ${hint}` : ''}`);
|
|
138
|
+
this.transformer = transformer;
|
|
139
|
+
this.requirement = requirement;
|
|
140
|
+
this.name = 'TransformerRuntimeMissingError';
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* A transformer violated the output contract: wrote outside its prefix (`..`/absolute path),
|
|
145
|
+
* declared an `entry` it never wrote, or wrote artifacts without declaring an entry. These are
|
|
146
|
+
* programming errors in the transformer, surfaced with the transformer's name so the broken one is
|
|
147
|
+
* obvious.
|
|
148
|
+
*/
|
|
149
|
+
export class TransformerOutputError extends Error {
|
|
150
|
+
code = 'E_MEDIA_TRANSFORMER_OUTPUT_INVALID';
|
|
151
|
+
constructor(transformer, reason) {
|
|
152
|
+
super(`Transformer "${transformer}" produced an invalid output: ${reason}`);
|
|
153
|
+
this.name = 'TransformerOutputError';
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* A metadata-only conversion (a probe, a blurhash) was asked for its file — `url`, `signedUrl` or
|
|
158
|
+
* `deliver` — but it has no artifact; only `record.conversions[name].meta` exists. Read the record
|
|
159
|
+
* instead of a URL.
|
|
160
|
+
*/
|
|
161
|
+
export class ConversionArtifactMissingError extends Error {
|
|
162
|
+
code = 'E_MEDIA_CONVERSION_ARTIFACT_MISSING';
|
|
163
|
+
constructor(mediaId, conversion) {
|
|
164
|
+
super(`Conversion "${conversion}" of media "${mediaId}" is metadata-only — it has no artifact to deliver. Its result lives on \`record.conversions['${conversion}'].meta\`.`);
|
|
165
|
+
this.name = 'ConversionArtifactMissingError';
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* The HLS transformer could not stream-copy the source: a track's codec cannot be carried by the
|
|
170
|
+
* segment format (MPEG-TS wants h264/aac), and no re-encode path exists in this runtime. Definitive
|
|
171
|
+
* for the file — retrying cannot fix it; re-encode the source, or provide a WebCodecs
|
|
172
|
+
* implementation (see `transformers.hls({ webcodecs })`).
|
|
173
|
+
*/
|
|
174
|
+
export class HlsSourceUnsupportedError extends Error {
|
|
175
|
+
code = 'E_MEDIA_HLS_SOURCE_UNSUPPORTED';
|
|
176
|
+
constructor(details) {
|
|
177
|
+
super(`HLS remux is impossible for this source: ${details}. Without an encoder (WebCodecs) the tracks can only be stream-copied, so an incompatible codec is definitive — re-encode the source to h264/aac, or configure \`transformers.hls({ webcodecs })\` with a WebCodecs implementation to enable the re-encode fallback.`);
|
|
178
|
+
this.name = 'HlsSourceUnsupportedError';
|
|
179
|
+
}
|
|
180
|
+
}
|
|
85
181
|
export class ImageProcessorMissingError extends Error {
|
|
86
182
|
code = 'E_MEDIA_IMAGE_PROCESSOR_MISSING';
|
|
87
183
|
constructor() {
|
|
@@ -128,6 +224,55 @@ export class UploadSessionExpiredError extends Error {
|
|
|
128
224
|
this.name = 'UploadSessionExpiredError';
|
|
129
225
|
}
|
|
130
226
|
}
|
|
227
|
+
/**
|
|
228
|
+
* A part size the S3 multipart API cannot honour: below the 5 MiB minimum (every part but the last
|
|
229
|
+
* must reach it, or `CompleteMultipartUpload` fails with `EntityTooSmall` AFTER the client uploaded
|
|
230
|
+
* everything), or small enough that the file would need more than the 10,000 parts S3 allows.
|
|
231
|
+
* Raised at `initiate`, where it costs nothing — the alternative is discovering it at complete,
|
|
232
|
+
* when the whole file has already crossed the wire.
|
|
233
|
+
*/
|
|
234
|
+
export class UploadPartSizeError extends Error {
|
|
235
|
+
code = 'E_MEDIA_UPLOAD_PART_SIZE';
|
|
236
|
+
constructor(detail) {
|
|
237
|
+
super(`Invalid multipart part size: ${detail}`);
|
|
238
|
+
this.name = 'UploadPartSizeError';
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
/** A confirmed part number outside `1..totalParts` for the session — a client slicing with the wrong part size. */
|
|
242
|
+
export class UploadPartOutOfRangeError extends Error {
|
|
243
|
+
partNumber;
|
|
244
|
+
totalParts;
|
|
245
|
+
code = 'E_MEDIA_UPLOAD_PART_OUT_OF_RANGE';
|
|
246
|
+
constructor(partNumber, totalParts) {
|
|
247
|
+
super(`Part number ${partNumber} is outside this upload's range (1..${totalParts}). The client must slice the file with the partSize the session was created with.`);
|
|
248
|
+
this.partNumber = partNumber;
|
|
249
|
+
this.totalParts = totalParts;
|
|
250
|
+
this.name = 'UploadPartOutOfRangeError';
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* `complete()` was asked to assemble an upload whose parts are not all accounted for (neither
|
|
255
|
+
* confirmed to the session nor supplied in the call). Failing fast here names the EXACT missing
|
|
256
|
+
* part numbers; letting S3 discover it returns an opaque `InvalidPart` after a round-trip.
|
|
257
|
+
*/
|
|
258
|
+
export class UploadPartsIncompleteError extends Error {
|
|
259
|
+
sessionId;
|
|
260
|
+
missingParts;
|
|
261
|
+
code = 'E_MEDIA_UPLOAD_PARTS_INCOMPLETE';
|
|
262
|
+
constructor(sessionId, missingParts) {
|
|
263
|
+
super(`Cannot complete upload session ${sessionId}: no ETag for part(s) ${missingParts.join(', ')}. Upload and confirm them (or pass them to complete()) first — status() lists what is pending.`);
|
|
264
|
+
this.sessionId = sessionId;
|
|
265
|
+
this.missingParts = missingParts;
|
|
266
|
+
this.name = 'UploadPartsIncompleteError';
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
export class DirectUploadsNotConfiguredError extends Error {
|
|
270
|
+
code = 'E_MEDIA_DIRECT_NOT_CONFIGURED';
|
|
271
|
+
constructor() {
|
|
272
|
+
super("Session-backed direct uploads are not configured. Set `uploads.direct` in config/media.ts (e.g. `direct: { store: 'lucid', stores: { lucid: uploadSessions.lucid() } }`) to enable the direct upload session store.");
|
|
273
|
+
this.name = 'DirectUploadsNotConfiguredError';
|
|
274
|
+
}
|
|
275
|
+
}
|
|
131
276
|
export class ResumableUploadsNotConfiguredError extends Error {
|
|
132
277
|
code = 'E_MEDIA_RESUMABLE_NOT_CONFIGURED';
|
|
133
278
|
constructor() {
|
package/dist/src/errors.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/errors.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/errors.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import type { DeliveryResult } from '../delivery.js';
|
|
2
|
+
import type { MediaLibrary } from '../media_library.js';
|
|
3
|
+
/** Identifies one file of a media's HLS package, handed to the URL callbacks. */
|
|
4
|
+
export interface HlsFileRef {
|
|
5
|
+
mediaId: string;
|
|
6
|
+
/** Package-relative artifact path (`'index.m3u8'`, `'playlist-1.m3u8'`, `'segment-0-3.ts'`). */
|
|
7
|
+
file: string;
|
|
8
|
+
}
|
|
9
|
+
/** Builds the URL a rewritten playlist reference should point at. */
|
|
10
|
+
export type HlsUrlBuilder = (ref: HlsFileRef) => string | Promise<string>;
|
|
11
|
+
/** What {@link HlsDeliveryHandler.handle} is asked to serve. */
|
|
12
|
+
export interface HlsDeliveryRequest {
|
|
13
|
+
mediaId: string;
|
|
14
|
+
/**
|
|
15
|
+
* Which file of the package, relative to the conversion prefix. Omit for the entry (master)
|
|
16
|
+
* playlist. Validated against the conversion's persisted artifact list, so a request can never
|
|
17
|
+
* reach outside the package.
|
|
18
|
+
*/
|
|
19
|
+
file?: string | undefined;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* What serving one HLS package file yields: playlists come back as rewritten text (they are
|
|
23
|
+
* *always* rewritten, never proxied raw — raw ones reference the storage layout, not URLs), and
|
|
24
|
+
* media files come back as the usual {@link DeliveryResult} (`redirect` to a signed URL, or a
|
|
25
|
+
* `stream` to pipe).
|
|
26
|
+
*/
|
|
27
|
+
export type HlsDeliveryResult = {
|
|
28
|
+
kind: 'playlist';
|
|
29
|
+
content: string;
|
|
30
|
+
contentType: string;
|
|
31
|
+
fileName: string;
|
|
32
|
+
} | DeliveryResult;
|
|
33
|
+
export interface HlsDeliveryHandlerOptions {
|
|
34
|
+
/** The {@link MediaLibrary} records are resolved from — or a `MediaManager`, whose `.library` is used. */
|
|
35
|
+
library: MediaLibrary | {
|
|
36
|
+
library: MediaLibrary;
|
|
37
|
+
};
|
|
38
|
+
/** Name of the HLS conversion on the record. Default `'hls'` (the {@link HlsTransformer} default). */
|
|
39
|
+
conversion?: string | undefined;
|
|
40
|
+
/**
|
|
41
|
+
* URL for a **sub-playlist** reference (master → media playlists, audio renditions). Required,
|
|
42
|
+
* and it should point back at a route of yours that calls this handler again — playlists must be
|
|
43
|
+
* rewritten on every hop, and your route is where your authorization runs. There is no safe
|
|
44
|
+
* library default: presigning a playlist would serve it raw from storage, whose relative
|
|
45
|
+
* references then resolve against the storage host and break (or leak).
|
|
46
|
+
*/
|
|
47
|
+
urlForPlaylist: HlsUrlBuilder;
|
|
48
|
+
/**
|
|
49
|
+
* URL for a **media** reference (segments, init sections). Default: a presigned URL straight to
|
|
50
|
+
* the object on the disk (`segmentTtlSeconds` lifetime) — the common case, letting players pull
|
|
51
|
+
* segments from storage/CDN without the bytes transiting your app. Point it at your own proxy
|
|
52
|
+
* route instead when storage isn't reachable from clients (then serve those requests with
|
|
53
|
+
* {@link HlsDeliveryHandler.handle}, which streams media files per `segmentDelivery`).
|
|
54
|
+
*/
|
|
55
|
+
urlForSegment?: HlsUrlBuilder | undefined;
|
|
56
|
+
/** Lifetime of default presigned segment URLs, seconds. Default 300. */
|
|
57
|
+
segmentTtlSeconds?: number | undefined;
|
|
58
|
+
/**
|
|
59
|
+
* How {@link HlsDeliveryHandler.handle} answers a request for a media file (it always answers
|
|
60
|
+
* playlists with rewritten text): `'redirect'` (default) to a presigned URL, or `'stream'` to
|
|
61
|
+
* proxy the bytes through the app.
|
|
62
|
+
*/
|
|
63
|
+
segmentDelivery?: 'redirect' | 'stream' | undefined;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Framework-agnostic HLS read path — the {@link MediaDeliveryHandler} of a transformer-generated
|
|
67
|
+
* HLS package. One route of yours receives `(:mediaId, :file?)` and delegates here; the handler
|
|
68
|
+
* resolves the record's HLS conversion, validates the requested file against the package's
|
|
69
|
+
* persisted artifact list, and:
|
|
70
|
+
*
|
|
71
|
+
* - for a **playlist**: returns its content with every relative reference rewritten — sub-playlist
|
|
72
|
+
* references through your `urlForPlaylist` (auth stays yours), media references through
|
|
73
|
+
* `urlForSegment` or a presigned URL;
|
|
74
|
+
* - for a **media file**: returns a `redirect` (presigned) or a `stream`, per `segmentDelivery`.
|
|
75
|
+
*
|
|
76
|
+
* ```ts
|
|
77
|
+
* const hls = new HlsDeliveryHandler({
|
|
78
|
+
* library: media,
|
|
79
|
+
* urlForPlaylist: ({ mediaId, file }) => router.makeUrl('videos.hls', { id: mediaId, file }),
|
|
80
|
+
* })
|
|
81
|
+
*
|
|
82
|
+
* router.get('/videos/:id/hls/:file?', async ({ params, response, auth }) => {
|
|
83
|
+
* await authorize(auth.user, params.id) // ← the app's job, as everywhere
|
|
84
|
+
* const result = await hls.handle({ mediaId: params.id, file: params.file })
|
|
85
|
+
* if (result.kind === 'redirect') return response.redirect(result.url)
|
|
86
|
+
* if (result.kind === 'stream') {
|
|
87
|
+
* response.header('content-type', result.mimeType)
|
|
88
|
+
* return response.stream(result.stream)
|
|
89
|
+
* }
|
|
90
|
+
* response.header('content-type', result.contentType)
|
|
91
|
+
* return response.send(result.content)
|
|
92
|
+
* }).use(middleware.auth())
|
|
93
|
+
* ```
|
|
94
|
+
*
|
|
95
|
+
* **This handler performs NO authorization** — the same split as {@link MediaDeliveryHandler} and
|
|
96
|
+
* `TusUploadHandler`: guard the route before calling `handle`. Note that a presigned segment URL
|
|
97
|
+
* (the default) is itself a capability: whoever holds it can fetch that segment until the TTL
|
|
98
|
+
* expires. That is the standard HLS trade-off — keep `segmentTtlSeconds` short, or use
|
|
99
|
+
* `segmentDelivery: 'stream'` with a segment `urlForSegment` pointing back at your route to keep
|
|
100
|
+
* every byte behind your auth.
|
|
101
|
+
*/
|
|
102
|
+
export declare class HlsDeliveryHandler {
|
|
103
|
+
private readonly library;
|
|
104
|
+
private readonly conversion;
|
|
105
|
+
private readonly urlForPlaylist;
|
|
106
|
+
private readonly urlForSegment;
|
|
107
|
+
private readonly segmentTtlSeconds;
|
|
108
|
+
private readonly segmentDelivery;
|
|
109
|
+
constructor(options: HlsDeliveryHandlerOptions);
|
|
110
|
+
handle(request: HlsDeliveryRequest): Promise<HlsDeliveryResult>;
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=delivery.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delivery.d.ts","sourceRoot":"","sources":["../../../src/hls/delivery.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAOrD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAQxD,iFAAiF;AACjF,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,gGAAgG;IAChG,IAAI,EAAE,MAAM,CAAC;CACd;AAED,qEAAqE;AACrE,MAAM,MAAM,aAAa,GAAG,CAAC,GAAG,EAAE,UAAU,KAAK,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;AAE1E,gEAAgE;AAChE,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC3B;AAED;;;;;GAKG;AACH,MAAM,MAAM,iBAAiB,GACzB;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAC5E,cAAc,CAAC;AAEnB,MAAM,WAAW,yBAAyB;IACxC,0GAA0G;IAC1G,OAAO,EAAE,YAAY,GAAG;QAAE,OAAO,EAAE,YAAY,CAAA;KAAE,CAAC;IAClD,sGAAsG;IACtG,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC;;;;;;OAMG;IACH,cAAc,EAAE,aAAa,CAAC;IAC9B;;;;;;OAMG;IACH,aAAa,CAAC,EAAE,aAAa,GAAG,SAAS,CAAC;IAC1C,wEAAwE;IACxE,iBAAiB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACvC;;;;OAIG;IACH,eAAe,CAAC,EAAE,UAAU,GAAG,QAAQ,GAAG,SAAS,CAAC;CACrD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAe;IACvC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAgB;IAC/C,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA4B;IAC1D,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAS;IAC3C,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAwB;gBAE5C,OAAO,EAAE,yBAAyB;IAUxC,MAAM,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,iBAAiB,CAAC;CA+DtE"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { DEFAULT_DELIVERY_SIGNED_TTL_SECONDS } from '../delivery.js';
|
|
2
|
+
import { ConversionArtifactMissingError, MediaNotFoundError, TransformNotReadyError, } from '../errors.js';
|
|
3
|
+
import { HLS_PLAYLIST_CONTENT_TYPE, hlsArtifactContentType, resolvePackagePath, rewriteHlsPlaylist, } from './playlist.js';
|
|
4
|
+
/**
|
|
5
|
+
* Framework-agnostic HLS read path — the {@link MediaDeliveryHandler} of a transformer-generated
|
|
6
|
+
* HLS package. One route of yours receives `(:mediaId, :file?)` and delegates here; the handler
|
|
7
|
+
* resolves the record's HLS conversion, validates the requested file against the package's
|
|
8
|
+
* persisted artifact list, and:
|
|
9
|
+
*
|
|
10
|
+
* - for a **playlist**: returns its content with every relative reference rewritten — sub-playlist
|
|
11
|
+
* references through your `urlForPlaylist` (auth stays yours), media references through
|
|
12
|
+
* `urlForSegment` or a presigned URL;
|
|
13
|
+
* - for a **media file**: returns a `redirect` (presigned) or a `stream`, per `segmentDelivery`.
|
|
14
|
+
*
|
|
15
|
+
* ```ts
|
|
16
|
+
* const hls = new HlsDeliveryHandler({
|
|
17
|
+
* library: media,
|
|
18
|
+
* urlForPlaylist: ({ mediaId, file }) => router.makeUrl('videos.hls', { id: mediaId, file }),
|
|
19
|
+
* })
|
|
20
|
+
*
|
|
21
|
+
* router.get('/videos/:id/hls/:file?', async ({ params, response, auth }) => {
|
|
22
|
+
* await authorize(auth.user, params.id) // ← the app's job, as everywhere
|
|
23
|
+
* const result = await hls.handle({ mediaId: params.id, file: params.file })
|
|
24
|
+
* if (result.kind === 'redirect') return response.redirect(result.url)
|
|
25
|
+
* if (result.kind === 'stream') {
|
|
26
|
+
* response.header('content-type', result.mimeType)
|
|
27
|
+
* return response.stream(result.stream)
|
|
28
|
+
* }
|
|
29
|
+
* response.header('content-type', result.contentType)
|
|
30
|
+
* return response.send(result.content)
|
|
31
|
+
* }).use(middleware.auth())
|
|
32
|
+
* ```
|
|
33
|
+
*
|
|
34
|
+
* **This handler performs NO authorization** — the same split as {@link MediaDeliveryHandler} and
|
|
35
|
+
* `TusUploadHandler`: guard the route before calling `handle`. Note that a presigned segment URL
|
|
36
|
+
* (the default) is itself a capability: whoever holds it can fetch that segment until the TTL
|
|
37
|
+
* expires. That is the standard HLS trade-off — keep `segmentTtlSeconds` short, or use
|
|
38
|
+
* `segmentDelivery: 'stream'` with a segment `urlForSegment` pointing back at your route to keep
|
|
39
|
+
* every byte behind your auth.
|
|
40
|
+
*/
|
|
41
|
+
export class HlsDeliveryHandler {
|
|
42
|
+
library;
|
|
43
|
+
conversion;
|
|
44
|
+
urlForPlaylist;
|
|
45
|
+
urlForSegment;
|
|
46
|
+
segmentTtlSeconds;
|
|
47
|
+
segmentDelivery;
|
|
48
|
+
constructor(options) {
|
|
49
|
+
const source = options.library;
|
|
50
|
+
this.library = 'library' in source ? source.library : source;
|
|
51
|
+
this.conversion = options.conversion ?? 'hls';
|
|
52
|
+
this.urlForPlaylist = options.urlForPlaylist;
|
|
53
|
+
this.urlForSegment = options.urlForSegment;
|
|
54
|
+
this.segmentTtlSeconds = options.segmentTtlSeconds ?? DEFAULT_DELIVERY_SIGNED_TTL_SECONDS;
|
|
55
|
+
this.segmentDelivery = options.segmentDelivery ?? 'redirect';
|
|
56
|
+
}
|
|
57
|
+
async handle(request) {
|
|
58
|
+
const { mediaId } = request;
|
|
59
|
+
const record = await this.library.find(mediaId);
|
|
60
|
+
if (!record)
|
|
61
|
+
throw new MediaNotFoundError(mediaId);
|
|
62
|
+
const variant = record.conversions[this.conversion];
|
|
63
|
+
if (!variant)
|
|
64
|
+
throw new TransformNotReadyError(mediaId, this.conversion);
|
|
65
|
+
if (variant.path === undefined || variant.disk === undefined) {
|
|
66
|
+
throw new ConversionArtifactMissingError(mediaId, this.conversion);
|
|
67
|
+
}
|
|
68
|
+
// The package's shape comes from what the transformer persisted; a hand-registered
|
|
69
|
+
// single-file conversion degrades to a one-file package.
|
|
70
|
+
const prefix = variant.prefix ?? variant.path.slice(0, variant.path.lastIndexOf('/') + 1);
|
|
71
|
+
const files = variant.files ?? [variant.path.slice(prefix.length)];
|
|
72
|
+
const entry = variant.path.slice(prefix.length);
|
|
73
|
+
const requested = request.file === undefined || request.file === '' ? entry : request.file;
|
|
74
|
+
// Membership in the persisted artifact list is the whole access check: no path arithmetic on
|
|
75
|
+
// caller input ever reaches the disk, so traversal is structurally impossible.
|
|
76
|
+
if (!files.includes(requested)) {
|
|
77
|
+
throw new MediaNotFoundError(`${mediaId}#${this.conversion}:${requested}`);
|
|
78
|
+
}
|
|
79
|
+
const disk = this.library.storage.disk(variant.disk);
|
|
80
|
+
const key = `${prefix}${requested}`;
|
|
81
|
+
if (requested.toLowerCase().endsWith('.m3u8')) {
|
|
82
|
+
const content = Buffer.from(await disk.getBytes(key)).toString('utf8');
|
|
83
|
+
const rewritten = await rewriteHlsPlaylist(content, async (ref) => {
|
|
84
|
+
const target = resolvePackagePath(requested, ref.uri);
|
|
85
|
+
// A relative reference that escapes the package or names a file the transformer never
|
|
86
|
+
// wrote is not ours to rewrite — leave it exactly as it was.
|
|
87
|
+
if (target === null || !files.includes(target))
|
|
88
|
+
return ref.uri;
|
|
89
|
+
if (ref.kind === 'playlist')
|
|
90
|
+
return this.urlForPlaylist({ mediaId, file: target });
|
|
91
|
+
if (this.urlForSegment)
|
|
92
|
+
return this.urlForSegment({ mediaId, file: target });
|
|
93
|
+
return disk.getSignedUrl(`${prefix}${target}`, { expiresIn: this.segmentTtlSeconds });
|
|
94
|
+
});
|
|
95
|
+
return {
|
|
96
|
+
kind: 'playlist',
|
|
97
|
+
content: rewritten,
|
|
98
|
+
contentType: HLS_PLAYLIST_CONTENT_TYPE,
|
|
99
|
+
fileName: requested,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
if (this.segmentDelivery === 'redirect') {
|
|
103
|
+
return {
|
|
104
|
+
kind: 'redirect',
|
|
105
|
+
url: await disk.getSignedUrl(key, { expiresIn: this.segmentTtlSeconds }),
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
const metadata = await disk.getMetaData(key);
|
|
109
|
+
return {
|
|
110
|
+
kind: 'stream',
|
|
111
|
+
stream: await disk.getStream(key),
|
|
112
|
+
mimeType: metadata.contentType ?? hlsArtifactContentType(requested) ?? 'application/octet-stream',
|
|
113
|
+
size: metadata.contentLength,
|
|
114
|
+
fileName: requested.slice(requested.lastIndexOf('/') + 1),
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=delivery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delivery.js","sourceRoot":"","sources":["../../../src/hls/delivery.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HLS playlist (`.m3u8`) reference rewriting — the read-side half of the HLS transformer.
|
|
3
|
+
*
|
|
4
|
+
* Playlists are STORED with references relative to the package's storage layout (that is what the
|
|
5
|
+
* muxer emits, and it keeps the stored artifacts location-agnostic). At serve time those
|
|
6
|
+
* references must become URLs the player can actually fetch — the app's authenticated proxy
|
|
7
|
+
* routes, presigned object URLs, a CDN — and only the app knows which. This module does the part
|
|
8
|
+
* that is the same everywhere: find every reference in a playlist, classify it, and let a
|
|
9
|
+
* callback decide the URL. See {@link HlsDeliveryHandler} for the assembled read path.
|
|
10
|
+
*/
|
|
11
|
+
/** Content type playlists are served with (RFC 8216's `application/vnd.apple.mpegurl`). */
|
|
12
|
+
export declare const HLS_PLAYLIST_CONTENT_TYPE = "application/vnd.apple.mpegurl";
|
|
13
|
+
/** Content type for MPEG-TS segments. */
|
|
14
|
+
export declare const HLS_SEGMENT_CONTENT_TYPE = "video/mp2t";
|
|
15
|
+
/** One URI reference found in a playlist, handed to the {@link HlsUriRewriter}. */
|
|
16
|
+
export interface HlsUriRef {
|
|
17
|
+
/** The reference exactly as it appears in the playlist (may carry a query string). */
|
|
18
|
+
uri: string;
|
|
19
|
+
/**
|
|
20
|
+
* `'playlist'` for `.m3u8` references (variant streams in a master playlist, audio/subtitle
|
|
21
|
+
* renditions via `#EXT-X-MEDIA`), `'media'` for everything else (segments, `#EXT-X-MAP` init
|
|
22
|
+
* sections, keys). Classified by extension, ignoring any query/fragment.
|
|
23
|
+
*/
|
|
24
|
+
kind: 'playlist' | 'media';
|
|
25
|
+
/**
|
|
26
|
+
* The tag whose `URI="…"` attribute holds this reference (`'EXT-X-MEDIA'`, `'EXT-X-MAP'`,
|
|
27
|
+
* `'EXT-X-I-FRAME-STREAM-INF'`, …), or `undefined` for a plain URI line.
|
|
28
|
+
*/
|
|
29
|
+
tag?: string;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Maps one playlist reference to the URI that should replace it. Return the input unchanged to
|
|
33
|
+
* keep a reference as-is. May be async — building the replacement routinely involves presigning.
|
|
34
|
+
*/
|
|
35
|
+
export type HlsUriRewriter = (ref: HlsUriRef) => string | Promise<string>;
|
|
36
|
+
/**
|
|
37
|
+
* Rewrite every **relative** URI reference in an HLS playlist through `rewrite`, covering all the
|
|
38
|
+
* places RFC 8216 puts one:
|
|
39
|
+
*
|
|
40
|
+
* - plain URI lines (segments in a media playlist, variant playlists in a master playlist),
|
|
41
|
+
* - `URI="…"` attributes on tags (`#EXT-X-MEDIA` audio/subtitle renditions, `#EXT-X-MAP` init
|
|
42
|
+
* sections, `#EXT-X-I-FRAME-STREAM-INF`, `#EXT-X-KEY`, …).
|
|
43
|
+
*
|
|
44
|
+
* Untouched, by design:
|
|
45
|
+
* - **absolute** references (`https://…`, protocol-relative `//…`, root-relative `/…`) — they no
|
|
46
|
+
* longer describe the storage layout, so rewriting them is not this function's business;
|
|
47
|
+
* - comments and every other tag/line, byte for byte (line endings included).
|
|
48
|
+
*/
|
|
49
|
+
export declare function rewriteHlsPlaylist(content: string, rewrite: HlsUriRewriter): Promise<string>;
|
|
50
|
+
/**
|
|
51
|
+
* Whether a playlist reference is relative to the playlist's own location — the only kind that
|
|
52
|
+
* describes the storage layout and therefore the only kind {@link rewriteHlsPlaylist} rewrites.
|
|
53
|
+
* Anything carrying a scheme (`https:`, `data:`), protocol-relative (`//cdn/…`) or root-relative
|
|
54
|
+
* (`/api/…`) is already an address, not a layout detail.
|
|
55
|
+
*/
|
|
56
|
+
export declare function isRelativeUri(uri: string): boolean;
|
|
57
|
+
/** Classify a reference by extension (query/fragment ignored): `.m3u8` ⇒ playlist, else media. */
|
|
58
|
+
export declare function classifyUri(uri: string): 'playlist' | 'media';
|
|
59
|
+
/**
|
|
60
|
+
* Resolve a reference found in playlist `fromFile` (both package-relative) to the package-relative
|
|
61
|
+
* path it points at, collapsing `.`/`..` segments. Returns `null` when the reference escapes the
|
|
62
|
+
* package root — the caller treats that as "not one of ours" and leaves it alone.
|
|
63
|
+
*/
|
|
64
|
+
export declare function resolvePackagePath(fromFile: string, uri: string): string | null;
|
|
65
|
+
/** Content type for one artifact of an HLS package, by extension. */
|
|
66
|
+
export declare function hlsArtifactContentType(file: string): string | undefined;
|
|
67
|
+
//# sourceMappingURL=playlist.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"playlist.d.ts","sourceRoot":"","sources":["../../../src/hls/playlist.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,2FAA2F;AAC3F,eAAO,MAAM,yBAAyB,kCAAkC,CAAC;AAEzE,yCAAyC;AACzC,eAAO,MAAM,wBAAwB,eAAe,CAAC;AAErD,mFAAmF;AACnF,MAAM,WAAW,SAAS;IACxB,sFAAsF;IACtF,GAAG,EAAE,MAAM,CAAC;IACZ;;;;OAIG;IACH,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC;IAC3B;;;OAGG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;;GAGG;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,GAAG,EAAE,SAAS,KAAK,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;AAE1E;;;;;;;;;;;;GAYG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,MAAM,CAAC,CAmBjB;AAyBD;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAGlD;AAED,kGAAkG;AAClG,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,GAAG,OAAO,CAG7D;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAe/E;AAED,qEAAqE;AACrE,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CASvE"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HLS playlist (`.m3u8`) reference rewriting — the read-side half of the HLS transformer.
|
|
3
|
+
*
|
|
4
|
+
* Playlists are STORED with references relative to the package's storage layout (that is what the
|
|
5
|
+
* muxer emits, and it keeps the stored artifacts location-agnostic). At serve time those
|
|
6
|
+
* references must become URLs the player can actually fetch — the app's authenticated proxy
|
|
7
|
+
* routes, presigned object URLs, a CDN — and only the app knows which. This module does the part
|
|
8
|
+
* that is the same everywhere: find every reference in a playlist, classify it, and let a
|
|
9
|
+
* callback decide the URL. See {@link HlsDeliveryHandler} for the assembled read path.
|
|
10
|
+
*/
|
|
11
|
+
/** Content type playlists are served with (RFC 8216's `application/vnd.apple.mpegurl`). */
|
|
12
|
+
export const HLS_PLAYLIST_CONTENT_TYPE = 'application/vnd.apple.mpegurl';
|
|
13
|
+
/** Content type for MPEG-TS segments. */
|
|
14
|
+
export const HLS_SEGMENT_CONTENT_TYPE = 'video/mp2t';
|
|
15
|
+
/**
|
|
16
|
+
* Rewrite every **relative** URI reference in an HLS playlist through `rewrite`, covering all the
|
|
17
|
+
* places RFC 8216 puts one:
|
|
18
|
+
*
|
|
19
|
+
* - plain URI lines (segments in a media playlist, variant playlists in a master playlist),
|
|
20
|
+
* - `URI="…"` attributes on tags (`#EXT-X-MEDIA` audio/subtitle renditions, `#EXT-X-MAP` init
|
|
21
|
+
* sections, `#EXT-X-I-FRAME-STREAM-INF`, `#EXT-X-KEY`, …).
|
|
22
|
+
*
|
|
23
|
+
* Untouched, by design:
|
|
24
|
+
* - **absolute** references (`https://…`, protocol-relative `//…`, root-relative `/…`) — they no
|
|
25
|
+
* longer describe the storage layout, so rewriting them is not this function's business;
|
|
26
|
+
* - comments and every other tag/line, byte for byte (line endings included).
|
|
27
|
+
*/
|
|
28
|
+
export async function rewriteHlsPlaylist(content, rewrite) {
|
|
29
|
+
// Split keeping the separators, so CRLF/LF survive exactly as they came.
|
|
30
|
+
const parts = content.split(/(\r?\n)/);
|
|
31
|
+
for (let i = 0; i < parts.length; i += 2) {
|
|
32
|
+
const line = parts[i];
|
|
33
|
+
if (line === undefined || line === '')
|
|
34
|
+
continue;
|
|
35
|
+
if (line.startsWith('#')) {
|
|
36
|
+
if (line.startsWith('#EXT'))
|
|
37
|
+
parts[i] = await rewriteTagUris(line, rewrite);
|
|
38
|
+
continue; // plain comment: untouched
|
|
39
|
+
}
|
|
40
|
+
const uri = line.trim();
|
|
41
|
+
if (uri === '' || !isRelativeUri(uri))
|
|
42
|
+
continue;
|
|
43
|
+
const replacement = await rewrite({ uri, kind: classifyUri(uri) });
|
|
44
|
+
// Preserve any surrounding whitespace on the line, replacing only the URI itself.
|
|
45
|
+
parts[i] = line.replace(uri, replacement);
|
|
46
|
+
}
|
|
47
|
+
return parts.join('');
|
|
48
|
+
}
|
|
49
|
+
const TAG_URI_ATTRIBUTE = /URI="([^"]*)"/g;
|
|
50
|
+
/** Rewrite every relative `URI="…"` attribute on one tag line. */
|
|
51
|
+
async function rewriteTagUris(line, rewrite) {
|
|
52
|
+
const colon = line.indexOf(':');
|
|
53
|
+
const tag = (colon === -1 ? line.slice(1) : line.slice(1, colon)).trim();
|
|
54
|
+
let output = '';
|
|
55
|
+
let consumed = 0;
|
|
56
|
+
for (const match of line.matchAll(TAG_URI_ATTRIBUTE)) {
|
|
57
|
+
const uri = match[1];
|
|
58
|
+
output += line.slice(consumed, match.index);
|
|
59
|
+
if (uri !== '' && isRelativeUri(uri)) {
|
|
60
|
+
const replacement = await rewrite({ uri, kind: classifyUri(uri), tag });
|
|
61
|
+
output += `URI="${replacement}"`;
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
output += match[0];
|
|
65
|
+
}
|
|
66
|
+
consumed = match.index + match[0].length;
|
|
67
|
+
}
|
|
68
|
+
return output + line.slice(consumed);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Whether a playlist reference is relative to the playlist's own location — the only kind that
|
|
72
|
+
* describes the storage layout and therefore the only kind {@link rewriteHlsPlaylist} rewrites.
|
|
73
|
+
* Anything carrying a scheme (`https:`, `data:`), protocol-relative (`//cdn/…`) or root-relative
|
|
74
|
+
* (`/api/…`) is already an address, not a layout detail.
|
|
75
|
+
*/
|
|
76
|
+
export function isRelativeUri(uri) {
|
|
77
|
+
if (uri.startsWith('/'))
|
|
78
|
+
return false; // covers '//' too
|
|
79
|
+
return !/^[a-z][a-z0-9+.-]*:/i.test(uri);
|
|
80
|
+
}
|
|
81
|
+
/** Classify a reference by extension (query/fragment ignored): `.m3u8` ⇒ playlist, else media. */
|
|
82
|
+
export function classifyUri(uri) {
|
|
83
|
+
const clean = uri.split(/[?#]/, 1)[0];
|
|
84
|
+
return clean.toLowerCase().endsWith('.m3u8') ? 'playlist' : 'media';
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Resolve a reference found in playlist `fromFile` (both package-relative) to the package-relative
|
|
88
|
+
* path it points at, collapsing `.`/`..` segments. Returns `null` when the reference escapes the
|
|
89
|
+
* package root — the caller treats that as "not one of ours" and leaves it alone.
|
|
90
|
+
*/
|
|
91
|
+
export function resolvePackagePath(fromFile, uri) {
|
|
92
|
+
const clean = uri.split(/[?#]/, 1)[0];
|
|
93
|
+
const slash = fromFile.lastIndexOf('/');
|
|
94
|
+
const base = slash === -1 ? '' : fromFile.slice(0, slash + 1);
|
|
95
|
+
const resolved = [];
|
|
96
|
+
for (const segment of `${base}${clean}`.split('/')) {
|
|
97
|
+
if (segment === '' || segment === '.')
|
|
98
|
+
continue;
|
|
99
|
+
if (segment === '..') {
|
|
100
|
+
if (resolved.length === 0)
|
|
101
|
+
return null;
|
|
102
|
+
resolved.pop();
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
resolved.push(segment);
|
|
106
|
+
}
|
|
107
|
+
return resolved.length === 0 ? null : resolved.join('/');
|
|
108
|
+
}
|
|
109
|
+
/** Content type for one artifact of an HLS package, by extension. */
|
|
110
|
+
export function hlsArtifactContentType(file) {
|
|
111
|
+
const lower = file.toLowerCase();
|
|
112
|
+
if (lower.endsWith('.m3u8'))
|
|
113
|
+
return HLS_PLAYLIST_CONTENT_TYPE;
|
|
114
|
+
if (lower.endsWith('.ts'))
|
|
115
|
+
return HLS_SEGMENT_CONTENT_TYPE;
|
|
116
|
+
if (lower.endsWith('.m4s') || lower.endsWith('.mp4'))
|
|
117
|
+
return 'video/mp4';
|
|
118
|
+
if (lower.endsWith('.aac'))
|
|
119
|
+
return 'audio/aac';
|
|
120
|
+
if (lower.endsWith('.mp3'))
|
|
121
|
+
return 'audio/mpeg';
|
|
122
|
+
if (lower.endsWith('.vtt'))
|
|
123
|
+
return 'text/vtt';
|
|
124
|
+
return undefined;
|
|
125
|
+
}
|
|
126
|
+
//# sourceMappingURL=playlist.js.map
|