@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.
Files changed (117) hide show
  1. package/CHANGELOG.md +121 -0
  2. package/README.md +206 -0
  3. package/dist/providers/media_provider.d.ts +3 -13
  4. package/dist/providers/media_provider.d.ts.map +1 -1
  5. package/dist/providers/media_provider.js +151 -4
  6. package/dist/providers/media_provider.js.map +1 -1
  7. package/dist/src/content_type.d.ts +6 -1
  8. package/dist/src/content_type.d.ts.map +1 -1
  9. package/dist/src/content_type.js +102 -7
  10. package/dist/src/content_type.js.map +1 -1
  11. package/dist/src/define_config.d.ts +88 -5
  12. package/dist/src/define_config.d.ts.map +1 -1
  13. package/dist/src/define_config.js +7 -2
  14. package/dist/src/define_config.js.map +1 -1
  15. package/dist/src/direct_upload.d.ts +177 -0
  16. package/dist/src/direct_upload.d.ts.map +1 -0
  17. package/dist/src/direct_upload.js +299 -0
  18. package/dist/src/direct_upload.js.map +1 -0
  19. package/dist/src/direct_upload_handler.d.ts +83 -0
  20. package/dist/src/direct_upload_handler.d.ts.map +1 -0
  21. package/dist/src/direct_upload_handler.js +180 -0
  22. package/dist/src/direct_upload_handler.js.map +1 -0
  23. package/dist/src/disks/factory.d.ts +11 -3
  24. package/dist/src/disks/factory.d.ts.map +1 -1
  25. package/dist/src/disks/factory.js +5 -3
  26. package/dist/src/disks/factory.js.map +1 -1
  27. package/dist/src/disks/s3.d.ts +10 -0
  28. package/dist/src/disks/s3.d.ts.map +1 -1
  29. package/dist/src/disks/s3.js +96 -22
  30. package/dist/src/disks/s3.js.map +1 -1
  31. package/dist/src/disks/sigv4.d.ts +58 -0
  32. package/dist/src/disks/sigv4.d.ts.map +1 -0
  33. package/dist/src/disks/sigv4.js +87 -0
  34. package/dist/src/disks/sigv4.js.map +1 -0
  35. package/dist/src/disks/xml_fallback.d.ts +3 -3
  36. package/dist/src/disks/xml_fallback.js +3 -3
  37. package/dist/src/errors.d.ts +104 -0
  38. package/dist/src/errors.d.ts.map +1 -1
  39. package/dist/src/errors.js +145 -0
  40. package/dist/src/errors.js.map +1 -1
  41. package/dist/src/hls/delivery.d.ts +112 -0
  42. package/dist/src/hls/delivery.d.ts.map +1 -0
  43. package/dist/src/hls/delivery.js +118 -0
  44. package/dist/src/hls/delivery.js.map +1 -0
  45. package/dist/src/hls/playlist.d.ts +67 -0
  46. package/dist/src/hls/playlist.d.ts.map +1 -0
  47. package/dist/src/hls/playlist.js +126 -0
  48. package/dist/src/hls/playlist.js.map +1 -0
  49. package/dist/src/index.d.ts +18 -3
  50. package/dist/src/index.d.ts.map +1 -1
  51. package/dist/src/index.js +13 -2
  52. package/dist/src/index.js.map +1 -1
  53. package/dist/src/media_collection.d.ts +8 -1
  54. package/dist/src/media_collection.d.ts.map +1 -1
  55. package/dist/src/media_collection.js +23 -1
  56. package/dist/src/media_collection.js.map +1 -1
  57. package/dist/src/media_library.d.ts +32 -2
  58. package/dist/src/media_library.d.ts.map +1 -1
  59. package/dist/src/media_library.js +218 -11
  60. package/dist/src/media_library.js.map +1 -1
  61. package/dist/src/media_manager.d.ts +37 -2
  62. package/dist/src/media_manager.d.ts.map +1 -1
  63. package/dist/src/media_manager.js +54 -1
  64. package/dist/src/media_manager.js.map +1 -1
  65. package/dist/src/media_record.d.ts +22 -2
  66. package/dist/src/media_record.d.ts.map +1 -1
  67. package/dist/src/services/booted_app.d.ts +9 -0
  68. package/dist/src/services/booted_app.d.ts.map +1 -0
  69. package/dist/src/services/booted_app.js +33 -0
  70. package/dist/src/services/booted_app.js.map +1 -0
  71. package/dist/src/services/main.d.ts +12 -0
  72. package/dist/src/services/main.d.ts.map +1 -1
  73. package/dist/src/services/main.js +15 -3
  74. package/dist/src/services/main.js.map +1 -1
  75. package/dist/src/single_file_store.d.ts +4 -0
  76. package/dist/src/single_file_store.d.ts.map +1 -1
  77. package/dist/src/single_file_store.js +8 -4
  78. package/dist/src/single_file_store.js.map +1 -1
  79. package/dist/src/testing/fake_transformer.d.ts +32 -0
  80. package/dist/src/testing/fake_transformer.d.ts.map +1 -0
  81. package/dist/src/testing/fake_transformer.js +32 -0
  82. package/dist/src/testing/fake_transformer.js.map +1 -0
  83. package/dist/src/testing/index.d.ts +2 -0
  84. package/dist/src/testing/index.d.ts.map +1 -1
  85. package/dist/src/testing/index.js +1 -0
  86. package/dist/src/testing/index.js.map +1 -1
  87. package/dist/src/transformer.d.ts +111 -0
  88. package/dist/src/transformer.d.ts.map +1 -0
  89. package/dist/src/transformer.js +2 -0
  90. package/dist/src/transformer.js.map +1 -0
  91. package/dist/src/transformers/factory.d.ts +30 -0
  92. package/dist/src/transformers/factory.d.ts.map +1 -0
  93. package/dist/src/transformers/factory.js +34 -0
  94. package/dist/src/transformers/factory.js.map +1 -0
  95. package/dist/src/transformers/hls.d.ts +110 -0
  96. package/dist/src/transformers/hls.d.ts.map +1 -0
  97. package/dist/src/transformers/hls.js +111 -0
  98. package/dist/src/transformers/hls.js.map +1 -0
  99. package/dist/src/transformers/mediabunny.d.ts +5 -0
  100. package/dist/src/transformers/mediabunny.d.ts.map +1 -0
  101. package/dist/src/transformers/mediabunny.js +150 -0
  102. package/dist/src/transformers/mediabunny.js.map +1 -0
  103. package/dist/src/transformers/mediabunny_loader.d.ts +15 -0
  104. package/dist/src/transformers/mediabunny_loader.d.ts.map +1 -0
  105. package/dist/src/transformers/mediabunny_loader.js +21 -0
  106. package/dist/src/transformers/mediabunny_loader.js.map +1 -0
  107. package/dist/src/transformers/probe.d.ts +56 -0
  108. package/dist/src/transformers/probe.d.ts.map +1 -0
  109. package/dist/src/transformers/probe.js +32 -0
  110. package/dist/src/transformers/probe.js.map +1 -0
  111. package/dist/src/transformers/source_file.d.ts +20 -0
  112. package/dist/src/transformers/source_file.d.ts.map +1 -0
  113. package/dist/src/transformers/source_file.js +30 -0
  114. package/dist/src/transformers/source_file.js.map +1 -0
  115. package/dist/stubs/config/media.stub +12 -0
  116. package/package.json +11 -7
  117. package/LICENSE +0 -21
@@ -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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"}
@@ -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() {
@@ -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