@meframe/server 0.0.6 → 0.0.8

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 (34) hide show
  1. package/dist/cjs/ServerExporterBase.js +203 -41
  2. package/dist/cjs/ServerExporterBase.js.map +1 -1
  3. package/dist/cjs/postprocess/ffmpeg-audio-mix.js +100 -30
  4. package/dist/cjs/postprocess/ffmpeg-audio-mix.js.map +1 -1
  5. package/dist/cjs/runner/runner.js +2 -1
  6. package/dist/cjs/runner/runner.js.map +1 -1
  7. package/dist/cjs/utils/local-spool-server.js +173 -0
  8. package/dist/cjs/utils/local-spool-server.js.map +1 -0
  9. package/dist/cjs/utils/multipart-upload.js +5 -1
  10. package/dist/cjs/utils/multipart-upload.js.map +1 -1
  11. package/dist/esm/ServerExporterBase.d.ts.map +1 -1
  12. package/dist/esm/ServerExporterBase.js +204 -42
  13. package/dist/esm/ServerExporterBase.js.map +1 -1
  14. package/dist/esm/postprocess/ffmpeg-audio-mix.d.ts +35 -1
  15. package/dist/esm/postprocess/ffmpeg-audio-mix.d.ts.map +1 -1
  16. package/dist/esm/postprocess/ffmpeg-audio-mix.js +98 -30
  17. package/dist/esm/postprocess/ffmpeg-audio-mix.js.map +1 -1
  18. package/dist/esm/runner/runner.d.ts +2 -1
  19. package/dist/esm/runner/runner.d.ts.map +1 -1
  20. package/dist/esm/runner/runner.js +2 -1
  21. package/dist/esm/runner/runner.js.map +1 -1
  22. package/dist/esm/types.d.ts +35 -0
  23. package/dist/esm/types.d.ts.map +1 -1
  24. package/dist/esm/utils/local-spool-server.d.ts +17 -0
  25. package/dist/esm/utils/local-spool-server.d.ts.map +1 -0
  26. package/dist/esm/utils/local-spool-server.js +167 -0
  27. package/dist/esm/utils/local-spool-server.js.map +1 -0
  28. package/dist/esm/utils/multipart-upload.d.ts +1 -0
  29. package/dist/esm/utils/multipart-upload.d.ts.map +1 -1
  30. package/dist/esm/utils/multipart-upload.js +5 -1
  31. package/dist/esm/utils/multipart-upload.js.map +1 -1
  32. package/dist/runner-browser/runner.mjs +645 -644
  33. package/docs/INTEGRATION.md +71 -4
  34. package/package.json +2 -2
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.runExportInPage = runExportInPage;
4
4
  async function runExportInPage(page, bridge, params) {
5
5
  const { model, exportOptions, partSizeBytes, uploadId, key, // reserved for future use (e.g., logging)
6
- runnerModuleCode, pageUrl, workerPath, } = params;
6
+ runnerModuleCode, pageUrl, workerPath, fonts, } = params;
7
7
  let settled = false;
8
8
  let doneResolve;
9
9
  let doneReject;
@@ -45,6 +45,7 @@ async function runExportInPage(page, bridge, params) {
45
45
  uploadId,
46
46
  key,
47
47
  workerPath,
48
+ fonts,
48
49
  };
