@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.
Files changed (137) hide show
  1. package/dist/Meframe.d.ts.map +1 -1
  2. package/dist/Meframe.js +2 -1
  3. package/dist/Meframe.js.map +1 -1
  4. package/dist/config/defaults.d.ts.map +1 -1
  5. package/dist/config/defaults.js +2 -1
  6. package/dist/config/defaults.js.map +1 -1
  7. package/dist/config/types.d.ts +3 -0
  8. package/dist/config/types.d.ts.map +1 -1
  9. package/dist/orchestrator/Orchestrator.d.ts.map +1 -1
  10. package/dist/orchestrator/Orchestrator.js +2 -1
  11. package/dist/orchestrator/Orchestrator.js.map +1 -1
  12. package/dist/orchestrator/types.d.ts +1 -0
  13. package/dist/orchestrator/types.d.ts.map +1 -1
  14. package/dist/stages/compose/types.d.ts +2 -1
  15. package/dist/stages/compose/types.d.ts.map +1 -1
  16. package/dist/stages/demux/MP4Demuxer.d.ts +0 -1
  17. package/dist/stages/demux/MP4Demuxer.d.ts.map +1 -1
  18. package/dist/utils/time-utils.d.ts +3 -2
  19. package/dist/utils/time-utils.d.ts.map +1 -1
  20. package/dist/utils/time-utils.js +2 -1
  21. package/dist/utils/time-utils.js.map +1 -1
  22. package/dist/vite-plugin.d.ts +5 -3
  23. package/dist/vite-plugin.d.ts.map +1 -1
  24. package/dist/vite-plugin.js +109 -52
  25. package/dist/vite-plugin.js.map +1 -1
  26. package/dist/worker/WorkerPool.d.ts +7 -0
  27. package/dist/worker/WorkerPool.d.ts.map +1 -1
  28. package/dist/worker/WorkerPool.js +29 -5
  29. package/dist/worker/WorkerPool.js.map +1 -1
  30. package/dist/{stages/demux → workers}/MP4Demuxer.js +4 -13
  31. package/dist/workers/MP4Demuxer.js.map +1 -0
  32. package/dist/workers/WorkerChannel.js +486 -0
  33. package/dist/workers/WorkerChannel.js.map +1 -0
  34. package/dist/{assets/video-demux.worker-D019I7GQ.js → workers/mp4box.all.js} +4 -912
  35. package/dist/workers/mp4box.all.js.map +1 -0
  36. package/dist/{assets/audio-compose.worker-nGVvHD5Q.js → workers/stages/compose/audio-compose.worker.js} +7 -481
  37. package/dist/workers/stages/compose/audio-compose.worker.js.map +1 -0
  38. package/dist/{assets/video-compose.worker-DPzsC21d.js → workers/stages/compose/video-compose.worker.js} +7 -481
  39. package/dist/workers/stages/compose/video-compose.worker.js.map +1 -0
  40. package/dist/{assets/decode.worker-DpWHsc7R.js → workers/stages/decode/decode.worker.js} +7 -481
  41. package/dist/workers/stages/decode/decode.worker.js.map +1 -0
  42. package/dist/{stages → workers/stages}/demux/audio-demux.worker.js +184 -4
  43. package/dist/workers/stages/demux/audio-demux.worker.js.map +1 -0
  44. package/dist/{stages → workers/stages}/demux/video-demux.worker.js +2 -3
  45. package/dist/workers/stages/demux/video-demux.worker.js.map +1 -0
  46. package/dist/{stages → workers/stages}/encode/encode.worker.js +238 -4
  47. package/dist/workers/stages/encode/encode.worker.js.map +1 -0
  48. package/dist/{stages/mux/MP4Muxer.js → workers/stages/mux/mux.worker.js} +244 -5
  49. package/dist/workers/stages/mux/mux.worker.js.map +1 -0
  50. package/package.json +21 -21
  51. package/dist/assets/audio-compose.worker-nGVvHD5Q.js.map +0 -1
  52. package/dist/assets/audio-demux.worker-xwWBtbAe.js +0 -8299
  53. package/dist/assets/audio-demux.worker-xwWBtbAe.js.map +0 -1
  54. package/dist/assets/decode.worker-DpWHsc7R.js.map +0 -1
  55. package/dist/assets/encode.worker-nfOb3kw6.js +0 -1026
  56. package/dist/assets/encode.worker-nfOb3kw6.js.map +0 -1
  57. package/dist/assets/mux.worker-uEMQY066.js +0 -8019
  58. package/dist/assets/mux.worker-uEMQY066.js.map +0 -1
  59. package/dist/assets/video-compose.worker-DPzsC21d.js.map +0 -1
  60. package/dist/assets/video-demux.worker-D019I7GQ.js.map +0 -1
  61. package/dist/model/types.js +0 -5
  62. package/dist/model/types.js.map +0 -1
  63. package/dist/plugins/BackpressureMonitor.js +0 -62
  64. package/dist/plugins/BackpressureMonitor.js.map +0 -1
  65. package/dist/stages/compose/AudioDucker.js +0 -161
  66. package/dist/stages/compose/AudioDucker.js.map +0 -1
  67. package/dist/stages/compose/AudioMixer.js +0 -373
  68. package/dist/stages/compose/AudioMixer.js.map +0 -1
  69. package/dist/stages/compose/FilterProcessor.js +0 -226
  70. package/dist/stages/compose/FilterProcessor.js.map +0 -1
  71. package/dist/stages/compose/LayerRenderer.js +0 -215
  72. package/dist/stages/compose/LayerRenderer.js.map +0 -1
  73. package/dist/stages/compose/TransitionProcessor.js +0 -189
  74. package/dist/stages/compose/TransitionProcessor.js.map +0 -1
  75. package/dist/stages/compose/VideoComposer.js +0 -186
  76. package/dist/stages/compose/VideoComposer.js.map +0 -1
  77. package/dist/stages/compose/audio-compose.worker.d.ts +0 -79
  78. package/dist/stages/compose/audio-compose.worker.d.ts.map +0 -1
  79. package/dist/stages/compose/audio-compose.worker.js +0 -540
  80. package/dist/stages/compose/audio-compose.worker.js.map +0 -1
  81. package/dist/stages/compose/audio-compose.worker2.js +0 -5
  82. package/dist/stages/compose/audio-compose.worker2.js.map +0 -1
  83. package/dist/stages/compose/video-compose.worker.d.ts +0 -60
  84. package/dist/stages/compose/video-compose.worker.d.ts.map +0 -1
  85. package/dist/stages/compose/video-compose.worker.js +0 -379
  86. package/dist/stages/compose/video-compose.worker.js.map +0 -1
  87. package/dist/stages/compose/video-compose.worker2.js +0 -5
  88. package/dist/stages/compose/video-compose.worker2.js.map +0 -1
  89. package/dist/stages/decode/AudioChunkDecoder.js +0 -82
  90. package/dist/stages/decode/AudioChunkDecoder.js.map +0 -1
  91. package/dist/stages/decode/BaseDecoder.js +0 -130
  92. package/dist/stages/decode/BaseDecoder.js.map +0 -1
  93. package/dist/stages/decode/VideoChunkDecoder.js +0 -199
  94. package/dist/stages/decode/VideoChunkDecoder.js.map +0 -1
  95. package/dist/stages/decode/decode.worker.d.ts +0 -70
  96. package/dist/stages/decode/decode.worker.d.ts.map +0 -1
  97. package/dist/stages/decode/decode.worker.js +0 -423
  98. package/dist/stages/decode/decode.worker.js.map +0 -1
  99. package/dist/stages/decode/decode.worker2.js +0 -5
  100. package/dist/stages/decode/decode.worker2.js.map +0 -1
  101. package/dist/stages/demux/MP3FrameParser.js +0 -186
  102. package/dist/stages/demux/MP3FrameParser.js.map +0 -1
  103. package/dist/stages/demux/MP4Demuxer.js.map +0 -1
  104. package/dist/stages/demux/audio-demux.worker.d.ts +0 -51
  105. package/dist/stages/demux/audio-demux.worker.d.ts.map +0 -1
  106. package/dist/stages/demux/audio-demux.worker.js.map +0 -1
  107. package/dist/stages/demux/audio-demux.worker2.js +0 -5
  108. package/dist/stages/demux/audio-demux.worker2.js.map +0 -1
  109. package/dist/stages/demux/video-demux.worker.d.ts +0 -51
  110. package/dist/stages/demux/video-demux.worker.d.ts.map +0 -1
  111. package/dist/stages/demux/video-demux.worker.js.map +0 -1
  112. package/dist/stages/demux/video-demux.worker2.js +0 -5
  113. package/dist/stages/demux/video-demux.worker2.js.map +0 -1
  114. package/dist/stages/encode/AudioChunkEncoder.js +0 -37
  115. package/dist/stages/encode/AudioChunkEncoder.js.map +0 -1
  116. package/dist/stages/encode/BaseEncoder.js +0 -164
  117. package/dist/stages/encode/BaseEncoder.js.map +0 -1
  118. package/dist/stages/encode/VideoChunkEncoder.js +0 -50
  119. package/dist/stages/encode/VideoChunkEncoder.js.map +0 -1
  120. package/dist/stages/encode/encode.worker.d.ts +0 -3
  121. package/dist/stages/encode/encode.worker.d.ts.map +0 -1
  122. package/dist/stages/encode/encode.worker.js.map +0 -1
  123. package/dist/stages/encode/encode.worker2.js +0 -5
  124. package/dist/stages/encode/encode.worker2.js.map +0 -1
  125. package/dist/stages/mux/MP4Muxer.js.map +0 -1
  126. package/dist/stages/mux/mux.worker.d.ts +0 -65
  127. package/dist/stages/mux/mux.worker.d.ts.map +0 -1
  128. package/dist/stages/mux/mux.worker.js +0 -219
  129. package/dist/stages/mux/mux.worker.js.map +0 -1
  130. package/dist/stages/mux/mux.worker2.js +0 -5
  131. package/dist/stages/mux/mux.worker2.js.map +0 -1
  132. package/dist/stages/mux/utils.js +0 -34
  133. package/dist/stages/mux/utils.js.map +0 -1
  134. package/dist/worker/worker-registry.d.ts +0 -12
  135. package/dist/worker/worker-registry.d.ts.map +0 -1
  136. package/dist/worker/worker-registry.js +0 -20
  137. package/dist/worker/worker-registry.js.map +0 -1
