@walkeros/cli 2.2.0-next-1772811722420 → 2.2.0-next-1773136823705
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +33 -7
- package/README.md +2 -2
- package/dist/cli.js +13117 -11794
- package/dist/examples/README.md +1 -1
- package/dist/index.d.ts +101 -122
- package/dist/index.js +1528 -850
- package/dist/index.js.map +1 -1
- package/examples/README.md +1 -1
- package/package.json +8 -5
- package/dist/runtime/main.js +0 -17484
package/dist/index.js
CHANGED
|
@@ -48,6 +48,87 @@ var init_cli_logger = __esm({
|
|
|
48
48
|
}
|
|
49
49
|
});
|
|
50
50
|
|
|
51
|
+
// src/core/timer.ts
|
|
52
|
+
function createTimer() {
|
|
53
|
+
let startTime = 0;
|
|
54
|
+
let endTime = 0;
|
|
55
|
+
return {
|
|
56
|
+
start() {
|
|
57
|
+
startTime = Date.now();
|
|
58
|
+
endTime = 0;
|
|
59
|
+
},
|
|
60
|
+
end() {
|
|
61
|
+
endTime = Date.now();
|
|
62
|
+
return endTime - startTime;
|
|
63
|
+
},
|
|
64
|
+
getElapsed() {
|
|
65
|
+
const currentTime = endTime || Date.now();
|
|
66
|
+
return currentTime - startTime;
|
|
67
|
+
},
|
|
68
|
+
format() {
|
|
69
|
+
const elapsed = this.getElapsed();
|
|
70
|
+
return (elapsed / 1e3).toFixed(2) + "s";
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
var init_timer = __esm({
|
|
75
|
+
"src/core/timer.ts"() {
|
|
76
|
+
"use strict";
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
// src/core/output.ts
|
|
81
|
+
import fs from "fs-extra";
|
|
82
|
+
import path from "path";
|
|
83
|
+
async function writeResult(content, options) {
|
|
84
|
+
if (options.output) {
|
|
85
|
+
const outputPath = path.resolve(options.output);
|
|
86
|
+
await fs.ensureDir(path.dirname(outputPath));
|
|
87
|
+
await fs.writeFile(outputPath, content);
|
|
88
|
+
} else {
|
|
89
|
+
process.stdout.write(content);
|
|
90
|
+
process.stdout.write("\n");
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
function createJsonOutput(success, data, error, duration) {
|
|
94
|
+
return {
|
|
95
|
+
success,
|
|
96
|
+
...data && { data },
|
|
97
|
+
...error && { error },
|
|
98
|
+
...duration && { duration }
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
function createSuccessOutput(data, duration) {
|
|
102
|
+
return createJsonOutput(true, data, void 0, duration);
|
|
103
|
+
}
|
|
104
|
+
function createErrorOutput(error, duration) {
|
|
105
|
+
return createJsonOutput(false, void 0, error, duration);
|
|
106
|
+
}
|
|
107
|
+
function formatBytes(bytes) {
|
|
108
|
+
return (bytes / 1024).toFixed(2);
|
|
109
|
+
}
|
|
110
|
+
var init_output = __esm({
|
|
111
|
+
"src/core/output.ts"() {
|
|
112
|
+
"use strict";
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
// src/core/tmp.ts
|
|
117
|
+
import os from "os";
|
|
118
|
+
import path2 from "path";
|
|
119
|
+
function getTmpPath(tmpDir, ...segments) {
|
|
120
|
+
const root = tmpDir || DEFAULT_TMP_ROOT;
|
|
121
|
+
const absoluteRoot = path2.isAbsolute(root) ? root : path2.resolve(root);
|
|
122
|
+
return path2.join(absoluteRoot, ...segments);
|
|
123
|
+
}
|
|
124
|
+
var DEFAULT_TMP_ROOT;
|
|
125
|
+
var init_tmp = __esm({
|
|
126
|
+
"src/core/tmp.ts"() {
|
|
127
|
+
"use strict";
|
|
128
|
+
DEFAULT_TMP_ROOT = os.tmpdir();
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
|
|
51
132
|
// src/lib/config-file.ts
|
|
52
133
|
import {
|
|
53
134
|
readFileSync,
|
|
@@ -143,6 +224,9 @@ async function deployAuthenticatedFetch(url, init) {
|
|
|
143
224
|
headers: { ...existingHeaders, Authorization: `Bearer ${token}` }
|
|
144
225
|
});
|
|
145
226
|
}
|
|
227
|
+
function resolveRunToken() {
|
|
228
|
+
return resolveDeployToken() ?? resolveToken()?.token ?? null;
|
|
229
|
+
}
|
|
146
230
|
function resolveBaseUrl() {
|
|
147
231
|
return resolveAppUrl();
|
|
148
232
|
}
|
|
@@ -158,220 +242,10 @@ var init_auth = __esm({
|
|
|
158
242
|
}
|
|
159
243
|
});
|
|
160
244
|
|
|
161
|
-
// src/version.ts
|
|
162
|
-
import { readFileSync as readFileSync2 } from "fs";
|
|
163
|
-
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
164
|
-
import { dirname as dirname2, join as join2 } from "path";
|
|
165
|
-
function findPackageJson() {
|
|
166
|
-
const paths = [
|
|
167
|
-
join2(versionDirname, "../package.json"),
|
|
168
|
-
// dist/ or src/
|
|
169
|
-
join2(versionDirname, "../../package.json")
|
|
170
|
-
// src/core/ (not used, but safe)
|
|
171
|
-
];
|
|
172
|
-
for (const p2 of paths) {
|
|
173
|
-
try {
|
|
174
|
-
return readFileSync2(p2, "utf-8");
|
|
175
|
-
} catch {
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
return JSON.stringify({ version: "0.0.0" });
|
|
179
|
-
}
|
|
180
|
-
var versionFilename, versionDirname, VERSION;
|
|
181
|
-
var init_version = __esm({
|
|
182
|
-
"src/version.ts"() {
|
|
183
|
-
"use strict";
|
|
184
|
-
versionFilename = fileURLToPath2(import.meta.url);
|
|
185
|
-
versionDirname = dirname2(versionFilename);
|
|
186
|
-
VERSION = JSON.parse(findPackageJson()).version;
|
|
187
|
-
}
|
|
188
|
-
});
|
|
189
|
-
|
|
190
|
-
// src/commands/run/heartbeat.ts
|
|
191
|
-
var heartbeat_exports = {};
|
|
192
|
-
__export(heartbeat_exports, {
|
|
193
|
-
startHeartbeat: () => startHeartbeat
|
|
194
|
-
});
|
|
195
|
-
import { randomUUID } from "crypto";
|
|
196
|
-
async function startHeartbeat(options) {
|
|
197
|
-
const projectId = options.projectId ?? requireProjectId();
|
|
198
|
-
const base = resolveBaseUrl();
|
|
199
|
-
const instanceId2 = randomUUID();
|
|
200
|
-
const healthEndpoint = options.healthEndpoint ?? "/health";
|
|
201
|
-
const intervalSec = options.heartbeatInterval ?? 60;
|
|
202
|
-
const log = createCLILogger();
|
|
203
|
-
const startTime = Date.now();
|
|
204
|
-
const heartbeatUrl = `${base}/api/projects/${projectId}/deployments/${options.deployment}/heartbeat`;
|
|
205
|
-
const initResponse = await deployAuthenticatedFetch(heartbeatUrl, {
|
|
206
|
-
method: "POST",
|
|
207
|
-
headers: { "Content-Type": "application/json" },
|
|
208
|
-
body: JSON.stringify({
|
|
209
|
-
url: options.url,
|
|
210
|
-
healthEndpoint,
|
|
211
|
-
instanceId: instanceId2,
|
|
212
|
-
cliVersion: VERSION
|
|
213
|
-
})
|
|
214
|
-
});
|
|
215
|
-
if (!initResponse.ok) {
|
|
216
|
-
const err = await initResponse.json().catch(() => ({}));
|
|
217
|
-
throw new Error(
|
|
218
|
-
err.error?.message || `Initial heartbeat failed (${initResponse.status})`
|
|
219
|
-
);
|
|
220
|
-
}
|
|
221
|
-
const initData = await initResponse.json();
|
|
222
|
-
log.info(
|
|
223
|
-
`Registered as ${instanceId2} on deployment ${options.deployment} (${initData.deploymentId})`
|
|
224
|
-
);
|
|
225
|
-
const heartbeatTimer = setInterval(async () => {
|
|
226
|
-
try {
|
|
227
|
-
const resp = await deployAuthenticatedFetch(heartbeatUrl, {
|
|
228
|
-
method: "POST",
|
|
229
|
-
headers: { "Content-Type": "application/json" },
|
|
230
|
-
body: JSON.stringify({
|
|
231
|
-
instanceId: instanceId2,
|
|
232
|
-
uptime: Math.floor((Date.now() - startTime) / 1e3),
|
|
233
|
-
cliVersion: VERSION,
|
|
234
|
-
metadata: {
|
|
235
|
-
nodeVersion: process.version,
|
|
236
|
-
platform: process.platform
|
|
237
|
-
}
|
|
238
|
-
})
|
|
239
|
-
});
|
|
240
|
-
if (resp.ok) {
|
|
241
|
-
const data = await resp.json();
|
|
242
|
-
if (data.action === "update" && data.bundleUrl) {
|
|
243
|
-
log.info(
|
|
244
|
-
`Update available: version ${data.versionNumber}, downloading from ${data.bundleUrl}`
|
|
245
|
-
);
|
|
246
|
-
} else if (data.action === "stop") {
|
|
247
|
-
log.info("Received stop signal from server, shutting down...");
|
|
248
|
-
await cleanup();
|
|
249
|
-
process.exit(0);
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
} catch (err) {
|
|
253
|
-
log.error(
|
|
254
|
-
`Heartbeat failed: ${err instanceof Error ? err.message : "Unknown error"}`
|
|
255
|
-
);
|
|
256
|
-
}
|
|
257
|
-
}, intervalSec * 1e3);
|
|
258
|
-
const cleanup = async () => {
|
|
259
|
-
clearInterval(heartbeatTimer);
|
|
260
|
-
try {
|
|
261
|
-
await deployAuthenticatedFetch(heartbeatUrl, {
|
|
262
|
-
method: "POST",
|
|
263
|
-
headers: { "Content-Type": "application/json" },
|
|
264
|
-
body: JSON.stringify({
|
|
265
|
-
instanceId: instanceId2,
|
|
266
|
-
uptime: Math.floor((Date.now() - startTime) / 1e3),
|
|
267
|
-
shutting_down: true
|
|
268
|
-
})
|
|
269
|
-
});
|
|
270
|
-
} catch {
|
|
271
|
-
}
|
|
272
|
-
};
|
|
273
|
-
process.on("SIGTERM", async () => {
|
|
274
|
-
await cleanup();
|
|
275
|
-
process.exit(0);
|
|
276
|
-
});
|
|
277
|
-
process.on("SIGINT", async () => {
|
|
278
|
-
await cleanup();
|
|
279
|
-
process.exit(0);
|
|
280
|
-
});
|
|
281
|
-
return { instanceId: instanceId2, deploymentId: initData.deploymentId, cleanup };
|
|
282
|
-
}
|
|
283
|
-
var init_heartbeat = __esm({
|
|
284
|
-
"src/commands/run/heartbeat.ts"() {
|
|
285
|
-
"use strict";
|
|
286
|
-
init_auth();
|
|
287
|
-
init_cli_logger();
|
|
288
|
-
init_version();
|
|
289
|
-
}
|
|
290
|
-
});
|
|
291
|
-
|
|
292
|
-
// src/commands/bundle/index.ts
|
|
293
|
-
init_cli_logger();
|
|
294
|
-
import path11 from "path";
|
|
295
|
-
import fs11 from "fs-extra";
|
|
296
|
-
import { getPlatform as getPlatform2 } from "@walkeros/core";
|
|
297
|
-
|
|
298
|
-
// src/core/index.ts
|
|
299
|
-
init_cli_logger();
|
|
300
|
-
|
|
301
|
-
// src/core/timer.ts
|
|
302
|
-
function createTimer() {
|
|
303
|
-
let startTime = 0;
|
|
304
|
-
let endTime = 0;
|
|
305
|
-
return {
|
|
306
|
-
start() {
|
|
307
|
-
startTime = Date.now();
|
|
308
|
-
endTime = 0;
|
|
309
|
-
},
|
|
310
|
-
end() {
|
|
311
|
-
endTime = Date.now();
|
|
312
|
-
return endTime - startTime;
|
|
313
|
-
},
|
|
314
|
-
getElapsed() {
|
|
315
|
-
const currentTime = endTime || Date.now();
|
|
316
|
-
return currentTime - startTime;
|
|
317
|
-
},
|
|
318
|
-
format() {
|
|
319
|
-
const elapsed = this.getElapsed();
|
|
320
|
-
return (elapsed / 1e3).toFixed(2) + "s";
|
|
321
|
-
}
|
|
322
|
-
};
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
// src/core/output.ts
|
|
326
|
-
import fs from "fs-extra";
|
|
327
|
-
import path from "path";
|
|
328
|
-
async function writeResult(content, options) {
|
|
329
|
-
if (options.output) {
|
|
330
|
-
const outputPath = path.resolve(options.output);
|
|
331
|
-
await fs.ensureDir(path.dirname(outputPath));
|
|
332
|
-
await fs.writeFile(outputPath, content);
|
|
333
|
-
} else {
|
|
334
|
-
process.stdout.write(content);
|
|
335
|
-
process.stdout.write("\n");
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
function createJsonOutput(success, data, error, duration) {
|
|
339
|
-
return {
|
|
340
|
-
success,
|
|
341
|
-
...data && { data },
|
|
342
|
-
...error && { error },
|
|
343
|
-
...duration && { duration }
|
|
344
|
-
};
|
|
345
|
-
}
|
|
346
|
-
function createSuccessOutput(data, duration) {
|
|
347
|
-
return createJsonOutput(true, data, void 0, duration);
|
|
348
|
-
}
|
|
349
|
-
function createErrorOutput(error, duration) {
|
|
350
|
-
return createJsonOutput(false, void 0, error, duration);
|
|
351
|
-
}
|
|
352
|
-
function formatBytes(bytes) {
|
|
353
|
-
return (bytes / 1024).toFixed(2);
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
// src/core/tmp.ts
|
|
357
|
-
import os from "os";
|
|
358
|
-
import path2 from "path";
|
|
359
|
-
var DEFAULT_TMP_ROOT = os.tmpdir();
|
|
360
|
-
function getTmpPath(tmpDir, ...segments) {
|
|
361
|
-
const root = tmpDir || DEFAULT_TMP_ROOT;
|
|
362
|
-
const absoluteRoot = path2.isAbsolute(root) ? root : path2.resolve(root);
|
|
363
|
-
return path2.join(absoluteRoot, ...segments);
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
// src/core/asset-resolver.ts
|
|
367
|
-
import { fileURLToPath } from "url";
|
|
368
|
-
import { existsSync as existsSync2 } from "fs";
|
|
369
|
-
import path4 from "path";
|
|
370
|
-
|
|
371
245
|
// src/config/utils.ts
|
|
246
|
+
import crypto from "crypto";
|
|
372
247
|
import fs2 from "fs-extra";
|
|
373
248
|
import path3 from "path";
|
|
374
|
-
init_auth();
|
|
375
249
|
function isUrl(str) {
|
|
376
250
|
try {
|
|
377
251
|
const url = new URL(str);
|
|
@@ -394,7 +268,8 @@ async function downloadFromUrl(url) {
|
|
|
394
268
|
const content = await response.text();
|
|
395
269
|
const downloadsDir = getTmpPath(void 0, "downloads");
|
|
396
270
|
await fs2.ensureDir(downloadsDir);
|
|
397
|
-
const
|
|
271
|
+
const downloadId = crypto.randomUUID().slice(0, 8);
|
|
272
|
+
const tempPath = path3.join(downloadsDir, `flow-${downloadId}.json`);
|
|
398
273
|
await fs2.writeFile(tempPath, content, "utf-8");
|
|
399
274
|
return tempPath;
|
|
400
275
|
} catch (error) {
|
|
@@ -485,9 +360,19 @@ async function loadJsonFromSource(source, options) {
|
|
|
485
360
|
);
|
|
486
361
|
}
|
|
487
362
|
}
|
|
363
|
+
var init_utils = __esm({
|
|
364
|
+
"src/config/utils.ts"() {
|
|
365
|
+
"use strict";
|
|
366
|
+
init_core();
|
|
367
|
+
init_tmp();
|
|
368
|
+
init_auth();
|
|
369
|
+
}
|
|
370
|
+
});
|
|
488
371
|
|
|
489
372
|
// src/core/asset-resolver.ts
|
|
490
|
-
|
|
373
|
+
import { fileURLToPath } from "url";
|
|
374
|
+
import { existsSync as existsSync2 } from "fs";
|
|
375
|
+
import path4 from "path";
|
|
491
376
|
function getAssetDir() {
|
|
492
377
|
if (cachedAssetDir) return cachedAssetDir;
|
|
493
378
|
const currentFile = fileURLToPath(import.meta.url);
|
|
@@ -515,16 +400,28 @@ function resolveAsset(assetPath, assetType, baseDir) {
|
|
|
515
400
|
}
|
|
516
401
|
return path4.resolve(baseDir || process.cwd(), assetPath);
|
|
517
402
|
}
|
|
403
|
+
var cachedAssetDir;
|
|
404
|
+
var init_asset_resolver = __esm({
|
|
405
|
+
"src/core/asset-resolver.ts"() {
|
|
406
|
+
"use strict";
|
|
407
|
+
init_utils();
|
|
408
|
+
}
|
|
409
|
+
});
|
|
518
410
|
|
|
519
411
|
// src/core/utils.ts
|
|
520
412
|
function getErrorMessage(error) {
|
|
521
413
|
return error instanceof Error ? error.message : String(error);
|
|
522
414
|
}
|
|
415
|
+
var init_utils2 = __esm({
|
|
416
|
+
"src/core/utils.ts"() {
|
|
417
|
+
"use strict";
|
|
418
|
+
}
|
|
419
|
+
});
|
|
523
420
|
|
|
524
421
|
// src/core/local-packages.ts
|
|
525
422
|
import path5 from "path";
|
|
526
423
|
import fs3 from "fs-extra";
|
|
527
|
-
async function resolveLocalPackage(packageName, localPath, configDir,
|
|
424
|
+
async function resolveLocalPackage(packageName, localPath, configDir, logger) {
|
|
528
425
|
const absolutePath = path5.isAbsolute(localPath) ? localPath : path5.resolve(configDir, localPath);
|
|
529
426
|
if (!await fs3.pathExists(absolutePath)) {
|
|
530
427
|
throw new Error(
|
|
@@ -540,7 +437,7 @@ async function resolveLocalPackage(packageName, localPath, configDir, logger2) {
|
|
|
540
437
|
const distPath = path5.join(absolutePath, "dist");
|
|
541
438
|
const hasDistFolder = await fs3.pathExists(distPath);
|
|
542
439
|
if (!hasDistFolder) {
|
|
543
|
-
|
|
440
|
+
logger.warn(
|
|
544
441
|
`\u26A0\uFE0F ${packageName}: No dist/ folder found. Using package root.`
|
|
545
442
|
);
|
|
546
443
|
}
|
|
@@ -551,7 +448,7 @@ async function resolveLocalPackage(packageName, localPath, configDir, logger2) {
|
|
|
551
448
|
hasDistFolder
|
|
552
449
|
};
|
|
553
450
|
}
|
|
554
|
-
async function copyLocalPackage(localPkg, targetDir,
|
|
451
|
+
async function copyLocalPackage(localPkg, targetDir, logger) {
|
|
555
452
|
const packageDir = path5.join(targetDir, "node_modules", localPkg.name);
|
|
556
453
|
await fs3.ensureDir(path5.dirname(packageDir));
|
|
557
454
|
await fs3.copy(
|
|
@@ -571,13 +468,17 @@ async function copyLocalPackage(localPkg, targetDir, logger2) {
|
|
|
571
468
|
}
|
|
572
469
|
}
|
|
573
470
|
}
|
|
574
|
-
|
|
471
|
+
logger.info(`\u{1F4E6} Using local: ${localPkg.name} from ${localPkg.absolutePath}`);
|
|
575
472
|
return packageDir;
|
|
576
473
|
}
|
|
474
|
+
var init_local_packages = __esm({
|
|
475
|
+
"src/core/local-packages.ts"() {
|
|
476
|
+
"use strict";
|
|
477
|
+
}
|
|
478
|
+
});
|
|
577
479
|
|
|
578
480
|
// src/core/input-detector.ts
|
|
579
481
|
import fs4 from "fs-extra";
|
|
580
|
-
init_auth();
|
|
581
482
|
async function detectInput(inputPath, platformOverride) {
|
|
582
483
|
const content = await loadContent(inputPath);
|
|
583
484
|
try {
|
|
@@ -602,6 +503,13 @@ async function loadContent(inputPath) {
|
|
|
602
503
|
}
|
|
603
504
|
return fs4.readFile(inputPath, "utf8");
|
|
604
505
|
}
|
|
506
|
+
var init_input_detector = __esm({
|
|
507
|
+
"src/core/input-detector.ts"() {
|
|
508
|
+
"use strict";
|
|
509
|
+
init_utils();
|
|
510
|
+
init_auth();
|
|
511
|
+
}
|
|
512
|
+
});
|
|
605
513
|
|
|
606
514
|
// src/core/stdin.ts
|
|
607
515
|
function isStdinPiped() {
|
|
@@ -618,9 +526,11 @@ async function readStdin() {
|
|
|
618
526
|
}
|
|
619
527
|
return content;
|
|
620
528
|
}
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
529
|
+
var init_stdin = __esm({
|
|
530
|
+
"src/core/stdin.ts"() {
|
|
531
|
+
"use strict";
|
|
532
|
+
}
|
|
533
|
+
});
|
|
624
534
|
|
|
625
535
|
// src/core/sse.ts
|
|
626
536
|
function parseSSEEvents(buffer) {
|
|
@@ -644,15 +554,35 @@ function parseSSEEvents(buffer) {
|
|
|
644
554
|
}
|
|
645
555
|
return { parsed: events, remainder };
|
|
646
556
|
}
|
|
557
|
+
var init_sse = __esm({
|
|
558
|
+
"src/core/sse.ts"() {
|
|
559
|
+
"use strict";
|
|
560
|
+
}
|
|
561
|
+
});
|
|
562
|
+
|
|
563
|
+
// src/core/index.ts
|
|
564
|
+
var init_core = __esm({
|
|
565
|
+
"src/core/index.ts"() {
|
|
566
|
+
"use strict";
|
|
567
|
+
init_cli_logger();
|
|
568
|
+
init_timer();
|
|
569
|
+
init_output();
|
|
570
|
+
init_tmp();
|
|
571
|
+
init_asset_resolver();
|
|
572
|
+
init_utils2();
|
|
573
|
+
init_local_packages();
|
|
574
|
+
init_input_detector();
|
|
575
|
+
init_stdin();
|
|
576
|
+
}
|
|
577
|
+
});
|
|
647
578
|
|
|
648
579
|
// src/config/validators.ts
|
|
649
580
|
import { schemas } from "@walkeros/core/dev";
|
|
650
|
-
var { safeParseSetup } = schemas;
|
|
651
581
|
function isObject(value) {
|
|
652
582
|
return typeof value === "object" && value !== null && !Array.isArray(value) && Object.prototype.toString.call(value) === "[object Object]";
|
|
653
583
|
}
|
|
654
|
-
function
|
|
655
|
-
const result =
|
|
584
|
+
function validateFlowConfig(data) {
|
|
585
|
+
const result = safeParseConfig(data);
|
|
656
586
|
if (!result.success) {
|
|
657
587
|
const errors = result.error.issues.map((issue) => {
|
|
658
588
|
const path15 = issue.path.length > 0 ? issue.path.map(String).join(".") : "root";
|
|
@@ -663,64 +593,76 @@ ${errors}`);
|
|
|
663
593
|
}
|
|
664
594
|
return result.data;
|
|
665
595
|
}
|
|
666
|
-
function getAvailableFlows(
|
|
667
|
-
return Object.keys(
|
|
596
|
+
function getAvailableFlows(config) {
|
|
597
|
+
return Object.keys(config.flows);
|
|
668
598
|
}
|
|
599
|
+
var safeParseConfig;
|
|
600
|
+
var init_validators = __esm({
|
|
601
|
+
"src/config/validators.ts"() {
|
|
602
|
+
"use strict";
|
|
603
|
+
({ safeParseConfig } = schemas);
|
|
604
|
+
}
|
|
605
|
+
});
|
|
669
606
|
|
|
670
607
|
// src/config/build-defaults.ts
|
|
671
|
-
var WEB_BUILD_DEFAULTS = {
|
|
672
|
-
format: "iife",
|
|
673
|
-
platform: "browser",
|
|
674
|
-
target: "es2020",
|
|
675
|
-
minify: true,
|
|
676
|
-
sourcemap: false,
|
|
677
|
-
cache: true,
|
|
678
|
-
windowCollector: "collector",
|
|
679
|
-
windowElb: "elb"
|
|
680
|
-
};
|
|
681
|
-
var SERVER_BUILD_DEFAULTS = {
|
|
682
|
-
format: "esm",
|
|
683
|
-
platform: "node",
|
|
684
|
-
target: "node20",
|
|
685
|
-
minify: true,
|
|
686
|
-
sourcemap: false,
|
|
687
|
-
cache: true
|
|
688
|
-
};
|
|
689
|
-
var DEFAULT_OUTPUT_PATHS = {
|
|
690
|
-
web: "./dist/walker.js",
|
|
691
|
-
server: "./dist/bundle.mjs"
|
|
692
|
-
};
|
|
693
608
|
function getBuildDefaults(platform) {
|
|
694
609
|
return platform === "web" ? WEB_BUILD_DEFAULTS : SERVER_BUILD_DEFAULTS;
|
|
695
610
|
}
|
|
696
611
|
function getDefaultOutput(platform) {
|
|
697
612
|
return DEFAULT_OUTPUT_PATHS[platform];
|
|
698
613
|
}
|
|
699
|
-
|
|
700
|
-
|
|
614
|
+
var WEB_BUILD_DEFAULTS, SERVER_BUILD_DEFAULTS, DEFAULT_OUTPUT_PATHS;
|
|
615
|
+
var init_build_defaults = __esm({
|
|
616
|
+
"src/config/build-defaults.ts"() {
|
|
617
|
+
"use strict";
|
|
618
|
+
WEB_BUILD_DEFAULTS = {
|
|
619
|
+
format: "iife",
|
|
620
|
+
platform: "browser",
|
|
621
|
+
target: "es2020",
|
|
622
|
+
minify: true,
|
|
623
|
+
sourcemap: false,
|
|
624
|
+
cache: true,
|
|
625
|
+
windowCollector: "collector",
|
|
626
|
+
windowElb: "elb"
|
|
627
|
+
};
|
|
628
|
+
SERVER_BUILD_DEFAULTS = {
|
|
629
|
+
format: "esm",
|
|
630
|
+
platform: "node",
|
|
631
|
+
target: "node20",
|
|
632
|
+
minify: true,
|
|
633
|
+
sourcemap: false,
|
|
634
|
+
cache: true
|
|
635
|
+
};
|
|
636
|
+
DEFAULT_OUTPUT_PATHS = {
|
|
637
|
+
web: "./dist/walker.js",
|
|
638
|
+
server: "./dist/bundle.mjs"
|
|
639
|
+
};
|
|
640
|
+
}
|
|
641
|
+
});
|
|
642
|
+
|
|
643
|
+
// src/config/loader.ts
|
|
701
644
|
import path6 from "path";
|
|
702
645
|
import fs5 from "fs-extra";
|
|
703
|
-
import {
|
|
704
|
-
var DEFAULT_INCLUDE_FOLDER = "./shared";
|
|
646
|
+
import { getFlowSettings, getPlatform } from "@walkeros/core";
|
|
705
647
|
function loadBundleConfig(rawConfig, options) {
|
|
706
|
-
const
|
|
707
|
-
const availableFlows = getAvailableFlows(
|
|
708
|
-
const flowName = resolveFlow(
|
|
709
|
-
let
|
|
710
|
-
const platform = getPlatform(
|
|
648
|
+
const config = validateFlowConfig(rawConfig);
|
|
649
|
+
const availableFlows = getAvailableFlows(config);
|
|
650
|
+
const flowName = resolveFlow(config, options.flowName, availableFlows);
|
|
651
|
+
let flowSettings = getFlowSettings(config, flowName, { deferred: true });
|
|
652
|
+
const platform = getPlatform(flowSettings);
|
|
711
653
|
if (!platform) {
|
|
712
654
|
throw new Error(
|
|
713
655
|
`Invalid configuration: flow "${flowName}" must have a "web" or "server" key.`
|
|
714
656
|
);
|
|
715
657
|
}
|
|
716
658
|
if (platform === "web") {
|
|
717
|
-
|
|
659
|
+
flowSettings = getFlowSettings(config, flowName);
|
|
718
660
|
}
|
|
719
661
|
const buildDefaults = getBuildDefaults(platform);
|
|
720
|
-
const packages =
|
|
662
|
+
const packages = flowSettings.packages || {};
|
|
721
663
|
const output = options.buildOverrides?.output || getDefaultOutput(platform);
|
|
722
664
|
const configDir = isUrl(options.configPath) ? process.cwd() : path6.dirname(options.configPath);
|
|
723
|
-
let includes =
|
|
665
|
+
let includes = config.include;
|
|
724
666
|
if (!includes) {
|
|
725
667
|
const defaultIncludePath = path6.resolve(configDir, DEFAULT_INCLUDE_FOLDER);
|
|
726
668
|
if (fs5.pathExistsSync(defaultIncludePath)) {
|
|
@@ -742,14 +684,14 @@ function loadBundleConfig(rawConfig, options) {
|
|
|
742
684
|
);
|
|
743
685
|
}
|
|
744
686
|
return {
|
|
745
|
-
|
|
687
|
+
flowSettings,
|
|
746
688
|
buildOptions,
|
|
747
689
|
flowName,
|
|
748
690
|
isMultiFlow,
|
|
749
691
|
availableFlows
|
|
750
692
|
};
|
|
751
693
|
}
|
|
752
|
-
function resolveFlow(
|
|
694
|
+
function resolveFlow(config, requestedFlow, available) {
|
|
753
695
|
if (available.length === 1) {
|
|
754
696
|
return available[0];
|
|
755
697
|
}
|
|
@@ -768,8 +710,8 @@ Available flows: ${available.join(", ")}`
|
|
|
768
710
|
return requestedFlow;
|
|
769
711
|
}
|
|
770
712
|
function loadAllFlows(rawConfig, options) {
|
|
771
|
-
const
|
|
772
|
-
const flows = getAvailableFlows(
|
|
713
|
+
const config = validateFlowConfig(rawConfig);
|
|
714
|
+
const flows = getAvailableFlows(config);
|
|
773
715
|
if (options.logger) {
|
|
774
716
|
options.logger.info(
|
|
775
717
|
`\u{1F4E6} Loading all ${flows.length} flows: ${flows.join(", ")}`
|
|
@@ -786,21 +728,29 @@ async function loadFlowConfig(configPath, options) {
|
|
|
786
728
|
const rawConfig = await loadJsonConfig(configPath);
|
|
787
729
|
return loadBundleConfig(rawConfig, { configPath, ...options });
|
|
788
730
|
}
|
|
731
|
+
var DEFAULT_INCLUDE_FOLDER;
|
|
732
|
+
var init_loader = __esm({
|
|
733
|
+
"src/config/loader.ts"() {
|
|
734
|
+
"use strict";
|
|
735
|
+
init_validators();
|
|
736
|
+
init_build_defaults();
|
|
737
|
+
init_utils();
|
|
738
|
+
DEFAULT_INCLUDE_FOLDER = "./shared";
|
|
739
|
+
}
|
|
740
|
+
});
|
|
789
741
|
|
|
790
|
-
// src/
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
import fs6 from "fs-extra";
|
|
742
|
+
// src/config/index.ts
|
|
743
|
+
var init_config = __esm({
|
|
744
|
+
"src/config/index.ts"() {
|
|
745
|
+
"use strict";
|
|
746
|
+
init_validators();
|
|
747
|
+
init_utils();
|
|
748
|
+
init_loader();
|
|
749
|
+
}
|
|
750
|
+
});
|
|
800
751
|
|
|
801
752
|
// src/core/cache-utils.ts
|
|
802
753
|
import { getHashServer } from "@walkeros/server-core";
|
|
803
|
-
var HASH_LENGTH = 12;
|
|
804
754
|
function isMutableVersion(version) {
|
|
805
755
|
return version === "latest" || version.includes("^") || version.includes("~") || version.includes("*") || version.includes("x");
|
|
806
756
|
}
|
|
@@ -821,15 +771,25 @@ function normalizeJson(content) {
|
|
|
821
771
|
const parsed = JSON.parse(content);
|
|
822
772
|
return JSON.stringify(parsed);
|
|
823
773
|
}
|
|
824
|
-
async function
|
|
774
|
+
async function getFlowSettingsCacheKey(content, date) {
|
|
825
775
|
const dateStr = date ?? getTodayDate();
|
|
826
776
|
const normalized = normalizeJson(content);
|
|
827
777
|
const input = `${normalized}:${dateStr}`;
|
|
828
778
|
return getHashServer(input, HASH_LENGTH);
|
|
829
779
|
}
|
|
780
|
+
var HASH_LENGTH;
|
|
781
|
+
var init_cache_utils = __esm({
|
|
782
|
+
"src/core/cache-utils.ts"() {
|
|
783
|
+
"use strict";
|
|
784
|
+
HASH_LENGTH = 12;
|
|
785
|
+
}
|
|
786
|
+
});
|
|
830
787
|
|
|
831
788
|
// src/commands/bundle/package-manager.ts
|
|
832
|
-
|
|
789
|
+
import pacote from "pacote";
|
|
790
|
+
import path7 from "path";
|
|
791
|
+
import fs6 from "fs-extra";
|
|
792
|
+
import semver from "semver";
|
|
833
793
|
async function withTimeout(promise, ms, errorMessage) {
|
|
834
794
|
let timer;
|
|
835
795
|
const timeout = new Promise((_2, reject) => {
|
|
@@ -841,132 +801,199 @@ async function withTimeout(promise, ms, errorMessage) {
|
|
|
841
801
|
clearTimeout(timer);
|
|
842
802
|
}
|
|
843
803
|
}
|
|
844
|
-
function getPackageDirectory(baseDir, packageName
|
|
804
|
+
function getPackageDirectory(baseDir, packageName) {
|
|
845
805
|
return path7.join(baseDir, "node_modules", packageName);
|
|
846
806
|
}
|
|
847
|
-
async function
|
|
848
|
-
const
|
|
849
|
-
const
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
807
|
+
async function collectAllSpecs(packages, logger, configDir) {
|
|
808
|
+
const allSpecs = /* @__PURE__ */ new Map();
|
|
809
|
+
const visited = /* @__PURE__ */ new Set();
|
|
810
|
+
const queue = packages.map((pkg) => ({
|
|
811
|
+
name: pkg.name,
|
|
812
|
+
spec: pkg.version,
|
|
813
|
+
source: "direct",
|
|
814
|
+
from: "flow.json",
|
|
815
|
+
optional: false,
|
|
816
|
+
localPath: pkg.path
|
|
817
|
+
}));
|
|
818
|
+
while (queue.length > 0) {
|
|
819
|
+
const item = queue.shift();
|
|
820
|
+
const visitKey = `${item.name}@${item.spec}`;
|
|
821
|
+
if (visited.has(visitKey)) continue;
|
|
822
|
+
visited.add(visitKey);
|
|
823
|
+
if (!allSpecs.has(item.name)) allSpecs.set(item.name, []);
|
|
824
|
+
allSpecs.get(item.name).push({
|
|
825
|
+
spec: item.spec,
|
|
826
|
+
source: item.source,
|
|
827
|
+
from: item.from,
|
|
828
|
+
optional: item.optional,
|
|
829
|
+
localPath: item.localPath
|
|
830
|
+
});
|
|
831
|
+
if (item.localPath) continue;
|
|
832
|
+
let manifest;
|
|
833
|
+
try {
|
|
834
|
+
manifest = await withTimeout(
|
|
835
|
+
pacote.manifest(`${item.name}@${item.spec}`, PACOTE_OPTS),
|
|
836
|
+
PACKAGE_DOWNLOAD_TIMEOUT_MS,
|
|
837
|
+
`Manifest fetch timed out: ${item.name}@${item.spec}`
|
|
838
|
+
);
|
|
839
|
+
} catch (error) {
|
|
840
|
+
logger.debug(
|
|
841
|
+
`Failed to fetch manifest for ${item.name}@${item.spec}: ${error}`
|
|
842
|
+
);
|
|
843
|
+
continue;
|
|
861
844
|
}
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
845
|
+
const m2 = manifest;
|
|
846
|
+
const deps = m2.dependencies || {};
|
|
847
|
+
for (const [depName, depSpec] of Object.entries(deps)) {
|
|
848
|
+
if (typeof depSpec === "string") {
|
|
849
|
+
queue.push({
|
|
850
|
+
name: depName,
|
|
851
|
+
spec: depSpec,
|
|
852
|
+
source: "dependency",
|
|
853
|
+
from: item.name,
|
|
854
|
+
optional: false
|
|
855
|
+
});
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
const peerDeps = m2.peerDependencies || {};
|
|
859
|
+
const peerMeta = m2.peerDependenciesMeta || {};
|
|
860
|
+
for (const [depName, depSpec] of Object.entries(peerDeps)) {
|
|
861
|
+
if (typeof depSpec === "string") {
|
|
862
|
+
const isOptional = peerMeta[depName]?.optional === true;
|
|
863
|
+
queue.push({
|
|
864
|
+
name: depName,
|
|
865
|
+
spec: depSpec,
|
|
866
|
+
source: "peerDependency",
|
|
867
|
+
from: item.name,
|
|
868
|
+
optional: isOptional
|
|
869
|
+
});
|
|
870
|
+
}
|
|
869
871
|
}
|
|
870
872
|
}
|
|
871
|
-
|
|
872
|
-
throw new Error(
|
|
873
|
-
`Version conflicts detected:
|
|
874
|
-
${conflicts.map((c2) => ` - ${c2}`).join("\n")}
|
|
875
|
-
|
|
876
|
-
Each package must use the same version across all declarations. Please update your configuration to use consistent versions.`
|
|
877
|
-
);
|
|
878
|
-
}
|
|
873
|
+
return allSpecs;
|
|
879
874
|
}
|
|
880
|
-
|
|
881
|
-
const
|
|
882
|
-
const
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
875
|
+
function resolveVersionConflicts(allSpecs, logger) {
|
|
876
|
+
const resolved = /* @__PURE__ */ new Map();
|
|
877
|
+
for (const [name, specs] of allSpecs) {
|
|
878
|
+
const localSpec = specs.find((s2) => s2.localPath);
|
|
879
|
+
if (localSpec) {
|
|
880
|
+
resolved.set(name, {
|
|
881
|
+
name,
|
|
882
|
+
version: "local",
|
|
883
|
+
localPath: localSpec.localPath
|
|
884
|
+
});
|
|
885
|
+
continue;
|
|
886
|
+
}
|
|
887
|
+
const nonPeerSpecs = specs.filter((s2) => s2.source !== "peerDependency");
|
|
888
|
+
const peerSpecs = specs.filter((s2) => s2.source === "peerDependency");
|
|
889
|
+
let activeSpecs;
|
|
890
|
+
if (nonPeerSpecs.length > 0) {
|
|
891
|
+
activeSpecs = nonPeerSpecs;
|
|
892
|
+
} else {
|
|
893
|
+
const requiredPeers = peerSpecs.filter((s2) => !s2.optional);
|
|
894
|
+
if (requiredPeers.length === 0) {
|
|
895
|
+
logger.debug(`Skipping optional peer dependency: ${name}`);
|
|
896
|
+
continue;
|
|
897
|
+
}
|
|
898
|
+
activeSpecs = requiredPeers;
|
|
899
|
+
}
|
|
900
|
+
activeSpecs.sort(
|
|
901
|
+
(a2, b2) => SOURCE_PRIORITY[a2.source] - SOURCE_PRIORITY[b2.source]
|
|
902
|
+
);
|
|
903
|
+
const directSpecs = activeSpecs.filter((s2) => s2.source === "direct");
|
|
904
|
+
const directExact = directSpecs.find((s2) => semver.valid(s2.spec) !== null);
|
|
905
|
+
let chosenVersion;
|
|
906
|
+
if (directExact) {
|
|
907
|
+
chosenVersion = directExact.spec;
|
|
908
|
+
} else if (directSpecs.length > 0) {
|
|
909
|
+
chosenVersion = directSpecs[0].spec;
|
|
910
|
+
} else {
|
|
911
|
+
const exactVersions = activeSpecs.filter((s2) => semver.valid(s2.spec) !== null).map((s2) => s2.spec);
|
|
912
|
+
const uniqueExact = [...new Set(exactVersions)];
|
|
913
|
+
if (uniqueExact.length > 1) {
|
|
914
|
+
throw new Error(
|
|
915
|
+
`Version conflict for ${name}: ${uniqueExact.join(" vs ")} (from ${activeSpecs.map((s2) => `${s2.spec} via ${s2.from}`).join(", ")})`
|
|
916
|
+
);
|
|
917
|
+
} else if (uniqueExact.length === 1) {
|
|
918
|
+
chosenVersion = uniqueExact[0];
|
|
919
|
+
} else {
|
|
920
|
+
chosenVersion = activeSpecs[0].spec;
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
if (semver.valid(chosenVersion)) {
|
|
924
|
+
for (const spec of specs) {
|
|
925
|
+
if (spec.localPath) continue;
|
|
926
|
+
if (semver.valid(spec.spec)) {
|
|
927
|
+
if (spec.spec !== chosenVersion) {
|
|
928
|
+
if (spec.source === "peerDependency") {
|
|
929
|
+
logger.warn(
|
|
930
|
+
`${name}@${chosenVersion} differs from peer constraint ${spec.spec} (from ${spec.from})`
|
|
931
|
+
);
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
} else {
|
|
935
|
+
if (!semver.satisfies(chosenVersion, spec.spec, {
|
|
936
|
+
includePrerelease: true
|
|
937
|
+
})) {
|
|
938
|
+
if (spec.source === "peerDependency") {
|
|
939
|
+
logger.warn(
|
|
940
|
+
`${name}@${chosenVersion} may not satisfy peer constraint ${spec.spec} (from ${spec.from})`
|
|
941
|
+
);
|
|
942
|
+
} else {
|
|
943
|
+
throw new Error(
|
|
944
|
+
`Version conflict: ${name}@${chosenVersion} does not satisfy ${spec.spec} required by ${spec.from}`
|
|
945
|
+
);
|
|
946
|
+
}
|
|
947
|
+
}
|
|
898
948
|
}
|
|
899
949
|
}
|
|
900
950
|
}
|
|
901
|
-
|
|
902
|
-
logger2.debug(`Failed to read dependencies for ${pkgKey}: ${error}`);
|
|
951
|
+
resolved.set(name, { name, version: chosenVersion });
|
|
903
952
|
}
|
|
904
|
-
return
|
|
953
|
+
return resolved;
|
|
905
954
|
}
|
|
906
|
-
async function downloadPackages(packages, targetDir,
|
|
955
|
+
async function downloadPackages(packages, targetDir, logger, useCache = true, configDir, tmpDir) {
|
|
907
956
|
const packagePaths = /* @__PURE__ */ new Map();
|
|
908
|
-
const downloadQueue = [...packages];
|
|
909
|
-
const processed = /* @__PURE__ */ new Set();
|
|
910
957
|
const userSpecifiedPackages = new Set(packages.map((p2) => p2.name));
|
|
958
|
+
validateNoDuplicatePackages(packages);
|
|
959
|
+
logger.debug("Resolving dependencies");
|
|
960
|
+
const allSpecs = await collectAllSpecs(packages, logger, configDir);
|
|
961
|
+
const resolved = resolveVersionConflicts(allSpecs, logger);
|
|
962
|
+
await fs6.ensureDir(targetDir);
|
|
911
963
|
const localPackageMap = /* @__PURE__ */ new Map();
|
|
912
964
|
for (const pkg of packages) {
|
|
913
|
-
if (pkg.path)
|
|
914
|
-
localPackageMap.set(pkg.name, pkg.path);
|
|
915
|
-
}
|
|
965
|
+
if (pkg.path) localPackageMap.set(pkg.name, pkg.path);
|
|
916
966
|
}
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
const pkg = downloadQueue.shift();
|
|
921
|
-
const pkgKey = `${pkg.name}@${pkg.version}`;
|
|
922
|
-
if (processed.has(pkgKey)) {
|
|
923
|
-
continue;
|
|
924
|
-
}
|
|
925
|
-
processed.add(pkgKey);
|
|
926
|
-
if (!pkg.path && localPackageMap.has(pkg.name)) {
|
|
927
|
-
pkg.path = localPackageMap.get(pkg.name);
|
|
928
|
-
}
|
|
929
|
-
if (pkg.path) {
|
|
967
|
+
for (const [name, pkg] of resolved) {
|
|
968
|
+
if (pkg.localPath || localPackageMap.has(name)) {
|
|
969
|
+
const localPath = pkg.localPath || localPackageMap.get(name);
|
|
930
970
|
const localPkg = await resolveLocalPackage(
|
|
931
|
-
|
|
932
|
-
|
|
971
|
+
name,
|
|
972
|
+
localPath,
|
|
933
973
|
configDir || process.cwd(),
|
|
934
|
-
|
|
974
|
+
logger
|
|
935
975
|
);
|
|
936
|
-
const installedPath = await copyLocalPackage(localPkg, targetDir,
|
|
937
|
-
packagePaths.set(
|
|
938
|
-
const deps = await resolveDependencies(pkg, installedPath, logger2);
|
|
939
|
-
for (const dep of deps) {
|
|
940
|
-
const depKey = `${dep.name}@${dep.version}`;
|
|
941
|
-
if (!processed.has(depKey)) {
|
|
942
|
-
downloadQueue.push(dep);
|
|
943
|
-
}
|
|
944
|
-
}
|
|
976
|
+
const installedPath = await copyLocalPackage(localPkg, targetDir, logger);
|
|
977
|
+
packagePaths.set(name, installedPath);
|
|
945
978
|
continue;
|
|
946
979
|
}
|
|
947
|
-
const packageSpec = `${
|
|
948
|
-
const packageDir = getPackageDirectory(targetDir,
|
|
949
|
-
const cachedPath = await getCachedPackagePath(
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
980
|
+
const packageSpec = `${name}@${pkg.version}`;
|
|
981
|
+
const packageDir = getPackageDirectory(targetDir, name);
|
|
982
|
+
const cachedPath = await getCachedPackagePath(
|
|
983
|
+
{ name, version: pkg.version },
|
|
984
|
+
tmpDir
|
|
985
|
+
);
|
|
986
|
+
if (useCache && await isPackageCached({ name, version: pkg.version }, tmpDir)) {
|
|
987
|
+
if (userSpecifiedPackages.has(name)) {
|
|
988
|
+
logger.debug(`Downloading ${packageSpec} (cached)`);
|
|
953
989
|
}
|
|
954
990
|
try {
|
|
955
991
|
await fs6.ensureDir(path7.dirname(packageDir));
|
|
956
992
|
await fs6.copy(cachedPath, packageDir);
|
|
957
|
-
packagePaths.set(
|
|
958
|
-
const deps = await resolveDependencies(pkg, packageDir, logger2);
|
|
959
|
-
for (const dep of deps) {
|
|
960
|
-
const depKey = `${dep.name}@${dep.version}`;
|
|
961
|
-
if (!processed.has(depKey)) {
|
|
962
|
-
downloadQueue.push(dep);
|
|
963
|
-
}
|
|
964
|
-
}
|
|
993
|
+
packagePaths.set(name, packageDir);
|
|
965
994
|
continue;
|
|
966
|
-
} catch
|
|
967
|
-
|
|
968
|
-
`Failed to use cache for ${packageSpec}, downloading fresh: ${error}`
|
|
969
|
-
);
|
|
995
|
+
} catch {
|
|
996
|
+
logger.debug(`Cache miss for ${packageSpec}, downloading fresh`);
|
|
970
997
|
}
|
|
971
998
|
}
|
|
972
999
|
try {
|
|
@@ -974,52 +1001,87 @@ async function downloadPackages(packages, targetDir, logger2, useCache = true, c
|
|
|
974
1001
|
const cacheDir = process.env.NPM_CACHE_DIR || getTmpPath(tmpDir, "cache", "npm");
|
|
975
1002
|
await withTimeout(
|
|
976
1003
|
pacote.extract(packageSpec, packageDir, {
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
// Force online fetching from registry (don't use cached workspace packages)
|
|
980
|
-
preferOnline: true,
|
|
981
|
-
// Cache for performance
|
|
982
|
-
cache: cacheDir,
|
|
983
|
-
// Don't resolve relative to workspace context
|
|
984
|
-
where: void 0
|
|
1004
|
+
...PACOTE_OPTS,
|
|
1005
|
+
cache: cacheDir
|
|
985
1006
|
}),
|
|
986
1007
|
PACKAGE_DOWNLOAD_TIMEOUT_MS,
|
|
987
1008
|
`Package download timed out after ${PACKAGE_DOWNLOAD_TIMEOUT_MS / 1e3}s: ${packageSpec}`
|
|
988
1009
|
);
|
|
989
|
-
if (userSpecifiedPackages.has(
|
|
990
|
-
|
|
991
|
-
const pkgJsonSize = pkgStats.size;
|
|
992
|
-
const sizeKB = (pkgJsonSize / 1024).toFixed(1);
|
|
993
|
-
logger2.debug(`Downloading ${packageSpec} (${sizeKB} KB)`);
|
|
1010
|
+
if (userSpecifiedPackages.has(name)) {
|
|
1011
|
+
logger.debug(`Downloading ${packageSpec}`);
|
|
994
1012
|
}
|
|
995
1013
|
if (useCache) {
|
|
996
1014
|
try {
|
|
997
1015
|
await fs6.ensureDir(path7.dirname(cachedPath));
|
|
998
1016
|
await fs6.copy(packageDir, cachedPath);
|
|
999
|
-
} catch
|
|
1000
|
-
}
|
|
1001
|
-
}
|
|
1002
|
-
packagePaths.set(pkg.name, packageDir);
|
|
1003
|
-
const deps = await resolveDependencies(pkg, packageDir, logger2);
|
|
1004
|
-
for (const dep of deps) {
|
|
1005
|
-
const depKey = `${dep.name}@${dep.version}`;
|
|
1006
|
-
if (!processed.has(depKey)) {
|
|
1007
|
-
downloadQueue.push(dep);
|
|
1017
|
+
} catch {
|
|
1008
1018
|
}
|
|
1009
1019
|
}
|
|
1020
|
+
packagePaths.set(name, packageDir);
|
|
1010
1021
|
} catch (error) {
|
|
1011
1022
|
throw new Error(`Failed to download ${packageSpec}: ${error}`);
|
|
1012
1023
|
}
|
|
1013
1024
|
}
|
|
1014
1025
|
return packagePaths;
|
|
1015
1026
|
}
|
|
1027
|
+
async function getCachedPackagePath(pkg, tmpDir) {
|
|
1028
|
+
const cacheDir = getTmpPath(tmpDir, "cache", "packages");
|
|
1029
|
+
const cacheKey = await getPackageCacheKey(pkg.name, pkg.version);
|
|
1030
|
+
return path7.join(cacheDir, cacheKey);
|
|
1031
|
+
}
|
|
1032
|
+
async function isPackageCached(pkg, tmpDir) {
|
|
1033
|
+
const cachedPath = await getCachedPackagePath(pkg, tmpDir);
|
|
1034
|
+
return fs6.pathExists(cachedPath);
|
|
1035
|
+
}
|
|
1036
|
+
function validateNoDuplicatePackages(packages) {
|
|
1037
|
+
const packageMap = /* @__PURE__ */ new Map();
|
|
1038
|
+
for (const pkg of packages) {
|
|
1039
|
+
if (!packageMap.has(pkg.name)) packageMap.set(pkg.name, []);
|
|
1040
|
+
packageMap.get(pkg.name).push(pkg.version);
|
|
1041
|
+
}
|
|
1042
|
+
const conflicts = [];
|
|
1043
|
+
for (const [name, versions] of packageMap.entries()) {
|
|
1044
|
+
const uniqueVersions = [...new Set(versions)];
|
|
1045
|
+
if (uniqueVersions.length > 1) {
|
|
1046
|
+
conflicts.push(`${name}: [${uniqueVersions.join(", ")}]`);
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
if (conflicts.length > 0) {
|
|
1050
|
+
throw new Error(
|
|
1051
|
+
`Version conflicts detected:
|
|
1052
|
+
${conflicts.map((c2) => ` - ${c2}`).join("\n")}
|
|
1053
|
+
|
|
1054
|
+
Each package must use the same version across all declarations. Please update your configuration to use consistent versions.`
|
|
1055
|
+
);
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1058
|
+
var PACKAGE_DOWNLOAD_TIMEOUT_MS, PACOTE_OPTS, SOURCE_PRIORITY;
|
|
1059
|
+
var init_package_manager = __esm({
|
|
1060
|
+
"src/commands/bundle/package-manager.ts"() {
|
|
1061
|
+
"use strict";
|
|
1062
|
+
init_core();
|
|
1063
|
+
init_cache_utils();
|
|
1064
|
+
init_tmp();
|
|
1065
|
+
PACKAGE_DOWNLOAD_TIMEOUT_MS = 6e4;
|
|
1066
|
+
PACOTE_OPTS = {
|
|
1067
|
+
registry: "https://registry.npmjs.org",
|
|
1068
|
+
preferOnline: true,
|
|
1069
|
+
where: void 0
|
|
1070
|
+
};
|
|
1071
|
+
SOURCE_PRIORITY = {
|
|
1072
|
+
direct: 0,
|
|
1073
|
+
dependency: 1,
|
|
1074
|
+
peerDependency: 2
|
|
1075
|
+
};
|
|
1076
|
+
}
|
|
1077
|
+
});
|
|
1016
1078
|
|
|
1017
1079
|
// src/core/build-cache.ts
|
|
1018
1080
|
import fs7 from "fs-extra";
|
|
1019
1081
|
import path8 from "path";
|
|
1020
1082
|
async function getBuildCachePath(configContent, tmpDir) {
|
|
1021
1083
|
const cacheDir = getTmpPath(tmpDir, "cache", "builds");
|
|
1022
|
-
const cacheKey = await
|
|
1084
|
+
const cacheKey = await getFlowSettingsCacheKey(configContent);
|
|
1023
1085
|
return path8.join(cacheDir, `${cacheKey}.js`);
|
|
1024
1086
|
}
|
|
1025
1087
|
async function isBuildCached(configContent, tmpDir) {
|
|
@@ -1038,8 +1100,20 @@ async function getCachedBuild(configContent, tmpDir) {
|
|
|
1038
1100
|
}
|
|
1039
1101
|
return null;
|
|
1040
1102
|
}
|
|
1103
|
+
var init_build_cache = __esm({
|
|
1104
|
+
"src/core/build-cache.ts"() {
|
|
1105
|
+
"use strict";
|
|
1106
|
+
init_cache_utils();
|
|
1107
|
+
init_tmp();
|
|
1108
|
+
}
|
|
1109
|
+
});
|
|
1041
1110
|
|
|
1042
1111
|
// src/commands/bundle/bundler.ts
|
|
1112
|
+
import crypto2 from "crypto";
|
|
1113
|
+
import esbuild from "esbuild";
|
|
1114
|
+
import path9 from "path";
|
|
1115
|
+
import fs8 from "fs-extra";
|
|
1116
|
+
import { packageNameToVariable, ENV_MARKER_PREFIX } from "@walkeros/core";
|
|
1043
1117
|
function isInlineCode(code) {
|
|
1044
1118
|
return code !== null && typeof code === "object" && !Array.isArray(code) && "push" in code;
|
|
1045
1119
|
}
|
|
@@ -1085,7 +1159,7 @@ function generateInlineCode(inline, config, env, chain, chainPropertyName, isDes
|
|
|
1085
1159
|
${chainLine.slice(0, -1)}` : ""}
|
|
1086
1160
|
}`;
|
|
1087
1161
|
}
|
|
1088
|
-
async function copyIncludes(includes, sourceDir, outputDir,
|
|
1162
|
+
async function copyIncludes(includes, sourceDir, outputDir, logger) {
|
|
1089
1163
|
for (const include of includes) {
|
|
1090
1164
|
const sourcePath = path9.resolve(sourceDir, include);
|
|
1091
1165
|
const folderName = path9.basename(include);
|
|
@@ -1099,15 +1173,15 @@ async function copyIncludes(includes, sourceDir, outputDir, logger2) {
|
|
|
1099
1173
|
}
|
|
1100
1174
|
if (await fs8.pathExists(sourcePath)) {
|
|
1101
1175
|
await fs8.copy(sourcePath, destPath);
|
|
1102
|
-
|
|
1176
|
+
logger.debug(`Copied ${include} to output`);
|
|
1103
1177
|
} else {
|
|
1104
|
-
|
|
1178
|
+
logger.warn(`Include folder not found: ${include}`);
|
|
1105
1179
|
}
|
|
1106
1180
|
}
|
|
1107
1181
|
}
|
|
1108
|
-
function generateCacheKeyContent(
|
|
1182
|
+
function generateCacheKeyContent(flowSettings, buildOptions) {
|
|
1109
1183
|
const configForCache = {
|
|
1110
|
-
flow:
|
|
1184
|
+
flow: flowSettings,
|
|
1111
1185
|
build: {
|
|
1112
1186
|
...buildOptions,
|
|
1113
1187
|
// Exclude non-deterministic fields from cache key
|
|
@@ -1117,62 +1191,64 @@ function generateCacheKeyContent(flowConfig, buildOptions) {
|
|
|
1117
1191
|
};
|
|
1118
1192
|
return JSON.stringify(configForCache);
|
|
1119
1193
|
}
|
|
1120
|
-
function
|
|
1194
|
+
function validateFlowConfig2(flowSettings, logger) {
|
|
1121
1195
|
let hasDeprecatedCodeTrue = false;
|
|
1122
|
-
const sources =
|
|
1196
|
+
const sources = flowSettings.sources || {};
|
|
1123
1197
|
for (const [sourceId, source] of Object.entries(sources)) {
|
|
1124
1198
|
if (source && typeof source === "object" && source.code === true) {
|
|
1125
|
-
|
|
1199
|
+
logger.warn(
|
|
1126
1200
|
`DEPRECATED: Source "${sourceId}" uses code: true which is no longer supported. Use $code: prefix in config values or create a source package instead.`
|
|
1127
1201
|
);
|
|
1128
1202
|
hasDeprecatedCodeTrue = true;
|
|
1129
1203
|
}
|
|
1130
1204
|
}
|
|
1131
|
-
const destinations =
|
|
1205
|
+
const destinations = flowSettings.destinations || {};
|
|
1132
1206
|
for (const [destId, dest] of Object.entries(destinations)) {
|
|
1133
1207
|
if (dest && typeof dest === "object" && dest.code === true) {
|
|
1134
|
-
|
|
1208
|
+
logger.warn(
|
|
1135
1209
|
`DEPRECATED: Destination "${destId}" uses code: true which is no longer supported. Use $code: prefix in config values or create a destination package instead.`
|
|
1136
1210
|
);
|
|
1137
1211
|
hasDeprecatedCodeTrue = true;
|
|
1138
1212
|
}
|
|
1139
1213
|
}
|
|
1140
|
-
const transformers =
|
|
1214
|
+
const transformers = flowSettings.transformers || {};
|
|
1141
1215
|
for (const [transformerId, transformer] of Object.entries(transformers)) {
|
|
1142
1216
|
if (transformer && typeof transformer === "object" && transformer.code === true) {
|
|
1143
|
-
|
|
1217
|
+
logger.warn(
|
|
1144
1218
|
`DEPRECATED: Transformer "${transformerId}" uses code: true which is no longer supported. Use $code: prefix in config values or create a transformer package instead.`
|
|
1145
1219
|
);
|
|
1146
1220
|
hasDeprecatedCodeTrue = true;
|
|
1147
1221
|
}
|
|
1148
1222
|
}
|
|
1149
1223
|
if (hasDeprecatedCodeTrue) {
|
|
1150
|
-
|
|
1224
|
+
logger.warn(
|
|
1151
1225
|
`See https://www.elbwalker.com/docs/walkeros/getting-started/flow for migration guide.`
|
|
1152
1226
|
);
|
|
1153
1227
|
}
|
|
1154
1228
|
return hasDeprecatedCodeTrue;
|
|
1155
1229
|
}
|
|
1156
|
-
async function bundleCore(
|
|
1230
|
+
async function bundleCore(flowSettings, buildOptions, logger, showStats = false) {
|
|
1157
1231
|
const bundleStartTime = Date.now();
|
|
1158
|
-
const hasDeprecatedFeatures =
|
|
1232
|
+
const hasDeprecatedFeatures = validateFlowConfig2(flowSettings, logger);
|
|
1159
1233
|
if (hasDeprecatedFeatures) {
|
|
1160
|
-
|
|
1234
|
+
logger.warn("Skipping deprecated code: true entries from bundle.");
|
|
1161
1235
|
}
|
|
1162
|
-
const
|
|
1236
|
+
const buildId = crypto2.randomUUID();
|
|
1237
|
+
const TEMP_DIR = buildOptions.tempDir || getTmpPath(void 0, `walkeros-build-${buildId}`);
|
|
1238
|
+
const CACHE_DIR = buildOptions.tempDir || getTmpPath();
|
|
1163
1239
|
if (buildOptions.cache !== false) {
|
|
1164
|
-
const configContent = generateCacheKeyContent(
|
|
1165
|
-
const cached = await isBuildCached(configContent,
|
|
1240
|
+
const configContent = generateCacheKeyContent(flowSettings, buildOptions);
|
|
1241
|
+
const cached = await isBuildCached(configContent, CACHE_DIR);
|
|
1166
1242
|
if (cached) {
|
|
1167
|
-
const cachedBuild = await getCachedBuild(configContent,
|
|
1243
|
+
const cachedBuild = await getCachedBuild(configContent, CACHE_DIR);
|
|
1168
1244
|
if (cachedBuild) {
|
|
1169
|
-
|
|
1245
|
+
logger.debug("Using cached build");
|
|
1170
1246
|
const outputPath = path9.resolve(buildOptions.output);
|
|
1171
1247
|
await fs8.ensureDir(path9.dirname(outputPath));
|
|
1172
1248
|
await fs8.writeFile(outputPath, cachedBuild);
|
|
1173
1249
|
const stats = await fs8.stat(outputPath);
|
|
1174
1250
|
const sizeKB = (stats.size / 1024).toFixed(1);
|
|
1175
|
-
|
|
1251
|
+
logger.info(`Output: ${outputPath} (${sizeKB} KB, cached)`);
|
|
1176
1252
|
if (showStats) {
|
|
1177
1253
|
const stats2 = await fs8.stat(outputPath);
|
|
1178
1254
|
const packageStats = Object.entries(buildOptions.packages).map(
|
|
@@ -1199,14 +1275,14 @@ async function bundleCore(flowConfig, buildOptions, logger2, showStats = false)
|
|
|
1199
1275
|
try {
|
|
1200
1276
|
await fs8.ensureDir(TEMP_DIR);
|
|
1201
1277
|
const hasSourcesOrDests = Object.keys(
|
|
1202
|
-
|
|
1278
|
+
flowSettings.sources || {}
|
|
1203
1279
|
).length > 0 || Object.keys(
|
|
1204
|
-
|
|
1280
|
+
flowSettings.destinations || {}
|
|
1205
1281
|
).length > 0;
|
|
1206
1282
|
if (hasSourcesOrDests && !buildOptions.packages["@walkeros/collector"]) {
|
|
1207
1283
|
buildOptions.packages["@walkeros/collector"] = {};
|
|
1208
1284
|
}
|
|
1209
|
-
|
|
1285
|
+
logger.debug("Downloading packages");
|
|
1210
1286
|
const packagesArray = Object.entries(buildOptions.packages).map(
|
|
1211
1287
|
([name, packageConfig]) => ({
|
|
1212
1288
|
name,
|
|
@@ -1218,11 +1294,11 @@ async function bundleCore(flowConfig, buildOptions, logger2, showStats = false)
|
|
|
1218
1294
|
const packagePaths = await downloadPackages(
|
|
1219
1295
|
packagesArray,
|
|
1220
1296
|
TEMP_DIR,
|
|
1221
|
-
|
|
1297
|
+
logger,
|
|
1222
1298
|
buildOptions.cache,
|
|
1223
1299
|
buildOptions.configDir,
|
|
1224
1300
|
// For resolving relative local paths
|
|
1225
|
-
|
|
1301
|
+
CACHE_DIR
|
|
1226
1302
|
);
|
|
1227
1303
|
for (const [pkgName, pkgPath] of packagePaths.entries()) {
|
|
1228
1304
|
if (pkgName.startsWith("@walkeros/")) {
|
|
@@ -1244,15 +1320,15 @@ async function bundleCore(flowConfig, buildOptions, logger2, showStats = false)
|
|
|
1244
1320
|
packageJsonPath,
|
|
1245
1321
|
JSON.stringify({ type: "module" }, null, 2)
|
|
1246
1322
|
);
|
|
1247
|
-
|
|
1323
|
+
logger.debug("Creating entry point");
|
|
1248
1324
|
const entryContent = await createEntryPoint(
|
|
1249
|
-
|
|
1325
|
+
flowSettings,
|
|
1250
1326
|
buildOptions,
|
|
1251
1327
|
packagePaths
|
|
1252
1328
|
);
|
|
1253
1329
|
const entryPath = path9.join(TEMP_DIR, "entry.js");
|
|
1254
1330
|
await fs8.writeFile(entryPath, entryContent);
|
|
1255
|
-
|
|
1331
|
+
logger.debug(
|
|
1256
1332
|
`Running esbuild (target: ${buildOptions.target || "es2018"}, format: ${buildOptions.format})`
|
|
1257
1333
|
);
|
|
1258
1334
|
const outputPath = path9.resolve(buildOptions.output);
|
|
@@ -1263,7 +1339,7 @@ async function bundleCore(flowConfig, buildOptions, logger2, showStats = false)
|
|
|
1263
1339
|
outputPath,
|
|
1264
1340
|
TEMP_DIR,
|
|
1265
1341
|
packagePaths,
|
|
1266
|
-
|
|
1342
|
+
logger
|
|
1267
1343
|
);
|
|
1268
1344
|
try {
|
|
1269
1345
|
await esbuild.build(esbuildOptions);
|
|
@@ -1278,12 +1354,12 @@ async function bundleCore(flowConfig, buildOptions, logger2, showStats = false)
|
|
|
1278
1354
|
const outputStats = await fs8.stat(outputPath);
|
|
1279
1355
|
const sizeKB = (outputStats.size / 1024).toFixed(1);
|
|
1280
1356
|
const buildTime = ((Date.now() - bundleStartTime) / 1e3).toFixed(1);
|
|
1281
|
-
|
|
1357
|
+
logger.info(`Output: ${outputPath} (${sizeKB} KB, ${buildTime}s)`);
|
|
1282
1358
|
if (buildOptions.cache !== false) {
|
|
1283
|
-
const configContent = generateCacheKeyContent(
|
|
1359
|
+
const configContent = generateCacheKeyContent(flowSettings, buildOptions);
|
|
1284
1360
|
const buildOutput = await fs8.readFile(outputPath, "utf-8");
|
|
1285
|
-
await cacheBuild(configContent, buildOutput,
|
|
1286
|
-
|
|
1361
|
+
await cacheBuild(configContent, buildOutput, CACHE_DIR);
|
|
1362
|
+
logger.debug("Build cached for future use");
|
|
1287
1363
|
}
|
|
1288
1364
|
let stats;
|
|
1289
1365
|
if (showStats) {
|
|
@@ -1300,12 +1376,17 @@ async function bundleCore(flowConfig, buildOptions, logger2, showStats = false)
|
|
|
1300
1376
|
buildOptions.include,
|
|
1301
1377
|
buildOptions.configDir || process.cwd(),
|
|
1302
1378
|
outputDir,
|
|
1303
|
-
|
|
1379
|
+
logger
|
|
1304
1380
|
);
|
|
1305
1381
|
}
|
|
1306
1382
|
return stats;
|
|
1307
1383
|
} catch (error) {
|
|
1308
1384
|
throw error;
|
|
1385
|
+
} finally {
|
|
1386
|
+
if (!buildOptions.tempDir) {
|
|
1387
|
+
fs8.remove(TEMP_DIR).catch(() => {
|
|
1388
|
+
});
|
|
1389
|
+
}
|
|
1309
1390
|
}
|
|
1310
1391
|
}
|
|
1311
1392
|
async function collectBundleStats(outputPath, packages, startTime, entryContent) {
|
|
@@ -1335,7 +1416,7 @@ async function collectBundleStats(outputPath, packages, startTime, entryContent)
|
|
|
1335
1416
|
treeshakingEffective
|
|
1336
1417
|
};
|
|
1337
1418
|
}
|
|
1338
|
-
function createEsbuildOptions(buildOptions, entryPath, outputPath, tempDir, packagePaths,
|
|
1419
|
+
function createEsbuildOptions(buildOptions, entryPath, outputPath, tempDir, packagePaths, logger) {
|
|
1339
1420
|
const alias = {};
|
|
1340
1421
|
const baseOptions = {
|
|
1341
1422
|
entryPoints: [entryPath],
|
|
@@ -1403,9 +1484,9 @@ function createEsbuildOptions(buildOptions, entryPath, outputPath, tempDir, pack
|
|
|
1403
1484
|
}
|
|
1404
1485
|
return baseOptions;
|
|
1405
1486
|
}
|
|
1406
|
-
function detectDestinationPackages(
|
|
1487
|
+
function detectDestinationPackages(flowSettings) {
|
|
1407
1488
|
const destinationPackages = /* @__PURE__ */ new Set();
|
|
1408
|
-
const destinations =
|
|
1489
|
+
const destinations = flowSettings.destinations;
|
|
1409
1490
|
if (destinations) {
|
|
1410
1491
|
for (const [destKey, destConfig] of Object.entries(destinations)) {
|
|
1411
1492
|
if (typeof destConfig === "object" && destConfig !== null && "code" in destConfig && destConfig.code === true) {
|
|
@@ -1418,9 +1499,9 @@ function detectDestinationPackages(flowConfig) {
|
|
|
1418
1499
|
}
|
|
1419
1500
|
return destinationPackages;
|
|
1420
1501
|
}
|
|
1421
|
-
function detectSourcePackages(
|
|
1502
|
+
function detectSourcePackages(flowSettings) {
|
|
1422
1503
|
const sourcePackages = /* @__PURE__ */ new Set();
|
|
1423
|
-
const sources =
|
|
1504
|
+
const sources = flowSettings.sources;
|
|
1424
1505
|
if (sources) {
|
|
1425
1506
|
for (const [sourceKey, sourceConfig] of Object.entries(sources)) {
|
|
1426
1507
|
if (typeof sourceConfig === "object" && sourceConfig !== null && "code" in sourceConfig && sourceConfig.code === true) {
|
|
@@ -1433,9 +1514,9 @@ function detectSourcePackages(flowConfig) {
|
|
|
1433
1514
|
}
|
|
1434
1515
|
return sourcePackages;
|
|
1435
1516
|
}
|
|
1436
|
-
function detectTransformerPackages(
|
|
1517
|
+
function detectTransformerPackages(flowSettings) {
|
|
1437
1518
|
const transformerPackages = /* @__PURE__ */ new Set();
|
|
1438
|
-
const transformers =
|
|
1519
|
+
const transformers = flowSettings.transformers;
|
|
1439
1520
|
if (transformers) {
|
|
1440
1521
|
for (const [transformerKey, transformerConfig] of Object.entries(
|
|
1441
1522
|
transformers
|
|
@@ -1450,9 +1531,9 @@ function detectTransformerPackages(flowConfig) {
|
|
|
1450
1531
|
}
|
|
1451
1532
|
return transformerPackages;
|
|
1452
1533
|
}
|
|
1453
|
-
function detectStorePackages(
|
|
1534
|
+
function detectStorePackages(flowSettings) {
|
|
1454
1535
|
const storePackages = /* @__PURE__ */ new Set();
|
|
1455
|
-
const stores =
|
|
1536
|
+
const stores = flowSettings.stores;
|
|
1456
1537
|
if (stores) {
|
|
1457
1538
|
for (const [, storeConfig] of Object.entries(stores)) {
|
|
1458
1539
|
if (typeof storeConfig === "object" && storeConfig !== null && "package" in storeConfig && typeof storeConfig.package === "string") {
|
|
@@ -1462,9 +1543,9 @@ function detectStorePackages(flowConfig) {
|
|
|
1462
1543
|
}
|
|
1463
1544
|
return storePackages;
|
|
1464
1545
|
}
|
|
1465
|
-
function detectExplicitCodeImports(
|
|
1546
|
+
function detectExplicitCodeImports(flowSettings) {
|
|
1466
1547
|
const explicitCodeImports = /* @__PURE__ */ new Map();
|
|
1467
|
-
const destinations =
|
|
1548
|
+
const destinations = flowSettings.destinations;
|
|
1468
1549
|
if (destinations) {
|
|
1469
1550
|
for (const [destKey, destConfig] of Object.entries(destinations)) {
|
|
1470
1551
|
if (typeof destConfig === "object" && destConfig !== null && "code" in destConfig && destConfig.code === true) {
|
|
@@ -1481,7 +1562,7 @@ function detectExplicitCodeImports(flowConfig) {
|
|
|
1481
1562
|
}
|
|
1482
1563
|
}
|
|
1483
1564
|
}
|
|
1484
|
-
const sources =
|
|
1565
|
+
const sources = flowSettings.sources;
|
|
1485
1566
|
if (sources) {
|
|
1486
1567
|
for (const [sourceKey, sourceConfig] of Object.entries(sources)) {
|
|
1487
1568
|
if (typeof sourceConfig === "object" && sourceConfig !== null && "code" in sourceConfig && sourceConfig.code === true) {
|
|
@@ -1498,7 +1579,7 @@ function detectExplicitCodeImports(flowConfig) {
|
|
|
1498
1579
|
}
|
|
1499
1580
|
}
|
|
1500
1581
|
}
|
|
1501
|
-
const transformers =
|
|
1582
|
+
const transformers = flowSettings.transformers;
|
|
1502
1583
|
if (transformers) {
|
|
1503
1584
|
for (const [transformerKey, transformerConfig] of Object.entries(
|
|
1504
1585
|
transformers
|
|
@@ -1517,7 +1598,7 @@ function detectExplicitCodeImports(flowConfig) {
|
|
|
1517
1598
|
}
|
|
1518
1599
|
}
|
|
1519
1600
|
}
|
|
1520
|
-
const stores =
|
|
1601
|
+
const stores = flowSettings.stores;
|
|
1521
1602
|
if (stores) {
|
|
1522
1603
|
for (const [, storeConfig] of Object.entries(stores)) {
|
|
1523
1604
|
if (typeof storeConfig === "object" && storeConfig !== null && "package" in storeConfig && typeof storeConfig.package === "string" && "code" in storeConfig && typeof storeConfig.code === "string") {
|
|
@@ -1596,7 +1677,6 @@ function generateImportStatements(packages, destinationPackages, sourcePackages,
|
|
|
1596
1677
|
}
|
|
1597
1678
|
return { importStatements, examplesMappings };
|
|
1598
1679
|
}
|
|
1599
|
-
var VALID_JS_IDENTIFIER = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
|
|
1600
1680
|
function validateComponentNames(components, section) {
|
|
1601
1681
|
for (const name of Object.keys(components)) {
|
|
1602
1682
|
if (!VALID_JS_IDENTIFIER.test(name)) {
|
|
@@ -1606,7 +1686,7 @@ function validateComponentNames(components, section) {
|
|
|
1606
1686
|
}
|
|
1607
1687
|
}
|
|
1608
1688
|
}
|
|
1609
|
-
function validateStoreReferences(
|
|
1689
|
+
function validateStoreReferences(flowSettings, storeIds) {
|
|
1610
1690
|
const refs = [];
|
|
1611
1691
|
function collectRefs(obj, path15) {
|
|
1612
1692
|
if (typeof obj === "string" && obj.startsWith("$store:")) {
|
|
@@ -1618,9 +1698,9 @@ function validateStoreReferences(flowConfig, storeIds) {
|
|
|
1618
1698
|
}
|
|
1619
1699
|
}
|
|
1620
1700
|
for (const [section, components] of Object.entries({
|
|
1621
|
-
sources:
|
|
1622
|
-
destinations:
|
|
1623
|
-
transformers:
|
|
1701
|
+
sources: flowSettings.sources || {},
|
|
1702
|
+
destinations: flowSettings.destinations || {},
|
|
1703
|
+
transformers: flowSettings.transformers || {}
|
|
1624
1704
|
})) {
|
|
1625
1705
|
for (const [id, component] of Object.entries(
|
|
1626
1706
|
components
|
|
@@ -1637,19 +1717,19 @@ function validateStoreReferences(flowConfig, storeIds) {
|
|
|
1637
1717
|
}
|
|
1638
1718
|
}
|
|
1639
1719
|
}
|
|
1640
|
-
async function createEntryPoint(
|
|
1641
|
-
const destinationPackages = detectDestinationPackages(
|
|
1642
|
-
const sourcePackages = detectSourcePackages(
|
|
1643
|
-
const transformerPackages = detectTransformerPackages(
|
|
1644
|
-
const storePackages = detectStorePackages(
|
|
1645
|
-
const explicitCodeImports = detectExplicitCodeImports(
|
|
1720
|
+
async function createEntryPoint(flowSettings, buildOptions, packagePaths) {
|
|
1721
|
+
const destinationPackages = detectDestinationPackages(flowSettings);
|
|
1722
|
+
const sourcePackages = detectSourcePackages(flowSettings);
|
|
1723
|
+
const transformerPackages = detectTransformerPackages(flowSettings);
|
|
1724
|
+
const storePackages = detectStorePackages(flowSettings);
|
|
1725
|
+
const explicitCodeImports = detectExplicitCodeImports(flowSettings);
|
|
1646
1726
|
const storeIds = new Set(
|
|
1647
1727
|
Object.keys(
|
|
1648
|
-
|
|
1728
|
+
flowSettings.stores || {}
|
|
1649
1729
|
)
|
|
1650
1730
|
);
|
|
1651
|
-
validateStoreReferences(
|
|
1652
|
-
const flowWithSections =
|
|
1731
|
+
validateStoreReferences(flowSettings, storeIds);
|
|
1732
|
+
const flowWithSections = flowSettings;
|
|
1653
1733
|
if (flowWithSections.sources)
|
|
1654
1734
|
validateComponentNames(flowWithSections.sources, "sources");
|
|
1655
1735
|
if (flowWithSections.destinations)
|
|
@@ -1667,9 +1747,9 @@ async function createEntryPoint(flowConfig, buildOptions, packagePaths) {
|
|
|
1667
1747
|
explicitCodeImports
|
|
1668
1748
|
);
|
|
1669
1749
|
const importsCode = importStatements.join("\n");
|
|
1670
|
-
const hasFlow = Object.values(
|
|
1750
|
+
const hasFlow = Object.values(flowSettings.sources || {}).some(
|
|
1671
1751
|
(s2) => s2.package || isInlineCode(s2.code)
|
|
1672
|
-
) || Object.values(
|
|
1752
|
+
) || Object.values(flowSettings.destinations || {}).some(
|
|
1673
1753
|
(d2) => d2.package || isInlineCode(d2.code)
|
|
1674
1754
|
);
|
|
1675
1755
|
if (!hasFlow) {
|
|
@@ -1678,8 +1758,12 @@ async function createEntryPoint(flowConfig, buildOptions, packagePaths) {
|
|
|
1678
1758
|
|
|
1679
1759
|
${userCode}` : userCode;
|
|
1680
1760
|
}
|
|
1681
|
-
const configObject = buildConfigObject(
|
|
1761
|
+
const { storesDeclaration, configObject } = buildConfigObject(
|
|
1762
|
+
flowSettings,
|
|
1763
|
+
explicitCodeImports
|
|
1764
|
+
);
|
|
1682
1765
|
const wrappedCode = generatePlatformWrapper(
|
|
1766
|
+
storesDeclaration,
|
|
1683
1767
|
configObject,
|
|
1684
1768
|
buildOptions.code || "",
|
|
1685
1769
|
buildOptions
|
|
@@ -1711,8 +1795,8 @@ ${firstError.text}`
|
|
|
1711
1795
|
` + (location ? ` at ${location.file}:${location.line}:${location.column}` : "")
|
|
1712
1796
|
);
|
|
1713
1797
|
}
|
|
1714
|
-
function buildConfigObject(
|
|
1715
|
-
const flowWithProps =
|
|
1798
|
+
function buildConfigObject(flowSettings, explicitCodeImports) {
|
|
1799
|
+
const flowWithProps = flowSettings;
|
|
1716
1800
|
const sources = flowWithProps.sources || {};
|
|
1717
1801
|
const destinations = flowWithProps.destinations || {};
|
|
1718
1802
|
const transformers = flowWithProps.transformers || {};
|
|
@@ -1821,24 +1905,25 @@ function buildConfigObject(flowConfig, explicitCodeImports) {
|
|
|
1821
1905
|
config: ${configStr}${envStr}
|
|
1822
1906
|
}`;
|
|
1823
1907
|
});
|
|
1908
|
+
const storesDeclaration = storesEntries.length > 0 ? `const stores = {
|
|
1909
|
+
${storesEntries.join(",\n")}
|
|
1910
|
+
};` : "const stores = {};";
|
|
1824
1911
|
const collectorStr = flowWithProps.collector ? `,
|
|
1825
1912
|
...${processConfigValue(flowWithProps.collector)}` : "";
|
|
1826
1913
|
const transformersStr = transformersEntries.length > 0 ? `,
|
|
1827
1914
|
transformers: {
|
|
1828
1915
|
${transformersEntries.join(",\n")}
|
|
1829
1916
|
}` : "";
|
|
1830
|
-
const
|
|
1831
|
-
stores: {
|
|
1832
|
-
${storesEntries.join(",\n")}
|
|
1833
|
-
}` : "";
|
|
1834
|
-
return `{
|
|
1917
|
+
const configObject = `{
|
|
1835
1918
|
sources: {
|
|
1836
1919
|
${sourcesEntries.join(",\n")}
|
|
1837
1920
|
},
|
|
1838
1921
|
destinations: {
|
|
1839
1922
|
${destinationsEntries.join(",\n")}
|
|
1840
|
-
}${transformersStr}
|
|
1923
|
+
}${transformersStr},
|
|
1924
|
+
stores${collectorStr}
|
|
1841
1925
|
}`;
|
|
1926
|
+
return { storesDeclaration, configObject };
|
|
1842
1927
|
}
|
|
1843
1928
|
function processConfigValue(value) {
|
|
1844
1929
|
return serializeWithCode(value, 0);
|
|
@@ -1907,7 +1992,7 @@ ${spaces}}`;
|
|
|
1907
1992
|
}
|
|
1908
1993
|
return JSON.stringify(value);
|
|
1909
1994
|
}
|
|
1910
|
-
function generatePlatformWrapper(configObject, userCode, buildOptions) {
|
|
1995
|
+
function generatePlatformWrapper(storesDeclaration, configObject, userCode, buildOptions) {
|
|
1911
1996
|
if (buildOptions.platform === "browser") {
|
|
1912
1997
|
const windowAssignments = [];
|
|
1913
1998
|
if (buildOptions.windowCollector) {
|
|
@@ -1922,6 +2007,8 @@ function generatePlatformWrapper(configObject, userCode, buildOptions) {
|
|
|
1922
2007
|
}
|
|
1923
2008
|
const assignments = windowAssignments.length > 0 ? "\n" + windowAssignments.join("\n") : "";
|
|
1924
2009
|
return `(async () => {
|
|
2010
|
+
${storesDeclaration}
|
|
2011
|
+
|
|
1925
2012
|
const config = ${configObject};
|
|
1926
2013
|
|
|
1927
2014
|
${userCode}
|
|
@@ -1933,6 +2020,8 @@ function generatePlatformWrapper(configObject, userCode, buildOptions) {
|
|
|
1933
2020
|
${userCode}
|
|
1934
2021
|
` : "";
|
|
1935
2022
|
return `export default async function(context = {}) {
|
|
2023
|
+
${storesDeclaration}
|
|
2024
|
+
|
|
1936
2025
|
const config = ${configObject};${codeSection}
|
|
1937
2026
|
// Apply context overrides (e.g., logger config from CLI)
|
|
1938
2027
|
if (context.logger) {
|
|
@@ -1959,6 +2048,16 @@ function generatePlatformWrapper(configObject, userCode, buildOptions) {
|
|
|
1959
2048
|
}`;
|
|
1960
2049
|
}
|
|
1961
2050
|
}
|
|
2051
|
+
var VALID_JS_IDENTIFIER;
|
|
2052
|
+
var init_bundler = __esm({
|
|
2053
|
+
"src/commands/bundle/bundler.ts"() {
|
|
2054
|
+
"use strict";
|
|
2055
|
+
init_package_manager();
|
|
2056
|
+
init_tmp();
|
|
2057
|
+
init_build_cache();
|
|
2058
|
+
VALID_JS_IDENTIFIER = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
|
|
2059
|
+
}
|
|
2060
|
+
});
|
|
1962
2061
|
|
|
1963
2062
|
// src/commands/bundle/upload.ts
|
|
1964
2063
|
import fs9 from "fs-extra";
|
|
@@ -1988,32 +2087,42 @@ async function uploadBundleToUrl(filePath, url, timeoutMs = 3e4) {
|
|
|
1988
2087
|
};
|
|
1989
2088
|
await doUpload(1);
|
|
1990
2089
|
}
|
|
2090
|
+
var init_upload = __esm({
|
|
2091
|
+
"src/commands/bundle/upload.ts"() {
|
|
2092
|
+
"use strict";
|
|
2093
|
+
}
|
|
2094
|
+
});
|
|
1991
2095
|
|
|
1992
2096
|
// src/commands/bundle/stats.ts
|
|
1993
|
-
function displayStats(stats,
|
|
1994
|
-
|
|
1995
|
-
|
|
2097
|
+
function displayStats(stats, logger) {
|
|
2098
|
+
logger.info("\n\u{1F4CA} Bundle Statistics");
|
|
2099
|
+
logger.info("\u2500".repeat(50));
|
|
1996
2100
|
const sizeKB = formatBytes(stats.totalSize);
|
|
1997
|
-
|
|
2101
|
+
logger.info(`Total Size: ${sizeKB} KB`);
|
|
1998
2102
|
const timeSeconds = (stats.buildTime / 1e3).toFixed(2);
|
|
1999
|
-
|
|
2103
|
+
logger.info(`Build Time: ${timeSeconds}s`);
|
|
2000
2104
|
const treeshakingStatus = stats.treeshakingEffective ? "\u2705 Effective" : "\u26A0\uFE0F Not optimal (consider using named imports)";
|
|
2001
|
-
|
|
2105
|
+
logger.info(`Tree-shaking: ${treeshakingStatus}`);
|
|
2002
2106
|
if (stats.packages.length > 0) {
|
|
2003
|
-
|
|
2107
|
+
logger.info(`
|
|
2004
2108
|
Package Breakdown:`);
|
|
2005
2109
|
stats.packages.forEach((pkg) => {
|
|
2006
2110
|
if (pkg.size > 0) {
|
|
2007
2111
|
const pkgSizeKB = formatBytes(pkg.size);
|
|
2008
|
-
|
|
2112
|
+
logger.info(` \u2022 ${pkg.name}: ${pkgSizeKB} KB`);
|
|
2009
2113
|
}
|
|
2010
2114
|
});
|
|
2011
2115
|
}
|
|
2012
|
-
|
|
2116
|
+
logger.info("\u2500".repeat(50));
|
|
2013
2117
|
}
|
|
2118
|
+
var init_stats = __esm({
|
|
2119
|
+
"src/commands/bundle/stats.ts"() {
|
|
2120
|
+
"use strict";
|
|
2121
|
+
init_core();
|
|
2122
|
+
}
|
|
2123
|
+
});
|
|
2014
2124
|
|
|
2015
2125
|
// src/core/api-client.ts
|
|
2016
|
-
init_auth();
|
|
2017
2126
|
import createClient from "openapi-fetch";
|
|
2018
2127
|
function createApiClient() {
|
|
2019
2128
|
const token = getToken();
|
|
@@ -2026,6 +2135,12 @@ function createApiClient() {
|
|
|
2026
2135
|
}
|
|
2027
2136
|
});
|
|
2028
2137
|
}
|
|
2138
|
+
var init_api_client = __esm({
|
|
2139
|
+
"src/core/api-client.ts"() {
|
|
2140
|
+
"use strict";
|
|
2141
|
+
init_auth();
|
|
2142
|
+
}
|
|
2143
|
+
});
|
|
2029
2144
|
|
|
2030
2145
|
// src/commands/bundle/dockerfile.ts
|
|
2031
2146
|
import path10 from "path";
|
|
@@ -2045,19 +2160,27 @@ function buildDockerfileContent(platform, includedFolders) {
|
|
|
2045
2160
|
lines.push("", `ENV BUNDLE=/app/flow/${bundleFile}`, "", "EXPOSE 8080", "");
|
|
2046
2161
|
return lines.join("\n");
|
|
2047
2162
|
}
|
|
2048
|
-
async function generateDockerfile(outputDir, platform,
|
|
2163
|
+
async function generateDockerfile(outputDir, platform, logger, customFile, includedFolders) {
|
|
2049
2164
|
const destPath = path10.join(outputDir, "Dockerfile");
|
|
2050
2165
|
if (customFile && await fs10.pathExists(customFile)) {
|
|
2051
2166
|
await fs10.copy(customFile, destPath);
|
|
2052
|
-
|
|
2167
|
+
logger.info(`Dockerfile: ${destPath} (copied from ${customFile})`);
|
|
2053
2168
|
return;
|
|
2054
2169
|
}
|
|
2055
2170
|
const dockerfile = buildDockerfileContent(platform, includedFolders || []);
|
|
2056
2171
|
await fs10.writeFile(destPath, dockerfile);
|
|
2057
|
-
|
|
2172
|
+
logger.info(`Dockerfile: ${destPath}`);
|
|
2058
2173
|
}
|
|
2174
|
+
var init_dockerfile = __esm({
|
|
2175
|
+
"src/commands/bundle/dockerfile.ts"() {
|
|
2176
|
+
"use strict";
|
|
2177
|
+
}
|
|
2178
|
+
});
|
|
2059
2179
|
|
|
2060
2180
|
// src/commands/bundle/index.ts
|
|
2181
|
+
import path11 from "path";
|
|
2182
|
+
import fs11 from "fs-extra";
|
|
2183
|
+
import { getPlatform as getPlatform2 } from "@walkeros/core";
|
|
2061
2184
|
function resolveOutputPath(output, buildOptions) {
|
|
2062
2185
|
const resolved = path11.resolve(output);
|
|
2063
2186
|
const ext = path11.extname(resolved);
|
|
@@ -2071,7 +2194,7 @@ async function bundleCommand(options) {
|
|
|
2071
2194
|
const timer = createTimer();
|
|
2072
2195
|
timer.start();
|
|
2073
2196
|
const writingToStdout = !options.output;
|
|
2074
|
-
const
|
|
2197
|
+
const logger = createCLILogger({
|
|
2075
2198
|
...options,
|
|
2076
2199
|
stderr: writingToStdout
|
|
2077
2200
|
});
|
|
@@ -2099,16 +2222,16 @@ async function bundleCommand(options) {
|
|
|
2099
2222
|
configPath = resolveAsset(file, "config");
|
|
2100
2223
|
rawConfig = await loadJsonConfig(configPath);
|
|
2101
2224
|
}
|
|
2102
|
-
const configsToBundle = options.all ? loadAllFlows(rawConfig, { configPath, logger
|
|
2225
|
+
const configsToBundle = options.all ? loadAllFlows(rawConfig, { configPath, logger }) : [
|
|
2103
2226
|
loadBundleConfig(rawConfig, {
|
|
2104
2227
|
configPath,
|
|
2105
2228
|
flowName: options.flow,
|
|
2106
|
-
logger
|
|
2229
|
+
logger
|
|
2107
2230
|
})
|
|
2108
2231
|
];
|
|
2109
2232
|
const results = [];
|
|
2110
2233
|
for (const {
|
|
2111
|
-
|
|
2234
|
+
flowSettings,
|
|
2112
2235
|
buildOptions,
|
|
2113
2236
|
flowName,
|
|
2114
2237
|
isMultiFlow
|
|
@@ -2132,39 +2255,39 @@ async function bundleCommand(options) {
|
|
|
2132
2255
|
buildOptions.output = getTmpPath(void 0, "stdout-bundle" + ext);
|
|
2133
2256
|
}
|
|
2134
2257
|
if (isMultiFlow || options.all) {
|
|
2135
|
-
|
|
2258
|
+
logger.info(`Bundling flow: ${flowName}...`);
|
|
2136
2259
|
} else {
|
|
2137
|
-
|
|
2260
|
+
logger.info("Bundling...");
|
|
2138
2261
|
}
|
|
2139
2262
|
const shouldCollectStats = options.stats || options.json;
|
|
2140
2263
|
const stats = await bundleCore(
|
|
2141
|
-
|
|
2264
|
+
flowSettings,
|
|
2142
2265
|
buildOptions,
|
|
2143
|
-
|
|
2266
|
+
logger,
|
|
2144
2267
|
shouldCollectStats
|
|
2145
2268
|
);
|
|
2146
2269
|
results.push({ flowName, success: true, stats });
|
|
2147
2270
|
if (uploadUrl) {
|
|
2148
2271
|
await uploadBundleToUrl(buildOptions.output, uploadUrl);
|
|
2149
|
-
|
|
2272
|
+
logger.info(`Uploaded to: ${sanitizeUrl(uploadUrl)}`);
|
|
2150
2273
|
await fs11.remove(buildOptions.output);
|
|
2151
2274
|
}
|
|
2152
2275
|
if (!options.json && !options.all && options.stats && stats) {
|
|
2153
|
-
displayStats(stats,
|
|
2276
|
+
displayStats(stats, logger);
|
|
2154
2277
|
}
|
|
2155
2278
|
if (writingToStdout && !options.json) {
|
|
2156
2279
|
const bundleContent = await fs11.readFile(buildOptions.output);
|
|
2157
2280
|
await writeResult(bundleContent, {});
|
|
2158
2281
|
}
|
|
2159
2282
|
if (options.dockerfile && options.output) {
|
|
2160
|
-
const platform = getPlatform2(
|
|
2283
|
+
const platform = getPlatform2(flowSettings);
|
|
2161
2284
|
if (platform) {
|
|
2162
2285
|
const outputDir = path11.dirname(buildOptions.output);
|
|
2163
2286
|
const customFile = typeof options.dockerfile === "string" ? options.dockerfile : void 0;
|
|
2164
2287
|
await generateDockerfile(
|
|
2165
2288
|
outputDir,
|
|
2166
2289
|
platform,
|
|
2167
|
-
|
|
2290
|
+
logger,
|
|
2168
2291
|
customFile,
|
|
2169
2292
|
buildOptions.include
|
|
2170
2293
|
);
|
|
@@ -2201,12 +2324,12 @@ async function bundleCommand(options) {
|
|
|
2201
2324
|
});
|
|
2202
2325
|
} else {
|
|
2203
2326
|
if (options.all) {
|
|
2204
|
-
|
|
2327
|
+
logger.info(
|
|
2205
2328
|
`
|
|
2206
2329
|
Build Summary: ${successCount}/${results.length} succeeded`
|
|
2207
2330
|
);
|
|
2208
2331
|
if (failureCount > 0) {
|
|
2209
|
-
|
|
2332
|
+
logger.error(`Failed: ${failureCount}`);
|
|
2210
2333
|
}
|
|
2211
2334
|
}
|
|
2212
2335
|
if (failureCount > 0) {
|
|
@@ -2223,7 +2346,7 @@ Build Summary: ${successCount}/${results.length} succeeded`
|
|
|
2223
2346
|
output: options.output
|
|
2224
2347
|
});
|
|
2225
2348
|
} else {
|
|
2226
|
-
|
|
2349
|
+
logger.error(`Error: ${errorMessage}`);
|
|
2227
2350
|
}
|
|
2228
2351
|
process.exit(1);
|
|
2229
2352
|
}
|
|
@@ -2237,7 +2360,7 @@ async function bundle(configOrPath, options = {}) {
|
|
|
2237
2360
|
} else {
|
|
2238
2361
|
rawConfig = configOrPath;
|
|
2239
2362
|
}
|
|
2240
|
-
const {
|
|
2363
|
+
const { flowSettings, buildOptions } = loadBundleConfig(rawConfig, {
|
|
2241
2364
|
configPath,
|
|
2242
2365
|
flowName: options.flowName,
|
|
2243
2366
|
buildOverrides: options.buildOverrides
|
|
@@ -2245,11 +2368,11 @@ async function bundle(configOrPath, options = {}) {
|
|
|
2245
2368
|
if (options.cache !== void 0) {
|
|
2246
2369
|
buildOptions.cache = options.cache;
|
|
2247
2370
|
}
|
|
2248
|
-
const
|
|
2371
|
+
const logger = createCLILogger(options);
|
|
2249
2372
|
return await bundleCore(
|
|
2250
|
-
|
|
2373
|
+
flowSettings,
|
|
2251
2374
|
buildOptions,
|
|
2252
|
-
|
|
2375
|
+
logger,
|
|
2253
2376
|
options.stats ?? false
|
|
2254
2377
|
);
|
|
2255
2378
|
}
|
|
@@ -2271,6 +2394,110 @@ async function bundleRemote(options) {
|
|
|
2271
2394
|
stats: statsHeader ? JSON.parse(statsHeader) : void 0
|
|
2272
2395
|
};
|
|
2273
2396
|
}
|
|
2397
|
+
var init_bundle = __esm({
|
|
2398
|
+
"src/commands/bundle/index.ts"() {
|
|
2399
|
+
"use strict";
|
|
2400
|
+
init_cli_logger();
|
|
2401
|
+
init_core();
|
|
2402
|
+
init_config();
|
|
2403
|
+
init_utils();
|
|
2404
|
+
init_bundler();
|
|
2405
|
+
init_upload();
|
|
2406
|
+
init_stats();
|
|
2407
|
+
init_api_client();
|
|
2408
|
+
init_dockerfile();
|
|
2409
|
+
}
|
|
2410
|
+
});
|
|
2411
|
+
|
|
2412
|
+
// src/runtime/cache.ts
|
|
2413
|
+
var cache_exports = {};
|
|
2414
|
+
__export(cache_exports, {
|
|
2415
|
+
readCache: () => readCache,
|
|
2416
|
+
readCacheConfig: () => readCacheConfig,
|
|
2417
|
+
writeCache: () => writeCache
|
|
2418
|
+
});
|
|
2419
|
+
import {
|
|
2420
|
+
existsSync as existsSync4,
|
|
2421
|
+
mkdirSync as mkdirSync2,
|
|
2422
|
+
copyFileSync,
|
|
2423
|
+
writeFileSync as writeFileSync3,
|
|
2424
|
+
readFileSync as readFileSync2
|
|
2425
|
+
} from "fs";
|
|
2426
|
+
import { join as join2 } from "path";
|
|
2427
|
+
function writeCache(cacheDir, bundlePath, configContent, version) {
|
|
2428
|
+
mkdirSync2(cacheDir, { recursive: true });
|
|
2429
|
+
copyFileSync(bundlePath, join2(cacheDir, "bundle.mjs"));
|
|
2430
|
+
writeFileSync3(join2(cacheDir, "config.json"), configContent, "utf-8");
|
|
2431
|
+
const meta = { version, timestamp: Date.now() };
|
|
2432
|
+
writeFileSync3(join2(cacheDir, "meta.json"), JSON.stringify(meta), "utf-8");
|
|
2433
|
+
}
|
|
2434
|
+
function readCache(cacheDir) {
|
|
2435
|
+
try {
|
|
2436
|
+
const metaPath = join2(cacheDir, "meta.json");
|
|
2437
|
+
const bundlePath = join2(cacheDir, "bundle.mjs");
|
|
2438
|
+
if (!existsSync4(metaPath) || !existsSync4(bundlePath)) return null;
|
|
2439
|
+
const meta = JSON.parse(readFileSync2(metaPath, "utf-8"));
|
|
2440
|
+
return { bundlePath, version: meta.version };
|
|
2441
|
+
} catch {
|
|
2442
|
+
return null;
|
|
2443
|
+
}
|
|
2444
|
+
}
|
|
2445
|
+
function readCacheConfig(cacheDir) {
|
|
2446
|
+
try {
|
|
2447
|
+
const configPath = join2(cacheDir, "config.json");
|
|
2448
|
+
if (!existsSync4(configPath)) return null;
|
|
2449
|
+
return readFileSync2(configPath, "utf-8");
|
|
2450
|
+
} catch {
|
|
2451
|
+
return null;
|
|
2452
|
+
}
|
|
2453
|
+
}
|
|
2454
|
+
var init_cache = __esm({
|
|
2455
|
+
"src/runtime/cache.ts"() {
|
|
2456
|
+
"use strict";
|
|
2457
|
+
}
|
|
2458
|
+
});
|
|
2459
|
+
|
|
2460
|
+
// src/commands/run/utils.ts
|
|
2461
|
+
var utils_exports = {};
|
|
2462
|
+
__export(utils_exports, {
|
|
2463
|
+
isPreBuiltConfig: () => isPreBuiltConfig,
|
|
2464
|
+
prepareBundleForRun: () => prepareBundleForRun
|
|
2465
|
+
});
|
|
2466
|
+
import path13 from "path";
|
|
2467
|
+
import fs14 from "fs-extra";
|
|
2468
|
+
async function prepareBundleForRun(configPath, options) {
|
|
2469
|
+
const tempDir = getTmpPath(
|
|
2470
|
+
void 0,
|
|
2471
|
+
`run-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`
|
|
2472
|
+
);
|
|
2473
|
+
await fs14.ensureDir(tempDir);
|
|
2474
|
+
const tempPath = path13.join(tempDir, "bundle.mjs");
|
|
2475
|
+
await bundle(configPath, {
|
|
2476
|
+
cache: true,
|
|
2477
|
+
verbose: options.verbose,
|
|
2478
|
+
silent: options.silent,
|
|
2479
|
+
flowName: options.flowName,
|
|
2480
|
+
buildOverrides: {
|
|
2481
|
+
output: tempPath,
|
|
2482
|
+
format: "esm",
|
|
2483
|
+
platform: "node"
|
|
2484
|
+
}
|
|
2485
|
+
});
|
|
2486
|
+
return tempPath;
|
|
2487
|
+
}
|
|
2488
|
+
function isPreBuiltConfig(configPath) {
|
|
2489
|
+
return configPath.endsWith(".mjs") || configPath.endsWith(".js") || configPath.endsWith(".cjs");
|
|
2490
|
+
}
|
|
2491
|
+
var init_utils3 = __esm({
|
|
2492
|
+
"src/commands/run/utils.ts"() {
|
|
2493
|
+
"use strict";
|
|
2494
|
+
init_bundle();
|
|
2495
|
+
init_core();
|
|
2496
|
+
}
|
|
2497
|
+
});
|
|
2498
|
+
|
|
2499
|
+
// src/index.ts
|
|
2500
|
+
init_bundle();
|
|
2274
2501
|
|
|
2275
2502
|
// src/commands/simulate/simulator.ts
|
|
2276
2503
|
import fs12 from "fs-extra";
|
|
@@ -2282,7 +2509,7 @@ import { assign as a, clone as c, debounce as u, getId as f, getGrantedConsent a
|
|
|
2282
2509
|
import { isArray as y } from "@walkeros/core";
|
|
2283
2510
|
import { tryCatch as b, tryCatchAsync as v } from "@walkeros/core";
|
|
2284
2511
|
import { getMappingValue as k, tryCatchAsync as C } from "@walkeros/core";
|
|
2285
|
-
import { isObject as O, tryCatchAsync as
|
|
2512
|
+
import { isObject as O, tryCatchAsync as j, useHooks as q } from "@walkeros/core";
|
|
2286
2513
|
import { assign as M, getId as Q, isFunction as V, isString as _ } from "@walkeros/core";
|
|
2287
2514
|
import { isObject as K } from "@walkeros/core";
|
|
2288
2515
|
import { getGrantedConsent as en, processEventMapping as tn, tryCatchAsync as on, useHooks as sn } from "@walkeros/core";
|
|
@@ -2322,20 +2549,20 @@ function E(n, e2 = {}) {
|
|
|
2322
2549
|
}
|
|
2323
2550
|
return t2;
|
|
2324
2551
|
}
|
|
2325
|
-
async function
|
|
2552
|
+
async function x(n, e2, t2) {
|
|
2326
2553
|
if (e2.init && !e2.config.init) {
|
|
2327
2554
|
const o2 = e2.type || "unknown", s2 = n.logger.scope(`transformer:${o2}`), r2 = { collector: n, logger: s2, id: t2, config: e2.config, env: $(e2.config.env) };
|
|
2328
2555
|
s2.debug("init");
|
|
2329
|
-
const i2 = await
|
|
2556
|
+
const i2 = await q(e2.init, "TransformerInit", n.hooks)(r2);
|
|
2330
2557
|
if (false === i2) return false;
|
|
2331
2558
|
e2.config = { ...i2 || e2.config, init: true }, s2.debug("init done");
|
|
2332
2559
|
}
|
|
2333
2560
|
return true;
|
|
2334
2561
|
}
|
|
2335
|
-
async function
|
|
2562
|
+
async function P(n, e2, t2, o2, s2, r2) {
|
|
2336
2563
|
const i2 = e2.type || "unknown", a2 = n.logger.scope(`transformer:${i2}`), c2 = { collector: n, logger: a2, id: t2, ingest: s2, config: e2.config, env: { ...$(e2.config.env), ...r2 ? { respond: r2 } : {} } };
|
|
2337
2564
|
a2.debug("push", { event: o2.name });
|
|
2338
|
-
const u2 = await
|
|
2565
|
+
const u2 = await q(e2.push, "TransformerPush", n.hooks)(o2, c2);
|
|
2339
2566
|
return a2.debug("push done"), u2;
|
|
2340
2567
|
}
|
|
2341
2568
|
async function S(n, e2, t2, o2, s2, r2) {
|
|
@@ -2346,8 +2573,8 @@ async function S(n, e2, t2, o2, s2, r2) {
|
|
|
2346
2573
|
n.logger.warn(`Transformer not found: ${o3}`);
|
|
2347
2574
|
continue;
|
|
2348
2575
|
}
|
|
2349
|
-
if (!await
|
|
2350
|
-
const r3 = await
|
|
2576
|
+
if (!await j(x)(n, t3, o3)) return n.logger.error(`Transformer init failed: ${o3}`), null;
|
|
2577
|
+
const r3 = await j(P, (e3) => (n.logger.scope(`transformer:${t3.type || "unknown"}`).error("Push failed", { error: e3 }), false))(n, t3, o3, i2, s2, a2);
|
|
2351
2578
|
if (false === r3) return null;
|
|
2352
2579
|
if (r3 && "object" == typeof r3) {
|
|
2353
2580
|
const { event: t4, respond: o4, next: c2 } = r3;
|
|
@@ -2547,10 +2774,10 @@ async function U(n, e2, t2 = {}, o2) {
|
|
|
2547
2774
|
})), g2 = {}, d2 = {}, m2 = {};
|
|
2548
2775
|
for (const e3 of f2) {
|
|
2549
2776
|
if (e3.skipped) continue;
|
|
2550
|
-
const t3 =
|
|
2777
|
+
const t3 = { type: e3.destination.type || "unknown", data: e3.response };
|
|
2551
2778
|
n.status.destinations[e3.id] || (n.status.destinations[e3.id] = { count: 0, failed: 0, duration: 0 });
|
|
2552
|
-
const
|
|
2553
|
-
e3.error ? (
|
|
2779
|
+
const o3 = n.status.destinations[e3.id], s3 = Date.now();
|
|
2780
|
+
e3.error ? (t3.error = e3.error, m2[e3.id] = t3, o3.failed++, o3.lastAt = s3, o3.duration += e3.totalDuration || 0, n.status.failed++) : e3.queue && e3.queue.length ? d2[e3.id] = t3 : (g2[e3.id] = t3, o3.count++, o3.lastAt = s3, o3.duration += e3.totalDuration || 0, n.status.out++);
|
|
2554
2781
|
}
|
|
2555
2782
|
return N({ event: e2, ...Object.keys(g2).length && { done: g2 }, ...Object.keys(d2).length && { queued: d2 }, ...Object.keys(m2).length && { failed: m2 } });
|
|
2556
2783
|
}
|
|
@@ -2817,6 +3044,9 @@ async function dn(n) {
|
|
|
2817
3044
|
|
|
2818
3045
|
// src/commands/simulate/simulator.ts
|
|
2819
3046
|
init_cli_logger();
|
|
3047
|
+
init_core();
|
|
3048
|
+
init_config();
|
|
3049
|
+
init_tmp();
|
|
2820
3050
|
|
|
2821
3051
|
// src/commands/simulate/env-loader.ts
|
|
2822
3052
|
async function loadDestinationEnvs(destinations) {
|
|
@@ -2859,13 +3089,13 @@ function callsToUsage(destName, calls) {
|
|
|
2859
3089
|
};
|
|
2860
3090
|
}
|
|
2861
3091
|
async function simulateCore(inputPath, event, options = {}) {
|
|
2862
|
-
const
|
|
3092
|
+
const logger = createCLILogger({
|
|
2863
3093
|
verbose: options.verbose || false,
|
|
2864
3094
|
silent: options.silent || false,
|
|
2865
3095
|
json: options.json || false
|
|
2866
3096
|
});
|
|
2867
3097
|
try {
|
|
2868
|
-
|
|
3098
|
+
logger.debug(`Simulating event: ${JSON.stringify(event)}`);
|
|
2869
3099
|
const result = await executeSimulation(event, inputPath, options.platform, {
|
|
2870
3100
|
flow: options.flow,
|
|
2871
3101
|
step: options.step,
|
|
@@ -2934,7 +3164,7 @@ async function executeSimulation(event, inputPath, platformOverride, options = {
|
|
|
2934
3164
|
const typedEvent = event;
|
|
2935
3165
|
if (detected.type !== "config") {
|
|
2936
3166
|
throw new Error(
|
|
2937
|
-
`Input "${inputPath}" is not valid JSON config. simulate only accepts Flow.
|
|
3167
|
+
`Input "${inputPath}" is not valid JSON config. simulate only accepts Flow.Config config files.`
|
|
2938
3168
|
);
|
|
2939
3169
|
}
|
|
2940
3170
|
return await executeConfigSimulation(
|
|
@@ -2985,12 +3215,12 @@ function parseStepTarget(stepTarget, flowConfig) {
|
|
|
2985
3215
|
throw new Error("No destination found in flow config");
|
|
2986
3216
|
}
|
|
2987
3217
|
async function executeConfigSimulation(_content, configPath, typedEvent, tempDir, startTime, flowName, stepTarget) {
|
|
2988
|
-
const {
|
|
3218
|
+
const { flowSettings } = await loadFlowConfig(configPath, {
|
|
2989
3219
|
flowName
|
|
2990
3220
|
});
|
|
2991
3221
|
const step = parseStepTarget(
|
|
2992
3222
|
stepTarget,
|
|
2993
|
-
|
|
3223
|
+
flowSettings
|
|
2994
3224
|
);
|
|
2995
3225
|
if (step.type === "destination") {
|
|
2996
3226
|
const packageName = step.config.package;
|
|
@@ -2999,7 +3229,7 @@ async function executeConfigSimulation(_content, configPath, typedEvent, tempDir
|
|
|
2999
3229
|
}
|
|
3000
3230
|
const destModule = await import(packageName);
|
|
3001
3231
|
const code = destModule.default || Object.values(destModule)[0];
|
|
3002
|
-
const destinations =
|
|
3232
|
+
const destinations = flowSettings.destinations;
|
|
3003
3233
|
const envs = await loadDestinationEnvs(destinations || {});
|
|
3004
3234
|
const destEnv = envs[step.name];
|
|
3005
3235
|
const result = await dn({
|
|
@@ -3049,6 +3279,7 @@ async function executeConfigSimulation(_content, configPath, typedEvent, tempDir
|
|
|
3049
3279
|
|
|
3050
3280
|
// src/commands/simulate/source-simulator.ts
|
|
3051
3281
|
import { JSDOM, VirtualConsole } from "jsdom";
|
|
3282
|
+
init_core();
|
|
3052
3283
|
async function loadSourcePackage(packageName) {
|
|
3053
3284
|
const mainModule = await import(packageName);
|
|
3054
3285
|
const code = mainModule.default || Object.values(mainModule)[0];
|
|
@@ -3126,6 +3357,9 @@ async function simulateSourceCLI(flowConfig, setupInput, options) {
|
|
|
3126
3357
|
|
|
3127
3358
|
// src/commands/simulate/index.ts
|
|
3128
3359
|
init_cli_logger();
|
|
3360
|
+
init_core();
|
|
3361
|
+
init_config();
|
|
3362
|
+
init_validators();
|
|
3129
3363
|
|
|
3130
3364
|
// src/commands/simulate/example-loader.ts
|
|
3131
3365
|
function findExample(config, exampleName, stepTarget) {
|
|
@@ -3231,7 +3465,7 @@ ${actualStr}`
|
|
|
3231
3465
|
|
|
3232
3466
|
// src/commands/simulate/index.ts
|
|
3233
3467
|
async function simulateCommand(options) {
|
|
3234
|
-
const
|
|
3468
|
+
const logger = createCLILogger({ ...options, stderr: true });
|
|
3235
3469
|
const startTime = Date.now();
|
|
3236
3470
|
try {
|
|
3237
3471
|
let config;
|
|
@@ -3279,7 +3513,7 @@ async function simulateCommand(options) {
|
|
|
3279
3513
|
);
|
|
3280
3514
|
await writeResult(errorOutput + "\n", { output: options.output });
|
|
3281
3515
|
} else {
|
|
3282
|
-
|
|
3516
|
+
logger.error(`Error: ${errorMessage}`);
|
|
3283
3517
|
}
|
|
3284
3518
|
process.exit(1);
|
|
3285
3519
|
}
|
|
@@ -3297,7 +3531,7 @@ async function simulate(configOrPath, event, options = {}) {
|
|
|
3297
3531
|
let exampleContext;
|
|
3298
3532
|
if (options.example) {
|
|
3299
3533
|
const rawConfig = await loadJsonConfig(configOrPath);
|
|
3300
|
-
const setup =
|
|
3534
|
+
const setup = validateFlowConfig(rawConfig);
|
|
3301
3535
|
const flowNames = Object.keys(setup.flows);
|
|
3302
3536
|
let flowName = options.flow;
|
|
3303
3537
|
if (!flowName) {
|
|
@@ -3310,13 +3544,13 @@ Available flows: ${flowNames.join(", ")}`
|
|
|
3310
3544
|
);
|
|
3311
3545
|
}
|
|
3312
3546
|
}
|
|
3313
|
-
const
|
|
3314
|
-
if (!
|
|
3547
|
+
const flowSettings = setup.flows[flowName];
|
|
3548
|
+
if (!flowSettings) {
|
|
3315
3549
|
throw new Error(
|
|
3316
3550
|
`Flow "${flowName}" not found. Available: ${flowNames.join(", ")}`
|
|
3317
3551
|
);
|
|
3318
3552
|
}
|
|
3319
|
-
const found = findExample(
|
|
3553
|
+
const found = findExample(flowSettings, options.example, options.step);
|
|
3320
3554
|
if (found.example.in === void 0) {
|
|
3321
3555
|
throw new Error(
|
|
3322
3556
|
`Example "${options.example}" in ${found.stepType}.${found.stepName} has no "in" value`
|
|
@@ -3333,7 +3567,7 @@ Available flows: ${flowNames.join(", ")}`
|
|
|
3333
3567
|
let result;
|
|
3334
3568
|
if (isSourceSimulation) {
|
|
3335
3569
|
const rawConfig = await loadJsonConfig(configOrPath);
|
|
3336
|
-
const setup =
|
|
3570
|
+
const setup = validateFlowConfig(rawConfig);
|
|
3337
3571
|
const flowNames = Object.keys(setup.flows);
|
|
3338
3572
|
const flowName = options.flow || (flowNames.length === 1 ? flowNames[0] : void 0);
|
|
3339
3573
|
if (!flowName) {
|
|
@@ -3342,15 +3576,15 @@ Available flows: ${flowNames.join(", ")}`
|
|
|
3342
3576
|
Available: ${flowNames.join(", ")}`
|
|
3343
3577
|
);
|
|
3344
3578
|
}
|
|
3345
|
-
const
|
|
3346
|
-
if (!
|
|
3579
|
+
const flowSettings = setup.flows[flowName];
|
|
3580
|
+
if (!flowSettings) {
|
|
3347
3581
|
throw new Error(
|
|
3348
3582
|
`Flow "${flowName}" not found. Available: ${flowNames.join(", ")}`
|
|
3349
3583
|
);
|
|
3350
3584
|
}
|
|
3351
3585
|
const sourceStep = exampleContext?.stepName || options.step.substring("source.".length);
|
|
3352
3586
|
result = await simulateSourceCLI(
|
|
3353
|
-
|
|
3587
|
+
flowSettings,
|
|
3354
3588
|
resolvedEvent,
|
|
3355
3589
|
{
|
|
3356
3590
|
flow: options.flow,
|
|
@@ -3398,6 +3632,10 @@ Available: ${flowNames.join(", ")}`
|
|
|
3398
3632
|
|
|
3399
3633
|
// src/commands/push/index.ts
|
|
3400
3634
|
init_cli_logger();
|
|
3635
|
+
init_core();
|
|
3636
|
+
init_tmp();
|
|
3637
|
+
init_config();
|
|
3638
|
+
init_bundler();
|
|
3401
3639
|
import path12 from "path";
|
|
3402
3640
|
import { JSDOM as JSDOM2, VirtualConsole as VirtualConsole2 } from "jsdom";
|
|
3403
3641
|
import fs13 from "fs-extra";
|
|
@@ -3405,7 +3643,7 @@ import { getPlatform as getPlatform3 } from "@walkeros/core";
|
|
|
3405
3643
|
import { schemas as schemas2 } from "@walkeros/core/dev";
|
|
3406
3644
|
import { Level as Level2 } from "@walkeros/core";
|
|
3407
3645
|
async function pushCore(inputPath, event, options = {}) {
|
|
3408
|
-
const
|
|
3646
|
+
const logger = createCLILogger({
|
|
3409
3647
|
silent: options.silent,
|
|
3410
3648
|
verbose: options.verbose
|
|
3411
3649
|
});
|
|
@@ -3426,11 +3664,11 @@ async function pushCore(inputPath, event, options = {}) {
|
|
|
3426
3664
|
data: parsedEvent.data || {}
|
|
3427
3665
|
};
|
|
3428
3666
|
if (!validatedEvent.name.includes(" ")) {
|
|
3429
|
-
|
|
3667
|
+
logger.info(
|
|
3430
3668
|
`Warning: Event name "${validatedEvent.name}" should follow "ENTITY ACTION" format (e.g., "page view")`
|
|
3431
3669
|
);
|
|
3432
3670
|
}
|
|
3433
|
-
|
|
3671
|
+
logger.debug("Detecting input type");
|
|
3434
3672
|
const detected = await detectInput(
|
|
3435
3673
|
inputPath,
|
|
3436
3674
|
options.platform
|
|
@@ -3444,7 +3682,7 @@ async function pushCore(inputPath, event, options = {}) {
|
|
|
3444
3682
|
verbose: options.verbose
|
|
3445
3683
|
},
|
|
3446
3684
|
validatedEvent,
|
|
3447
|
-
|
|
3685
|
+
logger,
|
|
3448
3686
|
(dir) => {
|
|
3449
3687
|
tempDir = dir;
|
|
3450
3688
|
}
|
|
@@ -3454,7 +3692,7 @@ async function pushCore(inputPath, event, options = {}) {
|
|
|
3454
3692
|
detected.content,
|
|
3455
3693
|
detected.platform,
|
|
3456
3694
|
validatedEvent,
|
|
3457
|
-
|
|
3695
|
+
logger,
|
|
3458
3696
|
(dir) => {
|
|
3459
3697
|
tempDir = dir;
|
|
3460
3698
|
},
|
|
@@ -3476,7 +3714,7 @@ async function pushCore(inputPath, event, options = {}) {
|
|
|
3476
3714
|
}
|
|
3477
3715
|
}
|
|
3478
3716
|
async function pushCommand(options) {
|
|
3479
|
-
const
|
|
3717
|
+
const logger = createCLILogger({ ...options, stderr: true });
|
|
3480
3718
|
const startTime = Date.now();
|
|
3481
3719
|
try {
|
|
3482
3720
|
let config;
|
|
@@ -3540,7 +3778,7 @@ async function pushCommand(options) {
|
|
|
3540
3778
|
);
|
|
3541
3779
|
await writeResult(errorOutput + "\n", { output: options.output });
|
|
3542
3780
|
} else {
|
|
3543
|
-
|
|
3781
|
+
logger.error(`Error: ${errorMessage}`);
|
|
3544
3782
|
}
|
|
3545
3783
|
process.exit(1);
|
|
3546
3784
|
}
|
|
@@ -3563,14 +3801,14 @@ async function push(configOrPath, event, options = {}) {
|
|
|
3563
3801
|
platform: options.platform
|
|
3564
3802
|
});
|
|
3565
3803
|
}
|
|
3566
|
-
async function executeConfigPush(options, validatedEvent,
|
|
3567
|
-
|
|
3568
|
-
const {
|
|
3804
|
+
async function executeConfigPush(options, validatedEvent, logger, setTempDir) {
|
|
3805
|
+
logger.debug("Loading flow configuration");
|
|
3806
|
+
const { flowSettings, buildOptions } = await loadFlowConfig(options.config, {
|
|
3569
3807
|
flowName: options.flow,
|
|
3570
|
-
logger
|
|
3808
|
+
logger
|
|
3571
3809
|
});
|
|
3572
|
-
const platform = getPlatform3(
|
|
3573
|
-
|
|
3810
|
+
const platform = getPlatform3(flowSettings);
|
|
3811
|
+
logger.debug("Bundling flow configuration");
|
|
3574
3812
|
const configDir = buildOptions.configDir || process.cwd();
|
|
3575
3813
|
const tempDir = getTmpPath(
|
|
3576
3814
|
void 0,
|
|
@@ -3592,21 +3830,21 @@ async function executeConfigPush(options, validatedEvent, logger2, setTempDir) {
|
|
|
3592
3830
|
windowElb: "elb"
|
|
3593
3831
|
}
|
|
3594
3832
|
};
|
|
3595
|
-
await bundleCore(
|
|
3596
|
-
|
|
3833
|
+
await bundleCore(flowSettings, pushBuildOptions, logger, false);
|
|
3834
|
+
logger.debug(`Bundle created: ${tempPath}`);
|
|
3597
3835
|
if (platform === "web") {
|
|
3598
|
-
|
|
3599
|
-
return executeWebPush(tempPath, validatedEvent,
|
|
3836
|
+
logger.debug("Executing in web environment (JSDOM)");
|
|
3837
|
+
return executeWebPush(tempPath, validatedEvent, logger);
|
|
3600
3838
|
} else if (platform === "server") {
|
|
3601
|
-
|
|
3602
|
-
return executeServerPush(tempPath, validatedEvent,
|
|
3839
|
+
logger.debug("Executing in server environment (Node.js)");
|
|
3840
|
+
return executeServerPush(tempPath, validatedEvent, logger, 6e4, {
|
|
3603
3841
|
logger: { level: options.verbose ? Level2.DEBUG : Level2.ERROR }
|
|
3604
3842
|
});
|
|
3605
3843
|
} else {
|
|
3606
3844
|
throw new Error(`Unsupported platform: ${platform}`);
|
|
3607
3845
|
}
|
|
3608
3846
|
}
|
|
3609
|
-
async function executeBundlePush(bundleContent, platform, validatedEvent,
|
|
3847
|
+
async function executeBundlePush(bundleContent, platform, validatedEvent, logger, setTempDir, context = {}) {
|
|
3610
3848
|
const tempDir = getTmpPath(
|
|
3611
3849
|
void 0,
|
|
3612
3850
|
`push-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`
|
|
@@ -3618,16 +3856,16 @@ async function executeBundlePush(bundleContent, platform, validatedEvent, logger
|
|
|
3618
3856
|
`bundle.${platform === "server" ? "mjs" : "js"}`
|
|
3619
3857
|
);
|
|
3620
3858
|
await fs13.writeFile(tempPath, bundleContent, "utf8");
|
|
3621
|
-
|
|
3859
|
+
logger.debug(`Bundle written to: ${tempPath}`);
|
|
3622
3860
|
if (platform === "web") {
|
|
3623
|
-
|
|
3624
|
-
return executeWebPush(tempPath, validatedEvent,
|
|
3861
|
+
logger.debug("Executing in web environment (JSDOM)");
|
|
3862
|
+
return executeWebPush(tempPath, validatedEvent, logger);
|
|
3625
3863
|
} else {
|
|
3626
|
-
|
|
3627
|
-
return executeServerPush(tempPath, validatedEvent,
|
|
3864
|
+
logger.debug("Executing in server environment (Node.js)");
|
|
3865
|
+
return executeServerPush(tempPath, validatedEvent, logger, 6e4, context);
|
|
3628
3866
|
}
|
|
3629
3867
|
}
|
|
3630
|
-
async function executeWebPush(bundlePath, event,
|
|
3868
|
+
async function executeWebPush(bundlePath, event, logger) {
|
|
3631
3869
|
const startTime = Date.now();
|
|
3632
3870
|
try {
|
|
3633
3871
|
const virtualConsole = new VirtualConsole2();
|
|
@@ -3638,10 +3876,10 @@ async function executeWebPush(bundlePath, event, logger2) {
|
|
|
3638
3876
|
virtualConsole
|
|
3639
3877
|
});
|
|
3640
3878
|
const { window } = dom;
|
|
3641
|
-
|
|
3879
|
+
logger.debug("Loading bundle...");
|
|
3642
3880
|
const bundleCode = await fs13.readFile(bundlePath, "utf8");
|
|
3643
3881
|
window.eval(bundleCode);
|
|
3644
|
-
|
|
3882
|
+
logger.debug("Waiting for collector...");
|
|
3645
3883
|
await waitForWindowProperty(
|
|
3646
3884
|
window,
|
|
3647
3885
|
"collector",
|
|
@@ -3649,7 +3887,7 @@ async function executeWebPush(bundlePath, event, logger2) {
|
|
|
3649
3887
|
);
|
|
3650
3888
|
const windowObj = window;
|
|
3651
3889
|
const collector = windowObj.collector;
|
|
3652
|
-
|
|
3890
|
+
logger.info(`Pushing event: ${event.name}`);
|
|
3653
3891
|
const elbResult = await collector.push({
|
|
3654
3892
|
name: event.name,
|
|
3655
3893
|
data: event.data
|
|
@@ -3667,7 +3905,7 @@ async function executeWebPush(bundlePath, event, logger2) {
|
|
|
3667
3905
|
};
|
|
3668
3906
|
}
|
|
3669
3907
|
}
|
|
3670
|
-
async function executeServerPush(bundlePath, event,
|
|
3908
|
+
async function executeServerPush(bundlePath, event, logger, timeout = 6e4, context = {}) {
|
|
3671
3909
|
const startTime = Date.now();
|
|
3672
3910
|
let timer;
|
|
3673
3911
|
try {
|
|
@@ -3678,12 +3916,12 @@ async function executeServerPush(bundlePath, event, logger2, timeout = 6e4, cont
|
|
|
3678
3916
|
);
|
|
3679
3917
|
});
|
|
3680
3918
|
const executePromise = (async () => {
|
|
3681
|
-
|
|
3919
|
+
logger.debug("Importing bundle...");
|
|
3682
3920
|
const flowModule = await import(bundlePath);
|
|
3683
3921
|
if (!flowModule.default || typeof flowModule.default !== "function") {
|
|
3684
3922
|
throw new Error("Bundle does not export default factory function");
|
|
3685
3923
|
}
|
|
3686
|
-
|
|
3924
|
+
logger.debug("Calling factory function...");
|
|
3687
3925
|
const result = await flowModule.default(context);
|
|
3688
3926
|
if (!result || !result.collector || typeof result.collector.push !== "function") {
|
|
3689
3927
|
throw new Error(
|
|
@@ -3691,7 +3929,7 @@ async function executeServerPush(bundlePath, event, logger2, timeout = 6e4, cont
|
|
|
3691
3929
|
);
|
|
3692
3930
|
}
|
|
3693
3931
|
const { collector } = result;
|
|
3694
|
-
|
|
3932
|
+
logger.info(`Pushing event: ${event.name}`);
|
|
3695
3933
|
const elbResult = await collector.push({
|
|
3696
3934
|
name: event.name,
|
|
3697
3935
|
data: event.data
|
|
@@ -3735,106 +3973,109 @@ function waitForWindowProperty(window, prop, timeout = 5e3) {
|
|
|
3735
3973
|
|
|
3736
3974
|
// src/commands/run/index.ts
|
|
3737
3975
|
init_cli_logger();
|
|
3976
|
+
init_core();
|
|
3977
|
+
init_config_file();
|
|
3978
|
+
init_auth();
|
|
3738
3979
|
import path14 from "path";
|
|
3739
3980
|
import { createRequire } from "module";
|
|
3981
|
+
import { writeFileSync as writeFileSync5 } from "fs";
|
|
3982
|
+
import { homedir as homedir2 } from "os";
|
|
3983
|
+
import { join as join4 } from "path";
|
|
3984
|
+
|
|
3985
|
+
// src/runtime/resolve-bundle.ts
|
|
3986
|
+
init_stdin();
|
|
3987
|
+
import { existsSync as existsSync3, writeFileSync as writeFileSync2 } from "fs";
|
|
3988
|
+
var TEMP_BUNDLE_PATH = "/tmp/walkeros-bundle.mjs";
|
|
3989
|
+
function isUrl2(value) {
|
|
3990
|
+
return value.startsWith("http://") || value.startsWith("https://");
|
|
3991
|
+
}
|
|
3992
|
+
async function fetchBundle(url) {
|
|
3993
|
+
const response = await fetch(url, { signal: AbortSignal.timeout(3e4) });
|
|
3994
|
+
if (!response.ok) {
|
|
3995
|
+
throw new Error(
|
|
3996
|
+
`Failed to fetch bundle from ${url}: ${response.status} ${response.statusText}`
|
|
3997
|
+
);
|
|
3998
|
+
}
|
|
3999
|
+
const content = await response.text();
|
|
4000
|
+
if (!content.trim()) {
|
|
4001
|
+
throw new Error(`Bundle fetched from ${url} is empty`);
|
|
4002
|
+
}
|
|
4003
|
+
writeFileSync2(TEMP_BUNDLE_PATH, content, "utf-8");
|
|
4004
|
+
return TEMP_BUNDLE_PATH;
|
|
4005
|
+
}
|
|
4006
|
+
async function readBundleFromStdin() {
|
|
4007
|
+
const content = await readStdin();
|
|
4008
|
+
writeFileSync2(TEMP_BUNDLE_PATH, content, "utf-8");
|
|
4009
|
+
return TEMP_BUNDLE_PATH;
|
|
4010
|
+
}
|
|
4011
|
+
async function resolveBundle(bundleEnv) {
|
|
4012
|
+
if (!isUrl2(bundleEnv) && existsSync3(bundleEnv)) {
|
|
4013
|
+
return { path: bundleEnv, source: "file" };
|
|
4014
|
+
}
|
|
4015
|
+
if (isStdinPiped()) {
|
|
4016
|
+
const path15 = await readBundleFromStdin();
|
|
4017
|
+
return { path: path15, source: "stdin" };
|
|
4018
|
+
}
|
|
4019
|
+
if (isUrl2(bundleEnv)) {
|
|
4020
|
+
const path15 = await fetchBundle(bundleEnv);
|
|
4021
|
+
return { path: path15, source: "url" };
|
|
4022
|
+
}
|
|
4023
|
+
return { path: bundleEnv, source: "file" };
|
|
4024
|
+
}
|
|
4025
|
+
|
|
4026
|
+
// src/runtime/config-fetcher.ts
|
|
4027
|
+
async function fetchConfig(options) {
|
|
4028
|
+
const url = `${options.appUrl}/api/projects/${options.projectId}/flows/${options.flowId}`;
|
|
4029
|
+
const headers = {
|
|
4030
|
+
Authorization: `Bearer ${options.token}`
|
|
4031
|
+
};
|
|
4032
|
+
if (options.lastEtag) {
|
|
4033
|
+
headers["If-None-Match"] = options.lastEtag;
|
|
4034
|
+
}
|
|
4035
|
+
const response = await fetch(url, {
|
|
4036
|
+
headers,
|
|
4037
|
+
signal: AbortSignal.timeout(3e4)
|
|
4038
|
+
});
|
|
4039
|
+
if (response.status === 304) {
|
|
4040
|
+
return { changed: false };
|
|
4041
|
+
}
|
|
4042
|
+
if (!response.ok) {
|
|
4043
|
+
if (response.status === 401 || response.status === 403) {
|
|
4044
|
+
throw new Error(
|
|
4045
|
+
`Config fetch failed (${response.status}): token may have expired \u2014 redeploy to rotate`
|
|
4046
|
+
);
|
|
4047
|
+
}
|
|
4048
|
+
throw new Error(
|
|
4049
|
+
`Config fetch failed: ${response.status} ${response.statusText}`
|
|
4050
|
+
);
|
|
4051
|
+
}
|
|
4052
|
+
const data = await response.json();
|
|
4053
|
+
const etag = response.headers.get("etag") || "";
|
|
4054
|
+
const version = etag.replace(/"/g, "");
|
|
4055
|
+
return {
|
|
4056
|
+
content: data.config,
|
|
4057
|
+
version,
|
|
4058
|
+
etag,
|
|
4059
|
+
changed: true
|
|
4060
|
+
};
|
|
4061
|
+
}
|
|
4062
|
+
|
|
4063
|
+
// src/commands/run/index.ts
|
|
4064
|
+
init_cache();
|
|
3740
4065
|
|
|
3741
4066
|
// src/commands/run/validators.ts
|
|
3742
|
-
|
|
4067
|
+
init_asset_resolver();
|
|
4068
|
+
import { existsSync as existsSync5 } from "fs";
|
|
3743
4069
|
|
|
3744
4070
|
// src/schemas/primitives.ts
|
|
3745
4071
|
import { z as z2 } from "@walkeros/core/dev";
|
|
3746
4072
|
var PortSchema = z2.number().int("Port must be an integer").min(1, "Port must be at least 1").max(65535, "Port must be at most 65535").describe("HTTP server port number");
|
|
3747
4073
|
var FilePathSchema = z2.string().min(1, "File path cannot be empty").describe("Path to configuration file");
|
|
3748
4074
|
|
|
3749
|
-
// src/schemas/run.ts
|
|
3750
|
-
import { z as z3 } from "@walkeros/core/dev";
|
|
3751
|
-
var RunOptionsSchema = z3.object({
|
|
3752
|
-
flow: FilePathSchema,
|
|
3753
|
-
port: PortSchema.default(8080),
|
|
3754
|
-
flowName: z3.string().optional().describe("Specific flow name to run")
|
|
3755
|
-
});
|
|
3756
|
-
|
|
3757
|
-
// src/schemas/validate.ts
|
|
3758
|
-
import { z as z4 } from "@walkeros/core/dev";
|
|
3759
|
-
var ValidationTypeSchema = z4.enum(["contract", "event", "flow", "mapping"]).describe('Validation type: "event", "flow", "mapping", or "contract"');
|
|
3760
|
-
var ValidateOptionsSchema = z4.object({
|
|
3761
|
-
flow: z4.string().optional().describe("Flow name for multi-flow configs"),
|
|
3762
|
-
path: z4.string().optional().describe(
|
|
3763
|
-
'Entry path for package schema validation (e.g., "destinations.snowplow", "sources.browser")'
|
|
3764
|
-
)
|
|
3765
|
-
});
|
|
3766
|
-
var ValidateInputShape = {
|
|
3767
|
-
type: ValidationTypeSchema,
|
|
3768
|
-
input: z4.string().min(1).describe("JSON string, file path, or URL to validate"),
|
|
3769
|
-
flow: z4.string().optional().describe("Flow name for multi-flow configs"),
|
|
3770
|
-
path: z4.string().optional().describe(
|
|
3771
|
-
'Entry path for package schema validation (e.g., "destinations.snowplow"). When provided, validates the entry against its package JSON Schema instead of using --type.'
|
|
3772
|
-
)
|
|
3773
|
-
};
|
|
3774
|
-
var ValidateInputSchema = z4.object(ValidateInputShape);
|
|
3775
|
-
|
|
3776
|
-
// src/schemas/bundle.ts
|
|
3777
|
-
import { z as z5 } from "@walkeros/core/dev";
|
|
3778
|
-
var BundleOptionsSchema = z5.object({
|
|
3779
|
-
silent: z5.boolean().optional().describe("Suppress all output"),
|
|
3780
|
-
verbose: z5.boolean().optional().describe("Enable verbose logging"),
|
|
3781
|
-
stats: z5.boolean().optional().default(true).describe("Return bundle statistics"),
|
|
3782
|
-
cache: z5.boolean().optional().default(true).describe("Enable package caching"),
|
|
3783
|
-
flowName: z5.string().optional().describe("Flow name for multi-flow configs")
|
|
3784
|
-
});
|
|
3785
|
-
var BundleInputShape = {
|
|
3786
|
-
configPath: FilePathSchema.describe(
|
|
3787
|
-
"Path to flow configuration file (JSON or JavaScript)"
|
|
3788
|
-
),
|
|
3789
|
-
flow: z5.string().optional().describe("Flow name for multi-flow configs"),
|
|
3790
|
-
stats: z5.boolean().optional().default(true).describe("Return bundle statistics"),
|
|
3791
|
-
output: z5.string().optional().describe("Output file path (defaults to config-defined)")
|
|
3792
|
-
};
|
|
3793
|
-
var BundleInputSchema = z5.object(BundleInputShape);
|
|
3794
|
-
|
|
3795
|
-
// src/schemas/simulate.ts
|
|
3796
|
-
import { z as z6 } from "@walkeros/core/dev";
|
|
3797
|
-
var PlatformSchema = z6.enum(["web", "server"]).describe("Platform type for event processing");
|
|
3798
|
-
var SimulateOptionsSchema = z6.object({
|
|
3799
|
-
silent: z6.boolean().optional().describe("Suppress all output"),
|
|
3800
|
-
verbose: z6.boolean().optional().describe("Enable verbose logging"),
|
|
3801
|
-
json: z6.boolean().optional().describe("Format output as JSON")
|
|
3802
|
-
});
|
|
3803
|
-
var SimulateInputShape = {
|
|
3804
|
-
configPath: FilePathSchema.describe("Path to flow configuration file"),
|
|
3805
|
-
event: z6.string().min(1).optional().describe(
|
|
3806
|
-
"Event as JSON string, file path, or URL. Optional when example is provided."
|
|
3807
|
-
),
|
|
3808
|
-
flow: z6.string().optional().describe("Flow name for multi-flow configs"),
|
|
3809
|
-
platform: PlatformSchema.optional().describe("Override platform detection"),
|
|
3810
|
-
example: z6.string().optional().describe(
|
|
3811
|
-
'Name of a step example to use as event input (uses its "in" value)'
|
|
3812
|
-
),
|
|
3813
|
-
step: z6.string().optional().describe(
|
|
3814
|
-
'Step target in type.name format (e.g. "destination.gtag") to narrow example lookup'
|
|
3815
|
-
)
|
|
3816
|
-
};
|
|
3817
|
-
var SimulateInputSchema = z6.object(SimulateInputShape);
|
|
3818
|
-
|
|
3819
|
-
// src/schemas/push.ts
|
|
3820
|
-
import { z as z7 } from "@walkeros/core/dev";
|
|
3821
|
-
var PushOptionsSchema = z7.object({
|
|
3822
|
-
silent: z7.boolean().optional().describe("Suppress all output"),
|
|
3823
|
-
verbose: z7.boolean().optional().describe("Enable verbose logging"),
|
|
3824
|
-
json: z7.boolean().optional().describe("Format output as JSON")
|
|
3825
|
-
});
|
|
3826
|
-
var PushInputShape = {
|
|
3827
|
-
configPath: FilePathSchema.describe("Path to flow configuration file"),
|
|
3828
|
-
event: z7.string().min(1).describe("Event as JSON string, file path, or URL"),
|
|
3829
|
-
flow: z7.string().optional().describe("Flow name for multi-flow configs"),
|
|
3830
|
-
platform: PlatformSchema.optional().describe("Override platform detection")
|
|
3831
|
-
};
|
|
3832
|
-
var PushInputSchema = z7.object(PushInputShape);
|
|
3833
|
-
|
|
3834
4075
|
// src/commands/run/validators.ts
|
|
3835
4076
|
function validateFlowFile(filePath) {
|
|
3836
4077
|
const absolutePath = resolveAsset(filePath, "bundle");
|
|
3837
|
-
if (!
|
|
4078
|
+
if (!existsSync5(absolutePath)) {
|
|
3838
4079
|
throw new Error(
|
|
3839
4080
|
`Flow file not found: ${filePath}
|
|
3840
4081
|
Resolved path: ${absolutePath}
|
|
@@ -3854,40 +4095,60 @@ function validatePort(port) {
|
|
|
3854
4095
|
}
|
|
3855
4096
|
}
|
|
3856
4097
|
|
|
3857
|
-
// src/commands/run/
|
|
3858
|
-
|
|
3859
|
-
|
|
3860
|
-
|
|
3861
|
-
|
|
3862
|
-
|
|
3863
|
-
|
|
3864
|
-
|
|
3865
|
-
|
|
3866
|
-
|
|
3867
|
-
|
|
3868
|
-
|
|
3869
|
-
|
|
3870
|
-
|
|
3871
|
-
|
|
3872
|
-
|
|
3873
|
-
|
|
3874
|
-
|
|
3875
|
-
|
|
3876
|
-
|
|
4098
|
+
// src/commands/run/index.ts
|
|
4099
|
+
init_utils3();
|
|
4100
|
+
|
|
4101
|
+
// src/commands/run/pipeline.ts
|
|
4102
|
+
import { writeFileSync as writeFileSync4 } from "fs";
|
|
4103
|
+
|
|
4104
|
+
// src/runtime/health-server.ts
|
|
4105
|
+
import http from "http";
|
|
4106
|
+
function createHealthServer(port, logger) {
|
|
4107
|
+
return new Promise((resolve2, reject) => {
|
|
4108
|
+
let flowHandler = null;
|
|
4109
|
+
const server = http.createServer((req, res) => {
|
|
4110
|
+
if (req.url === "/health" && req.method === "GET") {
|
|
4111
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
4112
|
+
res.end(JSON.stringify({ status: "ok" }));
|
|
4113
|
+
return;
|
|
4114
|
+
}
|
|
4115
|
+
if (req.url === "/ready" && req.method === "GET") {
|
|
4116
|
+
const code = flowHandler ? 200 : 503;
|
|
4117
|
+
res.writeHead(code, { "Content-Type": "application/json" });
|
|
4118
|
+
res.end(
|
|
4119
|
+
JSON.stringify({ status: flowHandler ? "ready" : "not_ready" })
|
|
4120
|
+
);
|
|
4121
|
+
return;
|
|
4122
|
+
}
|
|
4123
|
+
if (flowHandler) {
|
|
4124
|
+
flowHandler(req, res);
|
|
4125
|
+
return;
|
|
4126
|
+
}
|
|
4127
|
+
res.writeHead(503, { "Content-Type": "application/json" });
|
|
4128
|
+
res.end(JSON.stringify({ error: "No flow loaded" }));
|
|
4129
|
+
});
|
|
4130
|
+
server.keepAliveTimeout = 5e3;
|
|
4131
|
+
server.headersTimeout = 1e4;
|
|
4132
|
+
server.listen(port, "0.0.0.0", () => {
|
|
4133
|
+
logger.info(`Health server listening on port ${port}`);
|
|
4134
|
+
resolve2({
|
|
4135
|
+
server,
|
|
4136
|
+
setFlowHandler(handler) {
|
|
4137
|
+
flowHandler = handler;
|
|
4138
|
+
},
|
|
4139
|
+
close: () => new Promise((res, rej) => {
|
|
4140
|
+
server.close((err) => err ? rej(err) : res());
|
|
4141
|
+
})
|
|
4142
|
+
});
|
|
4143
|
+
});
|
|
4144
|
+
server.on("error", reject);
|
|
3877
4145
|
});
|
|
3878
|
-
return tempPath;
|
|
3879
|
-
}
|
|
3880
|
-
function isPreBuiltConfig(configPath) {
|
|
3881
|
-
return configPath.endsWith(".mjs") || configPath.endsWith(".js") || configPath.endsWith(".cjs");
|
|
3882
4146
|
}
|
|
3883
4147
|
|
|
3884
|
-
// src/commands/run/execution.ts
|
|
3885
|
-
import { createLogger as createLogger2, Level as Level3 } from "@walkeros/core";
|
|
3886
|
-
|
|
3887
4148
|
// src/runtime/runner.ts
|
|
3888
4149
|
import { pathToFileURL } from "url";
|
|
3889
4150
|
import { resolve, dirname } from "path";
|
|
3890
|
-
async function loadFlow(file, config,
|
|
4151
|
+
async function loadFlow(file, config, logger, loggerConfig, healthServer) {
|
|
3891
4152
|
const absolutePath = resolve(file);
|
|
3892
4153
|
const flowDir = dirname(absolutePath);
|
|
3893
4154
|
process.chdir(flowDir);
|
|
@@ -3900,7 +4161,7 @@ async function loadFlow(file, config, logger2, loggerConfig2, healthServer) {
|
|
|
3900
4161
|
}
|
|
3901
4162
|
const flowContext = {
|
|
3902
4163
|
...config,
|
|
3903
|
-
...
|
|
4164
|
+
...loggerConfig ? { logger: loggerConfig } : {},
|
|
3904
4165
|
...healthServer ? { externalServer: true } : {}
|
|
3905
4166
|
};
|
|
3906
4167
|
const result = await module.default(flowContext);
|
|
@@ -3919,73 +4180,389 @@ async function loadFlow(file, config, logger2, loggerConfig2, healthServer) {
|
|
|
3919
4180
|
httpHandler: result.httpHandler
|
|
3920
4181
|
};
|
|
3921
4182
|
}
|
|
3922
|
-
async function
|
|
3923
|
-
|
|
4183
|
+
async function swapFlow(currentHandle, newFile, config, logger, loggerConfig, healthServer) {
|
|
4184
|
+
logger.info("Shutting down current flow for hot-swap...");
|
|
4185
|
+
if (healthServer) {
|
|
4186
|
+
healthServer.setFlowHandler(null);
|
|
4187
|
+
}
|
|
3924
4188
|
try {
|
|
3925
|
-
|
|
3926
|
-
|
|
3927
|
-
|
|
3928
|
-
logger2.info(`Port: ${config.port}`);
|
|
3929
|
-
}
|
|
3930
|
-
const shutdown = async (signal) => {
|
|
3931
|
-
logger2.info(`Received ${signal}, shutting down gracefully...`);
|
|
3932
|
-
const forceTimer = setTimeout(() => {
|
|
3933
|
-
logger2.error("Shutdown timed out, forcing exit");
|
|
3934
|
-
process.exit(1);
|
|
3935
|
-
}, 15e3);
|
|
3936
|
-
try {
|
|
3937
|
-
if (handle.collector.command) {
|
|
3938
|
-
await handle.collector.command("shutdown");
|
|
3939
|
-
}
|
|
3940
|
-
logger2.info("Shutdown complete");
|
|
3941
|
-
clearTimeout(forceTimer);
|
|
3942
|
-
process.exit(0);
|
|
3943
|
-
} catch (error) {
|
|
3944
|
-
clearTimeout(forceTimer);
|
|
3945
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
3946
|
-
logger2.error(`Error during shutdown: ${message}`);
|
|
3947
|
-
process.exit(1);
|
|
3948
|
-
}
|
|
3949
|
-
};
|
|
3950
|
-
process.on("SIGTERM", () => shutdown("SIGTERM"));
|
|
3951
|
-
process.on("SIGINT", () => shutdown("SIGINT"));
|
|
3952
|
-
await new Promise(() => {
|
|
3953
|
-
});
|
|
4189
|
+
if (currentHandle.collector.command) {
|
|
4190
|
+
await currentHandle.collector.command("shutdown");
|
|
4191
|
+
}
|
|
3954
4192
|
} catch (error) {
|
|
3955
|
-
|
|
3956
|
-
|
|
3957
|
-
|
|
3958
|
-
|
|
4193
|
+
logger.debug(`Shutdown warning: ${error}`);
|
|
4194
|
+
}
|
|
4195
|
+
const newHandle = await loadFlow(
|
|
4196
|
+
newFile,
|
|
4197
|
+
config,
|
|
4198
|
+
logger,
|
|
4199
|
+
loggerConfig,
|
|
4200
|
+
healthServer
|
|
4201
|
+
);
|
|
4202
|
+
logger.info("Flow swapped successfully");
|
|
4203
|
+
return newHandle;
|
|
4204
|
+
}
|
|
4205
|
+
|
|
4206
|
+
// src/runtime/heartbeat.ts
|
|
4207
|
+
import { randomBytes } from "crypto";
|
|
4208
|
+
|
|
4209
|
+
// src/version.ts
|
|
4210
|
+
import { readFileSync as readFileSync3 } from "fs";
|
|
4211
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
4212
|
+
import { dirname as dirname2, join as join3 } from "path";
|
|
4213
|
+
var versionFilename = fileURLToPath2(import.meta.url);
|
|
4214
|
+
var versionDirname = dirname2(versionFilename);
|
|
4215
|
+
function findPackageJson() {
|
|
4216
|
+
const paths = [
|
|
4217
|
+
join3(versionDirname, "../package.json"),
|
|
4218
|
+
// dist/ or src/
|
|
4219
|
+
join3(versionDirname, "../../package.json")
|
|
4220
|
+
// src/core/ (not used, but safe)
|
|
4221
|
+
];
|
|
4222
|
+
for (const p2 of paths) {
|
|
4223
|
+
try {
|
|
4224
|
+
return readFileSync3(p2, "utf-8");
|
|
4225
|
+
} catch {
|
|
3959
4226
|
}
|
|
3960
|
-
throw error;
|
|
3961
4227
|
}
|
|
4228
|
+
return JSON.stringify({ version: "0.0.0" });
|
|
3962
4229
|
}
|
|
4230
|
+
var VERSION = JSON.parse(findPackageJson()).version;
|
|
3963
4231
|
|
|
3964
4232
|
// src/runtime/heartbeat.ts
|
|
3965
|
-
|
|
3966
|
-
|
|
4233
|
+
function computeCounterDelta(current, last) {
|
|
4234
|
+
const destinations = {};
|
|
4235
|
+
for (const [name, dest] of Object.entries(current.destinations)) {
|
|
4236
|
+
const prev = last.destinations[name] || {
|
|
4237
|
+
count: 0,
|
|
4238
|
+
failed: 0,
|
|
4239
|
+
duration: 0
|
|
4240
|
+
};
|
|
4241
|
+
destinations[name] = {
|
|
4242
|
+
count: dest.count - prev.count,
|
|
4243
|
+
failed: dest.failed - prev.failed,
|
|
4244
|
+
duration: dest.duration - prev.duration
|
|
4245
|
+
};
|
|
4246
|
+
}
|
|
4247
|
+
return {
|
|
4248
|
+
eventsIn: current.in - last.in,
|
|
4249
|
+
eventsOut: current.out - last.out,
|
|
4250
|
+
eventsFailed: current.failed - last.failed,
|
|
4251
|
+
destinations
|
|
4252
|
+
};
|
|
4253
|
+
}
|
|
3967
4254
|
var instanceId = randomBytes(8).toString("hex");
|
|
4255
|
+
function getInstanceId() {
|
|
4256
|
+
return instanceId;
|
|
4257
|
+
}
|
|
4258
|
+
function createHeartbeat(config, logger) {
|
|
4259
|
+
let timer = null;
|
|
4260
|
+
const startTime = Date.now();
|
|
4261
|
+
let configVersion = config.configVersion;
|
|
4262
|
+
let lastReported = {
|
|
4263
|
+
in: 0,
|
|
4264
|
+
out: 0,
|
|
4265
|
+
failed: 0,
|
|
4266
|
+
destinations: {}
|
|
4267
|
+
};
|
|
4268
|
+
async function sendOnce() {
|
|
4269
|
+
try {
|
|
4270
|
+
let counters;
|
|
4271
|
+
const status = config.getCounters?.();
|
|
4272
|
+
if (status) {
|
|
4273
|
+
const current = {
|
|
4274
|
+
in: status.in,
|
|
4275
|
+
out: status.out,
|
|
4276
|
+
failed: status.failed,
|
|
4277
|
+
destinations: { ...status.destinations }
|
|
4278
|
+
};
|
|
4279
|
+
counters = computeCounterDelta(current, lastReported);
|
|
4280
|
+
}
|
|
4281
|
+
const response = await fetch(
|
|
4282
|
+
`${config.appUrl}/api/projects/${config.projectId}/runners/heartbeat`,
|
|
4283
|
+
{
|
|
4284
|
+
method: "POST",
|
|
4285
|
+
headers: {
|
|
4286
|
+
Authorization: `Bearer ${config.token}`,
|
|
4287
|
+
"Content-Type": "application/json"
|
|
4288
|
+
},
|
|
4289
|
+
body: JSON.stringify({
|
|
4290
|
+
instanceId,
|
|
4291
|
+
flowId: config.flowId,
|
|
4292
|
+
...config.deploymentId && {
|
|
4293
|
+
deploymentId: config.deploymentId
|
|
4294
|
+
},
|
|
4295
|
+
configVersion,
|
|
4296
|
+
cliVersion: VERSION,
|
|
4297
|
+
uptime: Math.floor((Date.now() - startTime) / 1e3),
|
|
4298
|
+
...counters && { counters }
|
|
4299
|
+
}),
|
|
4300
|
+
signal: AbortSignal.timeout(1e4)
|
|
4301
|
+
}
|
|
4302
|
+
);
|
|
4303
|
+
if (response.ok && status) {
|
|
4304
|
+
lastReported = {
|
|
4305
|
+
in: status.in,
|
|
4306
|
+
out: status.out,
|
|
4307
|
+
failed: status.failed,
|
|
4308
|
+
destinations: { ...status.destinations }
|
|
4309
|
+
};
|
|
4310
|
+
}
|
|
4311
|
+
if (response.status === 401 || response.status === 403) {
|
|
4312
|
+
logger.error(
|
|
4313
|
+
`Heartbeat auth failed (${response.status}). Token may have expired \u2014 redeploy to rotate.`
|
|
4314
|
+
);
|
|
4315
|
+
}
|
|
4316
|
+
} catch (error) {
|
|
4317
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
4318
|
+
logger.warn(`Heartbeat failed: ${message}`);
|
|
4319
|
+
}
|
|
4320
|
+
}
|
|
4321
|
+
function start() {
|
|
4322
|
+
sendOnce();
|
|
4323
|
+
const jitter = config.intervalMs * 0.1 * (Math.random() * 2 - 1);
|
|
4324
|
+
timer = setInterval(() => sendOnce(), config.intervalMs + jitter);
|
|
4325
|
+
}
|
|
4326
|
+
function stop() {
|
|
4327
|
+
if (timer) {
|
|
4328
|
+
clearInterval(timer);
|
|
4329
|
+
timer = null;
|
|
4330
|
+
}
|
|
4331
|
+
}
|
|
4332
|
+
function updateConfigVersion(version) {
|
|
4333
|
+
configVersion = version;
|
|
4334
|
+
}
|
|
4335
|
+
return { start, stop, sendOnce, updateConfigVersion };
|
|
4336
|
+
}
|
|
4337
|
+
|
|
4338
|
+
// src/runtime/poller.ts
|
|
4339
|
+
function createPoller(config, logger) {
|
|
4340
|
+
let timer = null;
|
|
4341
|
+
let lastEtag;
|
|
4342
|
+
async function pollOnce() {
|
|
4343
|
+
try {
|
|
4344
|
+
const result = await fetchConfig({
|
|
4345
|
+
...config.fetchOptions,
|
|
4346
|
+
lastEtag
|
|
4347
|
+
});
|
|
4348
|
+
if (!result.changed) {
|
|
4349
|
+
logger.debug("Config unchanged");
|
|
4350
|
+
return;
|
|
4351
|
+
}
|
|
4352
|
+
logger.info(`New config version: ${result.version}`);
|
|
4353
|
+
lastEtag = result.etag;
|
|
4354
|
+
await config.onUpdate(result.content, result.version);
|
|
4355
|
+
logger.info("Config updated successfully");
|
|
4356
|
+
} catch (error) {
|
|
4357
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
4358
|
+
logger.error(`Poll error: ${message}`);
|
|
4359
|
+
}
|
|
4360
|
+
}
|
|
4361
|
+
function start() {
|
|
4362
|
+
lastEtag = void 0;
|
|
4363
|
+
const jitter = config.intervalMs * 0.15 * (Math.random() * 2 - 1);
|
|
4364
|
+
timer = setInterval(() => pollOnce(), config.intervalMs + jitter);
|
|
4365
|
+
logger.info(
|
|
4366
|
+
`Polling every ${Math.round((config.intervalMs + jitter) / 1e3)}s`
|
|
4367
|
+
);
|
|
4368
|
+
}
|
|
4369
|
+
function stop() {
|
|
4370
|
+
if (timer) {
|
|
4371
|
+
clearInterval(timer);
|
|
4372
|
+
timer = null;
|
|
4373
|
+
}
|
|
4374
|
+
}
|
|
4375
|
+
return { start, stop, pollOnce };
|
|
4376
|
+
}
|
|
3968
4377
|
|
|
3969
|
-
// src/
|
|
3970
|
-
var
|
|
3971
|
-
|
|
3972
|
-
|
|
3973
|
-
|
|
3974
|
-
|
|
3975
|
-
|
|
3976
|
-
|
|
4378
|
+
// src/runtime/secrets-fetcher.ts
|
|
4379
|
+
var SecretsHttpError = class extends Error {
|
|
4380
|
+
constructor(status, statusText) {
|
|
4381
|
+
super(`Failed to fetch secrets: ${status} ${statusText}`);
|
|
4382
|
+
this.status = status;
|
|
4383
|
+
this.name = "SecretsHttpError";
|
|
4384
|
+
}
|
|
4385
|
+
};
|
|
4386
|
+
async function fetchSecrets(options) {
|
|
4387
|
+
const { appUrl, token, projectId, flowId } = options;
|
|
4388
|
+
const url = `${appUrl}/api/projects/${encodeURIComponent(projectId)}/flows/${encodeURIComponent(flowId)}/secrets/values`;
|
|
4389
|
+
const res = await fetch(url, {
|
|
4390
|
+
headers: {
|
|
4391
|
+
Authorization: `Bearer ${token}`,
|
|
4392
|
+
"Content-Type": "application/json"
|
|
4393
|
+
}
|
|
4394
|
+
});
|
|
4395
|
+
if (!res.ok) {
|
|
4396
|
+
throw new SecretsHttpError(res.status, res.statusText);
|
|
4397
|
+
}
|
|
4398
|
+
const json = await res.json();
|
|
4399
|
+
return json.values;
|
|
4400
|
+
}
|
|
4401
|
+
|
|
4402
|
+
// src/commands/run/pipeline.ts
|
|
4403
|
+
init_cache();
|
|
4404
|
+
async function runPipeline(options) {
|
|
4405
|
+
const { bundlePath, port, logger, loggerConfig, api } = options;
|
|
4406
|
+
let configVersion;
|
|
4407
|
+
if (api) {
|
|
4408
|
+
await injectSecrets(api, logger);
|
|
4409
|
+
}
|
|
4410
|
+
logger.info(`walkeros/flow v${VERSION}`);
|
|
4411
|
+
logger.info(`Instance: ${getInstanceId()}`);
|
|
4412
|
+
const healthServer = await createHealthServer(port, logger);
|
|
4413
|
+
const runtimeConfig = { port };
|
|
4414
|
+
let handle;
|
|
4415
|
+
try {
|
|
4416
|
+
handle = await loadFlow(
|
|
4417
|
+
bundlePath,
|
|
4418
|
+
runtimeConfig,
|
|
4419
|
+
logger,
|
|
4420
|
+
loggerConfig,
|
|
4421
|
+
healthServer
|
|
4422
|
+
);
|
|
4423
|
+
} catch (error) {
|
|
4424
|
+
await healthServer.close();
|
|
4425
|
+
throw error;
|
|
4426
|
+
}
|
|
4427
|
+
logger.info("Flow running");
|
|
4428
|
+
logger.info(`Port: ${port}`);
|
|
4429
|
+
let heartbeat = null;
|
|
4430
|
+
let poller = null;
|
|
4431
|
+
if (api) {
|
|
4432
|
+
heartbeat = createHeartbeat(
|
|
4433
|
+
{
|
|
4434
|
+
appUrl: api.appUrl,
|
|
4435
|
+
token: api.token,
|
|
4436
|
+
projectId: api.projectId,
|
|
4437
|
+
flowId: api.flowId,
|
|
4438
|
+
configVersion,
|
|
4439
|
+
intervalMs: api.heartbeatIntervalMs,
|
|
4440
|
+
getCounters: () => handle.collector.status
|
|
4441
|
+
},
|
|
4442
|
+
logger
|
|
4443
|
+
);
|
|
4444
|
+
heartbeat.start();
|
|
4445
|
+
logger.info(`Heartbeat: active (every ${api.heartbeatIntervalMs / 1e3}s)`);
|
|
4446
|
+
poller = createPoller(
|
|
4447
|
+
{
|
|
4448
|
+
fetchOptions: {
|
|
4449
|
+
appUrl: api.appUrl,
|
|
4450
|
+
token: api.token,
|
|
4451
|
+
projectId: api.projectId,
|
|
4452
|
+
flowId: api.flowId
|
|
4453
|
+
},
|
|
4454
|
+
intervalMs: api.pollIntervalMs,
|
|
4455
|
+
onUpdate: async (content, version) => {
|
|
4456
|
+
try {
|
|
4457
|
+
await injectSecrets(api, logger);
|
|
4458
|
+
} catch (error) {
|
|
4459
|
+
logger.error(
|
|
4460
|
+
`Failed to refresh secrets during poll, skipping hot-swap: ${error instanceof Error ? error.message : error}`
|
|
4461
|
+
);
|
|
4462
|
+
return;
|
|
4463
|
+
}
|
|
4464
|
+
const tmpConfigPath = `/tmp/walkeros-flow-${Date.now()}.json`;
|
|
4465
|
+
writeFileSync4(
|
|
4466
|
+
tmpConfigPath,
|
|
4467
|
+
JSON.stringify(content, null, 2),
|
|
4468
|
+
"utf-8"
|
|
4469
|
+
);
|
|
4470
|
+
const newBundle = await api.prepareBundleForRun(tmpConfigPath, {
|
|
4471
|
+
verbose: false,
|
|
4472
|
+
silent: true,
|
|
4473
|
+
flowName: api.flowName
|
|
4474
|
+
});
|
|
4475
|
+
handle = await swapFlow(
|
|
4476
|
+
handle,
|
|
4477
|
+
newBundle,
|
|
4478
|
+
runtimeConfig,
|
|
4479
|
+
logger,
|
|
4480
|
+
loggerConfig,
|
|
4481
|
+
healthServer
|
|
4482
|
+
);
|
|
4483
|
+
writeCache(api.cacheDir, newBundle, JSON.stringify(content), version);
|
|
4484
|
+
configVersion = version;
|
|
4485
|
+
if (heartbeat) heartbeat.updateConfigVersion(version);
|
|
4486
|
+
logger.info(`Hot-swapped to version ${version}`);
|
|
4487
|
+
}
|
|
4488
|
+
},
|
|
4489
|
+
logger
|
|
4490
|
+
);
|
|
4491
|
+
poller.start();
|
|
4492
|
+
logger.info(`Polling: active (every ${api.pollIntervalMs / 1e3}s)`);
|
|
4493
|
+
}
|
|
4494
|
+
const shutdown = async (signal) => {
|
|
4495
|
+
logger.info(`Received ${signal}, shutting down...`);
|
|
4496
|
+
const forceTimer = setTimeout(() => {
|
|
4497
|
+
logger.error("Shutdown timed out, forcing exit");
|
|
4498
|
+
process.exit(1);
|
|
4499
|
+
}, 15e3);
|
|
4500
|
+
try {
|
|
4501
|
+
if (poller) poller.stop();
|
|
4502
|
+
if (heartbeat) heartbeat.stop();
|
|
4503
|
+
if (handle.collector.command) {
|
|
4504
|
+
await handle.collector.command("shutdown");
|
|
4505
|
+
}
|
|
4506
|
+
await healthServer.close();
|
|
4507
|
+
logger.info("Shutdown complete");
|
|
4508
|
+
clearTimeout(forceTimer);
|
|
4509
|
+
process.exit(0);
|
|
4510
|
+
} catch (error) {
|
|
4511
|
+
clearTimeout(forceTimer);
|
|
4512
|
+
logger.error(
|
|
4513
|
+
`Error during shutdown: ${error instanceof Error ? error.message : String(error)}`
|
|
4514
|
+
);
|
|
4515
|
+
process.exit(1);
|
|
4516
|
+
}
|
|
3977
4517
|
};
|
|
3978
|
-
|
|
4518
|
+
process.on("SIGTERM", () => shutdown("SIGTERM"));
|
|
4519
|
+
process.on("SIGINT", () => shutdown("SIGINT"));
|
|
4520
|
+
await new Promise(() => {
|
|
4521
|
+
});
|
|
4522
|
+
}
|
|
4523
|
+
async function injectSecrets(api, logger) {
|
|
4524
|
+
try {
|
|
4525
|
+
const secrets = await fetchSecrets({
|
|
4526
|
+
appUrl: api.appUrl,
|
|
4527
|
+
token: api.token,
|
|
4528
|
+
projectId: api.projectId,
|
|
4529
|
+
flowId: api.flowId
|
|
4530
|
+
});
|
|
4531
|
+
const count = Object.keys(secrets).length;
|
|
4532
|
+
if (count > 0) {
|
|
4533
|
+
for (const [name, value] of Object.entries(secrets)) {
|
|
4534
|
+
process.env[name] = value;
|
|
4535
|
+
}
|
|
4536
|
+
logger.info(`Injected ${count} secret(s) into environment`);
|
|
4537
|
+
}
|
|
4538
|
+
} catch (error) {
|
|
4539
|
+
if (error instanceof SecretsHttpError && (error.status === 401 || error.status === 403)) {
|
|
4540
|
+
throw error;
|
|
4541
|
+
}
|
|
4542
|
+
logger.warn(
|
|
4543
|
+
`Could not fetch secrets: ${error instanceof Error ? error.message : error}`
|
|
4544
|
+
);
|
|
4545
|
+
logger.info("Continuing without secrets (flow may not require them)");
|
|
4546
|
+
}
|
|
3979
4547
|
}
|
|
3980
4548
|
|
|
3981
4549
|
// src/commands/run/index.ts
|
|
3982
4550
|
var esmRequire = createRequire(import.meta.url);
|
|
4551
|
+
function defaultCacheDir() {
|
|
4552
|
+
const xdgCache = process.env.XDG_CACHE_HOME;
|
|
4553
|
+
const base = xdgCache || join4(homedir2(), ".cache");
|
|
4554
|
+
return join4(base, "walkeros");
|
|
4555
|
+
}
|
|
4556
|
+
async function lazyPrepareBundleForRun(configPath, options) {
|
|
4557
|
+
const { prepareBundleForRun: prepareBundleForRun2 } = await Promise.resolve().then(() => (init_utils3(), utils_exports));
|
|
4558
|
+
return prepareBundleForRun2(configPath, options);
|
|
4559
|
+
}
|
|
3983
4560
|
async function runCommand(options) {
|
|
3984
4561
|
const timer = createTimer();
|
|
3985
4562
|
timer.start();
|
|
3986
|
-
const
|
|
4563
|
+
const logger = createCLILogger(options);
|
|
3987
4564
|
try {
|
|
3988
|
-
const
|
|
4565
|
+
const port = options.port ?? 8080;
|
|
3989
4566
|
if (options.port !== void 0) {
|
|
3990
4567
|
validatePort(options.port);
|
|
3991
4568
|
}
|
|
@@ -3994,7 +4571,7 @@ async function runCommand(options) {
|
|
|
3994
4571
|
try {
|
|
3995
4572
|
esmRequire.resolve(dep);
|
|
3996
4573
|
} catch {
|
|
3997
|
-
|
|
4574
|
+
logger.error(
|
|
3998
4575
|
`Missing runtime dependency "${dep}"
|
|
3999
4576
|
Server flows require express and cors when running outside Docker.
|
|
4000
4577
|
Run: npm install express cors`
|
|
@@ -4002,84 +4579,167 @@ Run: npm install express cors`
|
|
|
4002
4579
|
process.exit(1);
|
|
4003
4580
|
}
|
|
4004
4581
|
}
|
|
4005
|
-
const
|
|
4006
|
-
|
|
4007
|
-
|
|
4008
|
-
|
|
4009
|
-
|
|
4010
|
-
|
|
4011
|
-
|
|
4012
|
-
|
|
4013
|
-
|
|
4014
|
-
|
|
4015
|
-
|
|
4016
|
-
|
|
4017
|
-
|
|
4018
|
-
|
|
4019
|
-
|
|
4020
|
-
|
|
4021
|
-
|
|
4022
|
-
|
|
4023
|
-
|
|
4024
|
-
|
|
4025
|
-
|
|
4026
|
-
|
|
4582
|
+
const flowId = options.flowId;
|
|
4583
|
+
const projectId = options.project;
|
|
4584
|
+
const token = resolveRunToken();
|
|
4585
|
+
const appUrl = resolveAppUrl();
|
|
4586
|
+
const flowName = options.flow;
|
|
4587
|
+
let apiConfig;
|
|
4588
|
+
if (flowId) {
|
|
4589
|
+
if (!token) {
|
|
4590
|
+
logger.error(
|
|
4591
|
+
`Remote flow requires authentication.
|
|
4592
|
+
|
|
4593
|
+
No token found. Authenticate first:
|
|
4594
|
+
$ walkeros auth login
|
|
4595
|
+
|
|
4596
|
+
Or set WALKEROS_TOKEN:
|
|
4597
|
+
$ export WALKEROS_TOKEN=<your-token>`
|
|
4598
|
+
);
|
|
4599
|
+
process.exit(1);
|
|
4600
|
+
}
|
|
4601
|
+
if (!projectId) {
|
|
4602
|
+
logger.error(
|
|
4603
|
+
`--flow-id requires --project or WALKEROS_PROJECT_ID.
|
|
4604
|
+
|
|
4605
|
+
Set the project:
|
|
4606
|
+
$ walkeros run --flow-id ${flowId} --project <your-project-id>
|
|
4607
|
+
$ export WALKEROS_PROJECT_ID=<your-project-id>`
|
|
4608
|
+
);
|
|
4609
|
+
process.exit(1);
|
|
4610
|
+
}
|
|
4611
|
+
apiConfig = {
|
|
4612
|
+
appUrl,
|
|
4613
|
+
token,
|
|
4614
|
+
projectId,
|
|
4615
|
+
flowId,
|
|
4616
|
+
heartbeatIntervalMs: parseInt(
|
|
4617
|
+
process.env.WALKEROS_HEARTBEAT_INTERVAL ?? process.env.HEARTBEAT_INTERVAL ?? "60",
|
|
4618
|
+
10
|
|
4619
|
+
) * 1e3,
|
|
4620
|
+
pollIntervalMs: parseInt(
|
|
4621
|
+
process.env.WALKEROS_POLL_INTERVAL ?? process.env.POLL_INTERVAL ?? "30",
|
|
4622
|
+
10
|
|
4623
|
+
) * 1e3,
|
|
4624
|
+
cacheDir: process.env.WALKEROS_CACHE_DIR ?? process.env.CACHE_DIR ?? defaultCacheDir(),
|
|
4625
|
+
flowName,
|
|
4626
|
+
prepareBundleForRun: lazyPrepareBundleForRun
|
|
4627
|
+
};
|
|
4027
4628
|
}
|
|
4028
|
-
|
|
4029
|
-
|
|
4030
|
-
|
|
4031
|
-
|
|
4629
|
+
const bundlePath = await resolveBundlePath(
|
|
4630
|
+
options.config,
|
|
4631
|
+
apiConfig,
|
|
4632
|
+
logger
|
|
4633
|
+
);
|
|
4634
|
+
logger.info("Starting flow...");
|
|
4635
|
+
await runPipeline({
|
|
4636
|
+
bundlePath,
|
|
4637
|
+
port,
|
|
4638
|
+
logger: logger.scope("runner"),
|
|
4639
|
+
loggerConfig: options.verbose ? { level: 0 } : void 0,
|
|
4640
|
+
api: apiConfig
|
|
4032
4641
|
});
|
|
4033
4642
|
} catch (error) {
|
|
4034
4643
|
const duration = timer.getElapsed() / 1e3;
|
|
4035
4644
|
const errorMessage = getErrorMessage(error);
|
|
4036
4645
|
if (options.json) {
|
|
4037
|
-
|
|
4646
|
+
logger.json({
|
|
4038
4647
|
success: false,
|
|
4039
4648
|
error: errorMessage,
|
|
4040
4649
|
duration
|
|
4041
4650
|
});
|
|
4042
4651
|
} else {
|
|
4043
|
-
|
|
4652
|
+
logger.error(`Error: ${errorMessage}`);
|
|
4044
4653
|
}
|
|
4045
4654
|
process.exit(1);
|
|
4046
4655
|
}
|
|
4047
4656
|
}
|
|
4048
|
-
async function
|
|
4049
|
-
|
|
4050
|
-
|
|
4051
|
-
|
|
4052
|
-
|
|
4053
|
-
|
|
4657
|
+
async function resolveBundlePath(configInput, apiConfig, logger) {
|
|
4658
|
+
if (configInput) {
|
|
4659
|
+
const resolved = await resolveBundle(configInput);
|
|
4660
|
+
if (resolved.source === "stdin") {
|
|
4661
|
+
logger.info("Bundle: received via stdin");
|
|
4662
|
+
} else if (resolved.source === "url") {
|
|
4663
|
+
logger.info("Bundle: fetched from URL");
|
|
4054
4664
|
} else {
|
|
4055
|
-
|
|
4665
|
+
logger.info(`Bundle: ${resolved.path}`);
|
|
4056
4666
|
}
|
|
4057
|
-
if (
|
|
4058
|
-
|
|
4667
|
+
if (isPreBuiltConfig(resolved.path)) {
|
|
4668
|
+
return path14.resolve(resolved.path);
|
|
4059
4669
|
}
|
|
4060
|
-
const
|
|
4061
|
-
|
|
4062
|
-
|
|
4063
|
-
|
|
4064
|
-
|
|
4065
|
-
|
|
4066
|
-
|
|
4670
|
+
const flowFile = validateFlowFile(resolved.path);
|
|
4671
|
+
logger.debug("Building flow bundle");
|
|
4672
|
+
return lazyPrepareBundleForRun(flowFile, {
|
|
4673
|
+
verbose: false,
|
|
4674
|
+
silent: true,
|
|
4675
|
+
flowName: apiConfig?.flowName
|
|
4676
|
+
});
|
|
4677
|
+
}
|
|
4678
|
+
if (apiConfig) {
|
|
4679
|
+
logger.info("Fetching config from API...");
|
|
4680
|
+
try {
|
|
4681
|
+
const result = await fetchConfig({
|
|
4682
|
+
appUrl: apiConfig.appUrl,
|
|
4683
|
+
token: apiConfig.token,
|
|
4684
|
+
projectId: apiConfig.projectId,
|
|
4685
|
+
flowId: apiConfig.flowId
|
|
4686
|
+
});
|
|
4687
|
+
if (result.changed) {
|
|
4688
|
+
const tmpConfigPath = `/tmp/walkeros-flow-${Date.now()}.json`;
|
|
4689
|
+
writeFileSync5(
|
|
4690
|
+
tmpConfigPath,
|
|
4691
|
+
JSON.stringify(result.content, null, 2),
|
|
4692
|
+
"utf-8"
|
|
4067
4693
|
);
|
|
4694
|
+
logger.info(`Config version: ${result.version}`);
|
|
4695
|
+
logger.info("Building flow...");
|
|
4696
|
+
const bundlePath = await lazyPrepareBundleForRun(tmpConfigPath, {
|
|
4697
|
+
verbose: false,
|
|
4698
|
+
silent: true,
|
|
4699
|
+
flowName: apiConfig.flowName
|
|
4700
|
+
});
|
|
4701
|
+
try {
|
|
4702
|
+
const { writeCache: writeCache2 } = await Promise.resolve().then(() => (init_cache(), cache_exports));
|
|
4703
|
+
writeCache2(
|
|
4704
|
+
apiConfig.cacheDir,
|
|
4705
|
+
bundlePath,
|
|
4706
|
+
JSON.stringify(result.content),
|
|
4707
|
+
result.version
|
|
4708
|
+
);
|
|
4709
|
+
} catch {
|
|
4710
|
+
logger.debug("Cache write failed (non-critical)");
|
|
4711
|
+
}
|
|
4712
|
+
return bundlePath;
|
|
4068
4713
|
}
|
|
4714
|
+
} catch (error) {
|
|
4715
|
+
logger.error(
|
|
4716
|
+
`API fetch failed: ${error instanceof Error ? error.message : error}`
|
|
4717
|
+
);
|
|
4718
|
+
const cached = readCache(apiConfig.cacheDir);
|
|
4719
|
+
if (cached) {
|
|
4720
|
+
logger.info(`Using cached bundle (version: ${cached.version})`);
|
|
4721
|
+
return cached.bundlePath;
|
|
4722
|
+
}
|
|
4723
|
+
throw new Error(
|
|
4724
|
+
"No config available. API fetch failed and no cached bundle."
|
|
4725
|
+
);
|
|
4069
4726
|
}
|
|
4070
|
-
|
|
4071
|
-
|
|
4072
|
-
|
|
4073
|
-
|
|
4074
|
-
|
|
4075
|
-
|
|
4076
|
-
|
|
4077
|
-
|
|
4078
|
-
|
|
4079
|
-
|
|
4080
|
-
await executeRunLocal(flowPath, {
|
|
4727
|
+
}
|
|
4728
|
+
const defaultFile = "server-collect.mjs";
|
|
4729
|
+
logger.debug(`No config specified, using default: ${defaultFile}`);
|
|
4730
|
+
return path14.resolve(defaultFile);
|
|
4731
|
+
}
|
|
4732
|
+
async function run(options) {
|
|
4733
|
+
const startTime = Date.now();
|
|
4734
|
+
try {
|
|
4735
|
+
await runCommand({
|
|
4736
|
+
config: options.config,
|
|
4081
4737
|
port: options.port,
|
|
4082
|
-
|
|
4738
|
+
flow: options.flow,
|
|
4739
|
+
flowId: options.flowId,
|
|
4740
|
+
project: options.project,
|
|
4741
|
+
verbose: options.verbose,
|
|
4742
|
+
silent: options.silent ?? true
|
|
4083
4743
|
});
|
|
4084
4744
|
return {
|
|
4085
4745
|
success: true,
|
|
@@ -4098,6 +4758,8 @@ async function run(options) {
|
|
|
4098
4758
|
|
|
4099
4759
|
// src/commands/validate/index.ts
|
|
4100
4760
|
init_cli_logger();
|
|
4761
|
+
init_core();
|
|
4762
|
+
init_config();
|
|
4101
4763
|
import chalk2 from "chalk";
|
|
4102
4764
|
|
|
4103
4765
|
// src/commands/validate/validators/contract.ts
|
|
@@ -4255,7 +4917,7 @@ function validateEvent(input) {
|
|
|
4255
4917
|
|
|
4256
4918
|
// src/commands/validate/validators/flow.ts
|
|
4257
4919
|
import { schemas as schemas4 } from "@walkeros/core/dev";
|
|
4258
|
-
var {
|
|
4920
|
+
var { validateFlowConfig: validateFlowConfig3 } = schemas4;
|
|
4259
4921
|
function validateFlow(input, options = {}) {
|
|
4260
4922
|
const errors = [];
|
|
4261
4923
|
const warnings = [];
|
|
@@ -4271,7 +4933,7 @@ function validateFlow(input, options = {}) {
|
|
|
4271
4933
|
});
|
|
4272
4934
|
return { valid: false, type: "flow", errors, warnings, details };
|
|
4273
4935
|
}
|
|
4274
|
-
const coreResult =
|
|
4936
|
+
const coreResult = validateFlowConfig3(json);
|
|
4275
4937
|
for (const issue of coreResult.errors) {
|
|
4276
4938
|
errors.push({
|
|
4277
4939
|
path: issue.path || "root",
|
|
@@ -4331,20 +4993,20 @@ function validateFlow(input, options = {}) {
|
|
|
4331
4993
|
const flowsToCheck = options.flow ? [options.flow] : flowNames;
|
|
4332
4994
|
let totalConnections = 0;
|
|
4333
4995
|
for (const name of flowsToCheck) {
|
|
4334
|
-
const
|
|
4335
|
-
if (!
|
|
4336
|
-
checkExampleCoverage(
|
|
4337
|
-
const connections = buildConnectionGraph(
|
|
4996
|
+
const flowSettings = flows[name];
|
|
4997
|
+
if (!flowSettings) continue;
|
|
4998
|
+
checkExampleCoverage(flowSettings, warnings);
|
|
4999
|
+
const connections = buildConnectionGraph(flowSettings);
|
|
4338
5000
|
for (const conn of connections) {
|
|
4339
5001
|
checkCompatibility(conn, errors, warnings);
|
|
4340
5002
|
}
|
|
4341
5003
|
totalConnections += connections.length;
|
|
4342
5004
|
const setupContract = config.contract;
|
|
4343
|
-
if (setupContract ||
|
|
5005
|
+
if (setupContract || flowSettings.contract) {
|
|
4344
5006
|
checkContractCompliance(
|
|
4345
|
-
|
|
5007
|
+
flowSettings,
|
|
4346
5008
|
setupContract,
|
|
4347
|
-
|
|
5009
|
+
flowSettings.contract,
|
|
4348
5010
|
warnings
|
|
4349
5011
|
);
|
|
4350
5012
|
}
|
|
@@ -4747,7 +5409,7 @@ function formatResult(result, options) {
|
|
|
4747
5409
|
return lines.join("\n");
|
|
4748
5410
|
}
|
|
4749
5411
|
async function validateCommand(options) {
|
|
4750
|
-
const
|
|
5412
|
+
const logger = createCLILogger({ ...options, stderr: true });
|
|
4751
5413
|
try {
|
|
4752
5414
|
let input;
|
|
4753
5415
|
if (isStdinPiped() && !options.input) {
|
|
@@ -4794,7 +5456,7 @@ async function validateCommand(options) {
|
|
|
4794
5456
|
);
|
|
4795
5457
|
await writeResult(errorOutput + "\n", { output: options.output });
|
|
4796
5458
|
} else {
|
|
4797
|
-
|
|
5459
|
+
logger.error(`Error: ${errorMessage}`);
|
|
4798
5460
|
}
|
|
4799
5461
|
process.exit(3);
|
|
4800
5462
|
}
|
|
@@ -4810,22 +5472,22 @@ async function openInBrowser(url) {
|
|
|
4810
5472
|
await open(url);
|
|
4811
5473
|
}
|
|
4812
5474
|
async function loginCommand(options) {
|
|
4813
|
-
const
|
|
5475
|
+
const logger = createCLILogger(options);
|
|
4814
5476
|
try {
|
|
4815
5477
|
const result = await login({ url: options.url });
|
|
4816
5478
|
if (options.json) {
|
|
4817
|
-
|
|
5479
|
+
logger.json(result);
|
|
4818
5480
|
} else if (result.success) {
|
|
4819
|
-
|
|
4820
|
-
|
|
5481
|
+
logger.info(`Logged in as ${result.email}`);
|
|
5482
|
+
logger.info(`Token stored in ${result.configPath}`);
|
|
4821
5483
|
}
|
|
4822
5484
|
process.exit(result.success ? 0 : 1);
|
|
4823
5485
|
} catch (error) {
|
|
4824
5486
|
const message = error instanceof Error ? error.message : String(error);
|
|
4825
5487
|
if (options.json) {
|
|
4826
|
-
|
|
5488
|
+
logger.json({ success: false, error: message });
|
|
4827
5489
|
} else {
|
|
4828
|
-
|
|
5490
|
+
logger.error(message);
|
|
4829
5491
|
}
|
|
4830
5492
|
process.exit(1);
|
|
4831
5493
|
}
|
|
@@ -4897,21 +5559,23 @@ async function login(options = {}) {
|
|
|
4897
5559
|
init_cli_logger();
|
|
4898
5560
|
init_config_file();
|
|
4899
5561
|
async function logoutCommand(options) {
|
|
4900
|
-
const
|
|
5562
|
+
const logger = createCLILogger(options);
|
|
4901
5563
|
const deleted = deleteConfig();
|
|
4902
5564
|
const configPath = getConfigPath();
|
|
4903
5565
|
if (options.json) {
|
|
4904
|
-
|
|
5566
|
+
logger.json({ success: true, deleted });
|
|
4905
5567
|
} else if (deleted) {
|
|
4906
|
-
|
|
5568
|
+
logger.info(`Logged out. Token removed from ${configPath}`);
|
|
4907
5569
|
} else {
|
|
4908
|
-
|
|
5570
|
+
logger.info("No stored credentials found.");
|
|
4909
5571
|
}
|
|
4910
5572
|
process.exit(0);
|
|
4911
5573
|
}
|
|
4912
5574
|
|
|
4913
5575
|
// src/commands/auth/index.ts
|
|
5576
|
+
init_api_client();
|
|
4914
5577
|
init_cli_logger();
|
|
5578
|
+
init_output();
|
|
4915
5579
|
async function whoami() {
|
|
4916
5580
|
const client = createApiClient();
|
|
4917
5581
|
const { data, error } = await client.GET("/api/auth/whoami");
|
|
@@ -4919,26 +5583,28 @@ async function whoami() {
|
|
|
4919
5583
|
return data;
|
|
4920
5584
|
}
|
|
4921
5585
|
async function whoamiCommand(options) {
|
|
4922
|
-
const
|
|
5586
|
+
const logger = createCLILogger(options);
|
|
4923
5587
|
try {
|
|
4924
5588
|
const result = await whoami();
|
|
4925
5589
|
if (options.json) {
|
|
4926
5590
|
await writeResult(JSON.stringify(result, null, 2), options);
|
|
4927
5591
|
} else {
|
|
4928
5592
|
const data = result;
|
|
4929
|
-
if (data.email)
|
|
4930
|
-
if (data.userId)
|
|
4931
|
-
if (data.projectId)
|
|
5593
|
+
if (data.email) logger.info(`${data.email}`);
|
|
5594
|
+
if (data.userId) logger.info(`User: ${data.userId}`);
|
|
5595
|
+
if (data.projectId) logger.info(`Project: ${data.projectId}`);
|
|
4932
5596
|
}
|
|
4933
5597
|
} catch (error) {
|
|
4934
|
-
|
|
5598
|
+
logger.error(error instanceof Error ? error.message : String(error));
|
|
4935
5599
|
process.exit(1);
|
|
4936
5600
|
}
|
|
4937
5601
|
}
|
|
4938
5602
|
|
|
4939
5603
|
// src/commands/projects/index.ts
|
|
5604
|
+
init_api_client();
|
|
4940
5605
|
init_auth();
|
|
4941
5606
|
init_cli_logger();
|
|
5607
|
+
init_output();
|
|
4942
5608
|
async function listProjects() {
|
|
4943
5609
|
const client = createApiClient();
|
|
4944
5610
|
const { data, error } = await client.GET("/api/projects");
|
|
@@ -4985,12 +5651,12 @@ async function deleteProject(options = {}) {
|
|
|
4985
5651
|
return data ?? { success: true };
|
|
4986
5652
|
}
|
|
4987
5653
|
async function handleResult(fn2, options) {
|
|
4988
|
-
const
|
|
5654
|
+
const logger = createCLILogger(options);
|
|
4989
5655
|
try {
|
|
4990
5656
|
const result = await fn2();
|
|
4991
5657
|
await writeResult(JSON.stringify(result, null, 2), options);
|
|
4992
5658
|
} catch (error) {
|
|
4993
|
-
|
|
5659
|
+
logger.error(error instanceof Error ? error.message : String(error));
|
|
4994
5660
|
process.exit(1);
|
|
4995
5661
|
}
|
|
4996
5662
|
}
|
|
@@ -5027,8 +5693,11 @@ async function deleteProjectCommand(projectId, options) {
|
|
|
5027
5693
|
}
|
|
5028
5694
|
|
|
5029
5695
|
// src/commands/flows/index.ts
|
|
5696
|
+
init_api_client();
|
|
5030
5697
|
init_auth();
|
|
5031
5698
|
init_cli_logger();
|
|
5699
|
+
init_output();
|
|
5700
|
+
init_stdin();
|
|
5032
5701
|
async function listFlows(options = {}) {
|
|
5033
5702
|
const id = options.projectId ?? requireProjectId();
|
|
5034
5703
|
const client = createApiClient();
|
|
@@ -5065,8 +5734,8 @@ async function createFlow(options) {
|
|
|
5065
5734
|
const client = createApiClient();
|
|
5066
5735
|
const { data, error } = await client.POST("/api/projects/{projectId}/flows", {
|
|
5067
5736
|
params: { path: { projectId: id } },
|
|
5068
|
-
//
|
|
5069
|
-
body: { name: options.name,
|
|
5737
|
+
// Config is user-provided JSON; server validates the full schema
|
|
5738
|
+
body: { name: options.name, config: options.content }
|
|
5070
5739
|
});
|
|
5071
5740
|
if (error) throw new Error(error.error?.message || "Failed to create flow");
|
|
5072
5741
|
return data;
|
|
@@ -5076,7 +5745,7 @@ async function updateFlow(options) {
|
|
|
5076
5745
|
const client = createApiClient();
|
|
5077
5746
|
const body = {};
|
|
5078
5747
|
if (options.name !== void 0) body.name = options.name;
|
|
5079
|
-
if (options.content !== void 0) body.
|
|
5748
|
+
if (options.content !== void 0) body.config = options.content;
|
|
5080
5749
|
const { data, error } = await client.PATCH(
|
|
5081
5750
|
"/api/projects/{projectId}/flows/{flowId}",
|
|
5082
5751
|
{
|
|
@@ -5118,12 +5787,12 @@ async function duplicateFlow(options) {
|
|
|
5118
5787
|
return data;
|
|
5119
5788
|
}
|
|
5120
5789
|
async function handleResult2(fn2, options) {
|
|
5121
|
-
const
|
|
5790
|
+
const logger = createCLILogger(options);
|
|
5122
5791
|
try {
|
|
5123
5792
|
const result = await fn2();
|
|
5124
5793
|
await writeResult(JSON.stringify(result, null, 2), options);
|
|
5125
5794
|
} catch (error) {
|
|
5126
|
-
|
|
5795
|
+
logger.error(error instanceof Error ? error.message : String(error));
|
|
5127
5796
|
process.exit(1);
|
|
5128
5797
|
}
|
|
5129
5798
|
}
|
|
@@ -5183,21 +5852,24 @@ async function readFlowStdin() {
|
|
|
5183
5852
|
}
|
|
5184
5853
|
|
|
5185
5854
|
// src/commands/deploy/index.ts
|
|
5855
|
+
init_api_client();
|
|
5186
5856
|
init_auth();
|
|
5857
|
+
init_sse();
|
|
5187
5858
|
init_cli_logger();
|
|
5188
|
-
|
|
5859
|
+
init_output();
|
|
5860
|
+
async function resolveSettingsId(options) {
|
|
5189
5861
|
const flow = await getFlow({
|
|
5190
5862
|
flowId: options.flowId,
|
|
5191
5863
|
projectId: options.projectId
|
|
5192
5864
|
});
|
|
5193
|
-
const
|
|
5194
|
-
if (!
|
|
5195
|
-
throw new Error("Flow has no
|
|
5865
|
+
const settings = flow.settings;
|
|
5866
|
+
if (!settings?.length) {
|
|
5867
|
+
throw new Error("Flow has no settings.");
|
|
5196
5868
|
}
|
|
5197
|
-
const match =
|
|
5869
|
+
const match = settings.find((c2) => c2.name === options.flowName);
|
|
5198
5870
|
if (!match) {
|
|
5199
5871
|
throw new Error(
|
|
5200
|
-
`Flow "${options.flowName}" not found. Available: ${
|
|
5872
|
+
`Flow "${options.flowName}" not found. Available: ${settings.map((c2) => c2.name).join(", ")}`
|
|
5201
5873
|
);
|
|
5202
5874
|
}
|
|
5203
5875
|
return match.id;
|
|
@@ -5207,8 +5879,8 @@ async function getAvailableFlowNames(options) {
|
|
|
5207
5879
|
flowId: options.flowId,
|
|
5208
5880
|
projectId: options.projectId
|
|
5209
5881
|
});
|
|
5210
|
-
const
|
|
5211
|
-
return
|
|
5882
|
+
const settings = flow.settings;
|
|
5883
|
+
return settings?.map((c2) => c2.name) ?? [];
|
|
5212
5884
|
}
|
|
5213
5885
|
async function streamDeploymentStatus(projectId, deploymentId, options) {
|
|
5214
5886
|
const base = resolveBaseUrl();
|
|
@@ -5255,15 +5927,15 @@ async function deploy(options) {
|
|
|
5255
5927
|
const projectId = options.projectId ?? requireProjectId();
|
|
5256
5928
|
const client = createApiClient();
|
|
5257
5929
|
if (options.flowName) {
|
|
5258
|
-
const
|
|
5930
|
+
const settingsId = await resolveSettingsId({
|
|
5259
5931
|
flowId: options.flowId,
|
|
5260
5932
|
projectId,
|
|
5261
5933
|
flowName: options.flowName
|
|
5262
5934
|
});
|
|
5263
|
-
return
|
|
5935
|
+
return deploySettings({
|
|
5264
5936
|
...options,
|
|
5265
5937
|
projectId,
|
|
5266
|
-
|
|
5938
|
+
settingsId,
|
|
5267
5939
|
timeout: options.timeout,
|
|
5268
5940
|
signal: options.signal,
|
|
5269
5941
|
onStatus: options.onStatus
|
|
@@ -5282,7 +5954,7 @@ async function deploy(options) {
|
|
|
5282
5954
|
projectId
|
|
5283
5955
|
});
|
|
5284
5956
|
throw new Error(
|
|
5285
|
-
`This flow has multiple
|
|
5957
|
+
`This flow has multiple settings. Use --flow <name> to specify one.
|
|
5286
5958
|
Available: ${names.join(", ")}`
|
|
5287
5959
|
);
|
|
5288
5960
|
}
|
|
@@ -5296,11 +5968,11 @@ Available: ${names.join(", ")}`
|
|
|
5296
5968
|
});
|
|
5297
5969
|
return { ...data, ...result };
|
|
5298
5970
|
}
|
|
5299
|
-
async function
|
|
5300
|
-
const { flowId, projectId,
|
|
5971
|
+
async function deploySettings(options) {
|
|
5972
|
+
const { flowId, projectId, settingsId } = options;
|
|
5301
5973
|
const base = resolveBaseUrl();
|
|
5302
5974
|
const response = await authenticatedFetch(
|
|
5303
|
-
`${base}/api/projects/${projectId}/flows/${flowId}/
|
|
5975
|
+
`${base}/api/projects/${projectId}/flows/${flowId}/settings/${settingsId}/deploy`,
|
|
5304
5976
|
{ method: "POST" }
|
|
5305
5977
|
);
|
|
5306
5978
|
if (!response.ok) {
|
|
@@ -5321,14 +5993,14 @@ async function deployConfig(options) {
|
|
|
5321
5993
|
async function getDeployment(options) {
|
|
5322
5994
|
const projectId = options.projectId ?? requireProjectId();
|
|
5323
5995
|
if (options.flowName) {
|
|
5324
|
-
const
|
|
5996
|
+
const settingsId = await resolveSettingsId({
|
|
5325
5997
|
flowId: options.flowId,
|
|
5326
5998
|
projectId,
|
|
5327
5999
|
flowName: options.flowName
|
|
5328
6000
|
});
|
|
5329
6001
|
const base = resolveBaseUrl();
|
|
5330
6002
|
const response = await authenticatedFetch(
|
|
5331
|
-
`${base}/api/projects/${projectId}/flows/${options.flowId}/
|
|
6003
|
+
`${base}/api/projects/${projectId}/flows/${options.flowId}/settings/${settingsId}/deploy`
|
|
5332
6004
|
);
|
|
5333
6005
|
if (!response.ok) {
|
|
5334
6006
|
const body = await response.json().catch(() => ({}));
|
|
@@ -5427,6 +6099,8 @@ async function getDeploymentCommand(flowId, options) {
|
|
|
5427
6099
|
// src/commands/deployments/index.ts
|
|
5428
6100
|
init_auth();
|
|
5429
6101
|
init_cli_logger();
|
|
6102
|
+
init_output();
|
|
6103
|
+
init_loader();
|
|
5430
6104
|
import { getPlatform as getPlatform4 } from "@walkeros/core";
|
|
5431
6105
|
async function listDeployments(options = {}) {
|
|
5432
6106
|
const id = options.projectId ?? requireProjectId();
|
|
@@ -5496,12 +6170,12 @@ async function deleteDeployment(options) {
|
|
|
5496
6170
|
return data ?? { success: true };
|
|
5497
6171
|
}
|
|
5498
6172
|
async function handleResult3(fn2, options) {
|
|
5499
|
-
const
|
|
6173
|
+
const logger = createCLILogger(options);
|
|
5500
6174
|
try {
|
|
5501
6175
|
const result = await fn2();
|
|
5502
6176
|
await writeResult(JSON.stringify(result, null, 2), options);
|
|
5503
6177
|
} catch (error) {
|
|
5504
|
-
|
|
6178
|
+
logger.error(error instanceof Error ? error.message : String(error));
|
|
5505
6179
|
process.exit(1);
|
|
5506
6180
|
}
|
|
5507
6181
|
}
|
|
@@ -5561,23 +6235,23 @@ async function createDeployCommand(config, options) {
|
|
|
5561
6235
|
);
|
|
5562
6236
|
}
|
|
5563
6237
|
const flow = await resp.json();
|
|
5564
|
-
if (!flow.
|
|
5565
|
-
const
|
|
5566
|
-
const flows =
|
|
5567
|
-
if (!flows) throw new Error("Invalid flow
|
|
6238
|
+
if (!flow.config) throw new Error("Flow has no config");
|
|
6239
|
+
const flowConfig = flow.config;
|
|
6240
|
+
const flows = flowConfig.flows;
|
|
6241
|
+
if (!flows) throw new Error("Invalid flow config: missing flows");
|
|
5568
6242
|
const flowName = options.flow ?? Object.keys(flows)[0];
|
|
5569
6243
|
if (!flowName) throw new Error("No flows found in config");
|
|
5570
|
-
const
|
|
5571
|
-
if (!
|
|
6244
|
+
const flowSettings = flows[flowName];
|
|
6245
|
+
if (!flowSettings || typeof flowSettings !== "object")
|
|
5572
6246
|
throw new Error("Invalid flow config");
|
|
5573
|
-
if ("web" in
|
|
5574
|
-
else if ("server" in
|
|
6247
|
+
if ("web" in flowSettings) type = "web";
|
|
6248
|
+
else if ("server" in flowSettings) type = "server";
|
|
5575
6249
|
else throw new Error('Flow must have "web" or "server" key');
|
|
5576
6250
|
} else {
|
|
5577
6251
|
const result2 = await loadFlowConfig(config, {
|
|
5578
6252
|
flowName: options.flow
|
|
5579
6253
|
});
|
|
5580
|
-
type = getPlatform4(result2.
|
|
6254
|
+
type = getPlatform4(result2.flowSettings);
|
|
5581
6255
|
}
|
|
5582
6256
|
const deployment = await createDeployment({
|
|
5583
6257
|
type,
|
|
@@ -5617,7 +6291,11 @@ async function createDeployCommand(config, options) {
|
|
|
5617
6291
|
}
|
|
5618
6292
|
|
|
5619
6293
|
// src/index.ts
|
|
6294
|
+
init_bundle();
|
|
5620
6295
|
init_auth();
|
|
6296
|
+
init_api_client();
|
|
6297
|
+
init_sse();
|
|
6298
|
+
init_utils();
|
|
5621
6299
|
export {
|
|
5622
6300
|
bundle,
|
|
5623
6301
|
bundleCommand,
|