@adonis-agora/media 0.8.2 → 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 +76 -0
- package/README.md +2 -2
- package/dist/providers/media_provider.d.ts.map +1 -1
- package/dist/providers/media_provider.js +113 -0
- 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/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
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { AttachmentManager } from './attachment.js';
|
|
2
|
-
import {
|
|
2
|
+
import { DirectUploadManager } from './direct_upload.js';
|
|
3
|
+
import { DirectUploadsNotConfiguredError, ResumableUploadsNotConfiguredError } from './errors.js';
|
|
3
4
|
import { MediaLibrary } from './media_library.js';
|
|
4
5
|
import { ResumableUploadManager } from './resumable_upload.js';
|
|
5
6
|
import { StorageManager } from './storage_manager.js';
|
|
@@ -28,6 +29,8 @@ export class MediaManager {
|
|
|
28
29
|
uploads;
|
|
29
30
|
/** Resumable (TUS) upload coordinator — present only when a session store is configured. */
|
|
30
31
|
#resumable;
|
|
32
|
+
/** Session-backed direct upload coordinator — present only when a session store is configured. */
|
|
33
|
+
#direct;
|
|
31
34
|
constructor(options) {
|
|
32
35
|
this.store = options.store;
|
|
33
36
|
this.storage = new StorageManager({ default: options.defaultDisk, resolve: options.resolve });
|
|
@@ -80,6 +83,25 @@ export class MediaManager {
|
|
|
80
83
|
: {}),
|
|
81
84
|
});
|
|
82
85
|
}
|
|
86
|
+
if (options.directUploadSessions !== undefined) {
|
|
87
|
+
this.#direct = new DirectUploadManager({
|
|
88
|
+
storage: this.storage,
|
|
89
|
+
sessions: options.directUploadSessions,
|
|
90
|
+
// The manager reads the whitelist from the same registry attach uses, so the initiate
|
|
91
|
+
// gate and the attach-time barrier cannot drift.
|
|
92
|
+
collections: this.library.collections,
|
|
93
|
+
...(options.directPartSize !== undefined ? { partSize: options.directPartSize } : {}),
|
|
94
|
+
...(options.directPresignTtlSeconds !== undefined
|
|
95
|
+
? { presignTtlSeconds: options.directPresignTtlSeconds }
|
|
96
|
+
: {}),
|
|
97
|
+
...(options.directSessionTtlSeconds !== undefined
|
|
98
|
+
? { sessionTtlSeconds: options.directSessionTtlSeconds }
|
|
99
|
+
: {}),
|
|
100
|
+
...(options.emitDiagnostics !== undefined
|
|
101
|
+
? { emitDiagnostics: options.emitDiagnostics }
|
|
102
|
+
: {}),
|
|
103
|
+
});
|
|
104
|
+
}
|
|
83
105
|
}
|
|
84
106
|
/**
|
|
85
107
|
* The resumable (TUS) upload coordinator. Throws {@link ResumableUploadsNotConfiguredError} unless
|
|
@@ -110,6 +132,37 @@ export class MediaManager {
|
|
|
110
132
|
const { key, disk, size } = await this.resumable.complete(sessionId);
|
|
111
133
|
return this.library.attachExisting({ ...input, key, disk, size });
|
|
112
134
|
}
|
|
135
|
+
/**
|
|
136
|
+
* The session-backed direct upload coordinator. Throws {@link DirectUploadsNotConfiguredError}
|
|
137
|
+
* unless a session store was configured via `uploads.direct` in `config/media.ts`.
|
|
138
|
+
*/
|
|
139
|
+
get direct() {
|
|
140
|
+
if (!this.#direct)
|
|
141
|
+
throw new DirectUploadsNotConfiguredError();
|
|
142
|
+
return this.#direct;
|
|
143
|
+
}
|
|
144
|
+
/** Whether session-backed direct uploads are configured (a session store is present). */
|
|
145
|
+
get hasDirect() {
|
|
146
|
+
return this.#direct !== undefined;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Finish a session-backed direct upload and register the assembled object as a media record, in
|
|
150
|
+
* one step — the direct-mode twin of {@link completeUploadToLibrary}, meeting the two layers at
|
|
151
|
+
* the manager the same way. `attachExisting` adopts the object zero-copy and re-validates the
|
|
152
|
+
* collection's whitelist against the REAL bytes (a short head read), so a client that lied about
|
|
153
|
+
* `contentType` at initiate is caught here, exactly like every other upload path.
|
|
154
|
+
*
|
|
155
|
+
* ```ts
|
|
156
|
+
* await media.completeDirectUploadToLibrary(sessionId, {
|
|
157
|
+
* ownerType: 'Lesson', ownerId: lesson.id, collection: 'video',
|
|
158
|
+
* fileName: 'original.mp4', mimeType: 'video/mp4',
|
|
159
|
+
* }, partsFromClient)
|
|
160
|
+
* ```
|
|
161
|
+
*/
|
|
162
|
+
async completeDirectUploadToLibrary(sessionId, input, parts = []) {
|
|
163
|
+
const { key, disk, size } = await this.direct.complete(sessionId, parts);
|
|
164
|
+
return this.library.attachExisting({ ...input, key, disk, size });
|
|
165
|
+
}
|
|
113
166
|
/**
|
|
114
167
|
* The registered collection configs — the single source of truth for `acceptsMimeTypes`. Exposed
|
|
115
168
|
* so the upload edge (`TusUploadHandler`) can enforce the very same whitelist the library will
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"media_manager.js","sourceRoot":"","sources":["../../src/media_manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAEpD,OAAO,EAAE,kCAAkC,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"media_manager.js","sourceRoot":"","sources":["../../src/media_manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One generated derivative of a media record, keyed by conversion name in
|
|
3
|
+
* {@link MediaRecord.conversions}. Three shapes share this type:
|
|
4
|
+
*
|
|
5
|
+
* - an **image conversion** (a `ConversionPreset`): `{ path, disk }` — one file.
|
|
6
|
+
* - a **transformer output with artifacts** (e.g. the HLS package): `path` is the entry artifact
|
|
7
|
+
* (the master playlist), `prefix` is the storage prefix holding every artifact, and `files`
|
|
8
|
+
* lists them all relative to `prefix` — the authority for serving files out of the package and
|
|
9
|
+
* for deleting it whole.
|
|
10
|
+
* - a **metadata-only transform** (a probe, a blurhash): no artifact at all — `path`/`disk` are
|
|
11
|
+
* absent and only `meta` carries the result.
|
|
12
|
+
*/
|
|
1
13
|
export interface MediaConversion {
|
|
2
|
-
|
|
3
|
-
|
|
14
|
+
/** Entry-point artifact key. Absent for metadata-only transforms. */
|
|
15
|
+
path?: string;
|
|
16
|
+
/** Disk holding the artifact(s). Absent when there are none. */
|
|
17
|
+
disk?: string;
|
|
18
|
+
/** Storage prefix (ends in `/`) holding every artifact of a multi-file conversion. */
|
|
19
|
+
prefix?: string;
|
|
20
|
+
/** Every artifact key relative to {@link prefix}, the entry included. */
|
|
21
|
+
files?: string[];
|
|
22
|
+
/** Transformer-reported metadata (duration, codecs, hashes, …), persisted verbatim. */
|
|
23
|
+
meta?: Record<string, unknown>;
|
|
4
24
|
}
|
|
5
25
|
/** A stored file associated with an owning entity (spatie media-library style). */
|
|
6
26
|
export interface MediaRecord {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"media_record.d.ts","sourceRoot":"","sources":["../../src/media_record.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"media_record.d.ts","sourceRoot":"","sources":["../../src/media_record.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,eAAe;IAC9B,qEAAqE;IACrE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,gEAAgE;IAChE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,sFAAsF;IACtF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,yEAAyE;IACzE,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,uFAAuF;IACvF,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC;AAED,mFAAmF;AACnF,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,0EAA0E;IAC1E,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC1C,kEAAkE;IAClE,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IAC7C,SAAS,EAAE,IAAI,CAAC;IAChB,SAAS,EAAE,IAAI,CAAC;CACjB"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { TransformResult, Transformer, TransformerContext } from '../transformer.js';
|
|
2
|
+
export interface FakeTransformerOptions<Name extends string = string> {
|
|
3
|
+
/** Conversion name this fake produces. */
|
|
4
|
+
name: Name;
|
|
5
|
+
eager?: boolean;
|
|
6
|
+
/** Artifacts to write through `context.write`, keyed by prefix-relative path. */
|
|
7
|
+
artifacts?: Record<string, string>;
|
|
8
|
+
/**
|
|
9
|
+
* Entry declared in the result. Defaults to the first artifact key; pass `null` for a
|
|
10
|
+
* metadata-only result (with no artifacts).
|
|
11
|
+
*/
|
|
12
|
+
entry?: string | null;
|
|
13
|
+
/** Metadata declared in the result. */
|
|
14
|
+
meta?: Record<string, unknown>;
|
|
15
|
+
/** Full behavior override — everything above but `name`/`eager` is ignored when set. */
|
|
16
|
+
behavior?: (context: TransformerContext) => Promise<TransformResult>;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Deterministic {@link Transformer} for tests — the transformer counterpart of
|
|
20
|
+
* `FakeImageProcessor`. It records every context it is called with and writes/declares exactly
|
|
21
|
+
* what it was configured to, so eager/deferred behaviour, artifact bookkeeping and rollback can be
|
|
22
|
+
* asserted without a media engine.
|
|
23
|
+
*/
|
|
24
|
+
export declare class FakeTransformer<Name extends string = string> implements Transformer {
|
|
25
|
+
readonly name: Name;
|
|
26
|
+
readonly eager: boolean;
|
|
27
|
+
readonly calls: TransformerContext[];
|
|
28
|
+
private readonly options;
|
|
29
|
+
constructor(options: FakeTransformerOptions<Name>);
|
|
30
|
+
transform(context: TransformerContext): Promise<TransformResult>;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=fake_transformer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fake_transformer.d.ts","sourceRoot":"","sources":["../../../src/testing/fake_transformer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAE1F,MAAM,WAAW,sBAAsB,CAAC,IAAI,SAAS,MAAM,GAAG,MAAM;IAClE,0CAA0C;IAC1C,IAAI,EAAE,IAAI,CAAC;IACX,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,iFAAiF;IACjF,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,uCAAuC;IACvC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,wFAAwF;IACxF,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,kBAAkB,KAAK,OAAO,CAAC,eAAe,CAAC,CAAC;CACtE;AAED;;;;;GAKG;AACH,qBAAa,eAAe,CAAC,IAAI,SAAS,MAAM,GAAG,MAAM,CAAE,YAAW,WAAW;IAC/E,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,kBAAkB,EAAE,CAAM;IAC1C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA+B;gBAE3C,OAAO,EAAE,sBAAsB,CAAC,IAAI,CAAC;IAM3C,SAAS,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,eAAe,CAAC;CAgBvE"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deterministic {@link Transformer} for tests — the transformer counterpart of
|
|
3
|
+
* `FakeImageProcessor`. It records every context it is called with and writes/declares exactly
|
|
4
|
+
* what it was configured to, so eager/deferred behaviour, artifact bookkeeping and rollback can be
|
|
5
|
+
* asserted without a media engine.
|
|
6
|
+
*/
|
|
7
|
+
export class FakeTransformer {
|
|
8
|
+
name;
|
|
9
|
+
eager;
|
|
10
|
+
calls = [];
|
|
11
|
+
options;
|
|
12
|
+
constructor(options) {
|
|
13
|
+
this.name = options.name;
|
|
14
|
+
this.eager = options.eager ?? false;
|
|
15
|
+
this.options = options;
|
|
16
|
+
}
|
|
17
|
+
async transform(context) {
|
|
18
|
+
this.calls.push(context);
|
|
19
|
+
if (this.options.behavior)
|
|
20
|
+
return this.options.behavior(context);
|
|
21
|
+
const artifacts = Object.entries(this.options.artifacts ?? {});
|
|
22
|
+
for (const [path, content] of artifacts) {
|
|
23
|
+
await context.write(path, Buffer.from(content, 'utf8'));
|
|
24
|
+
}
|
|
25
|
+
const entry = this.options.entry === null ? undefined : (this.options.entry ?? artifacts[0]?.[0]);
|
|
26
|
+
return {
|
|
27
|
+
...(entry !== undefined ? { entry } : {}),
|
|
28
|
+
...(this.options.meta !== undefined ? { meta: this.options.meta } : {}),
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=fake_transformer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fake_transformer.js","sourceRoot":"","sources":["../../../src/testing/fake_transformer.ts"],"names":[],"mappings":"AAmBA;;;;;GAKG;AACH,MAAM,OAAO,eAAe;IACjB,IAAI,CAAO;IACX,KAAK,CAAU;IACf,KAAK,GAAyB,EAAE,CAAC;IACzB,OAAO,CAA+B;IAEvD,YAAY,OAAqC;QAC/C,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;QACzB,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,KAAK,CAAC;QACpC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,OAA2B;QACzC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACzB,IAAI,IAAI,CAAC,OAAO,CAAC,QAAQ;YAAE,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QAEjE,MAAM,SAAS,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC;QAC/D,KAAK,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,SAAS,EAAE,CAAC;YACxC,MAAM,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;QAC1D,CAAC;QAED,MAAM,KAAK,GACT,IAAI,CAAC,OAAO,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,IAAI,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QACtF,OAAO;YACL,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACzC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACxE,CAAC;IACJ,CAAC;CACF"}
|
|
@@ -3,4 +3,6 @@ export { InMemoryUploadSessionStore } from './in_memory_upload_session_store.js'
|
|
|
3
3
|
export { InMemoryDisk, inMemoryDiskResolver } from './in_memory_disk.js';
|
|
4
4
|
export type { DiskVisibility } from './in_memory_disk.js';
|
|
5
5
|
export { FakeImageProcessor } from './fake_image_processor.js';
|
|
6
|
+
export { FakeTransformer } from './fake_transformer.js';
|
|
7
|
+
export type { FakeTransformerOptions } from './fake_transformer.js';
|
|
6
8
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/testing/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,EAAE,0BAA0B,EAAE,MAAM,qCAAqC,CAAC;AACjF,OAAO,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AACzE,YAAY,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/testing/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,EAAE,0BAA0B,EAAE,MAAM,qCAAqC,CAAC;AACjF,OAAO,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AACzE,YAAY,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,YAAY,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC"}
|
|
@@ -2,4 +2,5 @@ export { InMemoryMediaStore } from './in_memory_media_store.js';
|
|
|
2
2
|
export { InMemoryUploadSessionStore } from './in_memory_upload_session_store.js';
|
|
3
3
|
export { InMemoryDisk, inMemoryDiskResolver } from './in_memory_disk.js';
|
|
4
4
|
export { FakeImageProcessor } from './fake_image_processor.js';
|
|
5
|
+
export { FakeTransformer } from './fake_transformer.js';
|
|
5
6
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/testing/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,EAAE,0BAA0B,EAAE,MAAM,qCAAqC,CAAC;AACjF,OAAO,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAEzE,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/testing/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,EAAE,0BAA0B,EAAE,MAAM,qCAAqC,CAAC;AACjF,OAAO,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAEzE,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import type { Readable } from 'node:stream';
|
|
2
|
+
import type { MediaRecord } from './media_record.js';
|
|
3
|
+
import type { StorageManager } from './storage_manager.js';
|
|
4
|
+
import type { Disk } from './types.js';
|
|
5
|
+
/**
|
|
6
|
+
* Options for {@link TransformerContext.write}. `contentLength` matters when `contents` is a
|
|
7
|
+
* `Readable` on a disk that streams (S3 needs the length up front); it is ignored for byte payloads.
|
|
8
|
+
*/
|
|
9
|
+
export interface TransformerWriteOptions {
|
|
10
|
+
contentType?: string;
|
|
11
|
+
contentLength?: number;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Everything a {@link Transformer} gets to work with: the record being transformed, read access to
|
|
15
|
+
* its original bytes, and a sandboxed writer for the derived artifacts.
|
|
16
|
+
*
|
|
17
|
+
* The context — not the transformer — decides WHERE artifacts live: every {@link write} lands under
|
|
18
|
+
* {@link outputPrefix} (`<owner>/<id>/conversions/<name>/`), and the library tracks each written
|
|
19
|
+
* path so it can persist the artifact list on the record and delete every artifact when the media
|
|
20
|
+
* is deleted. A transformer never touches disk keys outside its prefix.
|
|
21
|
+
*/
|
|
22
|
+
export interface TransformerContext {
|
|
23
|
+
/** The media record whose content is being transformed. */
|
|
24
|
+
record: MediaRecord;
|
|
25
|
+
/** The disk holding the original object (and receiving the artifacts). */
|
|
26
|
+
disk: Disk;
|
|
27
|
+
/** Name of {@link disk}, as resolvable through the storage manager. */
|
|
28
|
+
diskName: string;
|
|
29
|
+
/**
|
|
30
|
+
* The storage façade, for reads OUTSIDE the record's own disk — auxiliary assets a transformer
|
|
31
|
+
* was configured with (a watermark logo on another disk, a font, a sidecar file). Artifact
|
|
32
|
+
* writes still go through {@link write}, never directly through a disk.
|
|
33
|
+
*/
|
|
34
|
+
storage: StorageManager;
|
|
35
|
+
/** Buffer the original's bytes. Convenient for small originals; prefer {@link getStream} for video. */
|
|
36
|
+
getBytes(): Promise<Uint8Array>;
|
|
37
|
+
/** Stream the original without buffering it. */
|
|
38
|
+
getStream(): Promise<Readable>;
|
|
39
|
+
/**
|
|
40
|
+
* Storage prefix (ending in `/`) reserved for this transformation's artifacts:
|
|
41
|
+
* `<ownerType>/<ownerId>/<collection>/<mediaId>/conversions/<transformerName>/`.
|
|
42
|
+
*/
|
|
43
|
+
outputPrefix: string;
|
|
44
|
+
/**
|
|
45
|
+
* Write one artifact at `outputPrefix + relativePath`. The path is validated (no `..`, no
|
|
46
|
+
* absolute paths) and recorded — the persisted conversion lists every written artifact, which is
|
|
47
|
+
* what makes multi-file outputs (an HLS package) deletable and servable file-by-file.
|
|
48
|
+
*
|
|
49
|
+
* A `Readable` with a known `contentLength` streams straight to the disk; anything else is
|
|
50
|
+
* buffered.
|
|
51
|
+
*/
|
|
52
|
+
write(relativePath: string, contents: Uint8Array | Readable, options?: TransformerWriteOptions): Promise<void>;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* What a {@link Transformer.transform} run reports back. The artifacts themselves were already
|
|
56
|
+
* written through {@link TransformerContext.write}; this names which of them is the entry point and
|
|
57
|
+
* attaches free-form metadata.
|
|
58
|
+
*/
|
|
59
|
+
export interface TransformResult {
|
|
60
|
+
/**
|
|
61
|
+
* The entry-point artifact, relative to {@link TransformerContext.outputPrefix} — what
|
|
62
|
+
* `url(id, name)` / `deliver(id, { conversion: name })` resolve for this conversion. Required
|
|
63
|
+
* when any artifact was written (and must be one of them); omit it for a metadata-only
|
|
64
|
+
* transform (a probe, a blurhash) that wrote nothing.
|
|
65
|
+
*/
|
|
66
|
+
entry?: string;
|
|
67
|
+
/**
|
|
68
|
+
* Transformer-specific metadata persisted verbatim on the conversion entry
|
|
69
|
+
* (`record.conversions[name].meta`): duration, resolution, codecs, a blurhash string — whatever
|
|
70
|
+
* the transformer learned. Must be JSON-serializable (the Lucid store serializes it).
|
|
71
|
+
*/
|
|
72
|
+
meta?: Record<string, unknown>;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* A pluggable content transformation: takes a stored media's content and produces derived
|
|
76
|
+
* artifacts on the disk and/or metadata on the record, persisted as a named conversion
|
|
77
|
+
* (`record.conversions[transformer.name]`).
|
|
78
|
+
*
|
|
79
|
+
* This is the seam the library's own {@link HlsTransformer} and {@link MetadataProbeTransformer}
|
|
80
|
+
* implement, and the one you implement for your own derivations — extract an audio track,
|
|
81
|
+
* stamp a watermark, generate a poster frame, request a transcription. The shapes it supports:
|
|
82
|
+
*
|
|
83
|
+
* - **many artifacts** — an HLS package (segments + playlists); `entry` names the master playlist.
|
|
84
|
+
* - **one artifact** — an optimized image, an extracted audio file; `entry` names it.
|
|
85
|
+
* - **no artifact** — a metadata probe or perceptual hash; return only `meta`.
|
|
86
|
+
* - **auxiliary inputs** — configure them on your transformer instance (bytes, a path, a media id)
|
|
87
|
+
* and read foreign disks through {@link TransformerContext.storage}.
|
|
88
|
+
*
|
|
89
|
+
* Registered per collection (`collections: [{ name, transformers: [...] }]`). Set `eager: true`
|
|
90
|
+
* only for cheap transforms — they run synchronously inside `attach`/`attachExisting` (and so
|
|
91
|
+
* inside a TUS finalize), and a failure rolls the new media back. Heavy transforms (video!) stay
|
|
92
|
+
* deferred: the app triggers them from its own job via `media.library.transform(id, name)`,
|
|
93
|
+
* which is idempotent — already generated ⇒ skip.
|
|
94
|
+
*
|
|
95
|
+
* Import heavy engines lazily INSIDE `transform` (the built-ins import `mediabunny` there), so
|
|
96
|
+
* configuring a transformer never loads its optional peer at boot. A transformer that needs a
|
|
97
|
+
* runtime capability the host lacks (e.g. WebCodecs for re-encoding) should throw
|
|
98
|
+
* {@link TransformerRuntimeMissingError} with a clear hint rather than failing obscurely.
|
|
99
|
+
*/
|
|
100
|
+
export interface Transformer {
|
|
101
|
+
/** Unique conversion name this transformer produces (the key in `record.conversions`). */
|
|
102
|
+
readonly name: string;
|
|
103
|
+
/**
|
|
104
|
+
* Run synchronously on attach (like an eager image conversion) instead of waiting for an
|
|
105
|
+
* explicit `transform()` call. Default `false` — transformations are assumed heavy.
|
|
106
|
+
*/
|
|
107
|
+
readonly eager?: boolean;
|
|
108
|
+
/** Produce the derived artifacts/metadata for one media record. */
|
|
109
|
+
transform(context: TransformerContext): Promise<TransformResult>;
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=transformer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transformer.d.ts","sourceRoot":"","sources":["../../src/transformer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAEvC;;;GAGG;AACH,MAAM,WAAW,uBAAuB;IACtC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,kBAAkB;IACjC,2DAA2D;IAC3D,MAAM,EAAE,WAAW,CAAC;IACpB,0EAA0E;IAC1E,IAAI,EAAE,IAAI,CAAC;IACX,uEAAuE;IACvE,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,OAAO,EAAE,cAAc,CAAC;IACxB,uGAAuG;IACvG,QAAQ,IAAI,OAAO,CAAC,UAAU,CAAC,CAAC;IAChC,gDAAgD;IAChD,SAAS,IAAI,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC/B;;;OAGG;IACH,YAAY,EAAE,MAAM,CAAC;IACrB;;;;;;;OAOG;IACH,KAAK,CACH,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,UAAU,GAAG,QAAQ,EAC/B,OAAO,CAAC,EAAE,uBAAuB,GAChC,OAAO,CAAC,IAAI,CAAC,CAAC;CAClB;AAED;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B;;;;;OAKG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,WAAW,WAAW;IAC1B,0FAA0F;IAC1F,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IACzB,mEAAmE;IACnE,SAAS,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;CAClE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transformer.js","sourceRoot":"","sources":["../../src/transformer.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { HlsTransformer, type HlsTransformerOptions } from './hls.js';
|
|
2
|
+
import { MetadataProbeTransformer, type MetadataProbeTransformerOptions } from './probe.js';
|
|
3
|
+
/**
|
|
4
|
+
* The transformer factory namespace used in `config/media.ts` — the {@link Transformer}
|
|
5
|
+
* counterpart of `processors`/`disks`/`stores`:
|
|
6
|
+
*
|
|
7
|
+
* ```ts
|
|
8
|
+
* import { defineConfig, transformers } from '@adonis-agora/media'
|
|
9
|
+
*
|
|
10
|
+
* export default defineConfig({
|
|
11
|
+
* collections: [
|
|
12
|
+
* {
|
|
13
|
+
* name: 'videos',
|
|
14
|
+
* acceptsMimeTypes: ['video/mp4'],
|
|
15
|
+
* transformers: [transformers.hls({ targetDuration: 4 }), transformers.probe()],
|
|
16
|
+
* },
|
|
17
|
+
* ],
|
|
18
|
+
* })
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* Constructing a transformer here never loads its engine — the optional `mediabunny` peer is
|
|
22
|
+
* imported inside the first `transform()` call, so config stays side-effect-free.
|
|
23
|
+
*/
|
|
24
|
+
export declare const transformers: {
|
|
25
|
+
/** Video → HLS package (MPEG-TS segments + playlists) via mediabunny. Default name `'hls'`. */
|
|
26
|
+
hls<Name extends string = "hls">(options?: HlsTransformerOptions<Name>): HlsTransformer<Name>;
|
|
27
|
+
/** Metadata-only probe (duration/resolution/codecs) via mediabunny. Default name `'probe'`. */
|
|
28
|
+
probe<Name extends string = "probe">(options?: MetadataProbeTransformerOptions<Name>): MetadataProbeTransformer<Name>;
|
|
29
|
+
};
|
|
30
|
+
//# sourceMappingURL=factory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../../src/transformers/factory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,KAAK,qBAAqB,EAAE,MAAM,UAAU,CAAC;AACtE,OAAO,EAAE,wBAAwB,EAAE,KAAK,+BAA+B,EAAE,MAAM,YAAY,CAAC;AAE5F;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,YAAY;IACvB,+FAA+F;QAC3F,IAAI,SAAS,MAAM,oBAAmB,qBAAqB,CAAC,IAAI,CAAC;IAGrE,+FAA+F;UACzF,IAAI,SAAS,MAAM,sBAAqB,+BAA+B,CAAC,IAAI,CAAC;CAGpF,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { HlsTransformer } from './hls.js';
|
|
2
|
+
import { MetadataProbeTransformer } from './probe.js';
|
|
3
|
+
/**
|
|
4
|
+
* The transformer factory namespace used in `config/media.ts` — the {@link Transformer}
|
|
5
|
+
* counterpart of `processors`/`disks`/`stores`:
|
|
6
|
+
*
|
|
7
|
+
* ```ts
|
|
8
|
+
* import { defineConfig, transformers } from '@adonis-agora/media'
|
|
9
|
+
*
|
|
10
|
+
* export default defineConfig({
|
|
11
|
+
* collections: [
|
|
12
|
+
* {
|
|
13
|
+
* name: 'videos',
|
|
14
|
+
* acceptsMimeTypes: ['video/mp4'],
|
|
15
|
+
* transformers: [transformers.hls({ targetDuration: 4 }), transformers.probe()],
|
|
16
|
+
* },
|
|
17
|
+
* ],
|
|
18
|
+
* })
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* Constructing a transformer here never loads its engine — the optional `mediabunny` peer is
|
|
22
|
+
* imported inside the first `transform()` call, so config stays side-effect-free.
|
|
23
|
+
*/
|
|
24
|
+
export const transformers = {
|
|
25
|
+
/** Video → HLS package (MPEG-TS segments + playlists) via mediabunny. Default name `'hls'`. */
|
|
26
|
+
hls(options = {}) {
|
|
27
|
+
return new HlsTransformer(options);
|
|
28
|
+
},
|
|
29
|
+
/** Metadata-only probe (duration/resolution/codecs) via mediabunny. Default name `'probe'`. */
|
|
30
|
+
probe(options = {}) {
|
|
31
|
+
return new MetadataProbeTransformer(options);
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
//# sourceMappingURL=factory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"factory.js","sourceRoot":"","sources":["../../../src/transformers/factory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAA8B,MAAM,UAAU,CAAC;AACtE,OAAO,EAAE,wBAAwB,EAAwC,MAAM,YAAY,CAAC;AAE5F;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,+FAA+F;IAC/F,GAAG,CAA8B,UAAuC,EAAE;QACxE,OAAO,IAAI,cAAc,CAAC,OAAO,CAAC,CAAC;IACrC,CAAC;IACD,+FAA+F;IAC/F,KAAK,CAAgC,UAAiD,EAAE;QACtF,OAAO,IAAI,wBAAwB,CAAC,OAAO,CAAC,CAAC;IAC/C,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import type { TransformResult, Transformer, TransformerContext } from '../transformer.js';
|
|
2
|
+
/**
|
|
3
|
+
* Lazily supplies a WebCodecs implementation (`{ VideoEncoder, VideoDecoder, AudioEncoder, … }`).
|
|
4
|
+
* Node has no built-in WebCodecs, which is exactly why the HLS transformer is remux-only by
|
|
5
|
+
* default — but NAPI-based implementations exist (e.g. `@napi-rs/webcodecs`), and injecting one
|
|
6
|
+
* unlocks the re-encode fallback for sources whose codecs cannot be stream-copied:
|
|
7
|
+
*
|
|
8
|
+
* ```ts
|
|
9
|
+
* transformers.hls({ webcodecs: () => import('@napi-rs/webcodecs') })
|
|
10
|
+
* ```
|
|
11
|
+
*
|
|
12
|
+
* The engine installs the provided classes onto `globalThis` (only the ones missing — a native
|
|
13
|
+
* implementation is never overwritten), because that is where the underlying media engine looks
|
|
14
|
+
* the API up.
|
|
15
|
+
*/
|
|
16
|
+
export type WebCodecsProvider = () => Promise<Record<string, unknown>>;
|
|
17
|
+
/** How a runtime can satisfy the WebCodecs requirement. See {@link resolveWebCodecsSupport}. */
|
|
18
|
+
export type WebCodecsSupport = 'native' | 'injected' | 'absent';
|
|
19
|
+
/**
|
|
20
|
+
* Detect how (whether) WebCodecs is available: `'native'` when the runtime already exposes
|
|
21
|
+
* `VideoEncoder`, `'injected'` when a {@link WebCodecsProvider} supplies one, `'absent'` otherwise.
|
|
22
|
+
* `'absent'` means encoding is impossible — transforms stay stream-copy only, and a transformer
|
|
23
|
+
* that cannot proceed without an encoder should throw `TransformerRuntimeMissingError`.
|
|
24
|
+
*/
|
|
25
|
+
export declare function resolveWebCodecsSupport(provider?: WebCodecsProvider): Promise<WebCodecsSupport>;
|
|
26
|
+
/** What {@link HlsRemuxEngine.remux} receives. */
|
|
27
|
+
export interface HlsRemuxRequest {
|
|
28
|
+
/** Local path of the source file. */
|
|
29
|
+
sourcePath: string;
|
|
30
|
+
/** Local directory the engine writes the whole package into (entry playlist at its root). */
|
|
31
|
+
outputDir: string;
|
|
32
|
+
/** File name of the entry (master) playlist, e.g. `index.m3u8`. */
|
|
33
|
+
entryName: string;
|
|
34
|
+
/** Target (max) segment duration in seconds. */
|
|
35
|
+
targetDuration: number;
|
|
36
|
+
/** Optional WebCodecs implementation enabling the re-encode fallback. */
|
|
37
|
+
webcodecs?: WebCodecsProvider | undefined;
|
|
38
|
+
}
|
|
39
|
+
/** What the engine learned about the source while remuxing — persisted into the conversion `meta`. */
|
|
40
|
+
export interface HlsRemuxSummary {
|
|
41
|
+
durationSeconds?: number;
|
|
42
|
+
width?: number;
|
|
43
|
+
height?: number;
|
|
44
|
+
videoCodec?: string | null;
|
|
45
|
+
audioCodec?: string | null;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* The engine seam of {@link HlsTransformer}: local file in, HLS package (playlists + segments) in
|
|
49
|
+
* a local directory out. The default engine is mediabunny, loaded lazily on first transform; tests
|
|
50
|
+
* inject a fake that writes files, so every bit of orchestration around the engine is testable
|
|
51
|
+
* without the optional peer.
|
|
52
|
+
*/
|
|
53
|
+
export interface HlsRemuxEngine {
|
|
54
|
+
remux(request: HlsRemuxRequest): Promise<HlsRemuxSummary>;
|
|
55
|
+
}
|
|
56
|
+
export interface HlsTransformerOptions<Name extends string = 'hls'> {
|
|
57
|
+
/** Conversion name on the record. Default `'hls'`. */
|
|
58
|
+
name?: Name;
|
|
59
|
+
/**
|
|
60
|
+
* Run inside attach. Default `false`, and think twice: a remux takes real time, and an eager
|
|
61
|
+
* failure rolls the attach back. The intended flow is deferred —
|
|
62
|
+
* `media.library.transform(id, 'hls')` from a job.
|
|
63
|
+
*/
|
|
64
|
+
eager?: boolean;
|
|
65
|
+
/** Target (max) segment duration in seconds. Default 4. */
|
|
66
|
+
targetDuration?: number;
|
|
67
|
+
/** WebCodecs implementation for the re-encode fallback (see {@link WebCodecsProvider}). */
|
|
68
|
+
webcodecs?: WebCodecsProvider;
|
|
69
|
+
/** Replace the mediabunny engine (mainly for tests). */
|
|
70
|
+
engine?: HlsRemuxEngine;
|
|
71
|
+
}
|
|
72
|
+
/** File name of the entry (master) playlist an {@link HlsTransformer} produces. */
|
|
73
|
+
export declare const HLS_ENTRY_PLAYLIST = "index.m3u8";
|
|
74
|
+
/**
|
|
75
|
+
* The built-in video {@link Transformer}: converts a stored video into an HLS package — MPEG-TS
|
|
76
|
+
* segments plus media playlists behind one master playlist — written under the conversion prefix
|
|
77
|
+
* and persisted as `record.conversions['hls']` with duration/resolution/codec metadata.
|
|
78
|
+
*
|
|
79
|
+
* **Remux-only by default.** The engine (mediabunny, pure JS — no ffmpeg binary) stream-copies
|
|
80
|
+
* the source's h264/aac tracks into segments without re-encoding, because encoding needs
|
|
81
|
+
* WebCodecs, which Node does not provide. Two consequences, both deliberate:
|
|
82
|
+
*
|
|
83
|
+
* - a source whose codecs MPEG-TS cannot carry (vp9, av1…) fails with a clear, definitive
|
|
84
|
+
* `HlsSourceUnsupportedError` — unless a {@link WebCodecsProvider} is configured, which enables
|
|
85
|
+
* the engine's re-encode fallback;
|
|
86
|
+
* - the package has a single variant at the original resolution. Multi-quality renditions are the
|
|
87
|
+
* documented evolution once an encoder is present (mediabunny supports fan-out video options),
|
|
88
|
+
* not something this transformer fakes today.
|
|
89
|
+
*
|
|
90
|
+
* The engine also carries the subtle bit the naive implementation gets wrong: AAC audio with
|
|
91
|
+
* priming (an mp4 edit list) starts at a **negative** timestamp, and a conversion trimmed at t=0
|
|
92
|
+
* would kick that track off the stream-copy fast path — impossible without an encoder. The
|
|
93
|
+
* conversion is therefore trimmed at the source's real first timestamp, shifting all tracks
|
|
94
|
+
* equally (sync is unchanged) and keeping every track copyable.
|
|
95
|
+
*
|
|
96
|
+
* Serving the result is the other half: playlists are stored with storage-relative references and
|
|
97
|
+
* must be rewritten per request — see {@link HlsDeliveryHandler}.
|
|
98
|
+
*/
|
|
99
|
+
export declare class HlsTransformer<Name extends string = 'hls'> implements Transformer {
|
|
100
|
+
readonly name: Name;
|
|
101
|
+
readonly eager: boolean;
|
|
102
|
+
private readonly targetDuration;
|
|
103
|
+
private readonly webcodecs;
|
|
104
|
+
private readonly engine;
|
|
105
|
+
constructor(options?: HlsTransformerOptions<Name>);
|
|
106
|
+
transform(context: TransformerContext): Promise<TransformResult>;
|
|
107
|
+
}
|
|
108
|
+
/** Drop `undefined` values so the persisted meta round-trips identically through JSON stores. */
|
|
109
|
+
export declare function compactMeta(meta: Record<string, unknown>): Record<string, unknown>;
|
|
110
|
+
//# sourceMappingURL=hls.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hls.d.ts","sourceRoot":"","sources":["../../../src/transformers/hls.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,eAAe,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAI1F;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,iBAAiB,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AAEvE,gGAAgG;AAChG,MAAM,MAAM,gBAAgB,GAAG,QAAQ,GAAG,UAAU,GAAG,QAAQ,CAAC;AAEhE;;;;;GAKG;AACH,wBAAsB,uBAAuB,CAC3C,QAAQ,CAAC,EAAE,iBAAiB,GAC3B,OAAO,CAAC,gBAAgB,CAAC,CAI3B;AAED,kDAAkD;AAClD,MAAM,WAAW,eAAe;IAC9B,qCAAqC;IACrC,UAAU,EAAE,MAAM,CAAC;IACnB,6FAA6F;IAC7F,SAAS,EAAE,MAAM,CAAC;IAClB,mEAAmE;IACnE,SAAS,EAAE,MAAM,CAAC;IAClB,gDAAgD;IAChD,cAAc,EAAE,MAAM,CAAC;IACvB,yEAAyE;IACzE,SAAS,CAAC,EAAE,iBAAiB,GAAG,SAAS,CAAC;CAC3C;AAED,sGAAsG;AACtG,MAAM,WAAW,eAAe;IAC9B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED;;;;;GAKG;AACH,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;CAC3D;AAED,MAAM,WAAW,qBAAqB,CAAC,IAAI,SAAS,MAAM,GAAG,KAAK;IAChE,sDAAsD;IACtD,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ;;;;OAIG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,2DAA2D;IAC3D,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,2FAA2F;IAC3F,SAAS,CAAC,EAAE,iBAAiB,CAAC;IAC9B,wDAAwD;IACxD,MAAM,CAAC,EAAE,cAAc,CAAC;CACzB;AAED,mFAAmF;AACnF,eAAO,MAAM,kBAAkB,eAAe,CAAC;AAE/C;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,qBAAa,cAAc,CAAC,IAAI,SAAS,MAAM,GAAG,KAAK,CAAE,YAAW,WAAW;IAC7E,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IACxC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAgC;IAC1D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA6B;gBAExC,OAAO,GAAE,qBAAqB,CAAC,IAAI,CAAM;IAQ/C,SAAS,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,eAAe,CAAC;CA8CvE;AAED,iGAAiG;AACjG,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAElF"}
|