49
50
  if (pageUrl) {
50
51
  // Ensure a trustworthy origin so Web APIs like WebCodecs are available.
@@ -1 +1 @@
1
- {"version":3,"file":"runner.js","sourceRoot":"","sources":["../../../src/runner/runner.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"runner.js","sourceRoot":"","sources":["../../../src/runner/runner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,173 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.createLocalSpoolServer = createLocalSpoolServer;
7
+ const promises_1 = __importDefault(require("node:fs/promises"));
8
+ const node_fs_1 = require("node:fs");
9
+ const node_http_1 = __importDefault(require("node:http"));
10
+ const node_crypto_1 = __importDefault(require("node:crypto"));
11
+ const node_path_1 = __importDefault(require("node:path"));
12
+ const SPOOL_TOKEN_HEADER = 'x-meframe-spool-token';
13
+ function readRequestBody(req) {
14
+ return new Promise((resolve, reject) => {
15
+ const chunks = [];
16
+ req.on('data', (c) => chunks.push(Buffer.isBuffer(c) ? c : Buffer.from(c)));
17
+ req.on('end', () => resolve(Buffer.concat(chunks)));
18
+ req.on('error', reject);
19
+ });
20
+ }
21
+ function sha1Hex(buffer) {
22
+ return node_crypto_1.default.createHash('sha1').update(buffer).digest('hex');
23
+ }
24
+ function setCorsHeaders(input) {
25
+ const origin = String(input.req.headers.origin ?? '');
26
+ if (origin) {
27
+ input.res.setHeader('Access-Control-Allow-Origin', origin);
28
+ input.res.setHeader('Vary', 'Origin');
29
+ }
30
+ else {
31
+ input.res.setHeader('Access-Control-Allow-Origin', '*');
32
+ }
33
+ input.res.setHeader('Access-Control-Allow-Methods', input.allowedMethods.join(', '));
34
+ const reqHeaders = String(input.req.headers['access-control-request-headers'] ?? '');
35
+ input.res.setHeader('Access-Control-Allow-Headers', reqHeaders || '*');
36
+ input.res.setHeader('Access-Control-Max-Age', '600');
37
+ input.res.setHeader('Access-Control-Expose-Headers', 'ETag');
38
+ // Chrome Private Network Access (PNA) preflight.
39
+ // When a public origin fetches a private network resource (e.g. 127.0.0.1),
40
+ // browsers may include `Access-Control-Request-Private-Network: true`.
41
+ // We must explicitly allow it.
42
+ if (String(input.req.headers['access-control-request-private-network'] ?? '') === 'true') {
43
+ input.res.setHeader('Access-Control-Allow-Private-Network', 'true');
44
+ }
45
+ else {
46
+ input.res.setHeader('Access-Control-Allow-Private-Network', 'true');
47
+ }
48
+ }
49
+ async function createLocalSpoolServer(input) {
50
+ const uploads = new Map();
51
+ const logger = input.logger;
52
+ const token = node_crypto_1.default.randomBytes(16).toString('hex');
53
+ const server = node_http_1.default.createServer(async (req, res) => {
54
+ try {
55
+ const url = new URL(req.url ?? '/', `http://${req.headers.host ?? input.host}`);
56
+ if (req.method === 'OPTIONS') {
57
+ setCorsHeaders({ req, res, allowedMethods: ['PUT', 'GET', 'OPTIONS'] });
58
+ res.writeHead(204);
59
+ res.end();
60
+ return;
61
+ }
62
+ if (req.method === 'GET' && url.pathname === '/') {
63
+ setCorsHeaders({ req, res, allowedMethods: ['PUT', 'GET', 'OPTIONS'] });
64
+ res.writeHead(200, {
65
+ 'Content-Type': 'text/html; charset=utf-8',
66
+ 'Cache-Control': 'no-store',
67
+ });
68
+ res.end('<!doctype html><html><body>meframe spool</body></html>');
69
+ return;
70
+ }
71
+ const m = /^\/upload\/([^/]+)\/(\d+)$/.exec(url.pathname);
72
+ if (req.method === 'PUT' && m) {
73
+ setCorsHeaders({ req, res, allowedMethods: ['PUT', 'GET', 'OPTIONS'] });
74
+ const reqToken = String(req.headers[SPOOL_TOKEN_HEADER] ?? '');
75
+ if (!reqToken || reqToken !== token) {
76
+ res.writeHead(403);
77
+ res.end('Forbidden');
78
+ return;
79
+ }
80
+ const uploadId = m[1];
81
+ const partNumber = Number(m[2]);
82
+ if (!Number.isFinite(partNumber) || partNumber <= 0) {
83
+ res.writeHead(400);
84
+ res.end('Invalid partNumber');
85
+ return;
86
+ }
87
+ const upload = uploads.get(uploadId);
88
+ if (!upload) {
89
+ res.writeHead(404);
90
+ res.end('Unknown uploadId');
91
+ return;
92
+ }
93
+ const body = await readRequestBody(req);
94
+ const etag = sha1Hex(body);
95
+ const partPath = node_path_1.default.join(upload.dir, `part-${String(partNumber).padStart(6, '0')}.bin`);
96
+ await promises_1.default.writeFile(partPath, body);
97
+ upload.parts.set(partNumber, { etag, path: partPath });
98
+ res.writeHead(200, { ETag: etag });
99
+ res.end();
100
+ return;
101
+ }
102
+ res.writeHead(404);
103
+ res.end('Not found');
104
+ }
105
+ catch (e) {
106
+ logger.warn('[local-spool] request failed', e);
107
+ res.writeHead(500);
108
+ res.end(String(e?.message ?? e));
109
+ }
110
+ });
111
+ await new Promise((resolve) => server.listen(0, input.host, () => resolve()));
112
+ const address = server.address();
113
+ if (!address || typeof address === 'string') {
114
+ throw new Error('Failed to start local spool server');
115
+ }
116
+ const baseUrl = `http://${address.address}:${address.port}`;
117
+ const store = {
118
+ async createMultipartUpload({ key, contentType, metadata }) {
119
+ const uploadId = node_crypto_1.default.randomUUID();
120
+ const dir = await promises_1.default.mkdtemp(node_path_1.default.join(node_path_1.default.dirname(input.outFilePath), 'spool-upload-'));
121
+ uploads.set(uploadId, {
122
+ key,
123
+ contentType,
124
+ metadata,
125
+ dir,
126
+ parts: new Map(),
127
+ });
128
+ return { uploadId };
129
+ },
130
+ async getUploadPartUrl({ uploadId, partNumber }) {
131
+ if (!uploads.has(uploadId)) {
132
+ throw new Error('Unknown uploadId');
133
+ }
134
+ return {
135
+ url: `${baseUrl}/upload/${uploadId}/${partNumber}`,
136
+ headers: { [SPOOL_TOKEN_HEADER]: token },
137
+ };
138
+ },
139
+ async completeMultipartUpload({ uploadId, parts }) {
140
+ const upload = uploads.get(uploadId);
141
+ if (!upload)
142
+ throw new Error('Unknown uploadId');
143
+ const out = (0, node_fs_1.createWriteStream)(input.outFilePath);
144
+ for (const p of parts) {
145
+ const record = upload.parts.get(p.partNumber);
146
+ if (!record)
147
+ throw new Error(`Missing part ${p.partNumber}`);
148
+ await new Promise((resolve, reject) => {
149
+ const s = (0, node_fs_1.createReadStream)(record.path);
150
+ s.on('error', reject);
151
+ s.on('end', () => resolve());
152
+ s.pipe(out, { end: false });
153
+ });
154
+ }
155
+ out.end();
156
+ await new Promise((resolve, reject) => out.on('close', () => resolve()).on('error', reject));
157
+ await promises_1.default.rm(upload.dir, { recursive: true, force: true });
158
+ uploads.delete(uploadId);
159
+ },
160
+ async abortMultipartUpload({ uploadId }) {
161
+ const upload = uploads.get(uploadId);
162
+ if (!upload)
163
+ return;
164
+ await promises_1.default.rm(upload.dir, { recursive: true, force: true });
165
+ uploads.delete(uploadId);
166
+ },
167
+ };
168
+ const close = async () => {
169
+ await new Promise((resolve) => server.close(() => resolve()));
170
+ };
171
+ return { baseUrl, store, close };
172
+ }
173
+ //# sourceMappingURL=local-spool-server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local-spool-server.js","sourceRoot":"","sources":["../../../src/utils/local-spool-server.ts"],"names":[],"mappings":";;;;;AAkEA,wDA+IC;AAjND,gEAAkC;AAClC,qCAA8D;AAC9D,0DAA6B;AAC7B,8DAAiC;AACjC,0DAA6B;AAS7B,MAAM,kBAAkB,GAAG,uBAAuB,CAAC;AAEnD,SAAS,eAAe,CAAC,GAAyB;IAChD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC5E,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QACpD,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC1B,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,OAAO,CAAC,MAAc;IAC7B,OAAO,qBAAM,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAChE,CAAC;AAED,SAAS,cAAc,CAAC,KAIvB;IACC,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC;IACtD,IAAI,MAAM,EAAE,CAAC;QACX,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,6BAA6B,EAAE,MAAM,CAAC,CAAC;QAC3D,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IACxC,CAAC;SAAM,CAAC;QACN,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,6BAA6B,EAAE,GAAG,CAAC,CAAC;IAC1D,CAAC;IACD,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,8BAA8B,EAAE,KAAK,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAErF,MAAM,UAAU,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,gCAAgC,CAAC,IAAI,EAAE,CAAC,CAAC;IACrF,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,8BAA8B,EAAE,UAAU,IAAI,GAAG,CAAC,CAAC;IACvE,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,wBAAwB,EAAE,KAAK,CAAC,CAAC;IACrD,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,+BAA+B,EAAE,MAAM,CAAC,CAAC;IAE7D,iDAAiD;IACjD,4EAA4E;IAC5E,uEAAuE;IACvE,+BAA+B;IAC/B,IAAI,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,wCAAwC,CAAC,IAAI,EAAE,CAAC,KAAK,MAAM,EAAE,CAAC;QACzF,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,sCAAsC,EAAE,MAAM,CAAC,CAAC;IACtE,CAAC;SAAM,CAAC;QACN,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,sCAAsC,EAAE,MAAM,CAAC,CAAC;IACtE,CAAC;AACH,CAAC;AAUM,KAAK,UAAU,sBAAsB,CAAC,KAI5C;IAKC,MAAM,OAAO,GAAG,IAAI,GAAG,EAAwB,CAAC;IAChD,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;IAC5B,MAAM,KAAK,GAAG,qBAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAErD,MAAM,MAAM,GAAG,mBAAI,CAAC,YAAY,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE;QAClD,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,GAAG,EAAE,UAAU,GAAG,CAAC,OAAO,CAAC,IAAI,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;YAEhF,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;gBAC7B,cAAc,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,cAAc,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,CAAC,EAAE,CAAC,CAAC;gBACxE,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;gBACnB,GAAG,CAAC,GAAG,EAAE,CAAC;gBACV,OAAO;YACT,CAAC;YAED,IAAI,GAAG,CAAC,MAAM,KAAK,KAAK,IAAI,GAAG,CAAC,QAAQ,KAAK,GAAG,EAAE,CAAC;gBACjD,cAAc,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,cAAc,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,CAAC,EAAE,CAAC,CAAC;gBACxE,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE;oBACjB,cAAc,EAAE,0BAA0B;oBAC1C,eAAe,EAAE,UAAU;iBAC5B,CAAC,CAAC;gBACH,GAAG,CAAC,GAAG,CAAC,wDAAwD,CAAC,CAAC;gBAClE,OAAO;YACT,CAAC;YAED,MAAM,CAAC,GAAG,4BAA4B,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YAC1D,IAAI,GAAG,CAAC,MAAM,KAAK,KAAK,IAAI,CAAC,EAAE,CAAC;gBAC9B,cAAc,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,cAAc,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,CAAC,EAAE,CAAC,CAAC;gBACxE,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,kBAAkB,CAAC,IAAI,EAAE,CAAC,CAAC;gBAC/D,IAAI,CAAC,QAAQ,IAAI,QAAQ,KAAK,KAAK,EAAE,CAAC;oBACpC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;oBACnB,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;oBACrB,OAAO;gBACT,CAAC;gBACD,MAAM,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAE,CAAC;gBACvB,MAAM,UAAU,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;gBAChC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,UAAU,IAAI,CAAC,EAAE,CAAC;oBACpD,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;oBACnB,GAAG,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;oBAC9B,OAAO;gBACT,CAAC;gBAED,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;gBACrC,IAAI,CAAC,MAAM,EAAE,CAAC;oBACZ,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;oBACnB,GAAG,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;oBAC5B,OAAO;gBACT,CAAC;gBAED,MAAM,IAAI,GAAG,MAAM,eAAe,CAAC,GAAG,CAAC,CAAC;gBACxC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;gBAC3B,MAAM,QAAQ,GAAG,mBAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,QAAQ,MAAM,CAAC,UAAU,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;gBAC1F,MAAM,kBAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;gBACnC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;gBAEvD,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;gBACnC,GAAG,CAAC,GAAG,EAAE,CAAC;gBACV,OAAO;YACT,CAAC;YAED,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;YACnB,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QACvB,CAAC;QAAC,OAAO,CAAM,EAAE,CAAC;YAChB,MAAM,CAAC,IAAI,CAAC,8BAA8B,EAAE,CAAC,CAAC,CAAC;YAC/C,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;YACnB,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC;QACnC,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,KAAK,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IACpF,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC;IACjC,IAAI,CAAC,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;QAC5C,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;IACxD,CAAC;IACD,MAAM,OAAO,GAAG,UAAU,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;IAE5D,MAAM,KAAK,GAAyB;QAClC,KAAK,CAAC,qBAAqB,CAAC,EAAE,GAAG,EAAE,WAAW,EAAE,QAAQ,EAAE;YACxD,MAAM,QAAQ,GAAG,qBAAM,CAAC,UAAU,EAAE,CAAC;YACrC,MAAM,GAAG,GAAG,MAAM,kBAAE,CAAC,OAAO,CAAC,mBAAI,CAAC,IAAI,CAAC,mBAAI,CAAC,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE,eAAe,CAAC,CAAC,CAAC;YAC1F,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE;gBACpB,GAAG;gBACH,WAAW;gBACX,QAAQ;gBACR,GAAG;gBACH,KAAK,EAAE,IAAI,GAAG,EAAE;aACjB,CAAC,CAAC;YACH,OAAO,EAAE,QAAQ,EAAE,CAAC;QACtB,CAAC;QACD,KAAK,CAAC,gBAAgB,CAAC,EAAE,QAAQ,EAAE,UAAU,EAAE;YAC7C,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAC3B,MAAM,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAC;YACtC,CAAC;YACD,OAAO;gBACL,GAAG,EAAE,GAAG,OAAO,WAAW,QAAQ,IAAI,UAAU,EAAE;gBAClD,OAAO,EAAE,EAAE,CAAC,kBAAkB,CAAC,EAAE,KAAK,EAAE;aACzC,CAAC;QACJ,CAAC;QACD,KAAK,CAAC,uBAAuB,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE;YAC/C,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YACrC,IAAI,CAAC,MAAM;gBAAE,MAAM,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAC;YAEjD,MAAM,GAAG,GAAG,IAAA,2BAAiB,EAAC,KAAK,CAAC,WAAW,CAAC,CAAC;YACjD,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;gBACtB,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;gBAC9C,IAAI,CAAC,MAAM;oBAAE,MAAM,IAAI,KAAK,CAAC,gBAAgB,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC;gBAC7D,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;oBAC1C,MAAM,CAAC,GAAG,IAAA,0BAAgB,EAAC,MAAM,CAAC,IAAI,CAAC,CAAC;oBACxC,CAAC,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;oBACtB,CAAC,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;oBAC7B,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,CAAC;gBAC9B,CAAC,CAAC,CAAC;YACL,CAAC;YACD,GAAG,CAAC,GAAG,EAAE,CAAC;YACV,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,CAC1C,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CACrD,CAAC;YAEF,MAAM,kBAAE,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YAC1D,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC3B,CAAC;QACD,KAAK,CAAC,oBAAoB,CAAC,EAAE,QAAQ,EAAE;YACrC,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YACrC,IAAI,CAAC,MAAM;gBAAE,OAAO;YACpB,MAAM,kBAAE,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YAC1D,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC3B,CAAC;KACF,CAAC;IAEF,MAAM,KAAK,GAAG,KAAK,IAAI,EAAE;QACvB,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IACtE,CAAC,CAAC;IAEF,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;AACnC,CAAC"}
@@ -16,7 +16,11 @@ async function uploadFileToMultipartStore(input) {
16
16
  throw new Error('partSizeBytes must be >= 5 MiB for multipart upload');
17
17
  }
18
18
  (0, abort_gate_js_1.throwIfAborted)(abortSignal);
19
- const { uploadId } = await store.createMultipartUpload({ key, contentType });
19
+ const { uploadId } = await store.createMultipartUpload({
20
+ key,
21
+ contentType,
22
+ metadata: input.metadata,
23
+ });
20
24
  if (!uploadId) {
21
25
  throw new Error('Failed to create multipart upload');
22
26
  }
@@ -1 +1 @@
1
- {"version":3,"file":"multipart-upload.js","sourceRoot":"","sources":["../../../src/utils/multipart-upload.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"multipart-upload.js","sourceRoot":"","sources":["../../../src/utils/multipart-upload.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"ServerExporterBase.d.ts","sourceRoot":"","sources":["../../src/ServerExporterBase.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAEV,kBAAkB,EAClB,mBAAmB,EACnB,qBAAqB,EACtB,MAAM,YAAY,CAAC;AAUpB,8BAAsB,kBAAkB;IACtC,SAAS,CAAC,QAAQ,CAAC,mBAAmB,IAAI,MAAM,GAAG,GAAG;IAEtD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAiC;IACvD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAwB;IAChD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,OAAO,CAKP;IACR,OAAO,CAAC,uBAAuB,CAAgC;gBAEnD,OAAO,EAAE,qBAAqB;IAS1C,OAAO,CAAC,gBAAgB;YAIV,8BAA8B;YAa9B,WAAW;IAyBzB,OAAO,CAAC,WAAW;IAWb,aAAa,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAsP5E,OAAO,CAAC,gBAAgB;YA0BV,mBAAmB;IA2BjC,OAAO,CAAC,kBAAkB;CAI3B"}
1
+ {"version":3,"file":"ServerExporterBase.d.ts","sourceRoot":"","sources":["../../src/ServerExporterBase.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAEV,kBAAkB,EAClB,mBAAmB,EACnB,qBAAqB,EACtB,MAAM,YAAY,CAAC;AAepB,8BAAsB,kBAAkB;IACtC,SAAS,CAAC,QAAQ,CAAC,mBAAmB,IAAI,MAAM,GAAG,GAAG;IAEtD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAiC;IACvD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAwB;IAChD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,OAAO,CAKP;IACR,OAAO,CAAC,uBAAuB,CAAgC;gBAEnD,OAAO,EAAE,qBAAqB;IAS1C,OAAO,CAAC,gBAAgB;YAIV,8BAA8B;YAa9B,WAAW;IAyBzB,OAAO,CAAC,WAAW;IAWb,aAAa,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAoZ5E,OAAO,CAAC,gBAAgB;YA0BV,mBAAmB;IA2BjC,OAAO,CAAC,kBAAkB;CAI3B"}
@@ -3,9 +3,11 @@ import fs from 'node:fs/promises';
3
3
  import os from 'node:os';
4
4
  import path from 'node:path';
5
5
  import { launch } from 'puppeteer-core';
6
- import { runFfmpegAudioMixPostProcess } from './postprocess/ffmpeg-audio-mix.js';
6
+ import { runFfmpegAudioMixPostProcess, runFfmpegAudioMixToFile, } from './postprocess/ffmpeg-audio-mix.js';
7
7
  import { runExportInPage } from './runner/runner.js';
8
8
  import { AbortError, createAbortError, createAbortGate, throwIfAborted, } from './utils/abort-gate.js';
9
+ import { createLocalSpoolServer } from './utils/local-spool-server.js';
10
+ import { uploadFileToMultipartStore } from './utils/multipart-upload.js';
9
11
  export class ServerExporterBase {
10
12
  store;
11
13
  options;
@@ -95,10 +97,14 @@ export class ServerExporterBase {
95
97
  let browser = null;
96
98
  let page = null;
97
99
  let uploadId = null;
100
+ let spoolServer = null;
101
+ let spoolDir = null;
102
+ let spoolFilePath = null;
98
103
  let userDataDir = null;
99
104
  let abortedByUser = false;
100
105
  let audioSkipped = false;
101
106
  let audioSkipMessage = null;
107
+ const runnerOutputTarget = this.options.runnerOutput?.target ?? 'spool';
102
108
  const { abortPromise, dispose: disposeAbortGate } = createAbortGate(input.abortSignal, () => {
103
109
  abortedByUser = true;
104
110
  // Hard-stop the page so the job can exit quickly (runner promise rejects on page close).
@@ -110,21 +116,51 @@ export class ServerExporterBase {
110
116
  partSizeBytes,
111
117
  headless: this.options.browser?.headless ?? true,
112
118
  executablePath: this.options.browser?.executablePath,
119
+ runnerOutputTarget,
113
120
  });
114
121
  throwIfAborted(input.abortSignal);
115
122
  userDataDir = await fs.mkdtemp(path.join(this.options.browser?.userDataDirBase ?? os.tmpdir(), 'meframe-server-'));
116
123
  log('Created userDataDir', { userDataDir });
117
- throwIfAborted(input.abortSignal);
118
- const uploadInit = await this.store.createMultipartUpload({
119
- key,
120
- contentType,
121
- metadata: input.metadata,
122
- });
123
- uploadId = uploadInit.uploadId;
124
- if (!uploadId) {
125
- throw new Error('Failed to create multipart upload');
124
+ if (runnerOutputTarget === 'store') {
125
+ throwIfAborted(input.abortSignal);
126
+ const uploadInit = await this.store.createMultipartUpload({
127
+ key,
128
+ contentType,
129
+ metadata: input.metadata,
130
+ });
131
+ uploadId = uploadInit.uploadId;
132
+ if (!uploadId) {
133
+ throw new Error('Failed to create multipart upload');
134
+ }
135
+ log('Multipart upload created', { uploadId });
136
+ }
137
+ else if (runnerOutputTarget === 'spool') {
138
+ const spoolOpts = this.options.runnerOutput?.spool ?? {};
139
+ const tmpDirBase = spoolOpts.tmpDirBase ?? os.tmpdir();
140
+ const host = spoolOpts.host ?? '127.0.0.1';
141
+ throwIfAborted(input.abortSignal);
142
+ spoolDir = await fs.mkdtemp(path.join(tmpDirBase, 'meframe-spool-'));
143
+ spoolFilePath = path.join(spoolDir, 'video-only.mp4');
144
+ spoolServer = await createLocalSpoolServer({
145
+ outFilePath: spoolFilePath,
146
+ host,
147
+ logger: logger,
148
+ });
149
+ // The runner uploads MP4 parts to this temporary localhost store.
150
+ const uploadInit = await spoolServer.store.createMultipartUpload({
151
+ key: 'spool/video-only.mp4',
152
+ contentType,
153
+ metadata: input.metadata,
154
+ });
155
+ uploadId = uploadInit.uploadId;
156
+ if (!uploadId) {
157
+ throw new Error('Failed to create local spool upload');
158
+ }
159
+ log('Local spool server ready', { baseUrl: spoolServer.baseUrl, uploadId, spoolDir });
160
+ }
161
+ else {
162
+ throw new Error(`Unknown runnerOutput.target: ${String(runnerOutputTarget)}`);
126
163
  }
127
- log('Multipart upload created', { uploadId });
128
164
  const parts = [];
129
165
  const onProgress = (evt) => {
130
166
  if (typeof evt?.message === 'string' &&
@@ -140,10 +176,18 @@ export class ServerExporterBase {
140
176
  log('Runner bundle loaded', { bytes: runnerModuleCode.length });
141
177
  log('Launching browser...');
142
178
  throwIfAborted(input.abortSignal);
179
+ const launchArgs = [...(this.options.browser?.launchArgs ?? [])];
180
+ if (runnerOutputTarget === 'spool' && spoolServer) {
181
+ // Allow https page to fetch(PUT) to http://127.0.0.1 (mixed content + private network access).
182
+ // This is restricted to the dedicated export Chromium instance.
183
+ launchArgs.push('--allow-running-insecure-content');
184
+ launchArgs.push(`--unsafely-treat-insecure-origin-as-secure=${spoolServer.baseUrl}`);
185
+ launchArgs.push('--disable-features=BlockInsecurePrivateNetworkRequests');
186
+ }
143
187
  browser = await launch({
144
188
  headless: this.options.browser?.headless ?? true,
145
189
  executablePath: this.options.browser?.executablePath,
146
- args: this.options.browser?.launchArgs,
190
+ args: launchArgs,
147
191
  userDataDir,
148
192
  });
149
193
  log('Browser launched');
@@ -168,12 +212,18 @@ export class ServerExporterBase {
168
212
  log('Running export in page...');
169
213
  await Promise.race([
170
214
  runExportInPage(page, {
171
- requestPartUrl: async (partNumber) => this.store.getUploadPartUrl({
172
- key,
173
- uploadId: uploadId,
174
- partNumber,
175
- expiresInSeconds: partUrlExpiresInSeconds,
176
- }),
215
+ requestPartUrl: async (partNumber) => runnerOutputTarget === 'store'
216
+ ? this.store.getUploadPartUrl({
217
+ key,
218
+ uploadId: uploadId,
219
+ partNumber,
220
+ expiresInSeconds: partUrlExpiresInSeconds,
221
+ })
222
+ : spoolServer.store.getUploadPartUrl({
223
+ key: 'spool/video-only.mp4',
224
+ uploadId: uploadId,
225
+ partNumber,
226
+ }),
177
227
  reportPartDone: async (partNumber, etag) => {
178
228
  const normalizedEtag = etag.replaceAll('"', '');
179
229
  parts.push({ partNumber, etag: normalizedEtag });
@@ -194,15 +244,27 @@ export class ServerExporterBase {
194
244
  runnerModuleCode,
195
245
  pageUrl: input.pageUrl,
196
246
  workerPath: input.workerPath,
247
+ fonts: input.fonts ?? [],
197
248
  }),
198
249
  abortPromise,
199
250
  ]);
200
251
  log('Runner resolved');
201
252
  parts.sort((a, b) => a.partNumber - b.partNumber);
202
253
  this.assertPartsValid(parts);
203
- log('Completing multipart upload...', { parts: parts.length });
204
- await this.store.completeMultipartUpload({ key, uploadId: uploadId, parts });
205
- log('Export completed', { key });
254
+ if (runnerOutputTarget === 'store') {
255
+ log('Completing multipart upload...', { parts: parts.length });
256
+ await this.store.completeMultipartUpload({ key, uploadId: uploadId, parts });
257
+ log('Export completed', { key });
258
+ }
259
+ else {
260
+ log('Completing local spool upload...', { parts: parts.length });
261
+ await spoolServer.store.completeMultipartUpload({
262
+ key: 'spool/video-only.mp4',
263
+ uploadId: uploadId,
264
+ parts,
265
+ });
266
+ log('Local spool completed', { spoolFilePath });
267
+ }
206
268
  const post = this.options.postProcess?.ffmpegAudioMix;
207
269
  if (post?.enabled && audioSkipped) {
208
270
  log('Postprocess: ffmpegAudioMix enabled and audio was skipped', {
@@ -215,41 +277,104 @@ export class ServerExporterBase {
215
277
  const ffprobePath = post.ffprobePath ?? 'ffprobe';
216
278
  const onFailure = post.onFailure ?? 'fallback';
217
279
  try {
218
- const result = await runFfmpegAudioMixPostProcess({
219
- store: this.store,
280
+ if (runnerOutputTarget === 'store') {
281
+ const result = await runFfmpegAudioMixPostProcess({
282
+ store: this.store,
283
+ model: input.model,
284
+ originalKey: key,
285
+ outputKey,
286
+ partSizeBytes,
287
+ contentType,
288
+ ffmpegPath,
289
+ ffprobePath,
290
+ audioBitrate,
291
+ resolveUploadedInput: post.resolveUploadedInput,
292
+ abortSignal: input.abortSignal,
293
+ logger,
294
+ onProgress: (evt) => {
295
+ onProgress({ progress: evt.progress, stage: evt.stage, message: evt.message });
296
+ },
297
+ });
298
+ if (!result.skipped && result.key !== key) {
299
+ log('Postprocess completed', { key: result.key });
300
+ }
301
+ else if (!result.skipped) {
302
+ log('Postprocess completed (overwritten)', { key: result.key });
303
+ }
304
+ else {
305
+ log('Postprocess skipped', { key: result.key });
306
+ }
307
+ return { key: result.key };
308
+ }
309
+ // spool mode: run FFmpeg to a local file, then upload once
310
+ const finalFilePath = path.join(spoolDir, 'final.mp4');
311
+ const result = await runFfmpegAudioMixToFile({
220
312
  model: input.model,
221
- originalKey: key,
222
- outputKey,
223
- partSizeBytes,
224
- contentType,
313
+ videoOnlyInput: { kind: 'file', filePath: spoolFilePath },
225
314
  ffmpegPath,
226
315
  ffprobePath,
227
316
  audioBitrate,
228
- resolveUploadedInput: post.resolveUploadedInput,
317
+ outFile: finalFilePath,
229
318
  abortSignal: input.abortSignal,
230
319
  logger,
231
- onProgress: (evt) => {
232
- onProgress({ progress: evt.progress, stage: evt.stage, message: evt.message });
233
- },
320
+ onProgress: (evt) => onProgress({ progress: evt.progress, stage: evt.stage, message: evt.message }),
234
321
  });
235
- if (!result.skipped && result.key !== key) {
236
- log('Postprocess completed', { key: result.key });
237
- }
238
- else if (!result.skipped) {
239
- log('Postprocess completed (overwritten)', { key: result.key });
240
- }
241
- else {
242
- log('Postprocess skipped', { key: result.key });
243
- }
244
- return { key: result.key };
322
+ const fileToUpload = result.skipped ? spoolFilePath : finalFilePath;
323
+ const keyToUpload = result.skipped ? key : outputKey;
324
+ onProgress({ stage: 'upload', progress: 0.8, message: 'Uploading final MP4' });
325
+ await uploadFileToMultipartStore({
326
+ store: this.store,
327
+ key: keyToUpload,
328
+ filePath: fileToUpload,
329
+ contentType,
330
+ partSizeBytes,
331
+ metadata: input.metadata,
332
+ abortSignal: input.abortSignal,
333
+ logger: logger,
334
+ });
335
+ onProgress({ stage: 'upload', progress: 1, message: 'Upload completed' });
336
+ return { key: keyToUpload };
245
337
  }
246
338
  catch (e) {
247
339
  logger.error('[ServerExporter] postprocess failed', e);
248
340
  if (onFailure === 'throw')
249
341
  throw e;
342
+ if (runnerOutputTarget === 'spool') {
343
+ // fallback: upload video-only once
344
+ onProgress({
345
+ stage: 'upload',
346
+ progress: 0.8,
347
+ message: 'Uploading video-only MP4 (fallback)',
348
+ });
349
+ await uploadFileToMultipartStore({
350
+ store: this.store,
351
+ key,
352
+ filePath: spoolFilePath,
353
+ contentType,
354
+ partSizeBytes,
355
+ metadata: input.metadata,
356
+ abortSignal: input.abortSignal,
357
+ logger: logger,
358
+ });
359
+ onProgress({ stage: 'upload', progress: 1, message: 'Upload completed (fallback)' });
360
+ }
250
361
  return { key };
251
362
  }
252
363
  }
364
+ if (runnerOutputTarget === 'spool') {
365
+ onProgress({ stage: 'upload', progress: 0.8, message: 'Uploading video-only MP4' });
366
+ await uploadFileToMultipartStore({
367
+ store: this.store,
368
+ key,
369
+ filePath: spoolFilePath,
370
+ contentType,
371
+ partSizeBytes,
372
+ metadata: input.metadata,
373
+ abortSignal: input.abortSignal,
374
+ logger: logger,
375
+ });
376
+ onProgress({ stage: 'upload', progress: 1, message: 'Upload completed' });
377
+ }
253
378
  return { key };
254
379
  }
255
380
  catch (error) {
@@ -264,7 +389,22 @@ export class ServerExporterBase {
264
389
  else {
265
390
  logger.error('[ServerExporter] export failed', error);
266
391
  }
267
- await this.abortMultipartUploadBestEffort({ key, uploadId, logger });
392
+ if (runnerOutputTarget === 'store') {
393
+ await this.abortMultipartUploadBestEffort({ key, uploadId, logger });
394
+ }
395
+ else if (runnerOutputTarget === 'spool') {
396
+ try {
397
+ if (spoolServer && uploadId) {
398
+ await spoolServer.store.abortMultipartUpload({
399
+ key: 'spool/video-only.mp4',
400
+ uploadId,
401
+ });
402
+ }
403
+ }
404
+ catch (e) {
405
+ logger.warn('[ServerExporter] abort failed', e);
406
+ }
407
+ }
268
408
  if (isAbort) {
269
409
  throw this.createAbortError();
270
410
  }
@@ -290,6 +430,28 @@ export class ServerExporterBase {
290
430
  logger.warn('[ServerExporter] cleanup failed', e);
291
431
  }
292
432
  }
433
+ if (spoolServer) {
434
+ try {
435
+ await spoolServer.close();
436
+ }
437
+ catch (e) {
438
+ logger.warn('[ServerExporter] cleanup failed', e);
439
+ }
440
+ }
441
+ if (spoolDir) {
442
+ const keep = this.options.runnerOutput?.spool?.keepIntermediate === true;
443
+ if (!keep) {
444
+ try {
445
+ await fs.rm(spoolDir, { recursive: true, force: true });
446
+ }
447
+ catch (e) {
448
+ logger.warn('[ServerExporter] cleanup failed', e);
449
+ }
450
+ }
451
+ else {
452
+ logger.info('[ServerExporter] keepIntermediate enabled', { spoolDir });
453
+ }
454
+ }
293
455
  this.releaseSlot();
294
456
  }
295
457
  }