@meframe/core 0.0.2 → 0.0.3
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/dist/Meframe.d.ts.map +1 -1
- package/dist/Meframe.js +2 -1
- package/dist/Meframe.js.map +1 -1
- package/dist/config/defaults.d.ts.map +1 -1
- package/dist/config/defaults.js +2 -1
- package/dist/config/defaults.js.map +1 -1
- package/dist/config/types.d.ts +3 -0
- package/dist/config/types.d.ts.map +1 -1
- package/dist/orchestrator/Orchestrator.d.ts.map +1 -1
- package/dist/orchestrator/Orchestrator.js +2 -1
- package/dist/orchestrator/Orchestrator.js.map +1 -1
- package/dist/orchestrator/types.d.ts +1 -0
- package/dist/orchestrator/types.d.ts.map +1 -1
- package/dist/stages/compose/types.d.ts +2 -1
- package/dist/stages/compose/types.d.ts.map +1 -1
- package/dist/stages/demux/MP4Demuxer.d.ts +0 -1
- package/dist/stages/demux/MP4Demuxer.d.ts.map +1 -1
- package/dist/utils/time-utils.d.ts +3 -2
- package/dist/utils/time-utils.d.ts.map +1 -1
- package/dist/utils/time-utils.js +2 -1
- package/dist/utils/time-utils.js.map +1 -1
- package/dist/vite-plugin.d.ts +5 -3
- package/dist/vite-plugin.d.ts.map +1 -1
- package/dist/vite-plugin.js +109 -52
- package/dist/vite-plugin.js.map +1 -1
- package/dist/worker/WorkerPool.d.ts +7 -0
- package/dist/worker/WorkerPool.d.ts.map +1 -1
- package/dist/worker/WorkerPool.js +29 -5
- package/dist/worker/WorkerPool.js.map +1 -1
- package/dist/{stages/demux → workers}/MP4Demuxer.js +4 -13
- package/dist/workers/MP4Demuxer.js.map +1 -0
- package/dist/workers/WorkerChannel.js +486 -0
- package/dist/workers/WorkerChannel.js.map +1 -0
- package/dist/{assets/video-demux.worker-D019I7GQ.js → workers/mp4box.all.js} +4 -912
- package/dist/workers/mp4box.all.js.map +1 -0
- package/dist/{assets/audio-compose.worker-nGVvHD5Q.js → workers/stages/compose/audio-compose.worker.js} +7 -481
- package/dist/workers/stages/compose/audio-compose.worker.js.map +1 -0
- package/dist/{assets/video-compose.worker-DPzsC21d.js → workers/stages/compose/video-compose.worker.js} +7 -481
- package/dist/workers/stages/compose/video-compose.worker.js.map +1 -0
- package/dist/{assets/decode.worker-DpWHsc7R.js → workers/stages/decode/decode.worker.js} +7 -481
- package/dist/workers/stages/decode/decode.worker.js.map +1 -0
- package/dist/{stages → workers/stages}/demux/audio-demux.worker.js +184 -4
- package/dist/workers/stages/demux/audio-demux.worker.js.map +1 -0
- package/dist/{stages → workers/stages}/demux/video-demux.worker.js +2 -3
- package/dist/workers/stages/demux/video-demux.worker.js.map +1 -0
- package/dist/{stages → workers/stages}/encode/encode.worker.js +238 -4
- package/dist/workers/stages/encode/encode.worker.js.map +1 -0
- package/dist/{stages/mux/MP4Muxer.js → workers/stages/mux/mux.worker.js} +244 -5
- package/dist/workers/stages/mux/mux.worker.js.map +1 -0
- package/package.json +21 -21
- package/dist/assets/audio-compose.worker-nGVvHD5Q.js.map +0 -1
- package/dist/assets/audio-demux.worker-xwWBtbAe.js +0 -8299
- package/dist/assets/audio-demux.worker-xwWBtbAe.js.map +0 -1
- package/dist/assets/decode.worker-DpWHsc7R.js.map +0 -1
- package/dist/assets/encode.worker-nfOb3kw6.js +0 -1026
- package/dist/assets/encode.worker-nfOb3kw6.js.map +0 -1
- package/dist/assets/mux.worker-uEMQY066.js +0 -8019
- package/dist/assets/mux.worker-uEMQY066.js.map +0 -1
- package/dist/assets/video-compose.worker-DPzsC21d.js.map +0 -1
- package/dist/assets/video-demux.worker-D019I7GQ.js.map +0 -1
- package/dist/model/types.js +0 -5
- package/dist/model/types.js.map +0 -1
- package/dist/plugins/BackpressureMonitor.js +0 -62
- package/dist/plugins/BackpressureMonitor.js.map +0 -1
- package/dist/stages/compose/AudioDucker.js +0 -161
- package/dist/stages/compose/AudioDucker.js.map +0 -1
- package/dist/stages/compose/AudioMixer.js +0 -373
- package/dist/stages/compose/AudioMixer.js.map +0 -1
- package/dist/stages/compose/FilterProcessor.js +0 -226
- package/dist/stages/compose/FilterProcessor.js.map +0 -1
- package/dist/stages/compose/LayerRenderer.js +0 -215
- package/dist/stages/compose/LayerRenderer.js.map +0 -1
- package/dist/stages/compose/TransitionProcessor.js +0 -189
- package/dist/stages/compose/TransitionProcessor.js.map +0 -1
- package/dist/stages/compose/VideoComposer.js +0 -186
- package/dist/stages/compose/VideoComposer.js.map +0 -1
- package/dist/stages/compose/audio-compose.worker.d.ts +0 -79
- package/dist/stages/compose/audio-compose.worker.d.ts.map +0 -1
- package/dist/stages/compose/audio-compose.worker.js +0 -540
- package/dist/stages/compose/audio-compose.worker.js.map +0 -1
- package/dist/stages/compose/audio-compose.worker2.js +0 -5
- package/dist/stages/compose/audio-compose.worker2.js.map +0 -1
- package/dist/stages/compose/video-compose.worker.d.ts +0 -60
- package/dist/stages/compose/video-compose.worker.d.ts.map +0 -1
- package/dist/stages/compose/video-compose.worker.js +0 -379
- package/dist/stages/compose/video-compose.worker.js.map +0 -1
- package/dist/stages/compose/video-compose.worker2.js +0 -5
- package/dist/stages/compose/video-compose.worker2.js.map +0 -1
- package/dist/stages/decode/AudioChunkDecoder.js +0 -82
- package/dist/stages/decode/AudioChunkDecoder.js.map +0 -1
- package/dist/stages/decode/BaseDecoder.js +0 -130
- package/dist/stages/decode/BaseDecoder.js.map +0 -1
- package/dist/stages/decode/VideoChunkDecoder.js +0 -199
- package/dist/stages/decode/VideoChunkDecoder.js.map +0 -1
- package/dist/stages/decode/decode.worker.d.ts +0 -70
- package/dist/stages/decode/decode.worker.d.ts.map +0 -1
- package/dist/stages/decode/decode.worker.js +0 -423
- package/dist/stages/decode/decode.worker.js.map +0 -1
- package/dist/stages/decode/decode.worker2.js +0 -5
- package/dist/stages/decode/decode.worker2.js.map +0 -1
- package/dist/stages/demux/MP3FrameParser.js +0 -186
- package/dist/stages/demux/MP3FrameParser.js.map +0 -1
- package/dist/stages/demux/MP4Demuxer.js.map +0 -1
- package/dist/stages/demux/audio-demux.worker.d.ts +0 -51
- package/dist/stages/demux/audio-demux.worker.d.ts.map +0 -1
- package/dist/stages/demux/audio-demux.worker.js.map +0 -1
- package/dist/stages/demux/audio-demux.worker2.js +0 -5
- package/dist/stages/demux/audio-demux.worker2.js.map +0 -1
- package/dist/stages/demux/video-demux.worker.d.ts +0 -51
- package/dist/stages/demux/video-demux.worker.d.ts.map +0 -1
- package/dist/stages/demux/video-demux.worker.js.map +0 -1
- package/dist/stages/demux/video-demux.worker2.js +0 -5
- package/dist/stages/demux/video-demux.worker2.js.map +0 -1
- package/dist/stages/encode/AudioChunkEncoder.js +0 -37
- package/dist/stages/encode/AudioChunkEncoder.js.map +0 -1
- package/dist/stages/encode/BaseEncoder.js +0 -164
- package/dist/stages/encode/BaseEncoder.js.map +0 -1
- package/dist/stages/encode/VideoChunkEncoder.js +0 -50
- package/dist/stages/encode/VideoChunkEncoder.js.map +0 -1
- package/dist/stages/encode/encode.worker.d.ts +0 -3
- package/dist/stages/encode/encode.worker.d.ts.map +0 -1
- package/dist/stages/encode/encode.worker.js.map +0 -1
- package/dist/stages/encode/encode.worker2.js +0 -5
- package/dist/stages/encode/encode.worker2.js.map +0 -1
- package/dist/stages/mux/MP4Muxer.js.map +0 -1
- package/dist/stages/mux/mux.worker.d.ts +0 -65
- package/dist/stages/mux/mux.worker.d.ts.map +0 -1
- package/dist/stages/mux/mux.worker.js +0 -219
- package/dist/stages/mux/mux.worker.js.map +0 -1
- package/dist/stages/mux/mux.worker2.js +0 -5
- package/dist/stages/mux/mux.worker2.js.map +0 -1
- package/dist/stages/mux/utils.js +0 -34
- package/dist/stages/mux/utils.js.map +0 -1
- package/dist/worker/worker-registry.d.ts +0 -12
- package/dist/worker/worker-registry.d.ts.map +0 -1
- package/dist/worker/worker-registry.js +0 -20
- package/dist/worker/worker-registry.js.map +0 -1
|
@@ -1,6 +1,33 @@
|
|
|
1
|
-
import "../../
|
|
2
|
-
import {
|
|
3
|
-
|
|
1
|
+
import { W as WorkerChannel, a as WorkerMessageType, b as WorkerState } from "../../WorkerChannel.js";
|
|
2
|
+
import { m as mp4box_all } from "../../mp4box.all.js";
|
|
3
|
+
function usToTimescale(microseconds, timescale) {
|
|
4
|
+
return Math.round(microseconds * timescale / 1e6);
|
|
5
|
+
}
|
|
6
|
+
function calculateTimescale(frameRate) {
|
|
7
|
+
if (!frameRate) return 9e4;
|
|
8
|
+
const commonRates = {
|
|
9
|
+
24: 24e3,
|
|
10
|
+
25: 25e3,
|
|
11
|
+
30: 3e4,
|
|
12
|
+
50: 5e4,
|
|
13
|
+
60: 6e4
|
|
14
|
+
};
|
|
15
|
+
return commonRates[Math.round(frameRate)] || 9e4;
|
|
16
|
+
}
|
|
17
|
+
function parseCodecString(codec) {
|
|
18
|
+
const parts = codec.split(".");
|
|
19
|
+
const result = { codec: parts[0] };
|
|
20
|
+
if (parts[0] === "avc1" || parts[0] === "hev1" || parts[0] === "hvc1") {
|
|
21
|
+
if (parts[1]) {
|
|
22
|
+
result.profile = parts[1].substring(0, 2);
|
|
23
|
+
result.level = parts[1].substring(4, 6);
|
|
24
|
+
}
|
|
25
|
+
} else if (parts[0] === "mp4a") {
|
|
26
|
+
if (parts[1]) result.objectType = parts[1];
|
|
27
|
+
if (parts[2]) result.audioObjectType = parts[2];
|
|
28
|
+
}
|
|
29
|
+
return result;
|
|
30
|
+
}
|
|
4
31
|
class MP4Muxer {
|
|
5
32
|
mp4boxFile;
|
|
6
33
|
tracks = /* @__PURE__ */ new Map();
|
|
@@ -256,7 +283,219 @@ class MP4Muxer {
|
|
|
256
283
|
this.outputChunks = [];
|
|
257
284
|
}
|
|
258
285
|
}
|
|
286
|
+
class MuxWorkerImpl {
|
|
287
|
+
channel;
|
|
288
|
+
muxer = null;
|
|
289
|
+
config = null;
|
|
290
|
+
constructor() {
|
|
291
|
+
this.channel = new WorkerChannel(self, {
|
|
292
|
+
name: "MuxWorker",
|
|
293
|
+
timeout: 6e4
|
|
294
|
+
// 60s for export operations
|
|
295
|
+
});
|
|
296
|
+
this.setupHandlers();
|
|
297
|
+
}
|
|
298
|
+
setupHandlers() {
|
|
299
|
+
this.channel.registerHandler("configure", this.handleConfigure.bind(this));
|
|
300
|
+
this.channel.registerHandler("connect", this.handleUnifiedConnect.bind(this));
|
|
301
|
+
this.channel.registerHandler("write_video_chunk", this.handleWriteVideoChunk.bind(this));
|
|
302
|
+
this.channel.registerHandler("write_audio_chunk", this.handleWriteAudioChunk.bind(this));
|
|
303
|
+
this.channel.registerHandler("flush", this.handleFlush.bind(this));
|
|
304
|
+
this.channel.registerHandler("finalize", this.handleFinalize.bind(this));
|
|
305
|
+
this.channel.registerHandler("get_stats", this.handleGetStats.bind(this));
|
|
306
|
+
this.channel.registerHandler(WorkerMessageType.Dispose, this.handleDispose.bind(this));
|
|
307
|
+
this.channel.receiveStream(this.handleInputStream.bind(this));
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Unified connect handler used by stream pipeline
|
|
311
|
+
*/
|
|
312
|
+
async handleUnifiedConnect(_payload) {
|
|
313
|
+
return { success: true };
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Connect to encoder worker to receive encoded chunks
|
|
317
|
+
*/
|
|
318
|
+
// private async handleConnectEncoder(_payload: {
|
|
319
|
+
// port: MessagePort;
|
|
320
|
+
// }): Promise<{ success: boolean }> {
|
|
321
|
+
// // Store the port for receiving encoded chunks
|
|
322
|
+
// // The actual stream handling is done via receiveStream in handleInputStream
|
|
323
|
+
// // This connection allows direct communication with the encoder worker
|
|
324
|
+
// return { success: true };
|
|
325
|
+
// }
|
|
326
|
+
/**
|
|
327
|
+
* Configure muxer with container settings
|
|
328
|
+
* @param payload.config - Muxer configuration including tracks and output format
|
|
329
|
+
* @param payload.initial - If true, initialize worker state; otherwise just update config
|
|
330
|
+
*/
|
|
331
|
+
async handleConfigure(payload) {
|
|
332
|
+
const { config, initial = false } = payload;
|
|
333
|
+
try {
|
|
334
|
+
if (initial) {
|
|
335
|
+
this.channel.state = WorkerState.Ready;
|
|
336
|
+
if (this.muxer) {
|
|
337
|
+
this.muxer.destroy();
|
|
338
|
+
}
|
|
339
|
+
this.config = config;
|
|
340
|
+
this.muxer = new MP4Muxer(config);
|
|
341
|
+
const trackCount = (config.video ? 1 : 0) + (config.audio ? 1 : 0);
|
|
342
|
+
this.channel.notify("configured", {
|
|
343
|
+
container: config.container,
|
|
344
|
+
hasVideo: !!config.video,
|
|
345
|
+
hasAudio: !!config.audio,
|
|
346
|
+
fragmented: !!config.mp4?.fragmented,
|
|
347
|
+
trackCount
|
|
348
|
+
});
|
|
349
|
+
return { success: true, tracks: trackCount };
|
|
350
|
+
} else {
|
|
351
|
+
if (!this.muxer) {
|
|
352
|
+
throw {
|
|
353
|
+
code: "NOT_INITIALIZED",
|
|
354
|
+
message: "Muxer not initialized. Call configure with initial=true first"
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
this.config = { ...this.config, ...config };
|
|
358
|
+
return { success: true };
|
|
359
|
+
}
|
|
360
|
+
} catch (error) {
|
|
361
|
+
throw {
|
|
362
|
+
code: error.code || "CONFIG_ERROR",
|
|
363
|
+
message: error.message
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* Write single video chunk
|
|
369
|
+
*/
|
|
370
|
+
async handleWriteVideoChunk(payload) {
|
|
371
|
+
if (!this.muxer) {
|
|
372
|
+
throw {
|
|
373
|
+
code: "NOT_INITIALIZED",
|
|
374
|
+
message: "Muxer not initialized"
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
this.muxer.writeVideoChunk(payload.chunk, payload.trackId);
|
|
378
|
+
return { bytesWritten: this.muxer.totalBytesWritten };
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* Write single audio chunk
|
|
382
|
+
*/
|
|
383
|
+
async handleWriteAudioChunk(payload) {
|
|
384
|
+
if (!this.muxer) {
|
|
385
|
+
throw {
|
|
386
|
+
code: "NOT_INITIALIZED",
|
|
387
|
+
message: "Muxer not initialized"
|
|
388
|
+
};
|
|
389
|
+
}
|
|
390
|
+
this.muxer.writeAudioChunk(payload.chunk, payload.trackId);
|
|
391
|
+
return { bytesWritten: this.muxer.totalBytesWritten };
|
|
392
|
+
}
|
|
393
|
+
/**
|
|
394
|
+
* Handle input stream from CacheManager (L2 encoded chunks)
|
|
395
|
+
* This is the main export path where CacheManager sends encoded chunks
|
|
396
|
+
*/
|
|
397
|
+
async handleInputStream(stream, metadata) {
|
|
398
|
+
if (!this.muxer) {
|
|
399
|
+
throw new Error("Muxer not configured");
|
|
400
|
+
}
|
|
401
|
+
const reader = stream.getReader();
|
|
402
|
+
let chunksProcessed = 0;
|
|
403
|
+
try {
|
|
404
|
+
this.channel.state = WorkerState.Processing;
|
|
405
|
+
while (true) {
|
|
406
|
+
const { done, value } = await reader.read();
|
|
407
|
+
if (done) break;
|
|
408
|
+
const isVideoChunk = metadata?.type === "video" || value.type === "key" || value.type === "delta";
|
|
409
|
+
if (isVideoChunk) {
|
|
410
|
+
this.muxer.writeVideoChunk(value, metadata?.trackId || 1);
|
|
411
|
+
} else {
|
|
412
|
+
this.muxer.writeAudioChunk(value, metadata?.trackId || 2);
|
|
413
|
+
}
|
|
414
|
+
chunksProcessed++;
|
|
415
|
+
if (chunksProcessed % 100 === 0) {
|
|
416
|
+
this.channel.notify("mux_progress", {
|
|
417
|
+
chunksProcessed,
|
|
418
|
+
bytesWritten: this.muxer.totalBytesWritten
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
this.muxer.flush();
|
|
423
|
+
this.channel.state = WorkerState.Ready;
|
|
424
|
+
this.channel.notify("mux_complete", {
|
|
425
|
+
chunksProcessed,
|
|
426
|
+
bytesWritten: this.muxer.totalBytesWritten
|
|
427
|
+
});
|
|
428
|
+
} finally {
|
|
429
|
+
reader.releaseLock();
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
/**
|
|
433
|
+
* Flush pending samples
|
|
434
|
+
*/
|
|
435
|
+
async handleFlush() {
|
|
436
|
+
if (!this.muxer) {
|
|
437
|
+
throw {
|
|
438
|
+
code: "NOT_INITIALIZED",
|
|
439
|
+
message: "Muxer not initialized"
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
this.muxer.flush();
|
|
443
|
+
return { success: true };
|
|
444
|
+
}
|
|
445
|
+
/**
|
|
446
|
+
* Finalize muxing and get output
|
|
447
|
+
* This completes the export process
|
|
448
|
+
*/
|
|
449
|
+
async handleFinalize() {
|
|
450
|
+
if (!this.muxer) {
|
|
451
|
+
throw {
|
|
452
|
+
code: "NOT_INITIALIZED",
|
|
453
|
+
message: "Muxer not initialized"
|
|
454
|
+
};
|
|
455
|
+
}
|
|
456
|
+
const blob = this.muxer.finalize();
|
|
457
|
+
this.channel.notify("export_done", {
|
|
458
|
+
blob,
|
|
459
|
+
totalBytes: blob.size
|
|
460
|
+
});
|
|
461
|
+
return {
|
|
462
|
+
success: true,
|
|
463
|
+
blob,
|
|
464
|
+
totalBytes: blob.size
|
|
465
|
+
};
|
|
466
|
+
}
|
|
467
|
+
/**
|
|
468
|
+
* Get muxer statistics
|
|
469
|
+
*/
|
|
470
|
+
async handleGetStats() {
|
|
471
|
+
if (!this.muxer) {
|
|
472
|
+
return { state: this.channel.state };
|
|
473
|
+
}
|
|
474
|
+
return {
|
|
475
|
+
bytesWritten: this.muxer.totalBytesWritten,
|
|
476
|
+
chunksCount: this.muxer.outputChunks.length,
|
|
477
|
+
isFinalized: this.muxer.isFinalized,
|
|
478
|
+
state: this.channel.state
|
|
479
|
+
};
|
|
480
|
+
}
|
|
481
|
+
/**
|
|
482
|
+
* Dispose worker and cleanup resources
|
|
483
|
+
*/
|
|
484
|
+
async handleDispose() {
|
|
485
|
+
this.muxer?.destroy();
|
|
486
|
+
this.muxer = null;
|
|
487
|
+
this.config = null;
|
|
488
|
+
this.channel.state = WorkerState.Disposed;
|
|
489
|
+
return { success: true };
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
const worker = new MuxWorkerImpl();
|
|
493
|
+
self.addEventListener("beforeunload", () => {
|
|
494
|
+
worker["handleDispose"]();
|
|
495
|
+
});
|
|
496
|
+
const mux_worker = null;
|
|
259
497
|
export {
|
|
260
|
-
|
|
498
|
+
MuxWorkerImpl,
|
|
499
|
+
mux_worker as default
|
|
261
500
|
};
|
|
262
|
-
//# sourceMappingURL=
|
|
501
|
+
//# sourceMappingURL=mux.worker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mux.worker.js","sources":["../../../../src/stages/mux/utils.ts","../../../../src/stages/mux/MP4Muxer.ts","../../../../src/stages/mux/mux.worker.ts"],"sourcesContent":["import type { EncodedChunkData, MuxSample } from './types';\n\n/**\n * Convert WebCodecs EncodedChunk to MuxSample\n */\nexport function encodedChunkToMuxSample(data: EncodedChunkData): MuxSample {\n const { chunk, trackId, type } = data;\n\n // Create buffer for chunk data\n const buffer = new Uint8Array(chunk.byteLength);\n chunk.copyTo(buffer);\n\n return {\n trackId,\n data: buffer,\n timestamp: chunk.timestamp,\n duration: chunk.duration || 0,\n isKeyFrame: type === 'video' ? (chunk as EncodedVideoChunk).type === 'key' : true, // Audio samples are always \"key frames\"\n };\n}\n\n/**\n * Convert microseconds to timescale units\n */\nexport function usToTimescale(microseconds: number, timescale: number): number {\n return Math.round((microseconds * timescale) / 1_000_000);\n}\n\n/**\n * Convert timescale units to microseconds\n */\nexport function timescaleToUs(units: number, timescale: number): number {\n return Math.round((units * 1_000_000) / timescale);\n}\n\n/**\n * Calculate optimal timescale for given frame rate\n */\nexport function calculateTimescale(frameRate?: number): number {\n if (!frameRate) return 90000; // Default for video\n\n // Common frame rates and their optimal timescales\n const commonRates: Record<number, number> = {\n 24: 24000,\n 25: 25000,\n 30: 30000,\n 50: 50000,\n 60: 60000,\n };\n\n return commonRates[Math.round(frameRate)] || 90000;\n}\n\n/**\n * Parse codec string to extract codec parameters\n * e.g., 'avc1.42E01E' -> { codec: 'avc1', profile: '42', level: '1E' }\n */\nexport function parseCodecString(codec: string): {\n codec: string;\n profile?: string;\n level?: string;\n} {\n const parts = codec.split('.');\n const result: any = { codec: parts[0] };\n\n if (parts[0] === 'avc1' || parts[0] === 'hev1' || parts[0] === 'hvc1') {\n // H.264/H.265 codec string format\n if (parts[1]) {\n result.profile = parts[1].substring(0, 2);\n result.level = parts[1].substring(4, 6);\n }\n } else if (parts[0] === 'mp4a') {\n // AAC codec string format\n if (parts[1]) result.objectType = parts[1];\n if (parts[2]) result.audioObjectType = parts[2];\n }\n\n return result;\n}\n\n/**\n * Create MP4 file brands based on codec\n */\nexport function createBrands(codecs: string[]): string[] {\n const brands = new Set<string>(['isom', 'iso2']);\n\n for (const codec of codecs) {\n if (codec.startsWith('avc1')) {\n brands.add('avc1');\n brands.add('mp41');\n } else if (codec.startsWith('hev1') || codec.startsWith('hvc1')) {\n brands.add('hev1');\n brands.add('hvc1');\n } else if (codec.startsWith('av01')) {\n brands.add('av01');\n } else if (codec.startsWith('mp4a')) {\n brands.add('mp41');\n }\n }\n\n return Array.from(brands);\n}\n","// @ts-ignore - mp4box doesn't have proper TypeScript definitions\nimport * as MP4Box from 'mp4box';\nimport type { MuxConfig, MuxTrack } from './types';\nimport { usToTimescale, calculateTimescale, parseCodecString } from './utils';\n\ninterface MP4TrackOptions {\n timescale: number;\n type: string;\n nb_samples: number;\n width?: number;\n height?: number;\n channel_count?: number;\n samplerate?: number;\n hdlr?: string;\n name?: string;\n codec?: string;\n avcDecoderConfigRecord?: Uint8Array;\n hvcDecoderConfigRecord?: Uint8Array;\n av1DecoderConfigRecord?: Uint8Array;\n audioDecoderConfig?: Uint8Array;\n opusDecoderConfig?: Uint8Array;\n}\n\n/**\n * MP4 Muxer - Multiplex encoded chunks into MP4 container\n * Terminal stage that consumes encoded chunks and produces MP4 file\n */\nexport class MP4Muxer {\n private mp4boxFile: any;\n tracks = new Map<number, MuxTrack>();\n private mp4Tracks = new Map<number, number>(); // muxTrackId -> mp4boxTrackId\n\n // Expose output chunks directly instead of getter\n outputChunks: Uint8Array[] = [];\n\n // Expose total bytes written as computed property\n get totalBytesWritten(): number {\n return this.outputChunks.reduce((sum, chunk) => sum + chunk.byteLength, 0);\n }\n\n // Expose finalized state\n isFinalized = false;\n\n private config: MuxConfig;\n\n constructor(config: MuxConfig = { container: 'mp4' }) {\n this.config = config;\n this.mp4boxFile = MP4Box.createFile();\n this.setupHandlers();\n this.initializeTracks();\n }\n\n private setupHandlers(): void {\n this.mp4boxFile.onError = (error: string) => {\n console.error('MP4Box error:', error);\n };\n\n // Called when MP4Box has data to write\n this.mp4boxFile.onSegment = (\n _id: number,\n _user: any,\n buffer: ArrayBuffer,\n _sampleNumber: number,\n _last: boolean\n ) => {\n const chunk = new Uint8Array(buffer);\n this.outputChunks.push(chunk);\n };\n\n // Handle initialization segment for fragmented MP4\n if (this.config.mp4?.fragmented) {\n this.mp4boxFile.onInitSegment = (_tracks: any[]) => {\n const initSegment = this.mp4boxFile.getInitializationSegment();\n if (initSegment) {\n const chunk = new Uint8Array(initSegment);\n this.outputChunks.push(chunk);\n }\n };\n }\n }\n\n private initializeTracks(): void {\n // Add video track if configured\n if (this.config.video) {\n const videoTrack: MuxTrack = {\n id: 1, // Default video track ID\n type: 'video',\n codec: this.config.video.codec,\n width: this.config.video.width,\n height: this.config.video.height,\n frameRate: this.config.video.frameRate,\n timescale: calculateTimescale(this.config.video.frameRate),\n codecConfig: this.config.video.description,\n };\n this.addTrack(videoTrack);\n }\n\n // Add audio track if configured\n if (this.config.audio) {\n const audioTrack: MuxTrack = {\n id: 2, // Default audio track ID\n type: 'audio',\n codec: this.config.audio.codec,\n sampleRate: this.config.audio.sampleRate,\n channelCount: this.config.audio.channelCount,\n timescale: this.config.audio.sampleRate,\n codecConfig: this.config.audio.description,\n };\n this.addTrack(audioTrack);\n }\n }\n\n private addTrack(track: MuxTrack): number {\n if (!this.mp4boxFile) {\n throw new Error('Muxer destroyed');\n }\n\n // Store track info\n this.tracks.set(track.id, track);\n\n // Create track options based on type\n const trackOptions =\n track.type === 'video'\n ? this.createVideoTrackOptions(track)\n : this.createAudioTrackOptions(track);\n\n // Add track to MP4Box\n const mp4TrackId = this.mp4boxFile.addTrack(trackOptions);\n this.mp4Tracks.set(track.id, mp4TrackId);\n\n // Configure track for fragmented mode if enabled\n if (this.config.mp4?.fragmented) {\n this.configureFragmentedTrack(mp4TrackId, track);\n }\n\n return track.id;\n }\n\n private configureFragmentedTrack(mp4TrackId: number, track: MuxTrack): void {\n const fragmentDuration = this.config.mp4?.fragmentDuration || 1_000_000; // 1 second default in microseconds\n\n let nbSamples: number;\n\n if (track.type === 'video') {\n // For video: calculate number of frames per fragment based on frame rate\n // nbSamples = fragment_duration_in_seconds * frame_rate\n const frameRate = track.frameRate || 30;\n const fragmentDurationInSeconds = fragmentDuration / 1_000_000;\n nbSamples = Math.ceil(fragmentDurationInSeconds * frameRate);\n } else {\n // For audio: calculate number of samples per fragment\n // Audio typically has many more samples (e.g., 48000 Hz sample rate)\n // A reasonable fragment might contain ~1 second of audio samples\n const sampleRate = track.sampleRate || 48000;\n const fragmentDurationInSeconds = fragmentDuration / 1_000_000;\n // For compressed audio (AAC, Opus), each \"sample\" is actually a frame containing multiple PCM samples\n // AAC frame typically contains 1024 PCM samples, so at 48kHz: 48000/1024 ≈ 47 frames per second\n const framesPerSecond = sampleRate / 1024; // Assuming AAC-like frame size\n nbSamples = Math.ceil(fragmentDurationInSeconds * framesPerSecond);\n }\n\n /**\n * setSegmentOptions parameters:\n * @param trackId - The track ID to configure\n * @param user - User data (passed to callbacks, we don't use it)\n * @param options - Segmentation options:\n * - nbSamples: Number of samples per segment/fragment\n * - rapAlignement: Random Access Point alignment - ensures segments start with keyframes\n * This is critical for seeking and adaptive streaming (HLS/DASH)\n */\n this.mp4boxFile.setSegmentOptions(mp4TrackId, null, {\n nbSamples,\n rapAlignement: true, // Align segments to keyframes for proper seeking\n });\n }\n\n private createVideoTrackOptions(track: MuxTrack): MP4TrackOptions {\n const options: MP4TrackOptions = {\n timescale: track.timescale || calculateTimescale(track.frameRate),\n type: 'video',\n nb_samples: 0,\n width: track.width,\n height: track.height,\n };\n\n // Configure codec-specific options\n const codecInfo = parseCodecString(track.codec);\n\n switch (codecInfo.codec) {\n case 'avc1':\n options.codec = 'avc1';\n options.avcDecoderConfigRecord = track.codecConfig;\n break;\n case 'hev1':\n case 'hvc1':\n options.codec = 'hvc1';\n options.hvcDecoderConfigRecord = track.codecConfig;\n break;\n case 'av01':\n options.codec = 'av01';\n options.av1DecoderConfigRecord = track.codecConfig;\n break;\n case 'vp09':\n options.codec = 'vp09';\n // VP9 specific configuration\n break;\n default:\n throw new Error(`Unsupported video codec: ${track.codec}`);\n }\n\n return options;\n }\n\n private createAudioTrackOptions(track: MuxTrack): MP4TrackOptions {\n const options: MP4TrackOptions = {\n timescale: track.timescale || track.sampleRate || 48000,\n type: 'audio',\n nb_samples: 0,\n channel_count: track.channelCount,\n samplerate: track.sampleRate,\n hdlr: 'soun',\n name: 'SoundHandler',\n };\n\n // Configure codec-specific options\n const codecInfo = parseCodecString(track.codec);\n\n switch (codecInfo.codec) {\n case 'mp4a':\n options.codec = 'mp4a.40.2'; // AAC-LC\n options.audioDecoderConfig = track.codecConfig;\n break;\n case 'opus':\n options.codec = 'Opus';\n options.opusDecoderConfig = track.codecConfig;\n break;\n case 'mp3':\n options.codec = 'mp3';\n break;\n case 'ac-3':\n options.codec = 'ac-3';\n break;\n case 'ec-3':\n options.codec = 'ec-3';\n break;\n default:\n throw new Error(`Unsupported audio codec: ${track.codec}`);\n }\n\n return options;\n }\n\n /**\n * Write video chunk to muxer\n */\n writeVideoChunk(chunk: EncodedVideoChunk, trackId: number = 1): void {\n const mp4TrackId = this.mp4Tracks.get(trackId);\n if (!mp4TrackId) {\n throw new Error(`Track ${trackId} not found`);\n }\n\n const track = this.tracks.get(trackId);\n if (!track) {\n throw new Error(`Track info for ${trackId} not found`);\n }\n\n // Create buffer for chunk data\n const data = new Uint8Array(chunk.byteLength);\n chunk.copyTo(data);\n\n // Convert timestamps to timescale units\n const pts = usToTimescale(chunk.timestamp, track.timescale);\n const dts =\n chunk.timestamp !== undefined ? usToTimescale(chunk.timestamp, track.timescale) : pts;\n const duration = usToTimescale(chunk.duration || 0, track.timescale);\n\n // Create MP4Box sample\n const mp4Sample: any = {\n data: data,\n pts: pts,\n dts: dts,\n duration: duration,\n is_sync: chunk.type === 'key',\n };\n\n // Add sample to track\n this.mp4boxFile.addSample(mp4TrackId, data, mp4Sample);\n }\n\n /**\n * Write audio chunk to muxer\n */\n writeAudioChunk(chunk: EncodedAudioChunk, trackId: number = 2): void {\n const mp4TrackId = this.mp4Tracks.get(trackId);\n if (!mp4TrackId) {\n throw new Error(`Track ${trackId} not found`);\n }\n\n const track = this.tracks.get(trackId);\n if (!track) {\n throw new Error(`Track info for ${trackId} not found`);\n }\n\n // Create buffer for chunk data\n const data = new Uint8Array(chunk.byteLength);\n chunk.copyTo(data);\n\n // Convert timestamps to timescale units\n const pts = usToTimescale(chunk.timestamp, track.timescale);\n const duration = usToTimescale(chunk.duration || 0, track.timescale);\n\n // Create MP4Box sample\n const mp4Sample: any = {\n data: data,\n pts: pts,\n dts: pts,\n duration: duration,\n is_sync: true, // Audio chunks are always sync samples\n };\n\n // Add sample to track\n this.mp4boxFile.addSample(mp4TrackId, data, mp4Sample);\n }\n\n /**\n * Flush pending samples\n */\n flush(): void {\n if (this.mp4boxFile) {\n this.mp4boxFile.flush();\n }\n }\n\n /**\n * Finalize and get the output\n */\n finalize(): Blob {\n if (this.isFinalized) {\n throw new Error('Muxer already finalized');\n }\n\n if (!this.mp4boxFile) {\n throw new Error('Muxer destroyed');\n }\n\n // Flush any remaining samples\n this.flush();\n\n // For non-fragmented mode, close to write moov box\n if (!this.config.mp4?.fragmented) {\n this.mp4boxFile.close();\n }\n\n this.isFinalized = true;\n\n // Return the muxed MP4 as a Blob\n return new Blob(this.outputChunks as BlobPart[], { type: 'video/mp4' });\n }\n\n /**\n * Clear output chunks (after they've been consumed)\n */\n clearOutputChunks(): void {\n this.outputChunks = [];\n }\n\n destroy(): void {\n this.mp4boxFile?.stop?.();\n this.mp4boxFile = null;\n this.tracks.clear();\n this.mp4Tracks.clear();\n this.outputChunks = [];\n }\n}\n","import { WorkerChannel } from '../../worker/WorkerChannel';\nimport { WorkerMessageType, WorkerState } from '../../worker/types';\nimport { MP4Muxer } from './MP4Muxer';\nimport type { MuxConfig } from './types';\n\n/**\n * MuxWorker - Final stage for video/audio multiplexing\n * Combines encoded video and audio tracks into container format (MP4)\n *\n * Pipeline: CacheManager → MuxWorker → Export (Blob/OPFS)\n *\n * Features:\n * - MP4 container muxing with mp4box.js\n * - Stream-based processing from L2 cache\n * - Support for fragmented MP4 (fMP4) for streaming\n * - Direct blob output for download\n */\nexport class MuxWorkerImpl {\n private channel: WorkerChannel;\n private muxer: MP4Muxer | null = null;\n private config: MuxConfig | null = null;\n\n constructor() {\n // Initialize WorkerChannel\n this.channel = new WorkerChannel(self as any, {\n name: 'MuxWorker',\n timeout: 60000, // 60s for export operations\n });\n\n this.setupHandlers();\n }\n\n private setupHandlers(): void {\n // Register message handlers\n this.channel.registerHandler('configure', this.handleConfigure.bind(this));\n // Unified stream connect (feature-flagged)\n this.channel.registerHandler('connect' as any, this.handleUnifiedConnect.bind(this));\n // Unified stream connect only\n this.channel.registerHandler('write_video_chunk', this.handleWriteVideoChunk.bind(this));\n this.channel.registerHandler('write_audio_chunk', this.handleWriteAudioChunk.bind(this));\n this.channel.registerHandler('flush', this.handleFlush.bind(this));\n this.channel.registerHandler('finalize', this.handleFinalize.bind(this));\n this.channel.registerHandler('get_stats', this.handleGetStats.bind(this));\n this.channel.registerHandler(WorkerMessageType.Dispose, this.handleDispose.bind(this));\n\n // Setup stream receiver from CacheManager (L2 encoded chunks)\n this.channel.receiveStream(this.handleInputStream.bind(this));\n }\n\n /**\n * Unified connect handler used by stream pipeline\n */\n private async handleUnifiedConnect(_payload: {\n direction: 'upstream';\n port: MessagePort;\n streamType: 'video' | 'audio' | 'frame' | 'chunk';\n }): Promise<{ success: boolean }> {\n // Mux receives encoded chunks via receiveStream already\n return { success: true };\n }\n\n /**\n * Connect to encoder worker to receive encoded chunks\n */\n // private async handleConnectEncoder(_payload: {\n // port: MessagePort;\n // }): Promise<{ success: boolean }> {\n // // Store the port for receiving encoded chunks\n // // The actual stream handling is done via receiveStream in handleInputStream\n // // This connection allows direct communication with the encoder worker\n // return { success: true };\n // }\n\n /**\n * Configure muxer with container settings\n * @param payload.config - Muxer configuration including tracks and output format\n * @param payload.initial - If true, initialize worker state; otherwise just update config\n */\n private async handleConfigure(payload: {\n config: MuxConfig;\n initial?: boolean;\n }): Promise<{ success: boolean; tracks?: number }> {\n const { config, initial = false } = payload;\n\n try {\n if (initial) {\n // Initial setup - set worker state to ready\n this.channel.state = WorkerState.Ready;\n\n // Create new muxer instance\n if (this.muxer) {\n this.muxer.destroy();\n }\n\n this.config = config;\n this.muxer = new MP4Muxer(config);\n\n const trackCount = (config.video ? 1 : 0) + (config.audio ? 1 : 0);\n\n // Notify configuration complete\n this.channel.notify('configured', {\n container: config.container,\n hasVideo: !!config.video,\n hasAudio: !!config.audio,\n fragmented: !!config.mp4?.fragmented,\n trackCount,\n });\n\n return { success: true, tracks: trackCount };\n } else {\n // Update configuration only\n if (!this.muxer) {\n throw {\n code: 'NOT_INITIALIZED',\n message: 'Muxer not initialized. Call configure with initial=true first',\n };\n }\n\n // MP4Muxer doesn't support runtime config updates\n // Would need to recreate for changes\n this.config = { ...this.config, ...config };\n\n return { success: true };\n }\n } catch (error: any) {\n throw {\n code: error.code || 'CONFIG_ERROR',\n message: error.message,\n };\n }\n }\n\n /**\n * Write single video chunk\n */\n private async handleWriteVideoChunk(payload: {\n chunk: EncodedVideoChunk;\n trackId?: number;\n }): Promise<{ bytesWritten: number }> {\n if (!this.muxer) {\n throw {\n code: 'NOT_INITIALIZED',\n message: 'Muxer not initialized',\n };\n }\n\n this.muxer.writeVideoChunk(payload.chunk, payload.trackId);\n\n return { bytesWritten: this.muxer.totalBytesWritten };\n }\n\n /**\n * Write single audio chunk\n */\n private async handleWriteAudioChunk(payload: {\n chunk: EncodedAudioChunk;\n trackId?: number;\n }): Promise<{ bytesWritten: number }> {\n if (!this.muxer) {\n throw {\n code: 'NOT_INITIALIZED',\n message: 'Muxer not initialized',\n };\n }\n\n this.muxer.writeAudioChunk(payload.chunk, payload.trackId);\n\n return { bytesWritten: this.muxer.totalBytesWritten };\n }\n\n /**\n * Handle input stream from CacheManager (L2 encoded chunks)\n * This is the main export path where CacheManager sends encoded chunks\n */\n private async handleInputStream(\n stream: ReadableStream<EncodedVideoChunk | EncodedAudioChunk>,\n metadata?: Record<string, any>\n ): Promise<void> {\n if (!this.muxer) {\n throw new Error('Muxer not configured');\n }\n\n const reader = stream.getReader();\n let chunksProcessed = 0;\n\n try {\n this.channel.state = WorkerState.Processing;\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n // Determine chunk type and write accordingly\n const isVideoChunk =\n metadata?.type === 'video' ||\n (value as any).type === 'key' ||\n (value as any).type === 'delta';\n\n if (isVideoChunk) {\n this.muxer.writeVideoChunk(value as EncodedVideoChunk, metadata?.trackId || 1);\n } else {\n this.muxer.writeAudioChunk(value as EncodedAudioChunk, metadata?.trackId || 2);\n }\n\n chunksProcessed++;\n\n // Report progress periodically\n if (chunksProcessed % 100 === 0) {\n this.channel.notify('mux_progress', {\n chunksProcessed,\n bytesWritten: this.muxer.totalBytesWritten,\n });\n }\n }\n\n // Flush after stream processing\n this.muxer.flush();\n\n this.channel.state = WorkerState.Ready;\n\n // Notify muxing complete\n this.channel.notify('mux_complete', {\n chunksProcessed,\n bytesWritten: this.muxer.totalBytesWritten,\n });\n } finally {\n reader.releaseLock();\n }\n }\n\n /**\n * Flush pending samples\n */\n private async handleFlush(): Promise<{ success: boolean }> {\n if (!this.muxer) {\n throw {\n code: 'NOT_INITIALIZED',\n message: 'Muxer not initialized',\n };\n }\n\n this.muxer.flush();\n return { success: true };\n }\n\n /**\n * Finalize muxing and get output\n * This completes the export process\n */\n private async handleFinalize(): Promise<{\n success: boolean;\n blob: Blob;\n totalBytes: number;\n }> {\n if (!this.muxer) {\n throw {\n code: 'NOT_INITIALIZED',\n message: 'Muxer not initialized',\n };\n }\n\n const blob = this.muxer.finalize();\n\n // Notify export completion as per architecture doc\n this.channel.notify('export_done', {\n blob,\n totalBytes: blob.size,\n });\n\n return {\n success: true,\n blob,\n totalBytes: blob.size,\n };\n }\n\n /**\n * Get muxer statistics\n */\n private async handleGetStats(): Promise<{\n bytesWritten?: number;\n chunksCount?: number;\n isFinalized?: boolean;\n state?: WorkerState;\n }> {\n if (!this.muxer) {\n return { state: this.channel.state };\n }\n\n return {\n bytesWritten: this.muxer.totalBytesWritten,\n chunksCount: this.muxer.outputChunks.length,\n isFinalized: this.muxer.isFinalized,\n state: this.channel.state,\n };\n }\n\n /**\n * Dispose worker and cleanup resources\n */\n private async handleDispose(): Promise<{ success: boolean }> {\n // Destroy muxer\n this.muxer?.destroy();\n this.muxer = null;\n this.config = null;\n\n this.channel.state = WorkerState.Disposed;\n\n return { success: true };\n }\n}\n\n// Initialize worker\nconst worker = new MuxWorkerImpl();\n\n// Handle worker termination\nself.addEventListener('beforeunload', () => {\n worker['handleDispose']();\n});\n\nexport default null; // Required for TypeScript worker compilation\n"],"names":["MP4Box.createFile"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@meframe/core",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
4
4
|
"description": "Next generation media processing framework based on WebCodecs",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -38,25 +38,6 @@
|
|
|
38
38
|
"LICENSE",
|
|
39
39
|
"CHANGELOG.md"
|
|
40
40
|
],
|
|
41
|
-
"scripts": {
|
|
42
|
-
"dev": "vite",
|
|
43
|
-
"build": "tsc && vite build",
|
|
44
|
-
"preview": "vite preview",
|
|
45
|
-
"prepublishOnly": "npm run lint && npm run type-check && npm run build",
|
|
46
|
-
"test": "vitest run",
|
|
47
|
-
"test:watch": "vitest",
|
|
48
|
-
"test:coverage": "vitest run --coverage",
|
|
49
|
-
"test:ui": "vitest --ui",
|
|
50
|
-
"test:integration": "vitest run --config vitest.integration.config.ts",
|
|
51
|
-
"test:e2e": "playwright test --project=chromium",
|
|
52
|
-
"test:e2e:ui": "playwright test --project=chromium --ui",
|
|
53
|
-
"test:e2e:debug": "playwright test --project=chromium --debug",
|
|
54
|
-
"lint": "eslint src --ignore-pattern '**/__tests__' --ignore-pattern '**/*.test.ts' --ignore-pattern '**/*.spec.ts'",
|
|
55
|
-
"lint:fix": "eslint src --fix --ignore-pattern '**/__tests__' --ignore-pattern '**/*.test.ts' --ignore-pattern '**/*.spec.ts'",
|
|
56
|
-
"type-check": "tsc --noEmit",
|
|
57
|
-
"clean": "rm -rf dist coverage",
|
|
58
|
-
"playwright:install": "playwright install chromium"
|
|
59
|
-
},
|
|
60
41
|
"dependencies": {
|
|
61
42
|
"mp4box": "^0.5.2"
|
|
62
43
|
},
|
|
@@ -107,5 +88,24 @@
|
|
|
107
88
|
"publishConfig": {
|
|
108
89
|
"access": "public",
|
|
109
90
|
"registry": "https://registry.npmjs.org/"
|
|
91
|
+
},
|
|
92
|
+
"scripts": {
|
|
93
|
+
"dev": "vite",
|
|
94
|
+
"build": "tsc && vite build && pnpm build:workers",
|
|
95
|
+
"build:workers": "vite build --config vite.worker.config.ts",
|
|
96
|
+
"preview": "vite preview",
|
|
97
|
+
"test": "vitest run",
|
|
98
|
+
"test:watch": "vitest",
|
|
99
|
+
"test:coverage": "vitest run --coverage",
|
|
100
|
+
"test:ui": "vitest --ui",
|
|
101
|
+
"test:integration": "vitest run --config vitest.integration.config.ts",
|
|
102
|
+
"test:e2e": "playwright test --project=chromium",
|
|
103
|
+
"test:e2e:ui": "playwright test --project=chromium --ui",
|
|
104
|
+
"test:e2e:debug": "playwright test --project=chromium --debug",
|
|
105
|
+
"lint": "eslint src --ignore-pattern '**/__tests__' --ignore-pattern '**/*.test.ts' --ignore-pattern '**/*.spec.ts' --ignore-pattern '**/*.worker.ts'",
|
|
106
|
+
"lint:fix": "eslint src --fix --ignore-pattern '**/__tests__' --ignore-pattern '**/*.test.ts' --ignore-pattern '**/*.spec.ts' --ignore-pattern '**/*.worker.ts'",
|
|
107
|
+
"type-check": "tsc --noEmit",
|
|
108
|
+
"clean": "rm -rf dist coverage",
|
|
109
|
+
"playwright:install": "playwright install chromium"
|
|
110
110
|
}
|
|
111
|
-
}
|
|
111
|
+
}
|