@walkeros/cli 3.0.2 → 4.0.0-next-1773967844643
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 +38 -0
- package/dist/cli.js +4079 -4081
- package/dist/dev.d.ts +0 -2
- package/dist/dev.js +6 -7
- package/dist/dev.js.map +1 -1
- package/dist/index.d.ts +55 -50
- package/dist/index.js +316 -332
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -193,50 +193,44 @@ var init_config_file = __esm({
|
|
|
193
193
|
}
|
|
194
194
|
});
|
|
195
195
|
|
|
196
|
-
// src/core/
|
|
197
|
-
function
|
|
198
|
-
|
|
199
|
-
return
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
196
|
+
// src/core/http.ts
|
|
197
|
+
function normalizeHeaders(headers) {
|
|
198
|
+
if (!headers) return {};
|
|
199
|
+
if (headers instanceof Headers) return Object.fromEntries(headers.entries());
|
|
200
|
+
if (Array.isArray(headers)) return Object.fromEntries(headers);
|
|
201
|
+
return headers;
|
|
202
|
+
}
|
|
203
|
+
function mergeAuthHeaders(token, headers) {
|
|
204
|
+
const normalized = normalizeHeaders(headers);
|
|
205
|
+
if (token) normalized.Authorization = `Bearer ${token}`;
|
|
206
|
+
return normalized;
|
|
207
|
+
}
|
|
208
|
+
async function apiFetch(path15, init) {
|
|
209
|
+
const baseUrl = resolveAppUrl();
|
|
210
|
+
const token = resolveToken()?.token;
|
|
211
|
+
return fetch(`${baseUrl}${path15}`, {
|
|
210
212
|
...init,
|
|
211
|
-
headers:
|
|
213
|
+
headers: mergeAuthHeaders(token, init?.headers)
|
|
212
214
|
});
|
|
213
215
|
}
|
|
214
|
-
async function
|
|
215
|
-
const
|
|
216
|
-
|
|
216
|
+
async function publicFetch(path15, init) {
|
|
217
|
+
const baseUrl = resolveAppUrl();
|
|
218
|
+
return fetch(`${baseUrl}${path15}`, init);
|
|
219
|
+
}
|
|
220
|
+
async function deployFetch(path15, init) {
|
|
221
|
+
const baseUrl = resolveAppUrl();
|
|
222
|
+
const token = resolveDeployToken() ?? resolveToken()?.token;
|
|
217
223
|
if (!token)
|
|
218
224
|
throw new Error(
|
|
219
225
|
"No authentication token available. Set WALKEROS_DEPLOY_TOKEN or run walkeros auth login."
|
|
220
226
|
);
|
|
221
|
-
|
|
222
|
-
return fetch(url, {
|
|
227
|
+
return fetch(`${baseUrl}${path15}`, {
|
|
223
228
|
...init,
|
|
224
|
-
headers:
|
|
229
|
+
headers: mergeAuthHeaders(token, init?.headers)
|
|
225
230
|
});
|
|
226
231
|
}
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
}
|
|
230
|
-
function resolveBaseUrl() {
|
|
231
|
-
return resolveAppUrl();
|
|
232
|
-
}
|
|
233
|
-
function requireProjectId() {
|
|
234
|
-
const projectId = process.env.WALKEROS_PROJECT_ID;
|
|
235
|
-
if (!projectId) throw new Error("WALKEROS_PROJECT_ID not set.");
|
|
236
|
-
return projectId;
|
|
237
|
-
}
|
|
238
|
-
var init_auth = __esm({
|
|
239
|
-
"src/core/auth.ts"() {
|
|
232
|
+
var init_http = __esm({
|
|
233
|
+
"src/core/http.ts"() {
|
|
240
234
|
"use strict";
|
|
241
235
|
init_config_file();
|
|
242
236
|
}
|
|
@@ -259,7 +253,10 @@ async function downloadFromUrl(url) {
|
|
|
259
253
|
throw new Error(`Invalid URL: ${url}`);
|
|
260
254
|
}
|
|
261
255
|
try {
|
|
262
|
-
const
|
|
256
|
+
const token = resolveToken()?.token;
|
|
257
|
+
const response = await fetch(url, {
|
|
258
|
+
headers: mergeAuthHeaders(token)
|
|
259
|
+
});
|
|
263
260
|
if (!response.ok) {
|
|
264
261
|
throw new Error(
|
|
265
262
|
`Failed to download ${url}: ${response.status} ${response.statusText}`
|
|
@@ -280,32 +277,44 @@ async function downloadFromUrl(url) {
|
|
|
280
277
|
}
|
|
281
278
|
}
|
|
282
279
|
async function loadJsonConfig(configPath) {
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
try {
|
|
295
|
-
const rawConfig = await fs2.readJson(absolutePath);
|
|
296
|
-
return rawConfig;
|
|
297
|
-
} catch (error) {
|
|
298
|
-
throw new Error(
|
|
299
|
-
`Invalid JSON in config file: ${configPath}. ${error instanceof Error ? error.message : error}`
|
|
300
|
-
);
|
|
301
|
-
} finally {
|
|
302
|
-
if (isTemporary) {
|
|
280
|
+
const trimmed = configPath.trim();
|
|
281
|
+
if (isUrl(trimmed)) {
|
|
282
|
+
const absolutePath2 = await downloadFromUrl(trimmed);
|
|
283
|
+
try {
|
|
284
|
+
const rawConfig = await fs2.readJson(absolutePath2);
|
|
285
|
+
return rawConfig;
|
|
286
|
+
} catch (error) {
|
|
287
|
+
throw new Error(
|
|
288
|
+
`Invalid JSON in config file: ${configPath}. ${error instanceof Error ? error.message : error}`
|
|
289
|
+
);
|
|
290
|
+
} finally {
|
|
303
291
|
try {
|
|
304
|
-
await fs2.remove(
|
|
292
|
+
await fs2.remove(absolutePath2);
|
|
305
293
|
} catch {
|
|
306
294
|
}
|
|
307
295
|
}
|
|
308
296
|
}
|
|
297
|
+
const absolutePath = path3.resolve(trimmed);
|
|
298
|
+
if (await fs2.pathExists(absolutePath)) {
|
|
299
|
+
try {
|
|
300
|
+
const rawConfig = await fs2.readJson(absolutePath);
|
|
301
|
+
return rawConfig;
|
|
302
|
+
} catch (error) {
|
|
303
|
+
throw new Error(
|
|
304
|
+
`Invalid JSON in config file: ${configPath}. ${error instanceof Error ? error.message : error}`
|
|
305
|
+
);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
|
|
309
|
+
try {
|
|
310
|
+
return JSON.parse(trimmed);
|
|
311
|
+
} catch (jsonError) {
|
|
312
|
+
throw new Error(
|
|
313
|
+
`Input appears to be JSON but contains errors: ${jsonError instanceof Error ? jsonError.message : String(jsonError)}`
|
|
314
|
+
);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
throw new Error(`Configuration file not found: ${absolutePath}`);
|
|
309
318
|
}
|
|
310
319
|
async function loadJsonFromSource(source, options) {
|
|
311
320
|
const paramName = options?.name || "input";
|
|
@@ -365,7 +374,8 @@ var init_utils = __esm({
|
|
|
365
374
|
"use strict";
|
|
366
375
|
init_core();
|
|
367
376
|
init_tmp();
|
|
368
|
-
|
|
377
|
+
init_http();
|
|
378
|
+
init_config_file();
|
|
369
379
|
}
|
|
370
380
|
});
|
|
371
381
|
|
|
@@ -495,7 +505,10 @@ function detectPlatformFromPath(inputPath) {
|
|
|
495
505
|
}
|
|
496
506
|
async function loadContent(inputPath) {
|
|
497
507
|
if (isUrl(inputPath)) {
|
|
498
|
-
const
|
|
508
|
+
const token = resolveToken()?.token;
|
|
509
|
+
const response = await fetch(inputPath, {
|
|
510
|
+
headers: mergeAuthHeaders(token)
|
|
511
|
+
});
|
|
499
512
|
if (!response.ok) {
|
|
500
513
|
throw new Error(`Failed to fetch ${inputPath}: ${response.status}`);
|
|
501
514
|
}
|
|
@@ -507,7 +520,8 @@ var init_input_detector = __esm({
|
|
|
507
520
|
"src/core/input-detector.ts"() {
|
|
508
521
|
"use strict";
|
|
509
522
|
init_utils();
|
|
510
|
-
|
|
523
|
+
init_http();
|
|
524
|
+
init_config_file();
|
|
511
525
|
}
|
|
512
526
|
});
|
|
513
527
|
|
|
@@ -532,6 +546,31 @@ var init_stdin = __esm({
|
|
|
532
546
|
}
|
|
533
547
|
});
|
|
534
548
|
|
|
549
|
+
// src/core/auth.ts
|
|
550
|
+
function getToken() {
|
|
551
|
+
const result = resolveToken();
|
|
552
|
+
return result?.token;
|
|
553
|
+
}
|
|
554
|
+
function getAuthHeaders() {
|
|
555
|
+
const token = getToken();
|
|
556
|
+
if (!token) return {};
|
|
557
|
+
return { Authorization: `Bearer ${token}` };
|
|
558
|
+
}
|
|
559
|
+
function resolveRunToken() {
|
|
560
|
+
return resolveDeployToken() ?? resolveToken()?.token ?? null;
|
|
561
|
+
}
|
|
562
|
+
function requireProjectId() {
|
|
563
|
+
const projectId = process.env.WALKEROS_PROJECT_ID;
|
|
564
|
+
if (!projectId) throw new Error("WALKEROS_PROJECT_ID not set.");
|
|
565
|
+
return projectId;
|
|
566
|
+
}
|
|
567
|
+
var init_auth = __esm({
|
|
568
|
+
"src/core/auth.ts"() {
|
|
569
|
+
"use strict";
|
|
570
|
+
init_config_file();
|
|
571
|
+
}
|
|
572
|
+
});
|
|
573
|
+
|
|
535
574
|
// src/core/sse.ts
|
|
536
575
|
function parseSSEEvents(buffer) {
|
|
537
576
|
const events = [];
|
|
@@ -574,6 +613,7 @@ var init_core = __esm({
|
|
|
574
613
|
init_input_detector();
|
|
575
614
|
init_stdin();
|
|
576
615
|
init_auth();
|
|
616
|
+
init_http();
|
|
577
617
|
init_sse();
|
|
578
618
|
}
|
|
579
619
|
});
|
|
@@ -1116,6 +1156,7 @@ var init_build_cache = __esm({
|
|
|
1116
1156
|
// src/commands/bundle/bundler.ts
|
|
1117
1157
|
import crypto2 from "crypto";
|
|
1118
1158
|
import esbuild from "esbuild";
|
|
1159
|
+
import { builtinModules } from "module";
|
|
1119
1160
|
import path9 from "path";
|
|
1120
1161
|
import fs8 from "fs-extra";
|
|
1121
1162
|
import { packageNameToVariable, ENV_MARKER_PREFIX } from "@walkeros/core";
|
|
@@ -1287,6 +1328,12 @@ async function bundleCore(flowSettings, buildOptions, logger, showStats = false)
|
|
|
1287
1328
|
if (hasSourcesOrDests && !buildOptions.packages["@walkeros/collector"]) {
|
|
1288
1329
|
buildOptions.packages["@walkeros/collector"] = {};
|
|
1289
1330
|
}
|
|
1331
|
+
const stepPackages = collectStepPackages(flowSettings);
|
|
1332
|
+
for (const pkg of stepPackages) {
|
|
1333
|
+
if (!buildOptions.packages[pkg]) {
|
|
1334
|
+
buildOptions.packages[pkg] = {};
|
|
1335
|
+
}
|
|
1336
|
+
}
|
|
1290
1337
|
logger.debug("Downloading packages");
|
|
1291
1338
|
const packagesArray = Object.entries(buildOptions.packages).map(
|
|
1292
1339
|
([name, packageConfig]) => ({
|
|
@@ -1457,23 +1504,8 @@ function createEsbuildOptions(buildOptions, entryPath, outputPath, tempDir, pack
|
|
|
1457
1504
|
};
|
|
1458
1505
|
baseOptions.external = buildOptions.external || [];
|
|
1459
1506
|
} else if (buildOptions.platform === "node") {
|
|
1460
|
-
const
|
|
1461
|
-
|
|
1462
|
-
"fs",
|
|
1463
|
-
"path",
|
|
1464
|
-
"os",
|
|
1465
|
-
"util",
|
|
1466
|
-
"stream",
|
|
1467
|
-
"buffer",
|
|
1468
|
-
"events",
|
|
1469
|
-
"http",
|
|
1470
|
-
"https",
|
|
1471
|
-
"url",
|
|
1472
|
-
"querystring",
|
|
1473
|
-
"zlib"
|
|
1474
|
-
];
|
|
1475
|
-
const npmPackages = ["express", "express/*", "cors", "cors/*"];
|
|
1476
|
-
baseOptions.external = buildOptions.external ? [...nodeBuiltins, ...npmPackages, ...buildOptions.external] : [...nodeBuiltins, ...npmPackages];
|
|
1507
|
+
const nodeExternals = getNodeExternals();
|
|
1508
|
+
baseOptions.external = buildOptions.external ? [...nodeExternals, ...buildOptions.external] : nodeExternals;
|
|
1477
1509
|
if (buildOptions.format === "esm") {
|
|
1478
1510
|
baseOptions.banner = {
|
|
1479
1511
|
js: `import { createRequire } from 'module';const require = createRequire(import.meta.url);`
|
|
@@ -1548,6 +1580,36 @@ function detectStorePackages(flowSettings) {
|
|
|
1548
1580
|
}
|
|
1549
1581
|
return storePackages;
|
|
1550
1582
|
}
|
|
1583
|
+
function getNodeExternals() {
|
|
1584
|
+
const externals = [];
|
|
1585
|
+
for (const mod of builtinModules) {
|
|
1586
|
+
if (mod.startsWith("_")) continue;
|
|
1587
|
+
externals.push(mod, `node:${mod}`, `${mod}/*`, `node:${mod}/*`);
|
|
1588
|
+
}
|
|
1589
|
+
return externals;
|
|
1590
|
+
}
|
|
1591
|
+
function collectStepPackages(flowSettings) {
|
|
1592
|
+
const allPackages = /* @__PURE__ */ new Set();
|
|
1593
|
+
for (const pkg of detectSourcePackages(flowSettings)) {
|
|
1594
|
+
allPackages.add(pkg);
|
|
1595
|
+
}
|
|
1596
|
+
for (const pkg of detectDestinationPackages(flowSettings)) {
|
|
1597
|
+
allPackages.add(pkg);
|
|
1598
|
+
}
|
|
1599
|
+
for (const pkg of detectTransformerPackages(flowSettings)) {
|
|
1600
|
+
allPackages.add(pkg);
|
|
1601
|
+
}
|
|
1602
|
+
for (const pkg of detectStorePackages(flowSettings)) {
|
|
1603
|
+
allPackages.add(pkg);
|
|
1604
|
+
}
|
|
1605
|
+
const npmPackages = /* @__PURE__ */ new Set();
|
|
1606
|
+
for (const pkg of allPackages) {
|
|
1607
|
+
if (!pkg.startsWith(".") && !pkg.startsWith("/")) {
|
|
1608
|
+
npmPackages.add(pkg);
|
|
1609
|
+
}
|
|
1610
|
+
}
|
|
1611
|
+
return npmPackages;
|
|
1612
|
+
}
|
|
1551
1613
|
function detectExplicitCodeImports(flowSettings) {
|
|
1552
1614
|
const explicitCodeImports = /* @__PURE__ */ new Map();
|
|
1553
1615
|
const destinations = flowSettings.destinations;
|
|
@@ -2133,7 +2195,7 @@ function createApiClient() {
|
|
|
2133
2195
|
const token = getToken();
|
|
2134
2196
|
if (!token) throw new Error("WALKEROS_TOKEN not set.");
|
|
2135
2197
|
return createClient({
|
|
2136
|
-
baseUrl:
|
|
2198
|
+
baseUrl: resolveAppUrl(),
|
|
2137
2199
|
headers: {
|
|
2138
2200
|
Authorization: `Bearer ${token}`,
|
|
2139
2201
|
"Content-Type": "application/json"
|
|
@@ -2144,6 +2206,7 @@ var init_api_client = __esm({
|
|
|
2144
2206
|
"src/core/api-client.ts"() {
|
|
2145
2207
|
"use strict";
|
|
2146
2208
|
init_auth();
|
|
2209
|
+
init_config_file();
|
|
2147
2210
|
}
|
|
2148
2211
|
});
|
|
2149
2212
|
|
|
@@ -2423,14 +2486,14 @@ __export(cache_exports, {
|
|
|
2423
2486
|
});
|
|
2424
2487
|
import {
|
|
2425
2488
|
existsSync as existsSync4,
|
|
2426
|
-
mkdirSync as
|
|
2489
|
+
mkdirSync as mkdirSync3,
|
|
2427
2490
|
copyFileSync,
|
|
2428
2491
|
writeFileSync as writeFileSync3,
|
|
2429
2492
|
readFileSync as readFileSync2
|
|
2430
2493
|
} from "fs";
|
|
2431
2494
|
import { join as join2 } from "path";
|
|
2432
2495
|
function writeCache(cacheDir, bundlePath, configContent, version) {
|
|
2433
|
-
|
|
2496
|
+
mkdirSync3(cacheDir, { recursive: true });
|
|
2434
2497
|
copyFileSync(bundlePath, join2(cacheDir, "bundle.mjs"));
|
|
2435
2498
|
writeFileSync3(join2(cacheDir, "config.json"), configContent, "utf-8");
|
|
2436
2499
|
const meta = { version, timestamp: Date.now() };
|
|
@@ -2937,7 +3000,7 @@ function rn(n, e2) {
|
|
|
2937
3000
|
}, () => J({ ok: false }))(), "Push", n.hooks);
|
|
2938
3001
|
}
|
|
2939
3002
|
async function un(n) {
|
|
2940
|
-
const e2 = r({ globalsStatic: {}, sessionStatic: {}, tagging: 0, run: true }, n, { merge: false, extend: false }), t2 = { level: n.logger?.level, handler: n.logger?.handler }, o2 = i(t2), s2 = { ...e2.globalsStatic, ...n.globals }, a2 = { allowed: false, config: e2, consent: n.consent || {}, count: 0, custom: n.custom || {}, destinations: {}, transformers: {}, stores: {}, globals: s2, group: "", hooks: {}, logger: o2, on: {}, queue: [], round: 0, session: void 0, status: { startedAt: Date.now(), in: 0, out: 0, failed: 0, sources: {}, destinations: {} }, timing: Date.now(), user: n.user || {}, version: "3.0.
|
|
3003
|
+
const e2 = r({ globalsStatic: {}, sessionStatic: {}, tagging: 0, run: true }, n, { merge: false, extend: false }), t2 = { level: n.logger?.level, handler: n.logger?.handler }, o2 = i(t2), s2 = { ...e2.globalsStatic, ...n.globals }, a2 = { allowed: false, config: e2, consent: n.consent || {}, count: 0, custom: n.custom || {}, destinations: {}, transformers: {}, stores: {}, globals: s2, group: "", hooks: {}, logger: o2, on: {}, queue: [], round: 0, session: void 0, status: { startedAt: Date.now(), in: 0, out: 0, failed: 0, sources: {}, destinations: {} }, timing: Date.now(), user: n.user || {}, version: "3.0.2", sources: {}, pending: { sources: {}, destinations: {} }, push: void 0, command: void 0 };
|
|
2941
3004
|
a2.push = rn(a2, (n2) => ({ timing: Math.round((Date.now() - a2.timing) / 10) / 100, source: { type: "collector", id: "", previous_id: "" }, ...n2 })), a2.command = (function(n2, e3) {
|
|
2942
3005
|
return an(async (t3, o3, s3) => await cn(async () => await e3(n2, t3, o3, s3), () => J({ ok: false }))(), "Command", n2.hooks);
|
|
2943
3006
|
})(a2, Y);
|
|
@@ -3034,14 +3097,8 @@ async function dn(n) {
|
|
|
3034
3097
|
})(n, e2);
|
|
3035
3098
|
case "source":
|
|
3036
3099
|
return await (async function(n2, e3) {
|
|
3037
|
-
const { code: t2, config: o2 = {},
|
|
3038
|
-
|
|
3039
|
-
if (s2) {
|
|
3040
|
-
const n3 = s2(r2, i2);
|
|
3041
|
-
"function" == typeof n3 && (u2 = n3);
|
|
3042
|
-
}
|
|
3043
|
-
const f2 = [], { collector: l2 } = await fn({ consent: a2 || c2, sources: { sim: { code: t2, config: o2, env: i2, next: "spy" } }, transformers: { spy: { code: () => ({ type: "spy", config: {}, push: (n3) => (f2.push(JSON.parse(JSON.stringify(n3))), { event: n3 }) }) } } });
|
|
3044
|
-
u2 && u2();
|
|
3100
|
+
const { code: t2, config: o2 = {}, createTrigger: s2, input: r2, consent: i2 } = n2, { content: a2, trigger: c2 } = r2, u2 = { functional: true, marketing: true, analytics: true }, f2 = [], l2 = { consent: i2 || u2, sources: { sim: { code: t2, config: o2, next: "spy" } }, transformers: { spy: { code: () => ({ type: "spy", config: {}, push: (n3) => (f2.push(JSON.parse(JSON.stringify(n3))), { event: n3 }) }) } } }, { trigger: g2 } = await s2(l2);
|
|
3101
|
+
void 0 !== a2 && await g2(c2?.type, c2?.options)(a2);
|
|
3045
3102
|
return { step: "source", name: n2.name, events: f2, calls: [], duration: Date.now() - e3 };
|
|
3046
3103
|
})(n, e2);
|
|
3047
3104
|
case "destination":
|
|
@@ -3141,9 +3198,6 @@ function formatSimulationResult(result, options = {}) {
|
|
|
3141
3198
|
if (result.capturedEvents) {
|
|
3142
3199
|
output.capturedEvents = result.capturedEvents;
|
|
3143
3200
|
}
|
|
3144
|
-
if (result.exampleMatch) {
|
|
3145
|
-
output.exampleMatch = result.exampleMatch;
|
|
3146
|
-
}
|
|
3147
3201
|
return JSON.stringify(output, null, 2);
|
|
3148
3202
|
}
|
|
3149
3203
|
const lines = [];
|
|
@@ -3158,17 +3212,6 @@ function formatSimulationResult(result, options = {}) {
|
|
|
3158
3212
|
lines.push(` - ${evt.name || "unknown"}`);
|
|
3159
3213
|
}
|
|
3160
3214
|
}
|
|
3161
|
-
if (result.exampleMatch) {
|
|
3162
|
-
const em = result.exampleMatch;
|
|
3163
|
-
if (em.match) {
|
|
3164
|
-
lines.push(`Example "${em.name}" (${em.step}): PASS`);
|
|
3165
|
-
} else {
|
|
3166
|
-
lines.push(`Example "${em.name}" (${em.step}): FAIL`);
|
|
3167
|
-
if (em.diff) {
|
|
3168
|
-
lines.push(em.diff);
|
|
3169
|
-
}
|
|
3170
|
-
}
|
|
3171
|
-
}
|
|
3172
3215
|
return lines.join("\n");
|
|
3173
3216
|
}
|
|
3174
3217
|
async function executeSimulation(event, inputPath, platformOverride, options = {}) {
|
|
@@ -3299,7 +3342,6 @@ async function executeConfigSimulation(_content, configPath, typedEvent, tempDir
|
|
|
3299
3342
|
}
|
|
3300
3343
|
|
|
3301
3344
|
// src/commands/simulate/source-simulator.ts
|
|
3302
|
-
import { JSDOM, VirtualConsole } from "jsdom";
|
|
3303
3345
|
init_core();
|
|
3304
3346
|
async function loadSourcePackage(packageName) {
|
|
3305
3347
|
const mainModule = await import(packageName);
|
|
@@ -3307,18 +3349,18 @@ async function loadSourcePackage(packageName) {
|
|
|
3307
3349
|
if (!code || typeof code !== "function") {
|
|
3308
3350
|
throw new Error(`Package ${packageName} missing source init function`);
|
|
3309
3351
|
}
|
|
3310
|
-
let
|
|
3352
|
+
let createTrigger;
|
|
3311
3353
|
try {
|
|
3312
3354
|
const devModule = await import(`${packageName}/dev`);
|
|
3313
3355
|
const examples = devModule.examples || devModule.default?.examples;
|
|
3314
|
-
if (examples?.
|
|
3315
|
-
|
|
3356
|
+
if (examples?.createTrigger && typeof examples.createTrigger === "function") {
|
|
3357
|
+
createTrigger = examples.createTrigger;
|
|
3316
3358
|
}
|
|
3317
3359
|
} catch {
|
|
3318
3360
|
}
|
|
3319
|
-
return { code,
|
|
3361
|
+
return { code, createTrigger };
|
|
3320
3362
|
}
|
|
3321
|
-
async function simulateSourceCLI(flowConfig,
|
|
3363
|
+
async function simulateSourceCLI(flowConfig, sourceInput, options) {
|
|
3322
3364
|
const startTime = Date.now();
|
|
3323
3365
|
try {
|
|
3324
3366
|
const sources = flowConfig.sources;
|
|
@@ -3335,32 +3377,22 @@ async function simulateSourceCLI(flowConfig, setupInput, options) {
|
|
|
3335
3377
|
if (!sourceConfig.package) {
|
|
3336
3378
|
throw new Error(`Source "${options.sourceStep}" has no package field`);
|
|
3337
3379
|
}
|
|
3338
|
-
const { code,
|
|
3339
|
-
|
|
3340
|
-
const dom = new JSDOM(
|
|
3341
|
-
"<!DOCTYPE html><html><head></head><body></body></html>",
|
|
3342
|
-
{
|
|
3343
|
-
url: "http://localhost",
|
|
3344
|
-
runScripts: "dangerously",
|
|
3345
|
-
pretendToBeVisual: true,
|
|
3346
|
-
virtualConsole
|
|
3347
|
-
}
|
|
3380
|
+
const { code, createTrigger } = await loadSourcePackage(
|
|
3381
|
+
sourceConfig.package
|
|
3348
3382
|
);
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
}
|
|
3383
|
+
if (!createTrigger) {
|
|
3384
|
+
throw new Error(
|
|
3385
|
+
`Source package ${sourceConfig.package} has no createTrigger export. Ensure the package exports createTrigger from its /dev subpath.`
|
|
3386
|
+
);
|
|
3387
|
+
}
|
|
3354
3388
|
const result = await dn({
|
|
3355
3389
|
step: "source",
|
|
3356
3390
|
name: options.sourceStep,
|
|
3357
3391
|
code,
|
|
3358
3392
|
config: sourceConfig.config || {},
|
|
3359
|
-
|
|
3360
|
-
input:
|
|
3361
|
-
env
|
|
3393
|
+
createTrigger,
|
|
3394
|
+
input: sourceInput || { content: void 0 }
|
|
3362
3395
|
});
|
|
3363
|
-
dom.window.close();
|
|
3364
3396
|
return {
|
|
3365
3397
|
success: !result.error,
|
|
3366
3398
|
error: result.error?.message,
|
|
@@ -3507,7 +3539,6 @@ async function simulateCommand(options) {
|
|
|
3507
3539
|
verbose: options.verbose,
|
|
3508
3540
|
silent: options.silent,
|
|
3509
3541
|
platform: options.platform,
|
|
3510
|
-
example: options.example,
|
|
3511
3542
|
step: options.step
|
|
3512
3543
|
});
|
|
3513
3544
|
const resultWithDuration = {
|
|
@@ -3518,8 +3549,7 @@ async function simulateCommand(options) {
|
|
|
3518
3549
|
json: options.json
|
|
3519
3550
|
});
|
|
3520
3551
|
await writeResult(formatted + "\n", { output: options.output });
|
|
3521
|
-
|
|
3522
|
-
process.exit(exitCode);
|
|
3552
|
+
process.exit(result.success ? 0 : 1);
|
|
3523
3553
|
} catch (error) {
|
|
3524
3554
|
const errorMessage = getErrorMessage(error);
|
|
3525
3555
|
if (options.json) {
|
|
@@ -3542,49 +3572,14 @@ async function simulateCommand(options) {
|
|
|
3542
3572
|
async function simulate(configOrPath, event, options = {}) {
|
|
3543
3573
|
if (typeof configOrPath !== "string") {
|
|
3544
3574
|
throw new Error(
|
|
3545
|
-
"simulate() currently only supports config file paths.
|
|
3575
|
+
"simulate() currently only supports config file paths. Please provide a path to a configuration file."
|
|
3546
3576
|
);
|
|
3547
3577
|
}
|
|
3548
3578
|
let resolvedEvent = event;
|
|
3549
3579
|
if (typeof event === "string") {
|
|
3550
3580
|
resolvedEvent = await loadJsonFromSource(event, { name: "event" });
|
|
3551
3581
|
}
|
|
3552
|
-
|
|
3553
|
-
if (options.example) {
|
|
3554
|
-
const rawConfig = await loadJsonConfig(configOrPath);
|
|
3555
|
-
const setup = validateFlowConfig(rawConfig);
|
|
3556
|
-
const flowNames = Object.keys(setup.flows);
|
|
3557
|
-
let flowName = options.flow;
|
|
3558
|
-
if (!flowName) {
|
|
3559
|
-
if (flowNames.length === 1) {
|
|
3560
|
-
flowName = flowNames[0];
|
|
3561
|
-
} else {
|
|
3562
|
-
throw new Error(
|
|
3563
|
-
`Multiple flows found. Use --flow to specify which flow contains the example.
|
|
3564
|
-
Available flows: ${flowNames.join(", ")}`
|
|
3565
|
-
);
|
|
3566
|
-
}
|
|
3567
|
-
}
|
|
3568
|
-
const flowSettings = setup.flows[flowName];
|
|
3569
|
-
if (!flowSettings) {
|
|
3570
|
-
throw new Error(
|
|
3571
|
-
`Flow "${flowName}" not found. Available: ${flowNames.join(", ")}`
|
|
3572
|
-
);
|
|
3573
|
-
}
|
|
3574
|
-
const found = findExample(flowSettings, options.example, options.step);
|
|
3575
|
-
if (found.example.in === void 0) {
|
|
3576
|
-
throw new Error(
|
|
3577
|
-
`Example "${options.example}" in ${found.stepType}.${found.stepName} has no "in" value`
|
|
3578
|
-
);
|
|
3579
|
-
}
|
|
3580
|
-
resolvedEvent = found.example.in;
|
|
3581
|
-
exampleContext = {
|
|
3582
|
-
stepType: found.stepType,
|
|
3583
|
-
stepName: found.stepName,
|
|
3584
|
-
expected: found.example.out
|
|
3585
|
-
};
|
|
3586
|
-
}
|
|
3587
|
-
const isSourceSimulation = exampleContext?.stepType === "source" || options.step?.startsWith("source.");
|
|
3582
|
+
const isSourceSimulation = options.step?.startsWith("source.");
|
|
3588
3583
|
let result;
|
|
3589
3584
|
if (isSourceSimulation) {
|
|
3590
3585
|
const rawConfig = await loadJsonConfig(configOrPath);
|
|
@@ -3603,7 +3598,7 @@ Available: ${flowNames.join(", ")}`
|
|
|
3603
3598
|
`Flow "${flowName}" not found. Available: ${flowNames.join(", ")}`
|
|
3604
3599
|
);
|
|
3605
3600
|
}
|
|
3606
|
-
const sourceStep =
|
|
3601
|
+
const sourceStep = options.step.substring("source.".length);
|
|
3607
3602
|
result = await simulateSourceCLI(
|
|
3608
3603
|
flowSettings,
|
|
3609
3604
|
resolvedEvent,
|
|
@@ -3616,38 +3611,15 @@ Available: ${flowNames.join(", ")}`
|
|
|
3616
3611
|
}
|
|
3617
3612
|
);
|
|
3618
3613
|
} else {
|
|
3619
|
-
const stepTarget = exampleContext ? `${exampleContext.stepType}.${exampleContext.stepName}` : options.step;
|
|
3620
3614
|
result = await simulateCore(configOrPath, resolvedEvent, {
|
|
3621
3615
|
json: options.json ?? false,
|
|
3622
3616
|
verbose: options.verbose ?? false,
|
|
3623
3617
|
silent: options.silent ?? false,
|
|
3624
3618
|
flow: options.flow,
|
|
3625
3619
|
platform: options.platform,
|
|
3626
|
-
step:
|
|
3620
|
+
step: options.step
|
|
3627
3621
|
});
|
|
3628
3622
|
}
|
|
3629
|
-
if (exampleContext && result.success) {
|
|
3630
|
-
const stepKey = `${exampleContext.stepType}.${exampleContext.stepName}`;
|
|
3631
|
-
if (exampleContext.expected === false) {
|
|
3632
|
-
const calls = result.usage?.[exampleContext.stepName];
|
|
3633
|
-
const wasFiltered = !calls || calls.length === 0;
|
|
3634
|
-
result.exampleMatch = {
|
|
3635
|
-
name: options.example,
|
|
3636
|
-
step: stepKey,
|
|
3637
|
-
expected: false,
|
|
3638
|
-
actual: wasFiltered ? false : calls,
|
|
3639
|
-
match: wasFiltered,
|
|
3640
|
-
diff: wasFiltered ? void 0 : `Expected event to be filtered, but ${calls.length} API call(s) were made`
|
|
3641
|
-
};
|
|
3642
|
-
} else if (exampleContext.expected !== void 0) {
|
|
3643
|
-
const actual = result.usage?.[exampleContext.stepName] ?? [];
|
|
3644
|
-
result.exampleMatch = {
|
|
3645
|
-
name: options.example,
|
|
3646
|
-
step: stepKey,
|
|
3647
|
-
...compareOutput(exampleContext.expected, actual)
|
|
3648
|
-
};
|
|
3649
|
-
}
|
|
3650
|
-
}
|
|
3651
3623
|
return result;
|
|
3652
3624
|
}
|
|
3653
3625
|
|
|
@@ -3658,7 +3630,7 @@ init_tmp();
|
|
|
3658
3630
|
init_config();
|
|
3659
3631
|
init_bundler();
|
|
3660
3632
|
import path12 from "path";
|
|
3661
|
-
import { JSDOM
|
|
3633
|
+
import { JSDOM, VirtualConsole } from "jsdom";
|
|
3662
3634
|
import fs13 from "fs-extra";
|
|
3663
3635
|
import { getPlatform as getPlatform3 } from "@walkeros/core";
|
|
3664
3636
|
import { schemas as schemas2 } from "@walkeros/core/dev";
|
|
@@ -3889,8 +3861,8 @@ async function executeBundlePush(bundleContent, platform, validatedEvent, logger
|
|
|
3889
3861
|
async function executeWebPush(bundlePath, event, logger) {
|
|
3890
3862
|
const startTime = Date.now();
|
|
3891
3863
|
try {
|
|
3892
|
-
const virtualConsole = new
|
|
3893
|
-
const dom = new
|
|
3864
|
+
const virtualConsole = new VirtualConsole();
|
|
3865
|
+
const dom = new JSDOM("<!DOCTYPE html><html><body></body></html>", {
|
|
3894
3866
|
url: "http://localhost",
|
|
3895
3867
|
runScripts: "dangerously",
|
|
3896
3868
|
resources: "usable",
|
|
@@ -3998,19 +3970,29 @@ init_core();
|
|
|
3998
3970
|
init_config_file();
|
|
3999
3971
|
init_auth();
|
|
4000
3972
|
import path14 from "path";
|
|
4001
|
-
import { createRequire } from "module";
|
|
4002
3973
|
import { writeFileSync as writeFileSync5 } from "fs";
|
|
4003
3974
|
import { homedir as homedir2 } from "os";
|
|
4004
3975
|
import { join as join4 } from "path";
|
|
4005
3976
|
|
|
4006
3977
|
// src/runtime/resolve-bundle.ts
|
|
4007
3978
|
init_stdin();
|
|
4008
|
-
import { existsSync as existsSync3, writeFileSync as writeFileSync2 } from "fs";
|
|
4009
|
-
|
|
3979
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
3980
|
+
import { dirname } from "path";
|
|
3981
|
+
function getDefaultWritePath() {
|
|
3982
|
+
if (existsSync3("/app/flow")) return "/app/flow/bundle.mjs";
|
|
3983
|
+
return "/tmp/walkeros-bundle.mjs";
|
|
3984
|
+
}
|
|
4010
3985
|
function isUrl2(value) {
|
|
4011
3986
|
return value.startsWith("http://") || value.startsWith("https://");
|
|
4012
3987
|
}
|
|
4013
|
-
|
|
3988
|
+
function writeBundleToDisk(writePath, content) {
|
|
3989
|
+
const dir = dirname(writePath);
|
|
3990
|
+
if (!existsSync3(dir)) {
|
|
3991
|
+
mkdirSync2(dir, { recursive: true });
|
|
3992
|
+
}
|
|
3993
|
+
writeFileSync2(writePath, content, "utf-8");
|
|
3994
|
+
}
|
|
3995
|
+
async function fetchBundle(url, writePath) {
|
|
4014
3996
|
const response = await fetch(url, { signal: AbortSignal.timeout(3e4) });
|
|
4015
3997
|
if (!response.ok) {
|
|
4016
3998
|
throw new Error(
|
|
@@ -4021,38 +4003,38 @@ async function fetchBundle(url) {
|
|
|
4021
4003
|
if (!content.trim()) {
|
|
4022
4004
|
throw new Error(`Bundle fetched from ${url} is empty`);
|
|
4023
4005
|
}
|
|
4024
|
-
|
|
4025
|
-
return
|
|
4006
|
+
writeBundleToDisk(writePath, content);
|
|
4007
|
+
return writePath;
|
|
4026
4008
|
}
|
|
4027
|
-
async function readBundleFromStdin() {
|
|
4009
|
+
async function readBundleFromStdin(writePath) {
|
|
4028
4010
|
const content = await readStdin();
|
|
4029
|
-
|
|
4030
|
-
return
|
|
4011
|
+
writeBundleToDisk(writePath, content);
|
|
4012
|
+
return writePath;
|
|
4031
4013
|
}
|
|
4032
4014
|
async function resolveBundle(bundleEnv) {
|
|
4015
|
+
const writePath = getDefaultWritePath();
|
|
4033
4016
|
if (!isUrl2(bundleEnv) && existsSync3(bundleEnv)) {
|
|
4034
4017
|
return { path: bundleEnv, source: "file" };
|
|
4035
4018
|
}
|
|
4036
|
-
if (isStdinPiped()) {
|
|
4037
|
-
const path15 = await readBundleFromStdin();
|
|
4038
|
-
return { path: path15, source: "stdin" };
|
|
4039
|
-
}
|
|
4040
4019
|
if (isUrl2(bundleEnv)) {
|
|
4041
|
-
const path15 = await fetchBundle(bundleEnv);
|
|
4020
|
+
const path15 = await fetchBundle(bundleEnv, writePath);
|
|
4042
4021
|
return { path: path15, source: "url" };
|
|
4043
4022
|
}
|
|
4023
|
+
if (isStdinPiped()) {
|
|
4024
|
+
const path15 = await readBundleFromStdin(writePath);
|
|
4025
|
+
return { path: path15, source: "stdin" };
|
|
4026
|
+
}
|
|
4044
4027
|
return { path: bundleEnv, source: "file" };
|
|
4045
4028
|
}
|
|
4046
4029
|
|
|
4047
4030
|
// src/runtime/config-fetcher.ts
|
|
4031
|
+
init_http();
|
|
4048
4032
|
async function fetchConfig(options) {
|
|
4049
4033
|
const url = `${options.appUrl}/api/projects/${options.projectId}/flows/${options.flowId}`;
|
|
4050
|
-
const headers =
|
|
4051
|
-
|
|
4052
|
-
|
|
4053
|
-
|
|
4054
|
-
headers["If-None-Match"] = options.lastEtag;
|
|
4055
|
-
}
|
|
4034
|
+
const headers = mergeAuthHeaders(
|
|
4035
|
+
options.token,
|
|
4036
|
+
options.lastEtag ? { "If-None-Match": options.lastEtag } : void 0
|
|
4037
|
+
);
|
|
4056
4038
|
const response = await fetch(url, {
|
|
4057
4039
|
headers,
|
|
4058
4040
|
signal: AbortSignal.timeout(3e4)
|
|
@@ -4131,7 +4113,7 @@ var BundleOptionsSchema = z5.object({
|
|
|
4131
4113
|
});
|
|
4132
4114
|
var BundleInputShape = {
|
|
4133
4115
|
configPath: FilePathSchema.describe(
|
|
4134
|
-
"Path to flow configuration file (JSON or JavaScript)"
|
|
4116
|
+
"Path to flow configuration file (JSON or JavaScript), URL, or inline JSON string"
|
|
4135
4117
|
),
|
|
4136
4118
|
flow: z5.string().optional().describe("Flow name for multi-flow configs"),
|
|
4137
4119
|
stats: z5.boolean().optional().default(true).describe("Return bundle statistics"),
|
|
@@ -4148,17 +4130,16 @@ var SimulateOptionsSchema = z6.object({
|
|
|
4148
4130
|
json: z6.boolean().optional().describe("Format output as JSON")
|
|
4149
4131
|
});
|
|
4150
4132
|
var SimulateInputShape = {
|
|
4151
|
-
configPath: FilePathSchema.describe(
|
|
4133
|
+
configPath: FilePathSchema.describe(
|
|
4134
|
+
"Path to flow configuration file, URL, or inline JSON string"
|
|
4135
|
+
),
|
|
4152
4136
|
event: z6.string().min(1).optional().describe(
|
|
4153
|
-
"Event as JSON string, file path, or URL.
|
|
4137
|
+
"Event as JSON string, file path, or URL. For sources: { content, trigger?, env? }."
|
|
4154
4138
|
),
|
|
4155
4139
|
flow: z6.string().optional().describe("Flow name for multi-flow configs"),
|
|
4156
4140
|
platform: PlatformSchema.optional().describe("Override platform detection"),
|
|
4157
|
-
example: z6.string().optional().describe(
|
|
4158
|
-
'Name of a step example to use as event input (uses its "in" value)'
|
|
4159
|
-
),
|
|
4160
4141
|
step: z6.string().optional().describe(
|
|
4161
|
-
'Step target in type.name format (e.g. "destination.gtag")
|
|
4142
|
+
'Step target in type.name format (e.g. "source.browser", "destination.gtag")'
|
|
4162
4143
|
)
|
|
4163
4144
|
};
|
|
4164
4145
|
var SimulateInputSchema = z6.object(SimulateInputShape);
|
|
@@ -4253,10 +4234,10 @@ function createHealthServer(port, logger) {
|
|
|
4253
4234
|
|
|
4254
4235
|
// src/runtime/runner.ts
|
|
4255
4236
|
import { pathToFileURL } from "url";
|
|
4256
|
-
import { resolve, dirname } from "path";
|
|
4237
|
+
import { resolve, dirname as dirname2 } from "path";
|
|
4257
4238
|
async function loadFlow(file, config, logger, loggerConfig, healthServer) {
|
|
4258
4239
|
const absolutePath = resolve(file);
|
|
4259
|
-
const flowDir =
|
|
4240
|
+
const flowDir = dirname2(absolutePath);
|
|
4260
4241
|
process.chdir(flowDir);
|
|
4261
4242
|
const fileUrl = pathToFileURL(absolutePath).href;
|
|
4262
4243
|
const module = await import(`${fileUrl}?t=${Date.now()}`);
|
|
@@ -4315,9 +4296,9 @@ import { randomBytes } from "crypto";
|
|
|
4315
4296
|
// src/version.ts
|
|
4316
4297
|
import { readFileSync as readFileSync3 } from "fs";
|
|
4317
4298
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
4318
|
-
import { dirname as
|
|
4299
|
+
import { dirname as dirname3, join as join3 } from "path";
|
|
4319
4300
|
var versionFilename = fileURLToPath2(import.meta.url);
|
|
4320
|
-
var versionDirname =
|
|
4301
|
+
var versionDirname = dirname3(versionFilename);
|
|
4321
4302
|
function findPackageJson() {
|
|
4322
4303
|
const paths = [
|
|
4323
4304
|
join3(versionDirname, "../package.json"),
|
|
@@ -4336,6 +4317,7 @@ function findPackageJson() {
|
|
|
4336
4317
|
var VERSION = JSON.parse(findPackageJson()).version;
|
|
4337
4318
|
|
|
4338
4319
|
// src/runtime/heartbeat.ts
|
|
4320
|
+
init_http();
|
|
4339
4321
|
function computeCounterDelta(current, last) {
|
|
4340
4322
|
const destinations = {};
|
|
4341
4323
|
for (const [name, dest] of Object.entries(current.destinations)) {
|
|
@@ -4357,6 +4339,17 @@ function computeCounterDelta(current, last) {
|
|
|
4357
4339
|
destinations
|
|
4358
4340
|
};
|
|
4359
4341
|
}
|
|
4342
|
+
function snapshotDestinations(destinations) {
|
|
4343
|
+
const result = {};
|
|
4344
|
+
for (const [name, dest] of Object.entries(destinations)) {
|
|
4345
|
+
result[name] = {
|
|
4346
|
+
count: dest.count,
|
|
4347
|
+
failed: dest.failed,
|
|
4348
|
+
duration: dest.duration
|
|
4349
|
+
};
|
|
4350
|
+
}
|
|
4351
|
+
return result;
|
|
4352
|
+
}
|
|
4360
4353
|
var instanceId = randomBytes(8).toString("hex");
|
|
4361
4354
|
function getInstanceId() {
|
|
4362
4355
|
return instanceId;
|
|
@@ -4374,13 +4367,14 @@ function createHeartbeat(config, logger) {
|
|
|
4374
4367
|
async function sendOnce() {
|
|
4375
4368
|
try {
|
|
4376
4369
|
let counters;
|
|
4370
|
+
let current;
|
|
4377
4371
|
const status = config.getCounters?.();
|
|
4378
4372
|
if (status) {
|
|
4379
|
-
|
|
4373
|
+
current = {
|
|
4380
4374
|
in: status.in,
|
|
4381
4375
|
out: status.out,
|
|
4382
4376
|
failed: status.failed,
|
|
4383
|
-
destinations:
|
|
4377
|
+
destinations: snapshotDestinations(status.destinations)
|
|
4384
4378
|
};
|
|
4385
4379
|
counters = computeCounterDelta(current, lastReported);
|
|
4386
4380
|
}
|
|
@@ -4388,10 +4382,9 @@ function createHeartbeat(config, logger) {
|
|
|
4388
4382
|
`${config.appUrl}/api/projects/${config.projectId}/runners/heartbeat`,
|
|
4389
4383
|
{
|
|
4390
4384
|
method: "POST",
|
|
4391
|
-
headers: {
|
|
4392
|
-
Authorization: `Bearer ${config.token}`,
|
|
4385
|
+
headers: mergeAuthHeaders(config.token, {
|
|
4393
4386
|
"Content-Type": "application/json"
|
|
4394
|
-
},
|
|
4387
|
+
}),
|
|
4395
4388
|
body: JSON.stringify({
|
|
4396
4389
|
instanceId,
|
|
4397
4390
|
flowId: config.flowId,
|
|
@@ -4406,13 +4399,8 @@ function createHeartbeat(config, logger) {
|
|
|
4406
4399
|
signal: AbortSignal.timeout(1e4)
|
|
4407
4400
|
}
|
|
4408
4401
|
);
|
|
4409
|
-
if (response.ok &&
|
|
4410
|
-
lastReported =
|
|
4411
|
-
in: status.in,
|
|
4412
|
-
out: status.out,
|
|
4413
|
-
failed: status.failed,
|
|
4414
|
-
destinations: { ...status.destinations }
|
|
4415
|
-
};
|
|
4402
|
+
if (response.ok && counters && current) {
|
|
4403
|
+
lastReported = current;
|
|
4416
4404
|
}
|
|
4417
4405
|
if (response.status === 401 || response.status === 403) {
|
|
4418
4406
|
logger.error(
|
|
@@ -4482,6 +4470,7 @@ function createPoller(config, logger) {
|
|
|
4482
4470
|
}
|
|
4483
4471
|
|
|
4484
4472
|
// src/runtime/secrets-fetcher.ts
|
|
4473
|
+
init_http();
|
|
4485
4474
|
var SecretsHttpError = class extends Error {
|
|
4486
4475
|
constructor(status, statusText) {
|
|
4487
4476
|
super(`Failed to fetch secrets: ${status} ${statusText}`);
|
|
@@ -4493,10 +4482,7 @@ async function fetchSecrets(options) {
|
|
|
4493
4482
|
const { appUrl, token, projectId, flowId } = options;
|
|
4494
4483
|
const url = `${appUrl}/api/projects/${encodeURIComponent(projectId)}/flows/${encodeURIComponent(flowId)}/secrets/values`;
|
|
4495
4484
|
const res = await fetch(url, {
|
|
4496
|
-
headers: {
|
|
4497
|
-
Authorization: `Bearer ${token}`,
|
|
4498
|
-
"Content-Type": "application/json"
|
|
4499
|
-
}
|
|
4485
|
+
headers: mergeAuthHeaders(token, { "Content-Type": "application/json" })
|
|
4500
4486
|
});
|
|
4501
4487
|
if (!res.ok) {
|
|
4502
4488
|
throw new SecretsHttpError(res.status, res.statusText);
|
|
@@ -4541,6 +4527,7 @@ async function runPipeline(options) {
|
|
|
4541
4527
|
token: api.token,
|
|
4542
4528
|
projectId: api.projectId,
|
|
4543
4529
|
flowId: api.flowId,
|
|
4530
|
+
deploymentId: api.deploymentId,
|
|
4544
4531
|
configVersion,
|
|
4545
4532
|
intervalMs: api.heartbeatIntervalMs,
|
|
4546
4533
|
getCounters: () => handle.collector.status
|
|
@@ -4653,7 +4640,6 @@ async function injectSecrets(api, logger) {
|
|
|
4653
4640
|
}
|
|
4654
4641
|
|
|
4655
4642
|
// src/commands/run/index.ts
|
|
4656
|
-
var esmRequire = createRequire(import.meta.url);
|
|
4657
4643
|
function defaultCacheDir() {
|
|
4658
4644
|
const xdgCache = process.env.XDG_CACHE_HOME;
|
|
4659
4645
|
const base = xdgCache || join4(homedir2(), ".cache");
|
|
@@ -4672,19 +4658,6 @@ async function runCommand(options) {
|
|
|
4672
4658
|
if (options.port !== void 0) {
|
|
4673
4659
|
validatePort(options.port);
|
|
4674
4660
|
}
|
|
4675
|
-
const runtimeDeps = ["express", "cors"];
|
|
4676
|
-
for (const dep of runtimeDeps) {
|
|
4677
|
-
try {
|
|
4678
|
-
esmRequire.resolve(dep);
|
|
4679
|
-
} catch {
|
|
4680
|
-
logger.error(
|
|
4681
|
-
`Missing runtime dependency "${dep}"
|
|
4682
|
-
Server flows require express and cors when running outside Docker.
|
|
4683
|
-
Run: npm install express cors`
|
|
4684
|
-
);
|
|
4685
|
-
process.exit(1);
|
|
4686
|
-
}
|
|
4687
|
-
}
|
|
4688
4661
|
const flowId = options.flowId;
|
|
4689
4662
|
const projectId = options.project;
|
|
4690
4663
|
const token = resolveRunToken();
|
|
@@ -4719,6 +4692,7 @@ Run: npm install express cors`
|
|
|
4719
4692
|
token,
|
|
4720
4693
|
projectId,
|
|
4721
4694
|
flowId,
|
|
4695
|
+
deploymentId: options.deploymentId,
|
|
4722
4696
|
heartbeatIntervalMs: parseInt(
|
|
4723
4697
|
process.env.WALKEROS_HEARTBEAT_INTERVAL ?? process.env.HEARTBEAT_INTERVAL ?? "60",
|
|
4724
4698
|
10
|
|
@@ -5868,6 +5842,30 @@ async function deleteProjectCommand(projectId, options) {
|
|
|
5868
5842
|
|
|
5869
5843
|
// src/commands/flows/index.ts
|
|
5870
5844
|
init_api_client();
|
|
5845
|
+
|
|
5846
|
+
// src/core/api-error.ts
|
|
5847
|
+
var ApiError = class extends Error {
|
|
5848
|
+
code;
|
|
5849
|
+
details;
|
|
5850
|
+
constructor(message, options) {
|
|
5851
|
+
super(message);
|
|
5852
|
+
this.name = "ApiError";
|
|
5853
|
+
this.code = options?.code;
|
|
5854
|
+
this.details = options?.details;
|
|
5855
|
+
}
|
|
5856
|
+
};
|
|
5857
|
+
function throwApiError(error, fallbackMessage) {
|
|
5858
|
+
if (error && typeof error === "object" && "error" in error && typeof error.error === "object") {
|
|
5859
|
+
const inner = error.error;
|
|
5860
|
+
const message = inner.message || fallbackMessage;
|
|
5861
|
+
const code = inner.code;
|
|
5862
|
+
const details = inner.details?.errors;
|
|
5863
|
+
throw new ApiError(message, { code, details });
|
|
5864
|
+
}
|
|
5865
|
+
throw new ApiError(fallbackMessage);
|
|
5866
|
+
}
|
|
5867
|
+
|
|
5868
|
+
// src/commands/flows/index.ts
|
|
5871
5869
|
init_auth();
|
|
5872
5870
|
init_cli_logger();
|
|
5873
5871
|
init_output();
|
|
@@ -5885,7 +5883,7 @@ async function listFlows(options = {}) {
|
|
|
5885
5883
|
}
|
|
5886
5884
|
}
|
|
5887
5885
|
});
|
|
5888
|
-
if (error)
|
|
5886
|
+
if (error) throwApiError(error, "Failed to list flows");
|
|
5889
5887
|
return data;
|
|
5890
5888
|
}
|
|
5891
5889
|
async function getFlow(options) {
|
|
@@ -5900,7 +5898,7 @@ async function getFlow(options) {
|
|
|
5900
5898
|
}
|
|
5901
5899
|
}
|
|
5902
5900
|
);
|
|
5903
|
-
if (error)
|
|
5901
|
+
if (error) throwApiError(error, "Failed to get flow");
|
|
5904
5902
|
return data;
|
|
5905
5903
|
}
|
|
5906
5904
|
async function createFlow(options) {
|
|
@@ -5911,7 +5909,7 @@ async function createFlow(options) {
|
|
|
5911
5909
|
// Config is user-provided JSON; server validates the full schema
|
|
5912
5910
|
body: { name: options.name, config: options.content }
|
|
5913
5911
|
});
|
|
5914
|
-
if (error)
|
|
5912
|
+
if (error) throwApiError(error, "Failed to create flow");
|
|
5915
5913
|
return data;
|
|
5916
5914
|
}
|
|
5917
5915
|
async function updateFlow(options) {
|
|
@@ -5931,7 +5929,7 @@ async function updateFlow(options) {
|
|
|
5931
5929
|
}
|
|
5932
5930
|
}
|
|
5933
5931
|
);
|
|
5934
|
-
if (error)
|
|
5932
|
+
if (error) throwApiError(error, "Failed to update flow");
|
|
5935
5933
|
return data;
|
|
5936
5934
|
}
|
|
5937
5935
|
async function deleteFlow(options) {
|
|
@@ -5943,7 +5941,7 @@ async function deleteFlow(options) {
|
|
|
5943
5941
|
params: { path: { projectId: id, flowId: options.flowId } }
|
|
5944
5942
|
}
|
|
5945
5943
|
);
|
|
5946
|
-
if (error)
|
|
5944
|
+
if (error) throwApiError(error, "Failed to delete flow");
|
|
5947
5945
|
return data ?? { success: true };
|
|
5948
5946
|
}
|
|
5949
5947
|
async function duplicateFlow(options) {
|
|
@@ -5956,8 +5954,7 @@ async function duplicateFlow(options) {
|
|
|
5956
5954
|
body: { name: options.name }
|
|
5957
5955
|
}
|
|
5958
5956
|
);
|
|
5959
|
-
if (error)
|
|
5960
|
-
throw new Error(error.error?.message || "Failed to duplicate flow");
|
|
5957
|
+
if (error) throwApiError(error, "Failed to duplicate flow");
|
|
5961
5958
|
return data;
|
|
5962
5959
|
}
|
|
5963
5960
|
async function handleResult2(fn2, options) {
|
|
@@ -6028,6 +6025,7 @@ async function readFlowStdin() {
|
|
|
6028
6025
|
// src/commands/deploy/index.ts
|
|
6029
6026
|
init_api_client();
|
|
6030
6027
|
init_auth();
|
|
6028
|
+
init_http();
|
|
6031
6029
|
init_sse();
|
|
6032
6030
|
init_cli_logger();
|
|
6033
6031
|
init_output();
|
|
@@ -6057,10 +6055,9 @@ async function getAvailableFlowNames(options) {
|
|
|
6057
6055
|
return settings?.map((c2) => c2.name) ?? [];
|
|
6058
6056
|
}
|
|
6059
6057
|
async function streamDeploymentStatus(projectId, deploymentId, options) {
|
|
6060
|
-
const base = resolveBaseUrl();
|
|
6061
6058
|
const timeoutMs = options.timeout ?? 12e4;
|
|
6062
|
-
const response = await
|
|
6063
|
-
|
|
6059
|
+
const response = await apiFetch(
|
|
6060
|
+
`/api/projects/${projectId}/deployments/${deploymentId}/stream`,
|
|
6064
6061
|
{
|
|
6065
6062
|
headers: { Accept: "text/event-stream" },
|
|
6066
6063
|
signal: options.signal ?? AbortSignal.timeout(timeoutMs)
|
|
@@ -6120,19 +6117,22 @@ async function deploy(options) {
|
|
|
6120
6117
|
{ params: { path: { projectId, flowId: options.flowId } } }
|
|
6121
6118
|
);
|
|
6122
6119
|
if (error) {
|
|
6123
|
-
|
|
6124
|
-
|
|
6125
|
-
|
|
6126
|
-
|
|
6127
|
-
|
|
6128
|
-
|
|
6129
|
-
|
|
6130
|
-
|
|
6131
|
-
|
|
6132
|
-
|
|
6133
|
-
|
|
6120
|
+
try {
|
|
6121
|
+
throwApiError(error, "Failed to start deployment");
|
|
6122
|
+
} catch (e2) {
|
|
6123
|
+
if (e2 instanceof ApiError && e2.code === "AMBIGUOUS_CONFIG") {
|
|
6124
|
+
const names = await getAvailableFlowNames({
|
|
6125
|
+
flowId: options.flowId,
|
|
6126
|
+
projectId
|
|
6127
|
+
});
|
|
6128
|
+
throw new ApiError(
|
|
6129
|
+
`This flow has multiple settings. Use --flow <name> to specify one.
|
|
6130
|
+
Available: ${names.join(", ")}`,
|
|
6131
|
+
{ code: "AMBIGUOUS_CONFIG" }
|
|
6132
|
+
);
|
|
6133
|
+
}
|
|
6134
|
+
throw e2;
|
|
6134
6135
|
}
|
|
6135
|
-
throw new Error(msg);
|
|
6136
6136
|
}
|
|
6137
6137
|
if (!options.wait) return data;
|
|
6138
6138
|
const result = await streamDeploymentStatus(projectId, data.deploymentId, {
|
|
@@ -6144,16 +6144,13 @@ Available: ${names.join(", ")}`
|
|
|
6144
6144
|
}
|
|
6145
6145
|
async function deploySettings(options) {
|
|
6146
6146
|
const { flowId, projectId, settingsId } = options;
|
|
6147
|
-
const
|
|
6148
|
-
|
|
6149
|
-
`${base}/api/projects/${projectId}/flows/${flowId}/settings/${settingsId}/deploy`,
|
|
6147
|
+
const response = await apiFetch(
|
|
6148
|
+
`/api/projects/${projectId}/flows/${flowId}/settings/${settingsId}/deploy`,
|
|
6150
6149
|
{ method: "POST" }
|
|
6151
6150
|
);
|
|
6152
6151
|
if (!response.ok) {
|
|
6153
6152
|
const body = await response.json().catch(() => ({}));
|
|
6154
|
-
|
|
6155
|
-
body.error?.message || `Deploy failed (${response.status})`
|
|
6156
|
-
);
|
|
6153
|
+
throwApiError(body, `Deploy failed (${response.status})`);
|
|
6157
6154
|
}
|
|
6158
6155
|
const data = await response.json();
|
|
6159
6156
|
if (!options.wait) return data;
|
|
@@ -6172,13 +6169,12 @@ async function getDeployment(options) {
|
|
|
6172
6169
|
projectId,
|
|
6173
6170
|
flowName: options.flowName
|
|
6174
6171
|
});
|
|
6175
|
-
const
|
|
6176
|
-
|
|
6177
|
-
`${base}/api/projects/${projectId}/flows/${options.flowId}/settings/${settingsId}/deploy`
|
|
6172
|
+
const response = await apiFetch(
|
|
6173
|
+
`/api/projects/${projectId}/flows/${options.flowId}/settings/${settingsId}/deploy`
|
|
6178
6174
|
);
|
|
6179
6175
|
if (!response.ok) {
|
|
6180
6176
|
const body = await response.json().catch(() => ({}));
|
|
6181
|
-
|
|
6177
|
+
throwApiError(body, "Failed to get deployment");
|
|
6182
6178
|
}
|
|
6183
6179
|
return response.json();
|
|
6184
6180
|
}
|
|
@@ -6187,8 +6183,7 @@ async function getDeployment(options) {
|
|
|
6187
6183
|
"/api/projects/{projectId}/flows/{flowId}/deploy",
|
|
6188
6184
|
{ params: { path: { projectId, flowId: options.flowId } } }
|
|
6189
6185
|
);
|
|
6190
|
-
if (error)
|
|
6191
|
-
throw new Error(error.error?.message || "Failed to get deployment");
|
|
6186
|
+
if (error) throwApiError(error, "Failed to get deployment");
|
|
6192
6187
|
return data;
|
|
6193
6188
|
}
|
|
6194
6189
|
var statusLabels = {
|
|
@@ -6272,73 +6267,59 @@ async function getDeploymentCommand(flowId, options) {
|
|
|
6272
6267
|
|
|
6273
6268
|
// src/commands/deployments/index.ts
|
|
6274
6269
|
init_auth();
|
|
6270
|
+
init_http();
|
|
6271
|
+
import { getPlatform as getPlatform4 } from "@walkeros/core";
|
|
6275
6272
|
init_cli_logger();
|
|
6276
6273
|
init_output();
|
|
6277
6274
|
init_loader();
|
|
6278
|
-
import { getPlatform as getPlatform4 } from "@walkeros/core";
|
|
6279
6275
|
async function listDeployments(options = {}) {
|
|
6280
6276
|
const id = options.projectId ?? requireProjectId();
|
|
6281
|
-
const base = resolveBaseUrl();
|
|
6282
6277
|
const params = new URLSearchParams();
|
|
6283
6278
|
if (options.type) params.set("type", options.type);
|
|
6284
6279
|
if (options.status) params.set("status", options.status);
|
|
6285
6280
|
const qs = params.toString();
|
|
6286
|
-
const response = await
|
|
6287
|
-
|
|
6281
|
+
const response = await apiFetch(
|
|
6282
|
+
`/api/projects/${id}/deployments${qs ? `?${qs}` : ""}`
|
|
6288
6283
|
);
|
|
6289
6284
|
if (!response.ok) {
|
|
6290
6285
|
const body = await response.json().catch(() => ({}));
|
|
6291
|
-
|
|
6292
|
-
body.error?.message || "Failed to list deployments"
|
|
6293
|
-
);
|
|
6286
|
+
throwApiError(body, "Failed to list deployments");
|
|
6294
6287
|
}
|
|
6295
6288
|
return response.json();
|
|
6296
6289
|
}
|
|
6297
6290
|
async function getDeploymentBySlug(options) {
|
|
6298
6291
|
const id = options.projectId ?? requireProjectId();
|
|
6299
|
-
const
|
|
6300
|
-
|
|
6301
|
-
`${base}/api/projects/${id}/deployments/${options.slug}`
|
|
6292
|
+
const response = await apiFetch(
|
|
6293
|
+
`/api/projects/${id}/deployments/${options.slug}`
|
|
6302
6294
|
);
|
|
6303
6295
|
if (!response.ok) {
|
|
6304
6296
|
const body = await response.json().catch(() => ({}));
|
|
6305
|
-
|
|
6306
|
-
body.error?.message || "Failed to get deployment"
|
|
6307
|
-
);
|
|
6297
|
+
throwApiError(body, "Failed to get deployment");
|
|
6308
6298
|
}
|
|
6309
6299
|
return response.json();
|
|
6310
6300
|
}
|
|
6311
6301
|
async function createDeployment(options) {
|
|
6312
6302
|
const id = options.projectId ?? requireProjectId();
|
|
6313
|
-
const
|
|
6314
|
-
|
|
6315
|
-
|
|
6316
|
-
{
|
|
6317
|
-
|
|
6318
|
-
headers: { "Content-Type": "application/json" },
|
|
6319
|
-
body: JSON.stringify({ type: options.type, label: options.label })
|
|
6320
|
-
}
|
|
6321
|
-
);
|
|
6303
|
+
const response = await apiFetch(`/api/projects/${id}/deployments`, {
|
|
6304
|
+
method: "POST",
|
|
6305
|
+
headers: { "Content-Type": "application/json" },
|
|
6306
|
+
body: JSON.stringify({ type: options.type, label: options.label })
|
|
6307
|
+
});
|
|
6322
6308
|
if (!response.ok) {
|
|
6323
6309
|
const body = await response.json().catch(() => ({}));
|
|
6324
|
-
|
|
6325
|
-
body.error?.message || "Failed to create deployment"
|
|
6326
|
-
);
|
|
6310
|
+
throwApiError(body, "Failed to create deployment");
|
|
6327
6311
|
}
|
|
6328
6312
|
return response.json();
|
|
6329
6313
|
}
|
|
6330
6314
|
async function deleteDeployment(options) {
|
|
6331
6315
|
const id = options.projectId ?? requireProjectId();
|
|
6332
|
-
const
|
|
6333
|
-
|
|
6334
|
-
`${base}/api/projects/${id}/deployments/${options.slug}`,
|
|
6316
|
+
const response = await apiFetch(
|
|
6317
|
+
`/api/projects/${id}/deployments/${options.slug}`,
|
|
6335
6318
|
{ method: "DELETE" }
|
|
6336
6319
|
);
|
|
6337
6320
|
if (!response.ok) {
|
|
6338
6321
|
const body = await response.json().catch(() => ({}));
|
|
6339
|
-
|
|
6340
|
-
body.error?.message || "Failed to delete deployment"
|
|
6341
|
-
);
|
|
6322
|
+
throwApiError(body, "Failed to delete deployment");
|
|
6342
6323
|
}
|
|
6343
6324
|
const data = await response.json().catch(() => null);
|
|
6344
6325
|
return data ?? { success: true };
|
|
@@ -6398,15 +6379,10 @@ async function createDeployCommand(config, options) {
|
|
|
6398
6379
|
const isRemoteFlow = config.startsWith("cfg_");
|
|
6399
6380
|
if (isRemoteFlow) {
|
|
6400
6381
|
const id = options.project ?? requireProjectId();
|
|
6401
|
-
const
|
|
6402
|
-
const resp = await authenticatedFetch(
|
|
6403
|
-
`${base}/api/projects/${id}/flows/${config}`
|
|
6404
|
-
);
|
|
6382
|
+
const resp = await apiFetch(`/api/projects/${id}/flows/${config}`);
|
|
6405
6383
|
if (!resp.ok) {
|
|
6406
6384
|
const body = await resp.json().catch(() => ({}));
|
|
6407
|
-
|
|
6408
|
-
body.error?.message || `Failed to fetch flow ${config}`
|
|
6409
|
-
);
|
|
6385
|
+
throwApiError(body, `Failed to fetch flow ${config}`);
|
|
6410
6386
|
}
|
|
6411
6387
|
const flow = await resp.json();
|
|
6412
6388
|
if (!flow.config) throw new Error("Flow has no config");
|
|
@@ -6466,12 +6442,16 @@ async function createDeployCommand(config, options) {
|
|
|
6466
6442
|
|
|
6467
6443
|
// src/commands/feedback/index.ts
|
|
6468
6444
|
init_config_file();
|
|
6445
|
+
init_http();
|
|
6469
6446
|
init_cli_logger();
|
|
6470
6447
|
import { createInterface } from "readline";
|
|
6471
6448
|
async function feedback(text, options) {
|
|
6472
6449
|
const config = readConfig();
|
|
6473
6450
|
const anonymous = options?.anonymous ?? config?.anonymousFeedback ?? true;
|
|
6474
6451
|
const payload = { text };
|
|
6452
|
+
if (options?.version) {
|
|
6453
|
+
payload.version = options.version;
|
|
6454
|
+
}
|
|
6475
6455
|
if (!anonymous && config?.email) {
|
|
6476
6456
|
payload.userId = config.email;
|
|
6477
6457
|
const projectId = process.env.WALKEROS_PROJECT_ID;
|
|
@@ -6479,8 +6459,7 @@ async function feedback(text, options) {
|
|
|
6479
6459
|
payload.projectId = projectId;
|
|
6480
6460
|
}
|
|
6481
6461
|
}
|
|
6482
|
-
const
|
|
6483
|
-
const response = await fetch(`${appUrl}/api/feedback`, {
|
|
6462
|
+
const response = await publicFetch("/api/feedback", {
|
|
6484
6463
|
method: "POST",
|
|
6485
6464
|
headers: { "Content-Type": "application/json" },
|
|
6486
6465
|
body: JSON.stringify(payload)
|
|
@@ -6538,11 +6517,14 @@ function promptUser(question) {
|
|
|
6538
6517
|
// src/index.ts
|
|
6539
6518
|
init_bundle();
|
|
6540
6519
|
init_auth();
|
|
6520
|
+
init_http();
|
|
6541
6521
|
init_api_client();
|
|
6542
6522
|
init_config_file();
|
|
6543
6523
|
init_sse();
|
|
6544
6524
|
init_utils();
|
|
6545
6525
|
export {
|
|
6526
|
+
ApiError,
|
|
6527
|
+
apiFetch,
|
|
6546
6528
|
bundle,
|
|
6547
6529
|
bundleCommand,
|
|
6548
6530
|
bundleRemote,
|
|
@@ -6562,8 +6544,8 @@ export {
|
|
|
6562
6544
|
deleteProject,
|
|
6563
6545
|
deleteProjectCommand,
|
|
6564
6546
|
deploy,
|
|
6565
|
-
deployAuthenticatedFetch,
|
|
6566
6547
|
deployCommand,
|
|
6548
|
+
deployFetch,
|
|
6567
6549
|
duplicateFlow,
|
|
6568
6550
|
duplicateFlowCommand,
|
|
6569
6551
|
feedback,
|
|
@@ -6588,16 +6570,18 @@ export {
|
|
|
6588
6570
|
loadJsonConfig,
|
|
6589
6571
|
loginCommand,
|
|
6590
6572
|
logoutCommand,
|
|
6573
|
+
mergeAuthHeaders,
|
|
6591
6574
|
parseSSEEvents,
|
|
6575
|
+
publicFetch,
|
|
6592
6576
|
push,
|
|
6593
6577
|
pushCommand,
|
|
6594
6578
|
readConfig,
|
|
6595
6579
|
requireProjectId,
|
|
6596
|
-
resolveBaseUrl,
|
|
6597
6580
|
run,
|
|
6598
6581
|
runCommand,
|
|
6599
6582
|
simulate,
|
|
6600
6583
|
simulateCommand,
|
|
6584
|
+
throwApiError,
|
|
6601
6585
|
updateFlow,
|
|
6602
6586
|
updateFlowCommand,
|
|
6603
6587
|
updateProject,
|