@molecule/api-media-streaming-hls 1.0.0 → 1.0.1

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 (2) hide show
  1. package/README.md +268 -0
  2. package/package.json +5 -4
package/README.md ADDED
@@ -0,0 +1,268 @@
1
+ <!--
2
+ AUTO-GENERATED — DO NOT EDIT THIS FILE.
3
+ Generated by `mlcl sync-docs` from the package's src/index.ts JSDoc + mlcl/registry.json.
4
+ Edits here are overwritten on the next commit (molecule's pre-commit hook regenerates).
5
+ To change this document, edit the module-level JSDoc in src/index.ts.
6
+ Generated: 2026-08-04T01:48:38.551Z
7
+ -->
8
+
9
+ # @molecule/api-media-streaming-hls
10
+
11
+ > **Auto-generated, AI-first package reference** for the [molecule.dev](https://molecule.dev) ecosystem.
12
+ > It is written to be read by coding agents as much as by people, and is generated from this
13
+ > package's source — edit `src/index.ts` JSDoc, not this file.
14
+
15
+ HLS media streaming provider for molecule.dev.
16
+
17
+ Provides HLS (HTTP Live Streaming) support via ffmpeg for media segmentation
18
+ and transcoding, with pure-TypeScript M3U8 playlist generation. Requires
19
+ ffmpeg to be installed on the host system.
20
+
21
+ ## Quick Start
22
+
23
+ ```typescript
24
+ import { setProvider, createStream } from '@molecule/api-media-streaming'
25
+ import { provider } from '@molecule/api-media-streaming-hls'
26
+
27
+ setProvider(provider)
28
+
29
+ const manifest = await createStream('/path/to/video.mp4', {
30
+ segmentDuration: 6,
31
+ protocol: 'hls',
32
+ })
33
+ console.log(manifest.manifestUri) // '/hls-…/index.m3u8'
34
+ ```
35
+
36
+ ## Type
37
+
38
+ `provider`
39
+
40
+ ## Installation
41
+
42
+ ```bash
43
+ npm install @molecule/api-media-streaming-hls @molecule/api-media-streaming
44
+ ```
45
+
46
+ ## API
47
+
48
+ ### Interfaces
49
+
50
+ #### `HlsConfig`
51
+
52
+ Configuration options for the HLS streaming provider.
53
+
54
+ ```typescript
55
+ interface HlsConfig {
56
+ /** Path to the ffmpeg binary. Defaults to `'ffmpeg'` (resolved via PATH). */
57
+ ffmpegPath?: string
58
+
59
+ /**
60
+ * Path to the ffprobe binary. RESERVED for future use — the current
61
+ * provider never invokes ffprobe (segment durations are taken from
62
+ * `segmentDuration`, not probed). Setting this has no effect today.
63
+ */
64
+ ffprobePath?: string
65
+
66
+ /** Base directory where stream output files are written. Defaults to `os.tmpdir()`. */
67
+ outputBasePath?: string
68
+
69
+ /** Default segment duration in seconds. Defaults to `6`. */
70
+ segmentDuration?: number
71
+
72
+ /** HLS playlist version. Defaults to `3`. */
73
+ hlsVersion?: number
74
+ }
75
+ ```
76
+
77
+ #### `M3u8PlaylistOptions`
78
+
79
+ Options for generating an M3U8 media playlist.
80
+
81
+ ```typescript
82
+ interface M3u8PlaylistOptions {
83
+ /** HLS playlist version. Defaults to `3`. */
84
+ version?: number
85
+
86
+ /** Target segment duration in seconds. Defaults to the maximum segment duration. */
87
+ targetDuration?: number
88
+
89
+ /** Whether this is a VOD (complete) or live (in-progress) playlist. Defaults to `'vod'`. */
90
+ playlistType?: 'vod' | 'event'
91
+
92
+ /** Media sequence number for the first segment. Defaults to `0`. */
93
+ mediaSequence?: number
94
+ }
95
+ ```
96
+
97
+ ### Functions
98
+
99
+ #### `assertSafePathComponent(value, label)`
100
+
101
+ Asserts that a caller-supplied value is a safe single path component.
102
+
103
+ Rejects empty strings, the relative segments `.` and `..`, anything
104
+ containing a path separator or NUL byte, and anything outside the
105
+ `[A-Za-z0-9._-]` allow-list (which also rejects shell metacharacters).
106
+
107
+ ```typescript
108
+ function assertSafePathComponent(value: string, label: string): string
109
+ ```
110
+
111
+ - `value` — The caller-supplied component (e.g. a stream id or profile name).
112
+ - `label` — Human-readable name of the field, used in the error message.
113
+
114
+ **Returns:** The validated component, unchanged.
115
+
116
+ #### `assertSegmentIndex(index)`
117
+
118
+ Asserts that a caller-supplied segment index is a non-negative integer.
119
+
120
+ ```typescript
121
+ function assertSegmentIndex(index: number): number
122
+ ```
123
+
124
+ - `index` — The caller-supplied segment index.
125
+
126
+ **Returns:** The validated index, unchanged.
127
+
128
+ #### `createProvider(config)`
129
+
130
+ Creates an HLS streaming provider.
131
+
132
+ ```typescript
133
+ function createProvider(config?: HlsConfig): StreamingProvider
134
+ ```
135
+
136
+ - `config` — Optional provider configuration.
137
+
138
+ **Returns:** A `StreamingProvider` backed by HLS / ffmpeg.
139
+
140
+ #### `generateMasterPlaylist(variants)`
141
+
142
+ Generates an M3U8 master playlist for adaptive bitrate streaming.
143
+
144
+ ```typescript
145
+ function generateMasterPlaylist(variants: TranscodeVariant[]): string
146
+ ```
147
+
148
+ - `variants` — The transcoded variant streams.
149
+
150
+ **Returns:** The master M3U8 playlist content as a string.
151
+
152
+ #### `generateMediaPlaylist(segments, options)`
153
+
154
+ Generates an M3U8 media playlist from a list of stream segments.
155
+
156
+ ```typescript
157
+ function generateMediaPlaylist(segments: StreamSegment[], options?: M3u8PlaylistOptions): string
158
+ ```
159
+
160
+ - `segments` — Ordered list of stream segments.
161
+ - `options` — Playlist generation options.
162
+
163
+ **Returns:** The M3U8 playlist content as a string.
164
+
165
+ #### `resolveWithinBase(base, parts)`
166
+
167
+ Resolves `parts` against `base` and asserts the result stays within `base`.
168
+
169
+ Defense-in-depth on top of {@link assertSafePathComponent}: even if a
170
+ component slipped through, the resolved absolute path is rejected unless it
171
+ is `base` itself or a descendant of it.
172
+
173
+ ```typescript
174
+ function resolveWithinBase(base: string, parts?: string[]): string
175
+ ```
176
+
177
+ - `base` — The intended base directory.
178
+ - `parts` — Path segments to append.
179
+
180
+ **Returns:** The resolved absolute path, guaranteed to be inside `base`.
181
+
182
+ ### Constants
183
+
184
+ #### `provider`
185
+
186
+ The provider implementation with default configuration.
187
+
188
+ ```typescript
189
+ const provider: StreamingProvider
190
+ ```
191
+
192
+ ## Core Interface
193
+
194
+ Implements `@molecule/api-media-streaming` interface.
195
+
196
+ ## Bond Wiring
197
+
198
+ Setup function to register this provider with the core interface:
199
+
200
+ ```typescript
201
+ import { setProvider } from '@molecule/api-media-streaming'
202
+ import { provider } from '@molecule/api-media-streaming-hls'
203
+
204
+ export function setupMediaStreamingHls(): void {
205
+ setProvider(provider)
206
+ }
207
+ ```
208
+
209
+ ## Injection Notes
210
+
211
+ ### Requirements
212
+
213
+ Peer dependencies:
214
+
215
+ - `@molecule/api-media-streaming` ^1.0.1
216
+
217
+ ### Runtime Dependencies
218
+
219
+ - `@molecule/api-media-streaming`
220
+
221
+ - **Requires the `ffmpeg` binary on the host** (resolved via PATH, or set
222
+ `createProvider({ ffmpegPath })`). A missing binary fails at first
223
+ `createStream()`/`transcode()` call with `spawn ffmpeg ENOENT` — verify
224
+ with `ffmpeg -version` before shipping.
225
+ - **The default output directory is `os.tmpdir()`** — volatile and served by
226
+ nothing. Pass `createProvider({ outputBasePath })` pointing at a directory
227
+ your server exposes (see the core remarks), or serve bytes through
228
+ `getSegment()` / `generateManifest()` endpoints.
229
+ - `createStream()` also caches every segment `Buffer` in an in-process map
230
+ (never evicted) so `getSegment()` is fast; memory grows by the full video
231
+ size per stream. `getSegment()` disk fallback looks ONLY under
232
+ `outputBasePath/<streamId>/` — a per-call `createStream(..., { outputPath })`
233
+ override writes segments where the fallback cannot find them after a
234
+ restart, and `transcode()` ignores `outputPath` entirely (always writes
235
+ under `outputBasePath`).
236
+ - `ffprobePath` in `HlsConfig` is currently RESERVED — no ffprobe call exists
237
+ yet; segment durations come from the requested `segmentDuration`.
238
+
239
+ ## E2E Tests
240
+
241
+ Integration checklist — drive the real UI (live preview, no mocks), adapt
242
+ each item to this app's actual upload/player screens, and check every box
243
+ off one by one. A box you can't check is an integration bug to fix — not a
244
+ skip. You can't judge real transcode QUALITY or a live A/V feed in the
245
+ sandbox; verify the pipeline + playback WIRING you own:
246
+
247
+ - [ ] Uploading/ingesting a media asset produces a real PLAYABLE stream: the
248
+ returned `manifestUri` (`.m3u8` for HLS / `.mpd` for DASH) loads in the
249
+ app's video player and actually plays — frames advance and the player
250
+ fetches segments (watch the network panel), never a broken/blank player.
251
+ - [ ] The stream is served from/through the APP'S OWN origin — an
252
+ `outputPath` under a directory the server exposes, or endpoints that return
253
+ `generateManifest(segments)` and stream `getSegment(streamId, index)` bytes.
254
+ The player must NOT hotlink a raw expiring provider URL, and no manifest or
255
+ segment request may 404.
256
+ - [ ] Processing STATE is observable and playback is gated on it: an asset
257
+ moves pending → processing → ready (StreamStatus), the UI reflects that,
258
+ and the player mounts only once status is 'ready' — never a dead player on
259
+ a still-transcoding asset.
260
+ - [ ] If adaptive bitrate is exposed, `transcode()` produced multiple
261
+ renditions: the master manifest (`masterManifestUri`) lists more than one
262
+ `variant` and the player can switch quality across them.
263
+ - [ ] If the app exposes a poster/thumbnail for an asset, it generates and
264
+ renders before playback (no blank tile).
265
+ - [ ] SECURITY — private media is AUTHORIZED on playback: the manifest and
266
+ segment endpoints check the requester (or hand out a signed/expiring URL),
267
+ so a user CANNOT fetch another user's stream by guessing its `id`/URL; and
268
+ provider keys stay server-side (never shipped to the client bundle).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@molecule/api-media-streaming-hls",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "HLS media streaming provider for molecule.dev — ffmpeg-based segmentation, transcoding, and M3U8 playlist generation",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -17,7 +17,8 @@
17
17
  }
18
18
  },
19
19
  "files": [
20
- "dist"
20
+ "dist",
21
+ "README.md"
21
22
  ],
22
23
  "keywords": [
23
24
  "molecule",
@@ -30,10 +31,10 @@
30
31
  ],
31
32
  "license": "Apache-2.0",
32
33
  "peerDependencies": {
33
- "@molecule/api-media-streaming": "^1.0.0"
34
+ "@molecule/api-media-streaming": "^1.0.1"
34
35
  },
35
36
  "devDependencies": {
36
- "@molecule/api-media-streaming": "1.0.0",
37
+ "@molecule/api-media-streaming": "1.0.1",
37
38
  "@types/node": "26.1.2",
38
39
  "typescript": "6.0.3",
39
40
  "vitest": "4.1.10"