@@ -1,72 +1,124 @@
1
- import { existsSync, readdirSync, mkdirSync, copyFileSync } from "fs";
2
- import { dirname, join, resolve } from "path";
1
+ import { existsSync, readFileSync, readdirSync, statSync, mkdirSync, copyFileSync } from "fs";
2
+ import { join, dirname, resolve } from "path";
3
+ const DEFAULT_WORKER_PATH = "meframe-workers";
4
+ function findCoreWorkerFiles() {
5
+ const findWorkers = (dir) => {
6
+ if (!existsSync(dir)) return [];
7
+ const files = [];
8
+ const entries = readdirSync(dir);
9
+ for (const entry of entries) {
10
+ const fullPath = join(dir, entry);
11
+ const stat = statSync(fullPath);
12
+ if (stat.isDirectory()) {
13
+ files.push(...findWorkers(fullPath));
14
+ } else if (entry.endsWith(".worker.js") || entry.endsWith(".worker.js.map")) {
15
+ files.push(fullPath);
16
+ }
17
+ }
18
+ return files;
19
+ };
20
+ try {
21
+ const corePackagePath = require.resolve("@meframe/core/package.json");
22
+ const coreDir = dirname(corePackagePath);
23
+ const workersDir = join(coreDir, "dist", "workers");
24
+ if (!existsSync(workersDir)) {
25
+ return null;
26
+ }
27
+ const files = findWorkers(workersDir);
28
+ return files.length > 0 ? { dir: workersDir, files } : null;
29
+ } catch {
30
+ const monorepoPath = resolve(process.cwd(), "../core/dist/workers");
31
+ if (!existsSync(monorepoPath)) {
32
+ return null;
33
+ }
34
+ const files = findWorkers(monorepoPath);
35
+ return files.length > 0 ? { dir: monorepoPath, files } : null;
36
+ }
37
+ }
3
38
  function meframePlugin(options = {}) {
4
- const { workerDir = "assets", verbose = false } = options;
39
+ const { workerPath = DEFAULT_WORKER_PATH, verbose = false } = options;
5
40
  let config;
41
+ let coreWorkers = null;
6
42
  return {
7
43
  name: "vite-plugin-meframe",
8
44
  configResolved(resolvedConfig) {
9
45
  config = resolvedConfig;
46
+ coreWorkers = findCoreWorkerFiles();
47
+ if (!coreWorkers && config.command === "serve") {
48
+ console.warn("[meframe] Cannot find @meframe/core worker files");
49
+ console.warn("[meframe] Make sure @meframe/core is installed and built");
50
+ }
10
51
  },
11
- closeBundle() {
12
- if (config.command !== "build") {
52
+ configureServer(server) {
53
+ const workers = findCoreWorkerFiles();
54
+ if (!workers) {
55
+ console.warn("[meframe] Worker files not found for development");
13
56
  return;
14
57
  }
15
- try {
16
- let coreAssetsDir;
17
- try {
18
- const corePackagePath = require.resolve("@meframe/core/package.json");
19
- const coreDir = dirname(corePackagePath);
20
- coreAssetsDir = join(coreDir, "dist", "assets");
21
- } catch {
22
- const monorepoPath = resolve(process.cwd(), "../core/dist/assets");
23
- if (existsSync(monorepoPath)) {
24
- coreAssetsDir = monorepoPath;
25
- } else {
26
- console.warn("[meframe] Cannot find @meframe/core worker assets");
27
- return;
28
- }
29
- }
30
- if (!existsSync(coreAssetsDir)) {
31
- console.warn("[meframe] Worker assets directory not found:", coreAssetsDir);
32
- console.warn(
33
- "[meframe] Please ensure @meframe/core is built: cd node_modules/@meframe/core && pnpm build"
34
- );
58
+ const workersSourceDir = workers.dir;
59
+ server.middlewares.use((req, res, next) => {
60
+ const url = req.url;
61
+ if (!url || !url.startsWith(`/${workerPath}/`)) {
62
+ next();
35
63
  return;
36
64
  }
37
- const workerFiles = readdirSync(coreAssetsDir).filter(
38
- (file) => file.includes(".worker-") && (file.endsWith(".js") || file.endsWith(".js.map"))
39
- );
40
- if (workerFiles.length === 0) {
41
- console.warn("[meframe] No worker files found in:", coreAssetsDir);
65
+ const relativePath = url.substring(`/${workerPath}/`.length).split("?")[0];
66
+ if (!relativePath) {
67
+ next();
42
68
  return;
43
69
  }
44
- const outDir = config.build.outDir || "dist";
45
- const outputDir = join(process.cwd(), outDir, workerDir);
46
- mkdirSync(outputDir, { recursive: true });
47
- let copiedCount = 0;
48
- const copiedFiles = [];
49
- for (const file of workerFiles) {
50
- const src = join(coreAssetsDir, file);
51
- const dest = join(outputDir, file);
70
+ const filePath = join(workersSourceDir, relativePath);
71
+ if (existsSync(filePath)) {
52
72
  try {
53
- copyFileSync(src, dest);
54
- copiedCount++;
55
- copiedFiles.push(file);
73
+ const content = readFileSync(filePath);
74
+ const isSourceMap = relativePath.endsWith(".map");
75
+ res.setHeader(
76
+ "Content-Type",
77
+ isSourceMap ? "application/json" : "application/javascript"
78
+ );
79
+ res.setHeader("Cache-Control", "no-cache");
80
+ res.end(content);
81
+ if (verbose) {
82
+ console.log(`[meframe] Served: ${relativePath}`);
83
+ }
84
+ return;
56
85
  } catch (error) {
57
- console.error(`[meframe] Failed to copy ${file}:`, error);
86
+ console.error(`[meframe] Error serving ${relativePath}:`, error);
87
+ res.statusCode = 500;
88
+ res.end("Internal Server Error");
89
+ return;
58
90
  }
59
91
  }
92
+ next();
93
+ });
94
+ console.log(`[meframe] Development: serving worker files from ${workersSourceDir}`);
95
+ },
96
+ closeBundle() {
97
+ if (config.command !== "build" || !coreWorkers) {
98
+ return;
99
+ }
100
+ try {
101
+ const copyDir = (src, dest) => {
102
+ if (!existsSync(src)) return;
103
+ mkdirSync(dest, { recursive: true });
104
+ const entries = readdirSync(src);
105
+ for (const entry of entries) {
106
+ const srcPath = join(src, entry);
107
+ const destPath = join(dest, entry);
108
+ const stat = statSync(srcPath);
109
+ if (stat.isDirectory()) {
110
+ copyDir(srcPath, destPath);
111
+ } else {
112
+ copyFileSync(srcPath, destPath);
113
+ }
114
+ }
115
+ };
116
+ const workersSourceDir = coreWorkers.dir;
117
+ const outDir = config.build.outDir || "dist";
118
+ const outputDir = join(process.cwd(), outDir, workerPath);
119
+ copyDir(workersSourceDir, outputDir);
60
120
  console.log(`
61
- [meframe] ✓ Copied ${copiedCount} worker files to ${outDir}/${workerDir}/`);
62
- if (verbose && copiedFiles.length > 0) {
63
- console.log("[meframe] Files copied:");
64
- copiedFiles.forEach((file) => console.log(` - ${file}`));
65
- }
66
- if (workerDir !== "assets") {
67
- console.log(`[meframe] ⚠️ Worker files are in ${outDir}/${workerDir}/`);
68
- console.log(`[meframe] Make sure your server can serve these files.`);
69
- }
121
+ [meframe] ✓ Copied worker files to ${outDir}/${workerPath}/`);
70
122
  } catch (error) {
71
123
  console.error("[meframe] Error in meframePlugin:", error);
72
124
  }
@@ -74,8 +126,13 @@ function meframePlugin(options = {}) {
74
126
  config() {
75
127
  return {
76
128
  worker: {
77
- // Ensure worker format is ESM
78
129
  format: "es"
130
+ },
131
+ server: {
132
+ fs: {
133
+ // Allow access to @meframe/core in node_modules
134
+ allow: [".."]
135
+ }
79
136
  }
80
137
  };
81
138
  }
@@ -1 +1 @@
1
- {"version":3,"file":"vite-plugin.js","sources":["../src/vite-plugin.ts"],"sourcesContent":["/**\n * Vite Plugin for @meframe/core\n *\n * Automatically copies worker files to the output directory during build.\n * This ensures worker files are accessible in production.\n *\n * Usage:\n * ```typescript\n * // vite.config.ts\n * import { meframePlugin } from '@meframe/core/vite-plugin';\n *\n * export default defineConfig({\n * plugins: [meframePlugin()]\n * });\n * ```\n */\n\nimport type { Plugin, ResolvedConfig } from 'vite';\nimport { copyFileSync, mkdirSync, existsSync, readdirSync } from 'fs';\nimport { join, dirname, resolve } from 'path';\n\nexport interface MeframePluginOptions {\n /**\n * Output directory for worker files (relative to build outDir)\n * @default 'assets'\n */\n workerDir?: string;\n\n /**\n * Enable verbose logging\n * @default false\n */\n verbose?: boolean;\n}\n\nexport function meframePlugin(options: MeframePluginOptions = {}): Plugin {\n const { workerDir = 'assets', verbose = false } = options;\n let config: ResolvedConfig;\n\n return {\n name: 'vite-plugin-meframe',\n\n configResolved(resolvedConfig) {\n config = resolvedConfig;\n },\n\n closeBundle() {\n // Only run in build mode\n if (config.command !== 'build') {\n return;\n }\n\n try {\n // Find @meframe/core in node_modules\n let coreAssetsDir: string;\n\n try {\n // Try to resolve from node_modules\n const corePackagePath = require.resolve('@meframe/core/package.json');\n const coreDir = dirname(corePackagePath);\n coreAssetsDir = join(coreDir, 'dist', 'assets');\n } catch {\n // Fallback for monorepo development\n const monorepoPath = resolve(process.cwd(), '../core/dist/assets');\n if (existsSync(monorepoPath)) {\n coreAssetsDir = monorepoPath;\n } else {\n console.warn('[meframe] Cannot find @meframe/core worker assets');\n return;\n }\n }\n\n if (!existsSync(coreAssetsDir)) {\n console.warn('[meframe] Worker assets directory not found:', coreAssetsDir);\n console.warn(\n '[meframe] Please ensure @meframe/core is built: cd node_modules/@meframe/core && pnpm build'\n );\n return;\n }\n\n // Get all worker files (*.js and *.js.map)\n const workerFiles = readdirSync(coreAssetsDir).filter(\n (file) => file.includes('.worker-') && (file.endsWith('.js') || file.endsWith('.js.map'))\n );\n\n if (workerFiles.length === 0) {\n console.warn('[meframe] No worker files found in:', coreAssetsDir);\n return;\n }\n\n // Determine output directory\n const outDir = config.build.outDir || 'dist';\n const outputDir = join(process.cwd(), outDir, workerDir);\n mkdirSync(outputDir, { recursive: true });\n\n // Copy worker files\n let copiedCount = 0;\n const copiedFiles: string[] = [];\n\n for (const file of workerFiles) {\n const src = join(coreAssetsDir, file);\n const dest = join(outputDir, file);\n\n try {\n copyFileSync(src, dest);\n copiedCount++;\n copiedFiles.push(file);\n } catch (error) {\n console.error(`[meframe] Failed to copy ${file}:`, error);\n }\n }\n\n // Log results\n console.log(`\\n[meframe] Copied ${copiedCount} worker files to ${outDir}/${workerDir}/`);\n\n if (verbose && copiedFiles.length > 0) {\n console.log('[meframe] Files copied:');\n copiedFiles.forEach((file) => console.log(` - ${file}`));\n }\n\n // Important note for users\n if (workerDir !== 'assets') {\n console.log(`[meframe] ⚠️ Worker files are in ${outDir}/${workerDir}/`);\n console.log(`[meframe] Make sure your server can serve these files.`);\n }\n } catch (error) {\n console.error('[meframe] Error in meframePlugin:', error);\n }\n },\n\n config() {\n return {\n worker: {\n // Ensure worker format is ESM\n format: 'es',\n },\n };\n },\n };\n}\n\nexport default meframePlugin;\n"],"names":[],"mappings":";;AAmCO,SAAS,cAAc,UAAgC,IAAY;AACxE,QAAM,EAAE,YAAY,UAAU,UAAU,UAAU;AAClD,MAAI;AAEJ,SAAO;AAAA,IACL,MAAM;AAAA,IAEN,eAAe,gBAAgB;AAC7B,eAAS;AAAA,IACX;AAAA,IAEA,cAAc;AAEZ,UAAI,OAAO,YAAY,SAAS;AAC9B;AAAA,MACF;AAEA,UAAI;AAEF,YAAI;AAEJ,YAAI;AAEF,gBAAM,kBAAkB,gBAAgB,4BAA4B;AACpE,gBAAM,UAAU,QAAQ,eAAe;AACvC,0BAAgB,KAAK,SAAS,QAAQ,QAAQ;AAAA,QAChD,QAAQ;AAEN,gBAAM,eAAe,QAAQ,QAAQ,IAAA,GAAO,qBAAqB;AACjE,cAAI,WAAW,YAAY,GAAG;AAC5B,4BAAgB;AAAA,UAClB,OAAO;AACL,oBAAQ,KAAK,mDAAmD;AAChE;AAAA,UACF;AAAA,QACF;AAEA,YAAI,CAAC,WAAW,aAAa,GAAG;AAC9B,kBAAQ,KAAK,gDAAgD,aAAa;AAC1E,kBAAQ;AAAA,YACN;AAAA,UAAA;AAEF;AAAA,QACF;AAGA,cAAM,cAAc,YAAY,aAAa,EAAE;AAAA,UAC7C,CAAC,SAAS,KAAK,SAAS,UAAU,MAAM,KAAK,SAAS,KAAK,KAAK,KAAK,SAAS,SAAS;AAAA,QAAA;AAGzF,YAAI,YAAY,WAAW,GAAG;AAC5B,kBAAQ,KAAK,uCAAuC,aAAa;AACjE;AAAA,QACF;AAGA,cAAM,SAAS,OAAO,MAAM,UAAU;AACtC,cAAM,YAAY,KAAK,QAAQ,IAAA,GAAO,QAAQ,SAAS;AACvD,kBAAU,WAAW,EAAE,WAAW,KAAA,CAAM;AAGxC,YAAI,cAAc;AAClB,cAAM,cAAwB,CAAA;AAE9B,mBAAW,QAAQ,aAAa;AAC9B,gBAAM,MAAM,KAAK,eAAe,IAAI;AACpC,gBAAM,OAAO,KAAK,WAAW,IAAI;AAEjC,cAAI;AACF,yBAAa,KAAK,IAAI;AACtB;AACA,wBAAY,KAAK,IAAI;AAAA,UACvB,SAAS,OAAO;AACd,oBAAQ,MAAM,4BAA4B,IAAI,KAAK,KAAK;AAAA,UAC1D;AAAA,QACF;AAGA,gBAAQ,IAAI;AAAA,qBAAwB,WAAW,oBAAoB,MAAM,IAAI,SAAS,GAAG;AAEzF,YAAI,WAAW,YAAY,SAAS,GAAG;AACrC,kBAAQ,IAAI,yBAAyB;AACrC,sBAAY,QAAQ,CAAC,SAAS,QAAQ,IAAI,OAAO,IAAI,EAAE,CAAC;AAAA,QAC1D;AAGA,YAAI,cAAc,UAAU;AAC1B,kBAAQ,IAAI,qCAAqC,MAAM,IAAI,SAAS,GAAG;AACvE,kBAAQ,IAAI,2DAA2D;AAAA,QACzE;AAAA,MACF,SAAS,OAAO;AACd,gBAAQ,MAAM,qCAAqC,KAAK;AAAA,MAC1D;AAAA,IACF;AAAA,IAEA,SAAS;AACP,aAAO;AAAA,QACL,QAAQ;AAAA;AAAA,UAEN,QAAQ;AAAA,QAAA;AAAA,MACV;AAAA,IAEJ;AAAA,EAAA;AAEJ;"}
1
+ {"version":3,"file":"vite-plugin.js","sources":["../src/vite-plugin.ts"],"sourcesContent":["/**\n * Vite Plugin for @meframe/core\n *\n * Provides unified worker file access in both development and production:\n * - Development: Serves workers via middleware from node_modules\n * - Production: Copies workers to output directory\n *\n * This ensures workers are always accessible at a consistent path.\n *\n * Usage:\n * ```typescript\n * // vite.config.ts\n * import { meframePlugin } from '@meframe/core/vite-plugin';\n *\n * export default defineConfig({\n * plugins: [meframePlugin()]\n * });\n * ```\n */\n\nimport type { Plugin, ResolvedConfig, ViteDevServer } from 'vite';\nimport { copyFileSync, mkdirSync, existsSync, readdirSync, statSync, readFileSync } from 'fs';\nimport { join, dirname, resolve } from 'path';\n\n/**\n * Default worker path (matches config/defaults.ts)\n */\nconst DEFAULT_WORKER_PATH = 'meframe-workers';\n\nexport interface MeframePluginOptions {\n /**\n * Virtual path prefix for worker files\n * Workers will be accessible at /{workerPath}/xxx.worker.js\n * Must match the workerPath in Meframe global config\n * @default 'meframe-workers'\n */\n workerPath?: string;\n\n /**\n * Enable verbose logging\n * @default false\n */\n verbose?: boolean;\n}\n\n/**\n * Find @meframe/core worker files\n * Workers are in dist/workers/ (built separately)\n */\nfunction findCoreWorkerFiles(): { dir: string; files: string[] } | null {\n const findWorkers = (dir: string): string[] => {\n if (!existsSync(dir)) return [];\n\n const files: string[] = [];\n const entries = readdirSync(dir);\n\n for (const entry of entries) {\n const fullPath = join(dir, entry);\n const stat = statSync(fullPath);\n\n if (stat.isDirectory()) {\n files.push(...findWorkers(fullPath));\n } else if (entry.endsWith('.worker.js') || entry.endsWith('.worker.js.map')) {\n files.push(fullPath);\n }\n }\n\n return files;\n };\n\n try {\n // Try to resolve from node_modules\n const corePackagePath = require.resolve('@meframe/core/package.json');\n const coreDir = dirname(corePackagePath);\n const workersDir = join(coreDir, 'dist', 'workers');\n\n if (!existsSync(workersDir)) {\n return null;\n }\n\n const files = findWorkers(workersDir);\n return files.length > 0 ? { dir: workersDir, files } : null;\n } catch {\n // Fallback for monorepo development\n const monorepoPath = resolve(process.cwd(), '../core/dist/workers');\n if (!existsSync(monorepoPath)) {\n return null;\n }\n\n const files = findWorkers(monorepoPath);\n return files.length > 0 ? { dir: monorepoPath, files } : null;\n }\n}\n\nexport function meframePlugin(options: MeframePluginOptions = {}): Plugin {\n const { workerPath = DEFAULT_WORKER_PATH, verbose = false } = options;\n let config: ResolvedConfig;\n let coreWorkers: { dir: string; files: string[] } | null = null;\n\n return {\n name: 'vite-plugin-meframe',\n\n configResolved(resolvedConfig) {\n config = resolvedConfig;\n coreWorkers = findCoreWorkerFiles();\n\n if (!coreWorkers && config.command === 'serve') {\n console.warn('[meframe] Cannot find @meframe/core worker files');\n console.warn('[meframe] Make sure @meframe/core is installed and built');\n }\n },\n\n configureServer(server: ViteDevServer) {\n // Development mode: Serve worker files via middleware\n const workers = findCoreWorkerFiles();\n\n if (!workers) {\n console.warn('[meframe] Worker files not found for development');\n return;\n }\n\n const workersSourceDir = workers.dir; // dist/workers\n\n // Middleware to serve files from dist/workers\n server.middlewares.use((req, res, next) => {\n const url = req.url;\n if (!url || !url.startsWith(`/${workerPath}/`)) {\n next();\n return;\n }\n\n // Remove the workerPath prefix to get relative path\n // e.g., /meframe-workers/stages/decode/decode.worker.js -> stages/decode/decode.worker.js\n const relativePath = url.substring(`/${workerPath}/`.length).split('?')[0];\n\n if (!relativePath) {\n next();\n return;\n }\n\n const filePath = join(workersSourceDir, relativePath);\n\n // Check if file exists\n if (existsSync(filePath)) {\n try {\n const content = readFileSync(filePath);\n const isSourceMap = relativePath.endsWith('.map');\n\n res.setHeader(\n 'Content-Type',\n isSourceMap ? 'application/json' : 'application/javascript'\n );\n res.setHeader('Cache-Control', 'no-cache');\n res.end(content);\n\n if (verbose) {\n console.log(`[meframe] Served: ${relativePath}`);\n }\n return;\n } catch (error) {\n console.error(`[meframe] Error serving ${relativePath}:`, error);\n res.statusCode = 500;\n res.end('Internal Server Error');\n return;\n }\n }\n\n next();\n });\n\n console.log(`[meframe] Development: serving worker files from ${workersSourceDir}`);\n },\n\n closeBundle() {\n // Only run in build mode\n if (config.command !== 'build' || !coreWorkers) {\n return;\n }\n\n try {\n const copyDir = (src: string, dest: string) => {\n if (!existsSync(src)) return;\n\n mkdirSync(dest, { recursive: true });\n const entries = readdirSync(src);\n\n for (const entry of entries) {\n const srcPath = join(src, entry);\n const destPath = join(dest, entry);\n const stat = statSync(srcPath);\n\n if (stat.isDirectory()) {\n copyDir(srcPath, destPath);\n } else {\n copyFileSync(srcPath, destPath);\n }\n }\n };\n\n const workersSourceDir = coreWorkers.dir; // dist/workers\n const outDir = config.build.outDir || 'dist';\n const outputDir = join(process.cwd(), outDir, workerPath);\n\n // Copy entire dist/workers structure\n copyDir(workersSourceDir, outputDir);\n\n // Log results\n console.log(`\\n[meframe] Copied worker files to ${outDir}/${workerPath}/`);\n } catch (error) {\n console.error('[meframe] Error in meframePlugin:', error);\n }\n },\n\n config() {\n return {\n worker: {\n format: 'es',\n },\n server: {\n fs: {\n // Allow access to @meframe/core in node_modules\n allow: ['..'],\n },\n },\n };\n },\n };\n}\n\nexport default meframePlugin;\n"],"names":[],"mappings":"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"}
@@ -6,12 +6,19 @@ import { EventPayloadMap } from '../event/events';
6
6
  export interface WorkerPoolConfig {
7
7
  eventBus: EventBus<EventPayloadMap>;
8
8
  workerConfigs?: Record<WorkerType, any>;
9
+ /** Worker files base path (default: '/meframe-workers') */
10
+ workerPath?: string;
9
11
  }
10
12
  export declare class WorkerPool {
11
13
  private pool;
12
14
  private eventBus;
13
15
  private workerConfigs;
16
+ private workerPath;
14
17
  constructor(config: WorkerPoolConfig);
18
+ /**
19
+ * Get worker URL for a specific worker type
20
+ */
21
+ private getWorkerUrl;
15
22
  /**
16
23
  * Get or create a worker instance
17
24
  * @param type - Worker type
@@ -1 +1 @@
1
- {"version":3,"file":"WorkerPool.d.ts","sourceRoot":"","sources":["../../src/worker/WorkerPool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAA0B,MAAM,SAAS,CAAC;AAEhF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAGvD,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,QAAQ,CAAC,eAAe,CAAC,CAAC;IACpC,aAAa,CAAC,EAAE,MAAM,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;CACzC;AAED,qBAAa,UAAU;IACrB,OAAO,CAAC,IAAI,CAAiC;IAC7C,OAAO,CAAC,QAAQ,CAA4B;IAC5C,OAAO,CAAC,aAAa,CAAsB;gBAE/B,MAAM,EAAE,gBAAgB;IAKpC;;;;;;OAMG;IACG,GAAG,CACP,IAAI,EAAE,UAAU,EAChB,EAAE,CAAC,EAAE,MAAM,EACX,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,OAAO,CAAC;QAAC,cAAc,CAAC,EAAE,OAAO,CAAA;KAAE,GACrD,OAAO,CAAC,UAAU,CAAC;IAyChB,SAAS,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;IAgB7D;;OAEG;IACH,SAAS,CAAC,IAAI,EAAE,UAAU,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI;IAU9C;;OAEG;IACH,YAAY,IAAI,IAAI;IAOpB;;OAEG;IACH,IAAI,MAAM,IAAI,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,UAAU,CAAC,CAAC,CAQrD;IAED;;OAEG;IACH,IAAI,aAAa,IAAI,MAAM,EAAE,CAE5B;IAED;;OAEG;IACH,GAAG,CAAC,IAAI,EAAE,UAAU,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO;CAI5C"}
1
+ {"version":3,"file":"WorkerPool.d.ts","sourceRoot":"","sources":["../../src/worker/WorkerPool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAA0B,MAAM,SAAS,CAAC;AAEhF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAEvD,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,QAAQ,CAAC,eAAe,CAAC,CAAC;IACpC,aAAa,CAAC,EAAE,MAAM,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;IACxC,2DAA2D;IAC3D,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAeD,qBAAa,UAAU;IACrB,OAAO,CAAC,IAAI,CAAiC;IAC7C,OAAO,CAAC,QAAQ,CAA4B;IAC5C,OAAO,CAAC,aAAa,CAAsB;IAC3C,OAAO,CAAC,UAAU,CAAS;gBAEf,MAAM,EAAE,gBAAgB;IAMpC;;OAEG;IACH,OAAO,CAAC,YAAY;IAmBpB;;;;;;OAMG;IACG,GAAG,CACP,IAAI,EAAE,UAAU,EAChB,EAAE,CAAC,EAAE,MAAM,EACX,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,OAAO,CAAC;QAAC,cAAc,CAAC,EAAE,OAAO,CAAA;KAAE,GACrD,OAAO,CAAC,UAAU,CAAC;IAsChB,SAAS,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;IAgB7D;;OAEG;IACH,SAAS,CAAC,IAAI,EAAE,UAAU,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI;IAU9C;;OAEG;IACH,YAAY,IAAI,IAAI;IAOpB;;OAEG;IACH,IAAI,MAAM,IAAI,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,UAAU,CAAC,CAAC,CAQrD;IAED;;OAEG;IACH,IAAI,aAAa,IAAI,MAAM,EAAE,CAE5B;IAED;;OAEG;IACH,GAAG,CAAC,IAAI,EAAE,UAAU,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO;CAI5C"}
@@ -1,13 +1,40 @@
1
1
  import { BaseWorker } from "./BaseWorker.js";
2
2
  import { WorkerMessageType } from "./types.js";
3
- import { WORKER_URLS } from "./worker-registry.js";
3
+ const WORKER_FILE_NAMES = {
4
+ videoDemux: "video-demux",
5
+ audioDemux: "audio-demux",
6
+ decode: "decode",
7
+ videoCompose: "video-compose",
8
+ audioCompose: "audio-compose",
9
+ encode: "encode",
10
+ mux: "mux"
11
+ };
4
12
  class WorkerPool {
5
13
  pool = /* @__PURE__ */ new Map();
6
14
  eventBus;
7
15
  workerConfigs;
16
+ workerPath;
8
17
  constructor(config) {
9
18
  this.eventBus = config.eventBus;
10
19
  this.workerConfigs = config.workerConfigs || {};
20
+ this.workerPath = config.workerPath || "/meframe-workers";
21
+ }
22
+ /**
23
+ * Get worker URL for a specific worker type
24
+ */
25
+ getWorkerUrl(type) {
26
+ const fileName = WORKER_FILE_NAMES[type];
27
+ const stageMap = {
28
+ "video-demux": "demux",
29
+ "audio-demux": "demux",
30
+ decode: "decode",
31
+ "video-compose": "compose",
32
+ "audio-compose": "compose",
33
+ encode: "encode",
34
+ mux: "mux"
35
+ };
36
+ const stage = stageMap[fileName];
37
+ return `${this.workerPath}/stages/${stage}/${fileName}.worker.js`;
11
38
  }
12
39
  /**
13
40
  * Get or create a worker instance
@@ -20,10 +47,7 @@ class WorkerPool {
20
47
  const key = id ? `${type}#${id}` : type;
21
48
  const existing = this.pool.get(key);
22
49
  if (!existing) {
23
- const url = WORKER_URLS[type];
24
- if (!url) {
25
- throw new Error(`Worker URL not found for type: ${type}`);
26
- }
50
+ const url = this.getWorkerUrl(type);
27
51
  const worker = new BaseWorker({
28
52
  type,
29
53
  url,
@@ -1 +1 @@
1
- {"version":3,"file":"WorkerPool.js","sources":["../../src/worker/WorkerPool.ts"],"sourcesContent":["/**\n * WorkerPool: Manages worker instances with key-based access\n * Provides lazy creation and unified management of workers\n */\n\nimport { BaseWorker } from './BaseWorker';\nimport type { WorkerType, WorkerStatus, WorkerConfigurePayload } from './types';\nimport { WorkerMessageType } from './types';\nimport type { EventBus } from '../event/EventBus';\nimport type { EventPayloadMap } from '../event/events';\nimport { WORKER_URLS } from './worker-registry';\n\nexport interface WorkerPoolConfig {\n eventBus: EventBus<EventPayloadMap>;\n workerConfigs?: Record<WorkerType, any>;\n}\n\nexport class WorkerPool {\n private pool = new Map<string, BaseWorker>();\n private eventBus: EventBus<EventPayloadMap>;\n private workerConfigs: Record<string, any>;\n\n constructor(config: WorkerPoolConfig) {\n this.eventBus = config.eventBus;\n this.workerConfigs = config.workerConfigs || {};\n }\n\n /**\n * Get or create a worker instance\n * @param type - Worker type\n * @param id - Optional ID for per-resource or per-clip workers\n * @param options - Optional configuration\n * - lazy: If true, skip initial configure (default: false)\n */\n async get(\n type: WorkerType,\n id?: string,\n options?: { lazy?: boolean; skipInitialize?: boolean }\n ): Promise<BaseWorker> {\n const key = id ? `${type}#${id}` : type;\n\n const existing = this.pool.get(key);\n if (!existing) {\n // Use pre-resolved worker URLs from registry\n const url = WORKER_URLS[type];\n if (!url) {\n throw new Error(`Worker URL not found for type: ${type}`);\n }\n\n const worker = new BaseWorker({\n type,\n url,\n eventBus: this.eventBus,\n clipId: id,\n });\n\n // Only initialize if not in lazy mode\n if (!options?.lazy && !options?.skipInitialize) {\n const config = this.workerConfigs[type];\n await worker.initialize(config);\n }\n\n this.pool.set(key, worker);\n return worker;\n }\n\n if (!options?.lazy && !options?.skipInitialize) {\n const config = this.workerConfigs[type];\n if (config) {\n await existing.send(WorkerMessageType.Configure, {\n config,\n initial: false,\n } as WorkerConfigurePayload);\n }\n }\n\n return existing;\n }\n\n async setConfig(type: WorkerType, config: any): Promise<void> {\n const existing = this.workerConfigs[type] || {};\n const mergedConfig = { ...existing, ...config };\n\n this.workerConfigs[type] = mergedConfig;\n\n for (const [key, worker] of this.pool.entries()) {\n if (key === type || key.startsWith(`${type}#`)) {\n await worker.send(WorkerMessageType.Configure, {\n config: mergedConfig,\n initial: false,\n } as WorkerConfigurePayload);\n }\n }\n }\n\n /**\n * Terminate a specific worker\n */\n terminate(type: WorkerType, id?: string): void {\n const key = id ? `${type}#${id}` : type;\n const worker = this.pool.get(key);\n\n if (worker) {\n worker.terminate();\n this.pool.delete(key);\n }\n }\n\n /**\n * Terminate all workers\n */\n terminateAll(): void {\n for (const worker of this.pool.values()) {\n worker.terminate();\n }\n this.pool.clear();\n }\n\n /**\n * Get status of all workers\n */\n get status(): Record<string, WorkerStatus[WorkerType]> {\n const result: Record<string, WorkerStatus[WorkerType]> = {};\n\n for (const [key, worker] of this.pool.entries()) {\n result[key] = worker.status;\n }\n\n return result;\n }\n\n /**\n * Get list of active worker keys\n */\n get activeWorkers(): string[] {\n return Array.from(this.pool.keys());\n }\n\n /**\n * Check if a worker exists\n */\n has(type: WorkerType, id?: string): boolean {\n const key = id ? `${type}#${id}` : type;\n return this.pool.has(key);\n }\n}\n"],"names":[],"mappings":";;;AAiBO,MAAM,WAAW;AAAA,EACd,2BAAW,IAAA;AAAA,EACX;AAAA,EACA;AAAA,EAER,YAAY,QAA0B;AACpC,SAAK,WAAW,OAAO;AACvB,SAAK,gBAAgB,OAAO,iBAAiB,CAAA;AAAA,EAC/C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,IACJ,MACA,IACA,SACqB;AACrB,UAAM,MAAM,KAAK,GAAG,IAAI,IAAI,EAAE,KAAK;AAEnC,UAAM,WAAW,KAAK,KAAK,IAAI,GAAG;AAClC,QAAI,CAAC,UAAU;AAEb,YAAM,MAAM,YAAY,IAAI;AAC5B,UAAI,CAAC,KAAK;AACR,cAAM,IAAI,MAAM,kCAAkC,IAAI,EAAE;AAAA,MAC1D;AAEA,YAAM,SAAS,IAAI,WAAW;AAAA,QAC5B;AAAA,QACA;AAAA,QACA,UAAU,KAAK;AAAA,QACf,QAAQ;AAAA,MAAA,CACT;AAGD,UAAI,CAAC,SAAS,QAAQ,CAAC,SAAS,gBAAgB;AAC9C,cAAM,SAAS,KAAK,cAAc,IAAI;AACtC,cAAM,OAAO,WAAW,MAAM;AAAA,MAChC;AAEA,WAAK,KAAK,IAAI,KAAK,MAAM;AACzB,aAAO;AAAA,IACT;AAEA,QAAI,CAAC,SAAS,QAAQ,CAAC,SAAS,gBAAgB;AAC9C,YAAM,SAAS,KAAK,cAAc,IAAI;AACtC,UAAI,QAAQ;AACV,cAAM,SAAS,KAAK,kBAAkB,WAAW;AAAA,UAC/C;AAAA,UACA,SAAS;AAAA,QAAA,CACgB;AAAA,MAC7B;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,UAAU,MAAkB,QAA4B;AAC5D,UAAM,WAAW,KAAK,cAAc,IAAI,KAAK,CAAA;AAC7C,UAAM,eAAe,EAAE,GAAG,UAAU,GAAG,OAAA;AAEvC,SAAK,cAAc,IAAI,IAAI;AAE3B,eAAW,CAAC,KAAK,MAAM,KAAK,KAAK,KAAK,WAAW;AAC/C,UAAI,QAAQ,QAAQ,IAAI,WAAW,GAAG,IAAI,GAAG,GAAG;AAC9C,cAAM,OAAO,KAAK,kBAAkB,WAAW;AAAA,UAC7C,QAAQ;AAAA,UACR,SAAS;AAAA,QAAA,CACgB;AAAA,MAC7B;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,UAAU,MAAkB,IAAmB;AAC7C,UAAM,MAAM,KAAK,GAAG,IAAI,IAAI,EAAE,KAAK;AACnC,UAAM,SAAS,KAAK,KAAK,IAAI,GAAG;AAEhC,QAAI,QAAQ;AACV,aAAO,UAAA;AACP,WAAK,KAAK,OAAO,GAAG;AAAA,IACtB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,eAAqB;AACnB,eAAW,UAAU,KAAK,KAAK,OAAA,GAAU;AACvC,aAAO,UAAA;AAAA,IACT;AACA,SAAK,KAAK,MAAA;AAAA,EACZ;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,SAAmD;AACrD,UAAM,SAAmD,CAAA;AAEzD,eAAW,CAAC,KAAK,MAAM,KAAK,KAAK,KAAK,WAAW;AAC/C,aAAO,GAAG,IAAI,OAAO;AAAA,IACvB;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,gBAA0B;AAC5B,WAAO,MAAM,KAAK,KAAK,KAAK,MAAM;AAAA,EACpC;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,MAAkB,IAAsB;AAC1C,UAAM,MAAM,KAAK,GAAG,IAAI,IAAI,EAAE,KAAK;AACnC,WAAO,KAAK,KAAK,IAAI,GAAG;AAAA,EAC1B;AACF;"}
1
+ {"version":3,"file":"WorkerPool.js","sources":["../../src/worker/WorkerPool.ts"],"sourcesContent":["/**\n * WorkerPool: Manages worker instances with key-based access\n * Provides lazy creation and unified management of workers\n */\n\nimport { BaseWorker } from './BaseWorker';\nimport type { WorkerType, WorkerStatus, WorkerConfigurePayload } from './types';\nimport { WorkerMessageType } from './types';\nimport type { EventBus } from '../event/EventBus';\nimport type { EventPayloadMap } from '../event/events';\n\nexport interface WorkerPoolConfig {\n eventBus: EventBus<EventPayloadMap>;\n workerConfigs?: Record<WorkerType, any>;\n /** Worker files base path (default: '/meframe-workers') */\n workerPath?: string;\n}\n\n/**\n * Worker name mapping (worker type -> file name)\n */\nconst WORKER_FILE_NAMES: Record<WorkerType, string> = {\n videoDemux: 'video-demux',\n audioDemux: 'audio-demux',\n decode: 'decode',\n videoCompose: 'video-compose',\n audioCompose: 'audio-compose',\n encode: 'encode',\n mux: 'mux',\n};\n\nexport class WorkerPool {\n private pool = new Map<string, BaseWorker>();\n private eventBus: EventBus<EventPayloadMap>;\n private workerConfigs: Record<string, any>;\n private workerPath: string;\n\n constructor(config: WorkerPoolConfig) {\n this.eventBus = config.eventBus;\n this.workerConfigs = config.workerConfigs || {};\n this.workerPath = config.workerPath || '/meframe-workers';\n }\n\n /**\n * Get worker URL for a specific worker type\n */\n private getWorkerUrl(type: WorkerType): string {\n const fileName = WORKER_FILE_NAMES[type];\n\n // Map worker type to its stage directory\n const stageMap: Record<string, string> = {\n 'video-demux': 'demux',\n 'audio-demux': 'demux',\n decode: 'decode',\n 'video-compose': 'compose',\n 'audio-compose': 'compose',\n encode: 'encode',\n mux: 'mux',\n };\n const stage = stageMap[fileName];\n\n // Workers are in stages subdirectory\n return `${this.workerPath}/stages/${stage}/${fileName}.worker.js`;\n }\n\n /**\n * Get or create a worker instance\n * @param type - Worker type\n * @param id - Optional ID for per-resource or per-clip workers\n * @param options - Optional configuration\n * - lazy: If true, skip initial configure (default: false)\n */\n async get(\n type: WorkerType,\n id?: string,\n options?: { lazy?: boolean; skipInitialize?: boolean }\n ): Promise<BaseWorker> {\n const key = id ? `${type}#${id}` : type;\n\n const existing = this.pool.get(key);\n if (!existing) {\n // Generate worker URL based on worker path and type\n const url = this.getWorkerUrl(type);\n\n const worker = new BaseWorker({\n type,\n url,\n eventBus: this.eventBus,\n clipId: id,\n });\n\n // Only initialize if not in lazy mode\n if (!options?.lazy && !options?.skipInitialize) {\n const config = this.workerConfigs[type];\n await worker.initialize(config);\n }\n\n this.pool.set(key, worker);\n return worker;\n }\n\n if (!options?.lazy && !options?.skipInitialize) {\n const config = this.workerConfigs[type];\n if (config) {\n await existing.send(WorkerMessageType.Configure, {\n config,\n initial: false,\n } as WorkerConfigurePayload);\n }\n }\n\n return existing;\n }\n\n async setConfig(type: WorkerType, config: any): Promise<void> {\n const existing = this.workerConfigs[type] || {};\n const mergedConfig = { ...existing, ...config };\n\n this.workerConfigs[type] = mergedConfig;\n\n for (const [key, worker] of this.pool.entries()) {\n if (key === type || key.startsWith(`${type}#`)) {\n await worker.send(WorkerMessageType.Configure, {\n config: mergedConfig,\n initial: false,\n } as WorkerConfigurePayload);\n }\n }\n }\n\n /**\n * Terminate a specific worker\n */\n terminate(type: WorkerType, id?: string): void {\n const key = id ? `${type}#${id}` : type;\n const worker = this.pool.get(key);\n\n if (worker) {\n worker.terminate();\n this.pool.delete(key);\n }\n }\n\n /**\n * Terminate all workers\n */\n terminateAll(): void {\n for (const worker of this.pool.values()) {\n worker.terminate();\n }\n this.pool.clear();\n }\n\n /**\n * Get status of all workers\n */\n get status(): Record<string, WorkerStatus[WorkerType]> {\n const result: Record<string, WorkerStatus[WorkerType]> = {};\n\n for (const [key, worker] of this.pool.entries()) {\n result[key] = worker.status;\n }\n\n return result;\n }\n\n /**\n * Get list of active worker keys\n */\n get activeWorkers(): string[] {\n return Array.from(this.pool.keys());\n }\n\n /**\n * Check if a worker exists\n */\n has(type: WorkerType, id?: string): boolean {\n const key = id ? `${type}#${id}` : type;\n return this.pool.has(key);\n }\n}\n"],"names":[],"mappings":"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"}
@@ -1,13 +1,10 @@
1
- import "../../node_modules/.pnpm/mp4box@0.5.4/node_modules/mp4box/dist/mp4box.all.js";
2
- import { BackpressureMonitor } from "../../plugins/BackpressureMonitor.js";
3
- import { __exports as mp4box_all } from "../../_virtual/mp4box.all.js";
1
+ import { m as mp4box_all } from "./mp4box.all.js";
4
2
  class MP4Demuxer {
5
3
  mp4boxFile;
6
4
  tracks = /* @__PURE__ */ new Map();
7
5
  isReady = false;
8
6
  videoController;
9
7
  audioController;
10
- backpressureMonitor;
11
8
  demuxHighWaterMark;
12
9
  onReadyCallback;
13
10
  fileOffset = 0;
@@ -15,7 +12,6 @@ class MP4Demuxer {
15
12
  audioTimestampOffset = null;
16
13
  constructor(config = {}) {
17
14
  this.mp4boxFile = mp4box_all.createFile();
18
- this.backpressureMonitor = new BackpressureMonitor();
19
15
  this.onReadyCallback = config.onReady;
20
16
  const DEFAULT_HIGH_WATER_MARK = 10;
21
17
  this.demuxHighWaterMark = config.highWaterMark ?? DEFAULT_HIGH_WATER_MARK;
@@ -155,9 +151,7 @@ class MP4Demuxer {
155
151
  start: (controller) => {
156
152
  this.videoController = controller;
157
153
  },
158
- transform: (chunk, controller) => {
159
- const desiredSize = controller.desiredSize ?? this.demuxHighWaterMark;
160
- this.backpressureMonitor.updateMetrics("demux-video", desiredSize);
154
+ transform: (chunk, _controller) => {
161
155
  const chunkData = new Uint8Array(chunk);
162
156
  this.appendBuffer(chunkData);
163
157
  this.mp4boxFile.flush();
@@ -186,9 +180,7 @@ class MP4Demuxer {
186
180
  start: (controller) => {
187
181
  this.audioController = controller;
188
182
  },
189
- transform: (chunk, controller) => {
190
- const desiredSize = controller.desiredSize ?? this.demuxHighWaterMark;
191
- this.backpressureMonitor.updateMetrics("demux-audio", desiredSize);
183
+ transform: (chunk, _controller) => {
192
184
  const chunkData = new Uint8Array(chunk);
193
185
  this.appendBuffer(chunkData);
194
186
  this.mp4boxFile.flush();
@@ -226,13 +218,12 @@ class MP4Demuxer {
226
218
  this.mp4boxFile?.stop();
227
219
  this.mp4boxFile = null;
228
220
  this.tracks.clear();
229
- this.backpressureMonitor.clear();
230
221
  this.isReady = false;
231
222
  this.videoTimestampOffset = null;
232
223
  this.audioTimestampOffset = null;
233
224
  }
234
225
  }
235
226
  export {
236
- MP4Demuxer
227
+ MP4Demuxer as M
237
228
  };
238
229
  //# sourceMappingURL=MP4Demuxer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MP4Demuxer.js","sources":["../../src/stages/demux/MP4Demuxer.ts"],"sourcesContent":["import * as MP4Box from 'mp4box';\nimport type { DemuxConfig, TrackInfo } from './types';\n\n/**\n * MP4 Demuxer - Extract encoded chunks from MP4 container\n * Simplified implementation following Stream API pattern\n */\nexport class MP4Demuxer {\n private mp4boxFile: any;\n tracks = new Map<number, TrackInfo>();\n isReady = false;\n private videoController?: TransformStreamDefaultController<EncodedVideoChunk>;\n private audioController?: TransformStreamDefaultController<EncodedAudioChunk>;\n private demuxHighWaterMark: number;\n private onReadyCallback?: () => void;\n private fileOffset = 0;\n private videoTimestampOffset: number | null = null;\n private audioTimestampOffset: number | null = null;\n\n constructor(config: DemuxConfig & { onReady?: () => void } = {}) {\n this.mp4boxFile = MP4Box.createFile();\n this.onReadyCallback = config.onReady;\n\n // Use provided config with local default as fallback\n const DEFAULT_HIGH_WATER_MARK = 10; // Default for video chunks\n this.demuxHighWaterMark = config.highWaterMark ?? DEFAULT_HIGH_WATER_MARK;\n\n this.setupHandlers();\n }\n\n updateConfig(config: DemuxConfig): void {\n this.demuxHighWaterMark = config.highWaterMark ?? this.demuxHighWaterMark;\n }\n\n private setupHandlers(): void {\n this.mp4boxFile.onError = (error: string) => {\n console.error('MP4Box error:', error);\n this.videoController?.error(new Error(error));\n this.audioController?.error(new Error(error));\n };\n\n this.mp4boxFile.onReady = (info: any) => {\n this.processTracks(info.tracks);\n this.isReady = true;\n\n // Call the ready callback before starting\n if (this.onReadyCallback) {\n this.onReadyCallback();\n }\n\n // Start processing samples after callback\n // Note: start() enables extraction, actual samples will be output\n // when flush() is called (by TransformStream's flush callback)\n this.mp4boxFile.start();\n };\n\n this.mp4boxFile.onSamples = (trackId: number, _user: any, samples: any[]) => {\n this.processSamples(trackId, samples);\n };\n }\n\n private processTracks(tracks: any[]): void {\n for (const track of tracks) {\n const trackInfo: TrackInfo = {\n id: track.id,\n type: track.type === 'video' ? 'video' : 'audio',\n codec: track.codec,\n timescale: track.timescale,\n };\n\n if (track.type === 'video') {\n trackInfo.width = track.video?.width;\n trackInfo.height = track.video?.height;\n trackInfo.description = this.getVideoDescription(track);\n } else if (track.type === 'audio') {\n trackInfo.sampleRate = track.audio?.sample_rate;\n trackInfo.numberOfChannels = track.audio?.channel_count;\n trackInfo.description = this.getAudioDescription(track);\n }\n\n this.tracks.set(track.id, trackInfo);\n\n // Configure extraction\n this.mp4boxFile.setExtractionOptions(track.id, track, {\n nbSamples: 30, // Batch size per callback (balance between latency and overhead)\n });\n }\n }\n\n private processSamples(trackId: number, samples: any[]): void {\n const track = this.tracks.get(trackId);\n if (!track) return;\n\n const timescale = track.timescale || 90000;\n for (const sample of samples) {\n const rawTimestamp = (sample.cts * 1000000) / timescale;\n const duration = (sample.duration * 1000000) / timescale;\n\n if (track.type === 'video') {\n if (!this.videoController) {\n console.error('[MP4Demuxer] videoController is null when trying to output chunk!');\n // Should not happen - stream should be created before appendBuffer\n return;\n }\n\n // Normalize timestamp: first frame starts at 0\n if (this.videoTimestampOffset === null) {\n this.videoTimestampOffset = rawTimestamp;\n }\n const timestamp = rawTimestamp - this.videoTimestampOffset;\n\n const chunk = new EncodedVideoChunk({\n type: sample.is_sync ? 'key' : 'delta',\n timestamp,\n duration,\n data: sample.data,\n });\n this.videoController.enqueue(chunk);\n } else if (track.type === 'audio' && this.audioController) {\n // Normalize timestamp: first frame starts at 0\n if (this.audioTimestampOffset === null) {\n this.audioTimestampOffset = rawTimestamp;\n }\n const timestamp = rawTimestamp - this.audioTimestampOffset;\n\n const chunk = new EncodedAudioChunk({\n type: 'key',\n timestamp,\n duration,\n data: sample.data,\n });\n this.audioController.enqueue(chunk);\n }\n }\n\n const last = samples[samples.length - 1].number;\n // Release memory immediately\n this.mp4boxFile.releaseUsedSamples(trackId, last + 1);\n }\n\n private getVideoDescription(track: any): ArrayBuffer | undefined {\n try {\n const fullTrack = this.mp4boxFile.getTrackById(track.id);\n for (const entry of fullTrack.mdia.minf.stbl.stsd.entries) {\n const box = entry.avcC ?? entry.hvcC ?? entry.av1C ?? entry.vpcC;\n if (box) {\n const stream = new (MP4Box as any).DataStream(\n undefined,\n 0,\n (MP4Box as any).DataStream.BIG_ENDIAN // IMPORTANT: must be BIG_ENDIAN\n );\n box.write(stream);\n return new Uint8Array(stream.buffer.slice(8)).buffer;\n }\n }\n } catch (error) {\n console.error('Failed to get video description:', error);\n }\n return undefined;\n }\n\n // private getVideoDescription(track: any): ArrayBuffer | undefined {\n // if (!this.mp4boxFile) return undefined;\n // return getVideoDescription(this.mp4boxFile, track);\n // }\n\n private getAudioDescription(track: any): ArrayBuffer | undefined {\n try {\n const fullTrack = this.mp4boxFile.getTrackById(track.id);\n for (const entry of fullTrack.mdia.minf.stbl.stsd.entries) {\n if (entry.esds || entry.dOps) {\n const stream = new (MP4Box as any).DataStream();\n (entry.esds || entry.dOps).write(stream);\n return new Uint8Array(stream.buffer.slice(8)).buffer;\n }\n }\n } catch (error) {\n console.error('Failed to get audio description:', error);\n }\n return undefined;\n }\n\n /**\n * Create transform stream for video track\n */\n createVideoStream(): TransformStream<Uint8Array, EncodedVideoChunk> {\n // const hasVideo = Array.from(this.tracks.values()).some((t) => t.type === 'video');\n return new TransformStream<Uint8Array, EncodedVideoChunk>(\n {\n start: (controller) => {\n this.videoController = controller;\n },\n transform: (chunk, _controller) => {\n // Create a copy to avoid buffer reuse issues (required for mp4box 0.5.x)\n const chunkData = new Uint8Array(chunk);\n this.appendBuffer(chunkData);\n\n // Flush after each append to trigger sample extraction immediately\n this.mp4boxFile.flush();\n },\n flush: async () => {\n // Trigger MP4Box flush\n this.mp4boxFile.flush();\n\n // Wait for MP4Box to complete sample extraction (onSamples callbacks)\n // Give MP4Box time to process asynchronously\n await new Promise((resolve) => setTimeout(resolve, 100));\n },\n },\n // Queuing strategy: use configuration\n {\n highWaterMark: this.demuxHighWaterMark,\n size: () => 1, // Count-based\n }\n );\n }\n\n /**\n * Create transform stream for audio track\n */\n createAudioStream(): TransformStream<Uint8Array, EncodedAudioChunk> | null {\n const hasAudio = Array.from(this.tracks.values()).some((t) => t.type === 'audio');\n if (!hasAudio) return null;\n\n return new TransformStream<Uint8Array, EncodedAudioChunk>(\n {\n start: (controller) => {\n this.audioController = controller;\n },\n transform: (chunk, _controller) => {\n // Create a copy to avoid buffer reuse issues (required for mp4box 0.5.x)\n const chunkData = new Uint8Array(chunk);\n this.appendBuffer(chunkData);\n\n // Flush after each append to trigger sample extraction immediately\n this.mp4boxFile.flush();\n },\n flush: () => {\n this.mp4boxFile.flush();\n },\n },\n // Queuing strategy: use configuration\n {\n highWaterMark: this.demuxHighWaterMark,\n size: () => 1,\n }\n );\n }\n\n appendBuffer(chunk: Uint8Array): void {\n const buffer = chunk.buffer as ArrayBuffer & { fileStart: number };\n buffer.fileStart = this.fileOffset;\n this.mp4boxFile.appendBuffer(buffer);\n this.fileOffset += chunk.byteLength;\n }\n\n /**\n * Get video track info if available\n */\n get videoTrackInfo(): TrackInfo | undefined {\n return Array.from(this.tracks.values()).find((track) => track.type === 'video');\n }\n\n /**\n * Get audio track info if available\n */\n get audioTrackInfo(): TrackInfo | undefined {\n return Array.from(this.tracks.values()).find((track) => track.type === 'audio');\n }\n\n destroy(): void {\n this.mp4boxFile?.stop();\n this.mp4boxFile = null;\n this.tracks.clear();\n this.isReady = false;\n this.videoTimestampOffset = null;\n this.audioTimestampOffset = null;\n }\n}\n"],"names":["MP4Box.createFile","MP4Box.DataStream"],"mappings":"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"}