@walkeros/cli 3.1.0 → 3.2.0-next-1775064795590
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 +75 -0
- package/README.md +50 -52
- package/dist/cli.js +2816 -2500
- package/dist/examples/README.md +4 -3
- package/dist/examples/flow-complete.json +18 -24
- package/dist/examples/flow-order-complete.json +1 -1
- package/dist/examples/flow-simple.json +1 -1
- package/dist/index.d.ts +156 -111
- package/dist/index.js +2111 -1753
- package/dist/index.js.map +1 -1
- package/examples/README.md +4 -3
- package/examples/flow-complete.json +18 -24
- package/examples/flow-order-complete.json +1 -1
- package/examples/flow-simple.json +1 -1
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
var __defProp = Object.defineProperty;
|
|
2
2
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
3
|
-
var __esm = (
|
|
4
|
-
return
|
|
3
|
+
var __esm = (fn, res) => function __init() {
|
|
4
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
5
5
|
};
|
|
6
6
|
var __export = (target, all) => {
|
|
7
7
|
for (var name in all)
|
|
@@ -205,26 +205,26 @@ function mergeAuthHeaders(token, headers) {
|
|
|
205
205
|
if (token) normalized.Authorization = `Bearer ${token}`;
|
|
206
206
|
return normalized;
|
|
207
207
|
}
|
|
208
|
-
async function apiFetch(
|
|
208
|
+
async function apiFetch(path19, init) {
|
|
209
209
|
const baseUrl = resolveAppUrl();
|
|
210
210
|
const token = resolveToken()?.token;
|
|
211
|
-
return fetch(`${baseUrl}${
|
|
211
|
+
return fetch(`${baseUrl}${path19}`, {
|
|
212
212
|
...init,
|
|
213
213
|
headers: mergeAuthHeaders(token, init?.headers)
|
|
214
214
|
});
|
|
215
215
|
}
|
|
216
|
-
async function publicFetch(
|
|
216
|
+
async function publicFetch(path19, init) {
|
|
217
217
|
const baseUrl = resolveAppUrl();
|
|
218
|
-
return fetch(`${baseUrl}${
|
|
218
|
+
return fetch(`${baseUrl}${path19}`, init);
|
|
219
219
|
}
|
|
220
|
-
async function deployFetch(
|
|
220
|
+
async function deployFetch(path19, init) {
|
|
221
221
|
const baseUrl = resolveAppUrl();
|
|
222
222
|
const token = resolveDeployToken() ?? resolveToken()?.token;
|
|
223
223
|
if (!token)
|
|
224
224
|
throw new Error(
|
|
225
225
|
"No authentication token available. Set WALKEROS_DEPLOY_TOKEN or run walkeros auth login."
|
|
226
226
|
);
|
|
227
|
-
return fetch(`${baseUrl}${
|
|
227
|
+
return fetch(`${baseUrl}${path19}`, {
|
|
228
228
|
...init,
|
|
229
229
|
headers: mergeAuthHeaders(token, init?.headers)
|
|
230
230
|
});
|
|
@@ -237,7 +237,6 @@ var init_http = __esm({
|
|
|
237
237
|
});
|
|
238
238
|
|
|
239
239
|
// src/config/utils.ts
|
|
240
|
-
import crypto from "crypto";
|
|
241
240
|
import fs2 from "fs-extra";
|
|
242
241
|
import path3 from "path";
|
|
243
242
|
function isUrl(str) {
|
|
@@ -248,132 +247,79 @@ function isUrl(str) {
|
|
|
248
247
|
return false;
|
|
249
248
|
}
|
|
250
249
|
}
|
|
251
|
-
async function
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
if (!response.ok) {
|
|
261
|
-
throw new Error(
|
|
262
|
-
`Failed to download ${url}: ${response.status} ${response.statusText}`
|
|
263
|
-
);
|
|
264
|
-
}
|
|
265
|
-
const content = await response.text();
|
|
266
|
-
const downloadsDir = getTmpPath(void 0, "downloads");
|
|
267
|
-
await fs2.ensureDir(downloadsDir);
|
|
268
|
-
const downloadId = crypto.randomUUID().slice(0, 8);
|
|
269
|
-
const tempPath = path3.join(downloadsDir, `flow-${downloadId}.json`);
|
|
270
|
-
await fs2.writeFile(tempPath, content, "utf-8");
|
|
271
|
-
return tempPath;
|
|
272
|
-
} catch (error) {
|
|
273
|
-
if (error instanceof Error) {
|
|
274
|
-
throw new Error(`Failed to download from URL: ${error.message}`);
|
|
275
|
-
}
|
|
276
|
-
throw error;
|
|
250
|
+
async function fetchContentString(url) {
|
|
251
|
+
const token = resolveToken()?.token;
|
|
252
|
+
const response = await fetch(url, {
|
|
253
|
+
headers: mergeAuthHeaders(token)
|
|
254
|
+
});
|
|
255
|
+
if (!response.ok) {
|
|
256
|
+
throw new Error(
|
|
257
|
+
`Failed to fetch ${url}: ${response.status} ${response.statusText}`
|
|
258
|
+
);
|
|
277
259
|
}
|
|
260
|
+
return response.text();
|
|
278
261
|
}
|
|
279
|
-
async function
|
|
280
|
-
const trimmed =
|
|
262
|
+
async function resolveContent(input) {
|
|
263
|
+
const trimmed = input.trim();
|
|
281
264
|
if (isUrl(trimmed)) {
|
|
282
|
-
|
|
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 {
|
|
291
|
-
try {
|
|
292
|
-
await fs2.remove(absolutePath2);
|
|
293
|
-
} catch {
|
|
294
|
-
}
|
|
295
|
-
}
|
|
265
|
+
return fetchContentString(trimmed);
|
|
296
266
|
}
|
|
297
267
|
const absolutePath = path3.resolve(trimmed);
|
|
298
268
|
if (await fs2.pathExists(absolutePath)) {
|
|
299
|
-
|
|
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
|
-
}
|
|
269
|
+
return fs2.readFile(absolutePath, "utf-8");
|
|
307
270
|
}
|
|
308
271
|
if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
272
|
+
return trimmed;
|
|
273
|
+
}
|
|
274
|
+
throw new Error(`Configuration file not found: ${absolutePath}`);
|
|
275
|
+
}
|
|
276
|
+
async function loadConfig(input, options) {
|
|
277
|
+
const json = options?.json !== false;
|
|
278
|
+
if (!json) {
|
|
279
|
+
return resolveContent(input);
|
|
280
|
+
}
|
|
281
|
+
const trimmed = input.trim();
|
|
282
|
+
try {
|
|
283
|
+
const content = await resolveContent(trimmed);
|
|
284
|
+
return JSON.parse(content);
|
|
285
|
+
} catch (error) {
|
|
286
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
287
|
+
if (errorMessage.includes("not found") || errorMessage.includes("Failed to fetch")) {
|
|
288
|
+
throw error;
|
|
289
|
+
}
|
|
290
|
+
if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
|
|
312
291
|
throw new Error(
|
|
313
|
-
`Input appears to be JSON but contains errors: ${
|
|
292
|
+
`Input appears to be JSON but contains errors: ${errorMessage}`
|
|
314
293
|
);
|
|
315
294
|
}
|
|
295
|
+
throw new Error(`Invalid JSON in config file: ${input}. ${errorMessage}`);
|
|
316
296
|
}
|
|
317
|
-
|
|
297
|
+
}
|
|
298
|
+
async function loadJsonConfig(configPath) {
|
|
299
|
+
return loadConfig(configPath, { json: true });
|
|
318
300
|
}
|
|
319
301
|
async function loadJsonFromSource(source, options) {
|
|
320
302
|
const paramName = options?.name || "input";
|
|
321
303
|
if (!source || source.trim() === "") {
|
|
322
|
-
if (options?.required) {
|
|
323
|
-
|
|
324
|
-
}
|
|
325
|
-
if (options?.fallback !== void 0) {
|
|
326
|
-
return options.fallback;
|
|
327
|
-
}
|
|
304
|
+
if (options?.required) throw new Error(`${paramName} is required`);
|
|
305
|
+
if (options?.fallback !== void 0) return options.fallback;
|
|
328
306
|
return {};
|
|
329
307
|
}
|
|
330
|
-
const trimmedSource = source.trim();
|
|
331
|
-
if (isUrl(trimmedSource)) {
|
|
332
|
-
try {
|
|
333
|
-
const tempPath = await downloadFromUrl(trimmedSource);
|
|
334
|
-
try {
|
|
335
|
-
const data = await fs2.readJson(tempPath);
|
|
336
|
-
return data;
|
|
337
|
-
} finally {
|
|
338
|
-
try {
|
|
339
|
-
await fs2.remove(tempPath);
|
|
340
|
-
} catch {
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
} catch (error) {
|
|
344
|
-
throw new Error(
|
|
345
|
-
`Failed to load ${paramName} from URL ${trimmedSource}: ${getErrorMessage(error)}`
|
|
346
|
-
);
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
const resolvedPath = path3.resolve(trimmedSource);
|
|
350
|
-
if (await fs2.pathExists(resolvedPath)) {
|
|
351
|
-
try {
|
|
352
|
-
const data = await fs2.readJson(resolvedPath);
|
|
353
|
-
return data;
|
|
354
|
-
} catch (error) {
|
|
355
|
-
throw new Error(
|
|
356
|
-
`Failed to parse ${paramName} from file ${trimmedSource}: ${getErrorMessage(error)}`
|
|
357
|
-
);
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
308
|
try {
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
if (!
|
|
365
|
-
return { name:
|
|
309
|
+
return await loadJsonConfig(source);
|
|
310
|
+
} catch (error) {
|
|
311
|
+
const trimmed = source.trim();
|
|
312
|
+
if (!trimmed.startsWith("{") && !trimmed.startsWith("[")) {
|
|
313
|
+
return { name: trimmed };
|
|
366
314
|
}
|
|
367
315
|
throw new Error(
|
|
368
|
-
`Failed to parse ${paramName}.
|
|
316
|
+
`Failed to parse ${paramName}. ${error instanceof Error ? error.message : String(error)}`
|
|
369
317
|
);
|
|
370
318
|
}
|
|
371
319
|
}
|
|
372
320
|
var init_utils = __esm({
|
|
373
321
|
"src/config/utils.ts"() {
|
|
374
322
|
"use strict";
|
|
375
|
-
init_core();
|
|
376
|
-
init_tmp();
|
|
377
323
|
init_http();
|
|
378
324
|
init_config_file();
|
|
379
325
|
}
|
|
@@ -433,33 +379,82 @@ import path5 from "path";
|
|
|
433
379
|
import fs3 from "fs-extra";
|
|
434
380
|
async function resolveLocalPackage(packageName, localPath, configDir, logger) {
|
|
435
381
|
const absolutePath = path5.isAbsolute(localPath) ? localPath : path5.resolve(configDir, localPath);
|
|
436
|
-
|
|
382
|
+
const stat = await fs3.stat(absolutePath).catch(() => null);
|
|
383
|
+
if (stat?.isFile()) {
|
|
384
|
+
return { name: packageName, absolutePath, type: "file" };
|
|
385
|
+
}
|
|
386
|
+
if (!stat) {
|
|
387
|
+
for (const ext of [".ts", ".mjs", ".js", ".json"]) {
|
|
388
|
+
const withExt = absolutePath + ext;
|
|
389
|
+
if (await fs3.pathExists(withExt)) {
|
|
390
|
+
return { name: packageName, absolutePath: withExt, type: "file" };
|
|
391
|
+
}
|
|
392
|
+
}
|
|
437
393
|
throw new Error(
|
|
438
394
|
`Local package path not found: ${localPath} (resolved to ${absolutePath})`
|
|
439
395
|
);
|
|
440
396
|
}
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
`No package.json found at ${absolutePath}. Is this a valid package directory?`
|
|
445
|
-
);
|
|
446
|
-
}
|
|
447
|
-
const distPath = path5.join(absolutePath, "dist");
|
|
448
|
-
const hasDistFolder = await fs3.pathExists(distPath);
|
|
449
|
-
if (!hasDistFolder) {
|
|
450
|
-
logger.warn(
|
|
451
|
-
`\u26A0\uFE0F ${packageName}: No dist/ folder found. Using package root.`
|
|
397
|
+
if (stat.isDirectory()) {
|
|
398
|
+
const hasPkgJson = await fs3.pathExists(
|
|
399
|
+
path5.join(absolutePath, "package.json")
|
|
452
400
|
);
|
|
401
|
+
if (hasPkgJson) {
|
|
402
|
+
const distPath = path5.join(absolutePath, "dist");
|
|
403
|
+
const hasDistFolder = await fs3.pathExists(distPath);
|
|
404
|
+
if (!hasDistFolder) {
|
|
405
|
+
logger.warn(
|
|
406
|
+
`\u26A0\uFE0F ${packageName}: No dist/ folder found. Using package root.`
|
|
407
|
+
);
|
|
408
|
+
}
|
|
409
|
+
return {
|
|
410
|
+
name: packageName,
|
|
411
|
+
absolutePath,
|
|
412
|
+
type: "package",
|
|
413
|
+
distPath: hasDistFolder ? distPath : absolutePath,
|
|
414
|
+
hasDistFolder
|
|
415
|
+
};
|
|
416
|
+
}
|
|
417
|
+
return { name: packageName, absolutePath, type: "directory" };
|
|
453
418
|
}
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
distPath: hasDistFolder ? distPath : absolutePath,
|
|
458
|
-
hasDistFolder
|
|
459
|
-
};
|
|
419
|
+
throw new Error(
|
|
420
|
+
`Local package path not found: ${localPath} (resolved to ${absolutePath})`
|
|
421
|
+
);
|
|
460
422
|
}
|
|
461
423
|
async function copyLocalPackage(localPkg, targetDir, logger) {
|
|
462
424
|
const packageDir = path5.join(targetDir, "node_modules", localPkg.name);
|
|
425
|
+
if (localPkg.type === "file") {
|
|
426
|
+
await fs3.ensureDir(packageDir);
|
|
427
|
+
const ext = path5.extname(localPkg.absolutePath);
|
|
428
|
+
await fs3.copy(localPkg.absolutePath, path5.join(packageDir, `index${ext}`));
|
|
429
|
+
await fs3.writeJson(path5.join(packageDir, "package.json"), {
|
|
430
|
+
name: localPkg.name,
|
|
431
|
+
main: `./index${ext}`
|
|
432
|
+
});
|
|
433
|
+
logger.info(
|
|
434
|
+
`\u{1F4E6} Using local file: ${localPkg.name} from ${localPkg.absolutePath}`
|
|
435
|
+
);
|
|
436
|
+
return packageDir;
|
|
437
|
+
}
|
|
438
|
+
if (localPkg.type === "directory") {
|
|
439
|
+
await fs3.ensureDir(path5.dirname(packageDir));
|
|
440
|
+
const entries = await fs3.readdir(localPkg.absolutePath);
|
|
441
|
+
for (const entry of entries) {
|
|
442
|
+
if (!["node_modules", ".turbo", ".git"].includes(entry)) {
|
|
443
|
+
await fs3.copy(
|
|
444
|
+
path5.join(localPkg.absolutePath, entry),
|
|
445
|
+
path5.join(packageDir, entry)
|
|
446
|
+
);
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
await fs3.writeJson(path5.join(packageDir, "package.json"), {
|
|
450
|
+
name: localPkg.name,
|
|
451
|
+
main: "./index.ts"
|
|
452
|
+
});
|
|
453
|
+
logger.info(
|
|
454
|
+
`\u{1F4E6} Using local dir: ${localPkg.name} from ${localPkg.absolutePath}`
|
|
455
|
+
);
|
|
456
|
+
return packageDir;
|
|
457
|
+
}
|
|
463
458
|
await fs3.ensureDir(path5.dirname(packageDir));
|
|
464
459
|
await fs3.copy(
|
|
465
460
|
path5.join(localPkg.absolutePath, "package.json"),
|
|
@@ -505,14 +500,11 @@ function detectPlatformFromPath(inputPath) {
|
|
|
505
500
|
}
|
|
506
501
|
async function loadContent(inputPath) {
|
|
507
502
|
if (isUrl(inputPath)) {
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
throw new Error(`Failed to fetch ${inputPath}: ${response.status}`);
|
|
514
|
-
}
|
|
515
|
-
return response.text();
|
|
503
|
+
return fetchContentString(inputPath);
|
|
504
|
+
}
|
|
505
|
+
const trimmed = inputPath.trim();
|
|
506
|
+
if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
|
|
507
|
+
return trimmed;
|
|
516
508
|
}
|
|
517
509
|
return fs4.readFile(inputPath, "utf8");
|
|
518
510
|
}
|
|
@@ -520,12 +512,12 @@ var init_input_detector = __esm({
|
|
|
520
512
|
"src/core/input-detector.ts"() {
|
|
521
513
|
"use strict";
|
|
522
514
|
init_utils();
|
|
523
|
-
init_http();
|
|
524
|
-
init_config_file();
|
|
525
515
|
}
|
|
526
516
|
});
|
|
527
517
|
|
|
528
518
|
// src/core/stdin.ts
|
|
519
|
+
import fs5 from "fs-extra";
|
|
520
|
+
import path6 from "path";
|
|
529
521
|
function isStdinPiped() {
|
|
530
522
|
return !process.stdin.isTTY;
|
|
531
523
|
}
|
|
@@ -540,9 +532,17 @@ async function readStdin() {
|
|
|
540
532
|
}
|
|
541
533
|
return content;
|
|
542
534
|
}
|
|
535
|
+
async function readStdinToTempFile(label) {
|
|
536
|
+
const content = await readStdin();
|
|
537
|
+
const tmpPath = getTmpPath(void 0, `stdin-${label}.json`);
|
|
538
|
+
await fs5.ensureDir(path6.dirname(tmpPath));
|
|
539
|
+
await fs5.writeFile(tmpPath, content, "utf-8");
|
|
540
|
+
return tmpPath;
|
|
541
|
+
}
|
|
543
542
|
var init_stdin = __esm({
|
|
544
543
|
"src/core/stdin.ts"() {
|
|
545
544
|
"use strict";
|
|
545
|
+
init_tmp();
|
|
546
546
|
}
|
|
547
547
|
});
|
|
548
548
|
|
|
@@ -599,6 +599,129 @@ var init_sse = __esm({
|
|
|
599
599
|
}
|
|
600
600
|
});
|
|
601
601
|
|
|
602
|
+
// src/core/event-validation.ts
|
|
603
|
+
import { schemas } from "@walkeros/core/dev";
|
|
604
|
+
function validateEvent(input, level = "strict") {
|
|
605
|
+
const errors = [];
|
|
606
|
+
const warnings = [];
|
|
607
|
+
const details = {};
|
|
608
|
+
if (typeof input !== "object" || input === null || Array.isArray(input)) {
|
|
609
|
+
errors.push({
|
|
610
|
+
path: "root",
|
|
611
|
+
message: "Event must be an object",
|
|
612
|
+
code: "NOT_AN_OBJECT"
|
|
613
|
+
});
|
|
614
|
+
return { valid: false, errors, warnings, details };
|
|
615
|
+
}
|
|
616
|
+
const event = input;
|
|
617
|
+
if (!("name" in event) || event.name === void 0) {
|
|
618
|
+
errors.push({
|
|
619
|
+
path: "name",
|
|
620
|
+
message: "Event must have a name field",
|
|
621
|
+
code: "MISSING_EVENT_NAME"
|
|
622
|
+
});
|
|
623
|
+
} else if (typeof event.name !== "string" || event.name.trim() === "") {
|
|
624
|
+
errors.push({
|
|
625
|
+
path: "name",
|
|
626
|
+
message: "Event name cannot be empty",
|
|
627
|
+
value: event.name,
|
|
628
|
+
code: "EMPTY_EVENT_NAME"
|
|
629
|
+
});
|
|
630
|
+
} else {
|
|
631
|
+
const name = event.name;
|
|
632
|
+
if (!name.includes(" ")) {
|
|
633
|
+
if (level === "strict") {
|
|
634
|
+
errors.push({
|
|
635
|
+
path: "name",
|
|
636
|
+
message: 'Event name must be "entity action" format with space (e.g., "page view")',
|
|
637
|
+
value: name,
|
|
638
|
+
code: "INVALID_EVENT_NAME"
|
|
639
|
+
});
|
|
640
|
+
details.entity = null;
|
|
641
|
+
details.action = null;
|
|
642
|
+
} else if (level === "standard") {
|
|
643
|
+
warnings.push({
|
|
644
|
+
path: "name",
|
|
645
|
+
message: `Event name "${name}" should follow "ENTITY ACTION" format (e.g., "page view")`
|
|
646
|
+
});
|
|
647
|
+
details.entity = null;
|
|
648
|
+
details.action = null;
|
|
649
|
+
}
|
|
650
|
+
} else {
|
|
651
|
+
const parts = name.trim().split(/\s+/);
|
|
652
|
+
const action = parts.pop();
|
|
653
|
+
const entity = parts.join(" ");
|
|
654
|
+
details.entity = entity;
|
|
655
|
+
details.action = action;
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
if (level === "minimal") {
|
|
659
|
+
return { valid: errors.length === 0, errors, warnings, details };
|
|
660
|
+
}
|
|
661
|
+
const zodResult = PartialEventSchema.safeParse(input);
|
|
662
|
+
if (!zodResult.success) {
|
|
663
|
+
for (const issue of zodResult.error.issues) {
|
|
664
|
+
const issuePath = issue.path.join(".");
|
|
665
|
+
if (issuePath === "name") continue;
|
|
666
|
+
errors.push({
|
|
667
|
+
path: issuePath || "root",
|
|
668
|
+
message: issue.message,
|
|
669
|
+
code: "SCHEMA_VALIDATION"
|
|
670
|
+
});
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
if (level === "strict") {
|
|
674
|
+
if (!event.consent) {
|
|
675
|
+
warnings.push({
|
|
676
|
+
path: "consent",
|
|
677
|
+
message: "No consent object provided",
|
|
678
|
+
suggestion: "Consider adding a consent object for GDPR/privacy compliance"
|
|
679
|
+
});
|
|
680
|
+
}
|
|
681
|
+
details.hasConsent = !!event.consent;
|
|
682
|
+
details.hasData = !!event.data;
|
|
683
|
+
details.hasContext = !!event.context;
|
|
684
|
+
}
|
|
685
|
+
return { valid: errors.length === 0, errors, warnings, details };
|
|
686
|
+
}
|
|
687
|
+
var PartialEventSchema;
|
|
688
|
+
var init_event_validation = __esm({
|
|
689
|
+
"src/core/event-validation.ts"() {
|
|
690
|
+
"use strict";
|
|
691
|
+
({ PartialEventSchema } = schemas);
|
|
692
|
+
}
|
|
693
|
+
});
|
|
694
|
+
|
|
695
|
+
// src/core/package-path.ts
|
|
696
|
+
import fs6 from "fs";
|
|
697
|
+
import path7 from "path";
|
|
698
|
+
function resolvePackageImportPath(packageName, packages, configDir, subpath) {
|
|
699
|
+
const entry = packages?.[packageName];
|
|
700
|
+
if (entry?.path) {
|
|
701
|
+
const resolved = path7.isAbsolute(entry.path) ? entry.path : path7.resolve(configDir, entry.path);
|
|
702
|
+
if (!subpath) return resolved;
|
|
703
|
+
try {
|
|
704
|
+
const pkgJson = JSON.parse(
|
|
705
|
+
fs6.readFileSync(path7.join(resolved, "package.json"), "utf8")
|
|
706
|
+
);
|
|
707
|
+
const exportKey = `.${subpath.startsWith("/") ? subpath : `/${subpath}`}`;
|
|
708
|
+
const exp = pkgJson.exports?.[exportKey];
|
|
709
|
+
if (exp) {
|
|
710
|
+
const target = typeof exp === "string" ? exp : exp.import || exp.require || exp.default;
|
|
711
|
+
if (target) return path7.join(resolved, target);
|
|
712
|
+
}
|
|
713
|
+
} catch {
|
|
714
|
+
}
|
|
715
|
+
return path7.join(resolved, subpath.replace(/^\//, ""));
|
|
716
|
+
}
|
|
717
|
+
return subpath ? `${packageName}${subpath}` : packageName;
|
|
718
|
+
}
|
|
719
|
+
var init_package_path = __esm({
|
|
720
|
+
"src/core/package-path.ts"() {
|
|
721
|
+
"use strict";
|
|
722
|
+
}
|
|
723
|
+
});
|
|
724
|
+
|
|
602
725
|
// src/core/index.ts
|
|
603
726
|
var init_core = __esm({
|
|
604
727
|
"src/core/index.ts"() {
|
|
@@ -615,20 +738,19 @@ var init_core = __esm({
|
|
|
615
738
|
init_auth();
|
|
616
739
|
init_http();
|
|
617
740
|
init_sse();
|
|
741
|
+
init_event_validation();
|
|
742
|
+
init_package_path();
|
|
618
743
|
}
|
|
619
744
|
});
|
|
620
745
|
|
|
621
746
|
// src/config/validators.ts
|
|
622
|
-
import { schemas } from "@walkeros/core/dev";
|
|
623
|
-
function isObject(value) {
|
|
624
|
-
return typeof value === "object" && value !== null && !Array.isArray(value) && Object.prototype.toString.call(value) === "[object Object]";
|
|
625
|
-
}
|
|
747
|
+
import { schemas as schemas2 } from "@walkeros/core/dev";
|
|
626
748
|
function validateFlowConfig(data) {
|
|
627
749
|
const result = safeParseConfig(data);
|
|
628
750
|
if (!result.success) {
|
|
629
751
|
const errors = result.error.issues.map((issue) => {
|
|
630
|
-
const
|
|
631
|
-
return ` - ${
|
|
752
|
+
const path19 = issue.path.length > 0 ? issue.path.map(String).join(".") : "root";
|
|
753
|
+
return ` - ${path19}: ${issue.message}`;
|
|
632
754
|
}).join("\n");
|
|
633
755
|
throw new Error(`Invalid configuration:
|
|
634
756
|
${errors}`);
|
|
@@ -642,7 +764,7 @@ var safeParseConfig;
|
|
|
642
764
|
var init_validators = __esm({
|
|
643
765
|
"src/config/validators.ts"() {
|
|
644
766
|
"use strict";
|
|
645
|
-
({ safeParseConfig } =
|
|
767
|
+
({ safeParseConfig } = schemas2);
|
|
646
768
|
}
|
|
647
769
|
});
|
|
648
770
|
|
|
@@ -664,7 +786,7 @@ var init_build_defaults = __esm({
|
|
|
664
786
|
minify: true,
|
|
665
787
|
sourcemap: false,
|
|
666
788
|
cache: true,
|
|
667
|
-
windowCollector: "
|
|
789
|
+
windowCollector: "walkerOS",
|
|
668
790
|
windowElb: "elb"
|
|
669
791
|
};
|
|
670
792
|
SERVER_BUILD_DEFAULTS = {
|
|
@@ -683,8 +805,8 @@ var init_build_defaults = __esm({
|
|
|
683
805
|
});
|
|
684
806
|
|
|
685
807
|
// src/config/loader.ts
|
|
686
|
-
import
|
|
687
|
-
import
|
|
808
|
+
import path8 from "path";
|
|
809
|
+
import fs7 from "fs-extra";
|
|
688
810
|
import { getFlowSettings, getPlatform } from "@walkeros/core";
|
|
689
811
|
function loadBundleConfig(rawConfig, options) {
|
|
690
812
|
const config = validateFlowConfig(rawConfig);
|
|
@@ -703,11 +825,11 @@ function loadBundleConfig(rawConfig, options) {
|
|
|
703
825
|
const buildDefaults = getBuildDefaults(platform);
|
|
704
826
|
const packages = flowSettings.packages || {};
|
|
705
827
|
const output = options.buildOverrides?.output || getDefaultOutput(platform);
|
|
706
|
-
const configDir = isUrl(options.configPath) ? process.cwd() :
|
|
828
|
+
const configDir = isUrl(options.configPath) ? process.cwd() : path8.dirname(options.configPath);
|
|
707
829
|
let includes = config.include;
|
|
708
830
|
if (!includes) {
|
|
709
|
-
const defaultIncludePath =
|
|
710
|
-
if (
|
|
831
|
+
const defaultIncludePath = path8.resolve(configDir, DEFAULT_INCLUDE_FOLDER);
|
|
832
|
+
if (fs7.pathExistsSync(defaultIncludePath)) {
|
|
711
833
|
includes = [DEFAULT_INCLUDE_FOLDER];
|
|
712
834
|
}
|
|
713
835
|
}
|
|
@@ -792,6 +914,43 @@ var init_config = __esm({
|
|
|
792
914
|
}
|
|
793
915
|
});
|
|
794
916
|
|
|
917
|
+
// src/commands/bundle/config-classifier.ts
|
|
918
|
+
function containsCodeMarkers(value) {
|
|
919
|
+
if (typeof value === "string") {
|
|
920
|
+
return value.startsWith("$code:") || value.startsWith("$store:") || value.includes("__WALKEROS_ENV:");
|
|
921
|
+
}
|
|
922
|
+
if (Array.isArray(value)) {
|
|
923
|
+
return value.some(containsCodeMarkers);
|
|
924
|
+
}
|
|
925
|
+
if (value !== null && typeof value === "object") {
|
|
926
|
+
return Object.values(value).some(
|
|
927
|
+
containsCodeMarkers
|
|
928
|
+
);
|
|
929
|
+
}
|
|
930
|
+
return false;
|
|
931
|
+
}
|
|
932
|
+
function classifyStepProperties(step) {
|
|
933
|
+
const codeProps = {};
|
|
934
|
+
const dataProps = {};
|
|
935
|
+
for (const [key, value] of Object.entries(step)) {
|
|
936
|
+
if (key === "code") {
|
|
937
|
+
codeProps[key] = value;
|
|
938
|
+
continue;
|
|
939
|
+
}
|
|
940
|
+
if (containsCodeMarkers(value)) {
|
|
941
|
+
codeProps[key] = value;
|
|
942
|
+
} else {
|
|
943
|
+
dataProps[key] = value;
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
return { codeProps, dataProps };
|
|
947
|
+
}
|
|
948
|
+
var init_config_classifier = __esm({
|
|
949
|
+
"src/commands/bundle/config-classifier.ts"() {
|
|
950
|
+
"use strict";
|
|
951
|
+
}
|
|
952
|
+
});
|
|
953
|
+
|
|
795
954
|
// src/core/cache-utils.ts
|
|
796
955
|
import { getHashServer } from "@walkeros/server-core";
|
|
797
956
|
import semver from "semver";
|
|
@@ -832,8 +991,8 @@ var init_cache_utils = __esm({
|
|
|
832
991
|
|
|
833
992
|
// src/commands/bundle/package-manager.ts
|
|
834
993
|
import pacote from "pacote";
|
|
835
|
-
import
|
|
836
|
-
import
|
|
994
|
+
import path9 from "path";
|
|
995
|
+
import fs8 from "fs-extra";
|
|
837
996
|
import semver2 from "semver";
|
|
838
997
|
async function withTimeout(promise, ms, errorMessage) {
|
|
839
998
|
let timer;
|
|
@@ -847,7 +1006,7 @@ async function withTimeout(promise, ms, errorMessage) {
|
|
|
847
1006
|
}
|
|
848
1007
|
}
|
|
849
1008
|
function getPackageDirectory(baseDir, packageName) {
|
|
850
|
-
return
|
|
1009
|
+
return path9.join(baseDir, "node_modules", packageName);
|
|
851
1010
|
}
|
|
852
1011
|
async function collectAllSpecs(packages, logger, configDir) {
|
|
853
1012
|
const allSpecs = /* @__PURE__ */ new Map();
|
|
@@ -873,7 +1032,47 @@ async function collectAllSpecs(packages, logger, configDir) {
|
|
|
873
1032
|
optional: item.optional,
|
|
874
1033
|
localPath: item.localPath
|
|
875
1034
|
});
|
|
876
|
-
if (item.localPath)
|
|
1035
|
+
if (item.localPath) {
|
|
1036
|
+
const resolvedPath = path9.isAbsolute(item.localPath) ? item.localPath : path9.resolve(configDir || process.cwd(), item.localPath);
|
|
1037
|
+
const candidatePath = path9.join(resolvedPath, "package.json");
|
|
1038
|
+
const hasPkgJson = await fs8.pathExists(candidatePath);
|
|
1039
|
+
if (hasPkgJson) {
|
|
1040
|
+
try {
|
|
1041
|
+
const pkgJson = await fs8.readJson(candidatePath);
|
|
1042
|
+
const deps2 = pkgJson.dependencies || {};
|
|
1043
|
+
for (const [depName, depSpec] of Object.entries(deps2)) {
|
|
1044
|
+
if (typeof depSpec === "string") {
|
|
1045
|
+
queue.push({
|
|
1046
|
+
name: depName,
|
|
1047
|
+
spec: depSpec,
|
|
1048
|
+
source: "dependency",
|
|
1049
|
+
from: item.name,
|
|
1050
|
+
optional: false
|
|
1051
|
+
});
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
const peerDeps2 = pkgJson.peerDependencies || {};
|
|
1055
|
+
const peerMeta2 = pkgJson.peerDependenciesMeta || {};
|
|
1056
|
+
for (const [depName, depSpec] of Object.entries(peerDeps2)) {
|
|
1057
|
+
if (typeof depSpec === "string") {
|
|
1058
|
+
const isOptional = peerMeta2[depName]?.optional === true;
|
|
1059
|
+
queue.push({
|
|
1060
|
+
name: depName,
|
|
1061
|
+
spec: depSpec,
|
|
1062
|
+
source: "peerDependency",
|
|
1063
|
+
from: item.name,
|
|
1064
|
+
optional: isOptional
|
|
1065
|
+
});
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1068
|
+
} catch (error) {
|
|
1069
|
+
logger.debug(
|
|
1070
|
+
`Failed to read package.json for local package ${item.name}: ${error}`
|
|
1071
|
+
);
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1074
|
+
continue;
|
|
1075
|
+
}
|
|
877
1076
|
let manifest;
|
|
878
1077
|
try {
|
|
879
1078
|
manifest = await withTimeout(
|
|
@@ -920,7 +1119,7 @@ async function collectAllSpecs(packages, logger, configDir) {
|
|
|
920
1119
|
function resolveVersionConflicts(allSpecs, logger) {
|
|
921
1120
|
const resolved = /* @__PURE__ */ new Map();
|
|
922
1121
|
for (const [name, specs] of allSpecs) {
|
|
923
|
-
const localSpec = specs.find((
|
|
1122
|
+
const localSpec = specs.find((s) => s.localPath);
|
|
924
1123
|
if (localSpec) {
|
|
925
1124
|
resolved.set(name, {
|
|
926
1125
|
name,
|
|
@@ -929,13 +1128,13 @@ function resolveVersionConflicts(allSpecs, logger) {
|
|
|
929
1128
|
});
|
|
930
1129
|
continue;
|
|
931
1130
|
}
|
|
932
|
-
const nonPeerSpecs = specs.filter((
|
|
933
|
-
const peerSpecs = specs.filter((
|
|
1131
|
+
const nonPeerSpecs = specs.filter((s) => s.source !== "peerDependency");
|
|
1132
|
+
const peerSpecs = specs.filter((s) => s.source === "peerDependency");
|
|
934
1133
|
let activeSpecs;
|
|
935
1134
|
if (nonPeerSpecs.length > 0) {
|
|
936
1135
|
activeSpecs = nonPeerSpecs;
|
|
937
1136
|
} else {
|
|
938
|
-
const requiredPeers = peerSpecs.filter((
|
|
1137
|
+
const requiredPeers = peerSpecs.filter((s) => !s.optional);
|
|
939
1138
|
if (requiredPeers.length === 0) {
|
|
940
1139
|
logger.debug(`Skipping optional peer dependency: ${name}`);
|
|
941
1140
|
continue;
|
|
@@ -945,19 +1144,19 @@ function resolveVersionConflicts(allSpecs, logger) {
|
|
|
945
1144
|
activeSpecs.sort(
|
|
946
1145
|
(a2, b2) => SOURCE_PRIORITY[a2.source] - SOURCE_PRIORITY[b2.source]
|
|
947
1146
|
);
|
|
948
|
-
const directSpecs = activeSpecs.filter((
|
|
949
|
-
const directExact = directSpecs.find((
|
|
1147
|
+
const directSpecs = activeSpecs.filter((s) => s.source === "direct");
|
|
1148
|
+
const directExact = directSpecs.find((s) => semver2.valid(s.spec) !== null);
|
|
950
1149
|
let chosenVersion;
|
|
951
1150
|
if (directExact) {
|
|
952
1151
|
chosenVersion = directExact.spec;
|
|
953
1152
|
} else if (directSpecs.length > 0) {
|
|
954
1153
|
chosenVersion = directSpecs[0].spec;
|
|
955
1154
|
} else {
|
|
956
|
-
const exactVersions = activeSpecs.filter((
|
|
1155
|
+
const exactVersions = activeSpecs.filter((s) => semver2.valid(s.spec) !== null).map((s) => s.spec);
|
|
957
1156
|
const uniqueExact = [...new Set(exactVersions)];
|
|
958
1157
|
if (uniqueExact.length > 1) {
|
|
959
1158
|
throw new Error(
|
|
960
|
-
`Version conflict for ${name}: ${uniqueExact.join(" vs ")} (from ${activeSpecs.map((
|
|
1159
|
+
`Version conflict for ${name}: ${uniqueExact.join(" vs ")} (from ${activeSpecs.map((s) => `${s.spec} via ${s.from}`).join(", ")})`
|
|
961
1160
|
);
|
|
962
1161
|
} else if (uniqueExact.length === 1) {
|
|
963
1162
|
chosenVersion = uniqueExact[0];
|
|
@@ -1004,7 +1203,7 @@ async function downloadPackages(packages, targetDir, logger, useCache = true, co
|
|
|
1004
1203
|
logger.debug("Resolving dependencies");
|
|
1005
1204
|
const allSpecs = await collectAllSpecs(packages, logger, configDir);
|
|
1006
1205
|
const resolved = resolveVersionConflicts(allSpecs, logger);
|
|
1007
|
-
await
|
|
1206
|
+
await fs8.ensureDir(targetDir);
|
|
1008
1207
|
const localPackageMap = /* @__PURE__ */ new Map();
|
|
1009
1208
|
for (const pkg of packages) {
|
|
1010
1209
|
if (pkg.path) localPackageMap.set(pkg.name, pkg.path);
|
|
@@ -1033,8 +1232,8 @@ async function downloadPackages(packages, targetDir, logger, useCache = true, co
|
|
|
1033
1232
|
logger.debug(`Downloading ${packageSpec} (cached)`);
|
|
1034
1233
|
}
|
|
1035
1234
|
try {
|
|
1036
|
-
await
|
|
1037
|
-
await
|
|
1235
|
+
await fs8.ensureDir(path9.dirname(packageDir));
|
|
1236
|
+
await fs8.copy(cachedPath, packageDir);
|
|
1038
1237
|
packagePaths.set(name, packageDir);
|
|
1039
1238
|
continue;
|
|
1040
1239
|
} catch {
|
|
@@ -1042,7 +1241,7 @@ async function downloadPackages(packages, targetDir, logger, useCache = true, co
|
|
|
1042
1241
|
}
|
|
1043
1242
|
}
|
|
1044
1243
|
try {
|
|
1045
|
-
await
|
|
1244
|
+
await fs8.ensureDir(path9.dirname(packageDir));
|
|
1046
1245
|
const cacheDir = process.env.NPM_CACHE_DIR || getTmpPath(tmpDir, "cache", "npm");
|
|
1047
1246
|
await withTimeout(
|
|
1048
1247
|
pacote.extract(packageSpec, packageDir, {
|
|
@@ -1057,8 +1256,8 @@ async function downloadPackages(packages, targetDir, logger, useCache = true, co
|
|
|
1057
1256
|
}
|
|
1058
1257
|
if (useCache) {
|
|
1059
1258
|
try {
|
|
1060
|
-
await
|
|
1061
|
-
await
|
|
1259
|
+
await fs8.ensureDir(path9.dirname(cachedPath));
|
|
1260
|
+
await fs8.copy(packageDir, cachedPath);
|
|
1062
1261
|
} catch {
|
|
1063
1262
|
}
|
|
1064
1263
|
}
|
|
@@ -1072,11 +1271,11 @@ async function downloadPackages(packages, targetDir, logger, useCache = true, co
|
|
|
1072
1271
|
async function getCachedPackagePath(pkg, tmpDir) {
|
|
1073
1272
|
const cacheDir = getTmpPath(tmpDir, "cache", "packages");
|
|
1074
1273
|
const cacheKey = await getPackageCacheKey(pkg.name, pkg.version);
|
|
1075
|
-
return
|
|
1274
|
+
return path9.join(cacheDir, cacheKey);
|
|
1076
1275
|
}
|
|
1077
1276
|
async function isPackageCached(pkg, tmpDir) {
|
|
1078
1277
|
const cachedPath = await getCachedPackagePath(pkg, tmpDir);
|
|
1079
|
-
return
|
|
1278
|
+
return fs8.pathExists(cachedPath);
|
|
1080
1279
|
}
|
|
1081
1280
|
function validateNoDuplicatePackages(packages) {
|
|
1082
1281
|
const packageMap = /* @__PURE__ */ new Map();
|
|
@@ -1122,29 +1321,57 @@ var init_package_manager = __esm({
|
|
|
1122
1321
|
});
|
|
1123
1322
|
|
|
1124
1323
|
// src/core/build-cache.ts
|
|
1125
|
-
import
|
|
1126
|
-
import
|
|
1324
|
+
import fs9 from "fs-extra";
|
|
1325
|
+
import path10 from "path";
|
|
1326
|
+
import { getHashServer as getHashServer2 } from "@walkeros/server-core";
|
|
1127
1327
|
async function getBuildCachePath(configContent, tmpDir) {
|
|
1128
1328
|
const cacheDir = getTmpPath(tmpDir, "cache", "builds");
|
|
1129
1329
|
const cacheKey = await getFlowSettingsCacheKey(configContent);
|
|
1130
|
-
return
|
|
1330
|
+
return path10.join(cacheDir, `${cacheKey}.js`);
|
|
1131
1331
|
}
|
|
1132
1332
|
async function isBuildCached(configContent, tmpDir) {
|
|
1133
1333
|
const cachePath = await getBuildCachePath(configContent, tmpDir);
|
|
1134
|
-
return
|
|
1334
|
+
return fs9.pathExists(cachePath);
|
|
1135
1335
|
}
|
|
1136
1336
|
async function cacheBuild(configContent, buildOutput, tmpDir) {
|
|
1137
1337
|
const cachePath = await getBuildCachePath(configContent, tmpDir);
|
|
1138
|
-
await
|
|
1139
|
-
await
|
|
1338
|
+
await fs9.ensureDir(path10.dirname(cachePath));
|
|
1339
|
+
await fs9.writeFile(cachePath, buildOutput, "utf-8");
|
|
1140
1340
|
}
|
|
1141
1341
|
async function getCachedBuild(configContent, tmpDir) {
|
|
1142
1342
|
const cachePath = await getBuildCachePath(configContent, tmpDir);
|
|
1143
|
-
if (await
|
|
1144
|
-
return await
|
|
1343
|
+
if (await fs9.pathExists(cachePath)) {
|
|
1344
|
+
return await fs9.readFile(cachePath, "utf-8");
|
|
1345
|
+
}
|
|
1346
|
+
return null;
|
|
1347
|
+
}
|
|
1348
|
+
async function getCodeCachePath(codeContent, tmpDir) {
|
|
1349
|
+
const cacheDir = getTmpPath(tmpDir, "cache", "code");
|
|
1350
|
+
const cacheKey = await getHashServer2(codeContent, 12);
|
|
1351
|
+
return path10.join(cacheDir, `${cacheKey}.js`);
|
|
1352
|
+
}
|
|
1353
|
+
async function cacheCode(codeContent, codeOutput, tmpDir) {
|
|
1354
|
+
const cachePath = await getCodeCachePath(codeContent, tmpDir);
|
|
1355
|
+
await fs9.ensureDir(path10.dirname(cachePath));
|
|
1356
|
+
await fs9.writeFile(cachePath, codeOutput, "utf-8");
|
|
1357
|
+
}
|
|
1358
|
+
async function getCachedCode(codeContent, tmpDir) {
|
|
1359
|
+
const cachePath = await getCodeCachePath(codeContent, tmpDir);
|
|
1360
|
+
if (await fs9.pathExists(cachePath)) {
|
|
1361
|
+
return fs9.readFile(cachePath, "utf-8");
|
|
1145
1362
|
}
|
|
1146
1363
|
return null;
|
|
1147
1364
|
}
|
|
1365
|
+
async function ensureCodeOnDisk(codeContent, compiledCode, tmpDir) {
|
|
1366
|
+
const cacheDir = getTmpPath(tmpDir, "cache", "code");
|
|
1367
|
+
const cacheKey = await getHashServer2(codeContent, 12);
|
|
1368
|
+
const cachePath = path10.join(cacheDir, `${cacheKey}.mjs`);
|
|
1369
|
+
if (!await fs9.pathExists(cachePath)) {
|
|
1370
|
+
await fs9.ensureDir(path10.dirname(cachePath));
|
|
1371
|
+
await fs9.writeFile(cachePath, compiledCode, "utf-8");
|
|
1372
|
+
}
|
|
1373
|
+
return cachePath;
|
|
1374
|
+
}
|
|
1148
1375
|
var init_build_cache = __esm({
|
|
1149
1376
|
"src/core/build-cache.ts"() {
|
|
1150
1377
|
"use strict";
|
|
@@ -1154,19 +1381,23 @@ var init_build_cache = __esm({
|
|
|
1154
1381
|
});
|
|
1155
1382
|
|
|
1156
1383
|
// src/commands/bundle/bundler.ts
|
|
1157
|
-
import
|
|
1384
|
+
import crypto from "crypto";
|
|
1158
1385
|
import esbuild from "esbuild";
|
|
1159
1386
|
import { builtinModules } from "module";
|
|
1160
|
-
import
|
|
1161
|
-
import
|
|
1387
|
+
import path11 from "path";
|
|
1388
|
+
import fs10 from "fs-extra";
|
|
1162
1389
|
import { packageNameToVariable, ENV_MARKER_PREFIX } from "@walkeros/core";
|
|
1163
1390
|
function isInlineCode(code) {
|
|
1164
1391
|
return code !== null && typeof code === "object" && !Array.isArray(code) && "push" in code;
|
|
1165
1392
|
}
|
|
1393
|
+
function hasCodeReference(code) {
|
|
1394
|
+
return isInlineCode(code) || typeof code === "string";
|
|
1395
|
+
}
|
|
1166
1396
|
function validateReference(type, name, ref) {
|
|
1167
1397
|
const hasPackage = !!ref.package;
|
|
1168
|
-
const
|
|
1169
|
-
|
|
1398
|
+
const hasInlineCode = isInlineCode(ref.code);
|
|
1399
|
+
const hasCode = hasCodeReference(ref.code);
|
|
1400
|
+
if (hasPackage && hasInlineCode) {
|
|
1170
1401
|
throw new Error(
|
|
1171
1402
|
`${type} "${name}": Cannot specify both package and code. Use one or the other.`
|
|
1172
1403
|
);
|
|
@@ -1207,18 +1438,18 @@ function generateInlineCode(inline, config, env, chain, chainPropertyName, isDes
|
|
|
1207
1438
|
}
|
|
1208
1439
|
async function copyIncludes(includes, sourceDir, outputDir, logger) {
|
|
1209
1440
|
for (const include of includes) {
|
|
1210
|
-
const sourcePath =
|
|
1211
|
-
const folderName =
|
|
1212
|
-
const destPath =
|
|
1213
|
-
const resolvedOutput =
|
|
1214
|
-
const resolvedSource =
|
|
1215
|
-
if (resolvedSource === resolvedOutput || resolvedOutput.startsWith(resolvedSource +
|
|
1441
|
+
const sourcePath = path11.resolve(sourceDir, include);
|
|
1442
|
+
const folderName = path11.basename(include);
|
|
1443
|
+
const destPath = path11.join(outputDir, folderName);
|
|
1444
|
+
const resolvedOutput = path11.resolve(outputDir);
|
|
1445
|
+
const resolvedSource = path11.resolve(sourcePath);
|
|
1446
|
+
if (resolvedSource === resolvedOutput || resolvedOutput.startsWith(resolvedSource + path11.sep) || resolvedSource.startsWith(resolvedOutput + path11.sep)) {
|
|
1216
1447
|
throw new Error(
|
|
1217
1448
|
`Circular include detected: "${include}" resolves to "${resolvedSource}" which overlaps with output directory "${resolvedOutput}"`
|
|
1218
1449
|
);
|
|
1219
1450
|
}
|
|
1220
|
-
if (await
|
|
1221
|
-
await
|
|
1451
|
+
if (await fs10.pathExists(sourcePath)) {
|
|
1452
|
+
await fs10.copy(sourcePath, destPath);
|
|
1222
1453
|
logger.debug(`Copied ${include} to output`);
|
|
1223
1454
|
} else {
|
|
1224
1455
|
logger.warn(`Include folder not found: ${include}`);
|
|
@@ -1279,7 +1510,7 @@ async function bundleCore(flowSettings, buildOptions, logger, showStats = false)
|
|
|
1279
1510
|
if (hasDeprecatedFeatures) {
|
|
1280
1511
|
logger.warn("Skipping deprecated code: true entries from bundle.");
|
|
1281
1512
|
}
|
|
1282
|
-
const buildId =
|
|
1513
|
+
const buildId = crypto.randomUUID();
|
|
1283
1514
|
const TEMP_DIR = buildOptions.tempDir || getTmpPath(void 0, `walkeros-build-${buildId}`);
|
|
1284
1515
|
const CACHE_DIR = buildOptions.tempDir || getTmpPath();
|
|
1285
1516
|
if (buildOptions.cache !== false) {
|
|
@@ -1289,14 +1520,14 @@ async function bundleCore(flowSettings, buildOptions, logger, showStats = false)
|
|
|
1289
1520
|
const cachedBuild = await getCachedBuild(configContent, CACHE_DIR);
|
|
1290
1521
|
if (cachedBuild) {
|
|
1291
1522
|
logger.debug("Using cached build");
|
|
1292
|
-
const outputPath =
|
|
1293
|
-
await
|
|
1294
|
-
await
|
|
1295
|
-
const stats = await
|
|
1523
|
+
const outputPath = path11.resolve(buildOptions.output);
|
|
1524
|
+
await fs10.ensureDir(path11.dirname(outputPath));
|
|
1525
|
+
await fs10.writeFile(outputPath, cachedBuild);
|
|
1526
|
+
const stats = await fs10.stat(outputPath);
|
|
1296
1527
|
const sizeKB = (stats.size / 1024).toFixed(1);
|
|
1297
1528
|
logger.info(`Output: ${outputPath} (${sizeKB} KB, cached)`);
|
|
1298
1529
|
if (showStats) {
|
|
1299
|
-
const stats2 = await
|
|
1530
|
+
const stats2 = await fs10.stat(outputPath);
|
|
1300
1531
|
const packageStats = Object.entries(buildOptions.packages).map(
|
|
1301
1532
|
([name, pkg]) => ({
|
|
1302
1533
|
name: `${name}@${pkg.version || "latest"}`,
|
|
@@ -1319,7 +1550,7 @@ async function bundleCore(flowSettings, buildOptions, logger, showStats = false)
|
|
|
1319
1550
|
}
|
|
1320
1551
|
}
|
|
1321
1552
|
try {
|
|
1322
|
-
await
|
|
1553
|
+
await fs10.ensureDir(TEMP_DIR);
|
|
1323
1554
|
const hasSourcesOrDests = Object.keys(
|
|
1324
1555
|
flowSettings.sources || {}
|
|
1325
1556
|
).length > 0 || Object.keys(
|
|
@@ -1328,9 +1559,28 @@ async function bundleCore(flowSettings, buildOptions, logger, showStats = false)
|
|
|
1328
1559
|
if (hasSourcesOrDests && !buildOptions.packages["@walkeros/collector"]) {
|
|
1329
1560
|
buildOptions.packages["@walkeros/collector"] = {};
|
|
1330
1561
|
}
|
|
1331
|
-
const stepPackages =
|
|
1562
|
+
const stepPackages = collectAllStepPackages(flowSettings);
|
|
1332
1563
|
for (const pkg of stepPackages) {
|
|
1333
|
-
|
|
1564
|
+
const isLocalPath = pkg.startsWith(".") || pkg.startsWith("/");
|
|
1565
|
+
if (isLocalPath) {
|
|
1566
|
+
const varName = packageNameToVariable(pkg);
|
|
1567
|
+
if (!buildOptions.packages[varName]) {
|
|
1568
|
+
buildOptions.packages[varName] = {
|
|
1569
|
+
path: pkg,
|
|
1570
|
+
imports: [`default as ${varName}`]
|
|
1571
|
+
};
|
|
1572
|
+
}
|
|
1573
|
+
for (const section of ["sources", "destinations", "transformers", "stores"]) {
|
|
1574
|
+
const steps = flowSettings[section];
|
|
1575
|
+
if (!steps) continue;
|
|
1576
|
+
for (const step of Object.values(steps)) {
|
|
1577
|
+
if (step.package === pkg) {
|
|
1578
|
+
step.code = varName;
|
|
1579
|
+
delete step.package;
|
|
1580
|
+
}
|
|
1581
|
+
}
|
|
1582
|
+
}
|
|
1583
|
+
} else if (!buildOptions.packages[pkg]) {
|
|
1334
1584
|
buildOptions.packages[pkg] = {};
|
|
1335
1585
|
}
|
|
1336
1586
|
}
|
|
@@ -1354,8 +1604,8 @@ async function bundleCore(flowSettings, buildOptions, logger, showStats = false)
|
|
|
1354
1604
|
);
|
|
1355
1605
|
for (const [pkgName, pkgPath] of packagePaths.entries()) {
|
|
1356
1606
|
if (pkgName.startsWith("@walkeros/")) {
|
|
1357
|
-
const pkgJsonPath =
|
|
1358
|
-
const pkgJson = await
|
|
1607
|
+
const pkgJsonPath = path11.join(pkgPath, "package.json");
|
|
1608
|
+
const pkgJson = await fs10.readJSON(pkgJsonPath);
|
|
1359
1609
|
if (!pkgJson.exports && pkgJson.module) {
|
|
1360
1610
|
pkgJson.exports = {
|
|
1361
1611
|
".": {
|
|
@@ -1363,67 +1613,135 @@ async function bundleCore(flowSettings, buildOptions, logger, showStats = false)
|
|
|
1363
1613
|
require: pkgJson.main
|
|
1364
1614
|
}
|
|
1365
1615
|
};
|
|
1366
|
-
await
|
|
1616
|
+
await fs10.writeJSON(pkgJsonPath, pkgJson, { spaces: 2 });
|
|
1367
1617
|
}
|
|
1368
1618
|
}
|
|
1369
1619
|
}
|
|
1370
|
-
const packageJsonPath =
|
|
1371
|
-
await
|
|
1620
|
+
const packageJsonPath = path11.join(TEMP_DIR, "package.json");
|
|
1621
|
+
await fs10.writeFile(
|
|
1372
1622
|
packageJsonPath,
|
|
1373
1623
|
JSON.stringify({ type: "module" }, null, 2)
|
|
1374
1624
|
);
|
|
1375
1625
|
logger.debug("Creating entry point");
|
|
1376
|
-
const
|
|
1626
|
+
const { codeEntry, dataPayload, hasFlow } = await createEntryPoint(
|
|
1377
1627
|
flowSettings,
|
|
1378
1628
|
buildOptions,
|
|
1379
1629
|
packagePaths
|
|
1380
1630
|
);
|
|
1381
|
-
const
|
|
1382
|
-
await
|
|
1383
|
-
|
|
1384
|
-
`Running esbuild (target: ${buildOptions.target || "es2018"}, format: ${buildOptions.format})`
|
|
1385
|
-
);
|
|
1386
|
-
const outputPath = path9.resolve(buildOptions.output);
|
|
1387
|
-
await fs8.ensureDir(path9.dirname(outputPath));
|
|
1388
|
-
const esbuildOptions = createEsbuildOptions(
|
|
1389
|
-
buildOptions,
|
|
1390
|
-
entryPath,
|
|
1391
|
-
outputPath,
|
|
1392
|
-
TEMP_DIR,
|
|
1393
|
-
packagePaths,
|
|
1394
|
-
logger
|
|
1395
|
-
);
|
|
1396
|
-
try {
|
|
1397
|
-
await esbuild.build(esbuildOptions);
|
|
1398
|
-
} catch (buildError) {
|
|
1399
|
-
throw createBuildError(
|
|
1400
|
-
buildError,
|
|
1401
|
-
buildOptions.code || ""
|
|
1402
|
-
);
|
|
1403
|
-
} finally {
|
|
1404
|
-
await esbuild.stop();
|
|
1405
|
-
}
|
|
1406
|
-
const outputStats = await fs8.stat(outputPath);
|
|
1407
|
-
const sizeKB = (outputStats.size / 1024).toFixed(1);
|
|
1408
|
-
const buildTime = ((Date.now() - bundleStartTime) / 1e3).toFixed(1);
|
|
1409
|
-
logger.info(`Output: ${outputPath} (${sizeKB} KB, ${buildTime}s)`);
|
|
1631
|
+
const outputPath = path11.resolve(buildOptions.output);
|
|
1632
|
+
await fs10.ensureDir(path11.dirname(outputPath));
|
|
1633
|
+
let compiledCode = null;
|
|
1410
1634
|
if (buildOptions.cache !== false) {
|
|
1411
|
-
|
|
1412
|
-
const buildOutput = await fs8.readFile(outputPath, "utf-8");
|
|
1413
|
-
await cacheBuild(configContent, buildOutput, CACHE_DIR);
|
|
1414
|
-
logger.debug("Build cached for future use");
|
|
1635
|
+
compiledCode = await getCachedCode(codeEntry, CACHE_DIR);
|
|
1415
1636
|
}
|
|
1416
|
-
|
|
1637
|
+
if (compiledCode) {
|
|
1638
|
+
logger.debug("Using cached compiled code (config-only change)");
|
|
1639
|
+
} else {
|
|
1640
|
+
logger.debug(
|
|
1641
|
+
`Running esbuild (target: ${buildOptions.target || "es2018"}, format: ${buildOptions.format})`
|
|
1642
|
+
);
|
|
1643
|
+
const entryPath = path11.join(TEMP_DIR, "entry.js");
|
|
1644
|
+
await fs10.writeFile(entryPath, codeEntry);
|
|
1645
|
+
const esbuildOptions = createEsbuildOptions(
|
|
1646
|
+
{ ...buildOptions, minify: false },
|
|
1647
|
+
entryPath,
|
|
1648
|
+
outputPath,
|
|
1649
|
+
TEMP_DIR,
|
|
1650
|
+
packagePaths,
|
|
1651
|
+
logger
|
|
1652
|
+
);
|
|
1653
|
+
try {
|
|
1654
|
+
await esbuild.build(esbuildOptions);
|
|
1655
|
+
} catch (buildError) {
|
|
1656
|
+
throw createBuildError(
|
|
1657
|
+
buildError,
|
|
1658
|
+
buildOptions.code || ""
|
|
1659
|
+
);
|
|
1660
|
+
} finally {
|
|
1661
|
+
await esbuild.stop();
|
|
1662
|
+
}
|
|
1663
|
+
compiledCode = await fs10.readFile(outputPath, "utf-8");
|
|
1664
|
+
if (buildOptions.cache !== false) {
|
|
1665
|
+
await cacheCode(codeEntry, compiledCode, CACHE_DIR);
|
|
1666
|
+
}
|
|
1667
|
+
}
|
|
1668
|
+
const stage1Path = await ensureCodeOnDisk(
|
|
1669
|
+
codeEntry,
|
|
1670
|
+
compiledCode,
|
|
1671
|
+
CACHE_DIR
|
|
1672
|
+
);
|
|
1673
|
+
if (buildOptions.skipWrapper || !hasFlow) {
|
|
1674
|
+
const dataDeclaration = `const __configData = ${dataPayload};
|
|
1675
|
+
export { __configData };`;
|
|
1676
|
+
const banner = buildOptions.platform === "node" ? `import { createRequire } from 'module';const require = createRequire(import.meta.url);
|
|
1677
|
+
` : "";
|
|
1678
|
+
const esmOutput = `${banner}${compiledCode}
|
|
1679
|
+
${dataDeclaration}`;
|
|
1680
|
+
await fs10.writeFile(outputPath, esmOutput);
|
|
1681
|
+
} else {
|
|
1682
|
+
const stage2Entry = (buildOptions.platform || "node") === "browser" ? generateWebEntry(stage1Path, dataPayload, {
|
|
1683
|
+
windowCollector: buildOptions.windowCollector,
|
|
1684
|
+
windowElb: buildOptions.windowElb
|
|
1685
|
+
}) : generateServerEntry(stage1Path, dataPayload);
|
|
1686
|
+
const stage2EntryPath = path11.join(TEMP_DIR, "stage2.mjs");
|
|
1687
|
+
await fs10.writeFile(stage2EntryPath, stage2Entry);
|
|
1688
|
+
const stage2Options = {
|
|
1689
|
+
entryPoints: [stage2EntryPath],
|
|
1690
|
+
bundle: true,
|
|
1691
|
+
format: "esm",
|
|
1692
|
+
platform: buildOptions.platform,
|
|
1693
|
+
outfile: outputPath,
|
|
1694
|
+
treeShaking: true,
|
|
1695
|
+
logLevel: "error",
|
|
1696
|
+
minify: buildOptions.minify,
|
|
1697
|
+
...buildOptions.minify && {
|
|
1698
|
+
minifyWhitespace: buildOptions.minifyOptions?.whitespace ?? true,
|
|
1699
|
+
minifyIdentifiers: buildOptions.minifyOptions?.identifiers ?? true,
|
|
1700
|
+
minifySyntax: buildOptions.minifyOptions?.syntax ?? true,
|
|
1701
|
+
legalComments: buildOptions.minifyOptions?.legalComments ?? "none",
|
|
1702
|
+
charset: "utf8"
|
|
1703
|
+
}
|
|
1704
|
+
};
|
|
1705
|
+
if (buildOptions.platform === "browser") {
|
|
1706
|
+
stage2Options.define = {
|
|
1707
|
+
"process.env.NODE_ENV": '"production"',
|
|
1708
|
+
global: "globalThis"
|
|
1709
|
+
};
|
|
1710
|
+
stage2Options.target = buildOptions.target || "es2018";
|
|
1711
|
+
} else {
|
|
1712
|
+
stage2Options.external = getNodeExternals();
|
|
1713
|
+
stage2Options.banner = {
|
|
1714
|
+
js: `import { createRequire } from 'module';const require = createRequire(import.meta.url);`
|
|
1715
|
+
};
|
|
1716
|
+
stage2Options.target = buildOptions.target || "node18";
|
|
1717
|
+
}
|
|
1718
|
+
try {
|
|
1719
|
+
await esbuild.build(stage2Options);
|
|
1720
|
+
} finally {
|
|
1721
|
+
await esbuild.stop();
|
|
1722
|
+
}
|
|
1723
|
+
}
|
|
1724
|
+
const outputStats = await fs10.stat(outputPath);
|
|
1725
|
+
const sizeKB = (outputStats.size / 1024).toFixed(1);
|
|
1726
|
+
const buildTime = ((Date.now() - bundleStartTime) / 1e3).toFixed(1);
|
|
1727
|
+
logger.info(`Output: ${outputPath} (${sizeKB} KB, ${buildTime}s)`);
|
|
1728
|
+
if (buildOptions.cache !== false) {
|
|
1729
|
+
const configContent = generateCacheKeyContent(flowSettings, buildOptions);
|
|
1730
|
+
const buildOutput = await fs10.readFile(outputPath, "utf-8");
|
|
1731
|
+
await cacheBuild(configContent, buildOutput, CACHE_DIR);
|
|
1732
|
+
logger.debug("Build cached for future use");
|
|
1733
|
+
}
|
|
1734
|
+
let stats;
|
|
1417
1735
|
if (showStats) {
|
|
1418
1736
|
stats = await collectBundleStats(
|
|
1419
1737
|
outputPath,
|
|
1420
1738
|
buildOptions.packages,
|
|
1421
1739
|
bundleStartTime,
|
|
1422
|
-
|
|
1740
|
+
codeEntry
|
|
1423
1741
|
);
|
|
1424
1742
|
}
|
|
1425
1743
|
if (buildOptions.include && buildOptions.include.length > 0) {
|
|
1426
|
-
const outputDir =
|
|
1744
|
+
const outputDir = path11.dirname(outputPath);
|
|
1427
1745
|
await copyIncludes(
|
|
1428
1746
|
buildOptions.include,
|
|
1429
1747
|
buildOptions.configDir || process.cwd(),
|
|
@@ -1436,13 +1754,13 @@ async function bundleCore(flowSettings, buildOptions, logger, showStats = false)
|
|
|
1436
1754
|
throw error;
|
|
1437
1755
|
} finally {
|
|
1438
1756
|
if (!buildOptions.tempDir) {
|
|
1439
|
-
|
|
1757
|
+
fs10.remove(TEMP_DIR).catch(() => {
|
|
1440
1758
|
});
|
|
1441
1759
|
}
|
|
1442
1760
|
}
|
|
1443
1761
|
}
|
|
1444
1762
|
async function collectBundleStats(outputPath, packages, startTime, entryContent) {
|
|
1445
|
-
const stats = await
|
|
1763
|
+
const stats = await fs10.stat(outputPath);
|
|
1446
1764
|
const totalSize = stats.size;
|
|
1447
1765
|
const buildTime = Date.now() - startTime;
|
|
1448
1766
|
const packageStats = Object.entries(packages).map(([name, pkg]) => {
|
|
@@ -1473,7 +1791,8 @@ function createEsbuildOptions(buildOptions, entryPath, outputPath, tempDir, pack
|
|
|
1473
1791
|
const baseOptions = {
|
|
1474
1792
|
entryPoints: [entryPath],
|
|
1475
1793
|
bundle: true,
|
|
1476
|
-
format:
|
|
1794
|
+
format: "esm",
|
|
1795
|
+
// Always ESM — platform wrapper handles final format
|
|
1477
1796
|
platform: buildOptions.platform,
|
|
1478
1797
|
outfile: outputPath,
|
|
1479
1798
|
absWorkingDir: tempDir,
|
|
@@ -1506,11 +1825,6 @@ function createEsbuildOptions(buildOptions, entryPath, outputPath, tempDir, pack
|
|
|
1506
1825
|
} else if (buildOptions.platform === "node") {
|
|
1507
1826
|
const nodeExternals = getNodeExternals();
|
|
1508
1827
|
baseOptions.external = buildOptions.external ? [...nodeExternals, ...buildOptions.external] : nodeExternals;
|
|
1509
|
-
if (buildOptions.format === "esm") {
|
|
1510
|
-
baseOptions.banner = {
|
|
1511
|
-
js: `import { createRequire } from 'module';const require = createRequire(import.meta.url);`
|
|
1512
|
-
};
|
|
1513
|
-
}
|
|
1514
1828
|
}
|
|
1515
1829
|
if (buildOptions.target) {
|
|
1516
1830
|
baseOptions.target = buildOptions.target;
|
|
@@ -1521,64 +1835,19 @@ function createEsbuildOptions(buildOptions, entryPath, outputPath, tempDir, pack
|
|
|
1521
1835
|
}
|
|
1522
1836
|
return baseOptions;
|
|
1523
1837
|
}
|
|
1524
|
-
function
|
|
1525
|
-
const
|
|
1526
|
-
const
|
|
1527
|
-
if (
|
|
1528
|
-
for (const [
|
|
1529
|
-
if (typeof
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
destinationPackages.add(destConfig.package);
|
|
1534
|
-
}
|
|
1535
|
-
}
|
|
1536
|
-
}
|
|
1537
|
-
return destinationPackages;
|
|
1538
|
-
}
|
|
1539
|
-
function detectSourcePackages(flowSettings) {
|
|
1540
|
-
const sourcePackages = /* @__PURE__ */ new Set();
|
|
1541
|
-
const sources = flowSettings.sources;
|
|
1542
|
-
if (sources) {
|
|
1543
|
-
for (const [sourceKey, sourceConfig] of Object.entries(sources)) {
|
|
1544
|
-
if (typeof sourceConfig === "object" && sourceConfig !== null && "code" in sourceConfig && sourceConfig.code === true) {
|
|
1545
|
-
continue;
|
|
1546
|
-
}
|
|
1547
|
-
if (typeof sourceConfig === "object" && sourceConfig !== null && "package" in sourceConfig && typeof sourceConfig.package === "string") {
|
|
1548
|
-
sourcePackages.add(sourceConfig.package);
|
|
1549
|
-
}
|
|
1550
|
-
}
|
|
1551
|
-
}
|
|
1552
|
-
return sourcePackages;
|
|
1553
|
-
}
|
|
1554
|
-
function detectTransformerPackages(flowSettings) {
|
|
1555
|
-
const transformerPackages = /* @__PURE__ */ new Set();
|
|
1556
|
-
const transformers = flowSettings.transformers;
|
|
1557
|
-
if (transformers) {
|
|
1558
|
-
for (const [transformerKey, transformerConfig] of Object.entries(
|
|
1559
|
-
transformers
|
|
1560
|
-
)) {
|
|
1561
|
-
if (typeof transformerConfig === "object" && transformerConfig !== null && "code" in transformerConfig && transformerConfig.code === true) {
|
|
1562
|
-
continue;
|
|
1563
|
-
}
|
|
1564
|
-
if (typeof transformerConfig === "object" && transformerConfig !== null && "package" in transformerConfig && typeof transformerConfig.package === "string") {
|
|
1565
|
-
transformerPackages.add(transformerConfig.package);
|
|
1566
|
-
}
|
|
1567
|
-
}
|
|
1568
|
-
}
|
|
1569
|
-
return transformerPackages;
|
|
1570
|
-
}
|
|
1571
|
-
function detectStorePackages(flowSettings) {
|
|
1572
|
-
const storePackages = /* @__PURE__ */ new Set();
|
|
1573
|
-
const stores = flowSettings.stores;
|
|
1574
|
-
if (stores) {
|
|
1575
|
-
for (const [, storeConfig] of Object.entries(stores)) {
|
|
1576
|
-
if (typeof storeConfig === "object" && storeConfig !== null && "package" in storeConfig && typeof storeConfig.package === "string") {
|
|
1577
|
-
storePackages.add(storeConfig.package);
|
|
1838
|
+
function detectStepPackages(flowSettings, section) {
|
|
1839
|
+
const packages = /* @__PURE__ */ new Set();
|
|
1840
|
+
const steps = flowSettings[section];
|
|
1841
|
+
if (steps) {
|
|
1842
|
+
for (const [, stepConfig] of Object.entries(steps)) {
|
|
1843
|
+
if (typeof stepConfig !== "object" || stepConfig === null) continue;
|
|
1844
|
+
if ("code" in stepConfig && stepConfig.code === true) continue;
|
|
1845
|
+
if ("package" in stepConfig && typeof stepConfig.package === "string") {
|
|
1846
|
+
packages.add(stepConfig.package);
|
|
1578
1847
|
}
|
|
1579
1848
|
}
|
|
1580
1849
|
}
|
|
1581
|
-
return
|
|
1850
|
+
return packages;
|
|
1582
1851
|
}
|
|
1583
1852
|
function getNodeExternals() {
|
|
1584
1853
|
const externals = [];
|
|
@@ -1588,27 +1857,20 @@ function getNodeExternals() {
|
|
|
1588
1857
|
}
|
|
1589
1858
|
return externals;
|
|
1590
1859
|
}
|
|
1591
|
-
function
|
|
1860
|
+
function collectAllStepPackages(flowSettings) {
|
|
1592
1861
|
const allPackages = /* @__PURE__ */ new Set();
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
for (const
|
|
1600
|
-
|
|
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);
|
|
1862
|
+
const sections = [
|
|
1863
|
+
"sources",
|
|
1864
|
+
"destinations",
|
|
1865
|
+
"transformers",
|
|
1866
|
+
"stores"
|
|
1867
|
+
];
|
|
1868
|
+
for (const section of sections) {
|
|
1869
|
+
for (const pkg of detectStepPackages(flowSettings, section)) {
|
|
1870
|
+
allPackages.add(pkg);
|
|
1609
1871
|
}
|
|
1610
1872
|
}
|
|
1611
|
-
return
|
|
1873
|
+
return allPackages;
|
|
1612
1874
|
}
|
|
1613
1875
|
function detectExplicitCodeImports(flowSettings) {
|
|
1614
1876
|
const explicitCodeImports = /* @__PURE__ */ new Map();
|
|
@@ -1755,12 +2017,12 @@ function validateComponentNames(components, section) {
|
|
|
1755
2017
|
}
|
|
1756
2018
|
function validateStoreReferences(flowSettings, storeIds) {
|
|
1757
2019
|
const refs = [];
|
|
1758
|
-
function collectRefs(obj,
|
|
2020
|
+
function collectRefs(obj, path19) {
|
|
1759
2021
|
if (typeof obj === "string" && obj.startsWith("$store:")) {
|
|
1760
|
-
refs.push({ ref: obj.slice(7), location:
|
|
2022
|
+
refs.push({ ref: obj.slice(7), location: path19 });
|
|
1761
2023
|
} else if (obj && typeof obj === "object") {
|
|
1762
2024
|
for (const [key, val] of Object.entries(obj)) {
|
|
1763
|
-
collectRefs(val, `${
|
|
2025
|
+
collectRefs(val, `${path19}.${key}`);
|
|
1764
2026
|
}
|
|
1765
2027
|
}
|
|
1766
2028
|
}
|
|
@@ -1785,10 +2047,10 @@ function validateStoreReferences(flowSettings, storeIds) {
|
|
|
1785
2047
|
}
|
|
1786
2048
|
}
|
|
1787
2049
|
async function createEntryPoint(flowSettings, buildOptions, packagePaths) {
|
|
1788
|
-
const
|
|
1789
|
-
const
|
|
1790
|
-
const transformerPackages =
|
|
1791
|
-
const storePackages =
|
|
2050
|
+
const sourcePackages = detectStepPackages(flowSettings, "sources");
|
|
2051
|
+
const destinationPackages = detectStepPackages(flowSettings, "destinations");
|
|
2052
|
+
const transformerPackages = detectStepPackages(flowSettings, "transformers");
|
|
2053
|
+
const storePackages = detectStepPackages(flowSettings, "stores");
|
|
1792
2054
|
const explicitCodeImports = detectExplicitCodeImports(flowSettings);
|
|
1793
2055
|
const storeIds = new Set(
|
|
1794
2056
|
Object.keys(
|
|
@@ -1815,29 +2077,30 @@ async function createEntryPoint(flowSettings, buildOptions, packagePaths) {
|
|
|
1815
2077
|
);
|
|
1816
2078
|
const importsCode = importStatements.join("\n");
|
|
1817
2079
|
const hasFlow = Object.values(flowSettings.sources || {}).some(
|
|
1818
|
-
(
|
|
2080
|
+
(s) => s.package || hasCodeReference(s.code)
|
|
1819
2081
|
) || Object.values(flowSettings.destinations || {}).some(
|
|
1820
|
-
(d2) => d2.package ||
|
|
2082
|
+
(d2) => d2.package || hasCodeReference(d2.code)
|
|
1821
2083
|
);
|
|
1822
2084
|
if (!hasFlow) {
|
|
1823
2085
|
const userCode = buildOptions.code || "";
|
|
1824
|
-
return
|
|
2086
|
+
return {
|
|
2087
|
+
codeEntry: importsCode ? `${importsCode}
|
|
1825
2088
|
|
|
1826
|
-
${userCode}` : userCode
|
|
2089
|
+
${userCode}` : userCode,
|
|
2090
|
+
dataPayload: "{}",
|
|
2091
|
+
hasFlow: false
|
|
2092
|
+
};
|
|
1827
2093
|
}
|
|
1828
|
-
const { storesDeclaration,
|
|
1829
|
-
|
|
1830
|
-
explicitCodeImports
|
|
1831
|
-
);
|
|
1832
|
-
const wrappedCode = generatePlatformWrapper(
|
|
2094
|
+
const { storesDeclaration, codeConfigObject, dataPayload } = buildSplitConfigObject(flowSettings, explicitCodeImports);
|
|
2095
|
+
const wireConfigModule = generateSplitWireConfigModule(
|
|
1833
2096
|
storesDeclaration,
|
|
1834
|
-
|
|
1835
|
-
buildOptions.code || ""
|
|
1836
|
-
buildOptions
|
|
2097
|
+
codeConfigObject,
|
|
2098
|
+
buildOptions.code || ""
|
|
1837
2099
|
);
|
|
1838
|
-
|
|
2100
|
+
const codeEntry = importsCode ? `${importsCode}
|
|
1839
2101
|
|
|
1840
|
-
${
|
|
2102
|
+
${wireConfigModule}` : wireConfigModule;
|
|
2103
|
+
return { codeEntry, dataPayload, hasFlow: true };
|
|
1841
2104
|
}
|
|
1842
2105
|
function createBuildError(buildError, code) {
|
|
1843
2106
|
if (!buildError.errors || buildError.errors.length === 0) {
|
|
@@ -1862,12 +2125,55 @@ ${firstError.text}`
|
|
|
1862
2125
|
` + (location ? ` at ${location.file}:${location.line}:${location.column}` : "")
|
|
1863
2126
|
);
|
|
1864
2127
|
}
|
|
1865
|
-
function
|
|
2128
|
+
function buildSplitConfigObject(flowSettings, explicitCodeImports) {
|
|
1866
2129
|
const flowWithProps = flowSettings;
|
|
1867
2130
|
const sources = flowWithProps.sources || {};
|
|
1868
2131
|
const destinations = flowWithProps.destinations || {};
|
|
1869
2132
|
const transformers = flowWithProps.transformers || {};
|
|
1870
2133
|
const stores = flowWithProps.stores || {};
|
|
2134
|
+
const dataPayloadObj = {};
|
|
2135
|
+
function resolveCodeVar(step) {
|
|
2136
|
+
if (step.code && typeof step.code === "string" && !step.package) {
|
|
2137
|
+
return step.code;
|
|
2138
|
+
}
|
|
2139
|
+
if (step.code && typeof step.code === "string" && step.package && explicitCodeImports.has(step.package)) {
|
|
2140
|
+
return step.code;
|
|
2141
|
+
}
|
|
2142
|
+
return packageNameToVariable(step.package);
|
|
2143
|
+
}
|
|
2144
|
+
function getStepProps(step) {
|
|
2145
|
+
const props = {};
|
|
2146
|
+
for (const [key, value] of Object.entries(step)) {
|
|
2147
|
+
if (key === "code" || key === "package") continue;
|
|
2148
|
+
if (value !== void 0 && value !== null) {
|
|
2149
|
+
props[key] = value;
|
|
2150
|
+
}
|
|
2151
|
+
}
|
|
2152
|
+
return props;
|
|
2153
|
+
}
|
|
2154
|
+
function buildSplitStepEntry(section, stepId, step) {
|
|
2155
|
+
const codeVar = resolveCodeVar(
|
|
2156
|
+
step
|
|
2157
|
+
);
|
|
2158
|
+
const stepProps = getStepProps(step);
|
|
2159
|
+
const { codeProps, dataProps } = classifyStepProperties(stepProps);
|
|
2160
|
+
const codeEntries = [];
|
|
2161
|
+
codeEntries.push(`code: ${codeVar}`);
|
|
2162
|
+
for (const [key, value] of Object.entries(codeProps)) {
|
|
2163
|
+
if (key === "code") continue;
|
|
2164
|
+
codeEntries.push(`${key}: ${processConfigValue(value)}`);
|
|
2165
|
+
}
|
|
2166
|
+
for (const key of Object.keys(dataProps)) {
|
|
2167
|
+
codeEntries.push(`${key}: __data.${section}.${stepId}.${key}`);
|
|
2168
|
+
}
|
|
2169
|
+
if (Object.keys(dataProps).length > 0) {
|
|
2170
|
+
if (!dataPayloadObj[section]) dataPayloadObj[section] = {};
|
|
2171
|
+
dataPayloadObj[section][stepId] = dataProps;
|
|
2172
|
+
}
|
|
2173
|
+
return ` ${stepId}: {
|
|
2174
|
+
${codeEntries.join(",\n ")}
|
|
2175
|
+
}`;
|
|
2176
|
+
}
|
|
1871
2177
|
Object.entries(sources).forEach(([name, source]) => {
|
|
1872
2178
|
if (source.code !== true) {
|
|
1873
2179
|
validateReference("Source", name, source);
|
|
@@ -1884,104 +2190,89 @@ function buildConfigObject(flowSettings, explicitCodeImports) {
|
|
|
1884
2190
|
}
|
|
1885
2191
|
});
|
|
1886
2192
|
const sourcesEntries = Object.entries(sources).filter(
|
|
1887
|
-
([, source]) => source.code !== true && (source.package ||
|
|
2193
|
+
([, source]) => source.code !== true && (source.package || hasCodeReference(source.code))
|
|
1888
2194
|
).map(([key, source]) => {
|
|
1889
2195
|
if (isInlineCode(source.code)) {
|
|
1890
2196
|
return ` ${key}: ${generateInlineCode(source.code, source.config || {}, source.env, source.next, "next")}`;
|
|
1891
2197
|
}
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
}
|
|
1898
|
-
const configStr = source.config ? processConfigValue(source.config) : "{}";
|
|
1899
|
-
const envStr = source.env ? `,
|
|
1900
|
-
env: ${processConfigValue(source.env)}` : "";
|
|
1901
|
-
const nextStr = source.next ? `,
|
|
1902
|
-
next: ${JSON.stringify(source.next)}` : "";
|
|
1903
|
-
return ` ${key}: {
|
|
1904
|
-
code: ${codeVar},
|
|
1905
|
-
config: ${configStr}${envStr}${nextStr}
|
|
1906
|
-
}`;
|
|
2198
|
+
return buildSplitStepEntry(
|
|
2199
|
+
"sources",
|
|
2200
|
+
key,
|
|
2201
|
+
source
|
|
2202
|
+
);
|
|
1907
2203
|
});
|
|
1908
2204
|
const destinationsEntries = Object.entries(destinations).filter(
|
|
1909
|
-
([, dest]) => dest.code !== true && (dest.package ||
|
|
2205
|
+
([, dest]) => dest.code !== true && (dest.package || hasCodeReference(dest.code))
|
|
1910
2206
|
).map(([key, dest]) => {
|
|
1911
2207
|
if (isInlineCode(dest.code)) {
|
|
1912
2208
|
return ` ${key}: ${generateInlineCode(dest.code, dest.config || {}, dest.env, dest.before, "before", true)}`;
|
|
1913
2209
|
}
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
}
|
|
1920
|
-
const configStr = dest.config ? processConfigValue(dest.config) : "{}";
|
|
1921
|
-
const envStr = dest.env ? `,
|
|
1922
|
-
env: ${processConfigValue(dest.env)}` : "";
|
|
1923
|
-
const beforeStr = dest.before ? `,
|
|
1924
|
-
before: ${JSON.stringify(dest.before)}` : "";
|
|
1925
|
-
return ` ${key}: {
|
|
1926
|
-
code: ${codeVar},
|
|
1927
|
-
config: ${configStr}${envStr}${beforeStr}
|
|
1928
|
-
}`;
|
|
2210
|
+
return buildSplitStepEntry(
|
|
2211
|
+
"destinations",
|
|
2212
|
+
key,
|
|
2213
|
+
dest
|
|
2214
|
+
);
|
|
1929
2215
|
});
|
|
1930
2216
|
const transformersEntries = Object.entries(transformers).filter(
|
|
1931
|
-
([, transformer]) => transformer.code !== true && (transformer.package ||
|
|
2217
|
+
([, transformer]) => transformer.code !== true && (transformer.package || hasCodeReference(transformer.code))
|
|
1932
2218
|
).map(([key, transformer]) => {
|
|
1933
2219
|
if (isInlineCode(transformer.code)) {
|
|
1934
2220
|
return ` ${key}: ${generateInlineCode(transformer.code, transformer.config || {}, transformer.env, transformer.next, "next")}`;
|
|
1935
2221
|
}
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
}
|
|
1942
|
-
const configStr = transformer.config ? processConfigValue(transformer.config) : "{}";
|
|
1943
|
-
const envStr = transformer.env ? `,
|
|
1944
|
-
env: ${processConfigValue(transformer.env)}` : "";
|
|
1945
|
-
const nextStr = transformer.next ? `,
|
|
1946
|
-
next: ${JSON.stringify(transformer.next)}` : "";
|
|
1947
|
-
return ` ${key}: {
|
|
1948
|
-
code: ${codeVar},
|
|
1949
|
-
config: ${configStr}${envStr}${nextStr}
|
|
1950
|
-
}`;
|
|
2222
|
+
return buildSplitStepEntry(
|
|
2223
|
+
"transformers",
|
|
2224
|
+
key,
|
|
2225
|
+
transformer
|
|
2226
|
+
);
|
|
1951
2227
|
});
|
|
1952
2228
|
Object.entries(stores).forEach(([name, store]) => {
|
|
1953
|
-
if (store.package ||
|
|
2229
|
+
if (store.package || hasCodeReference(store.code)) {
|
|
1954
2230
|
validateReference("Store", name, store);
|
|
1955
2231
|
}
|
|
1956
2232
|
});
|
|
1957
|
-
const storesEntries = Object.entries(stores).filter(([, store]) => store.package ||
|
|
2233
|
+
const storesEntries = Object.entries(stores).filter(([, store]) => store.package || hasCodeReference(store.code)).map(([key, store]) => {
|
|
1958
2234
|
if (isInlineCode(store.code)) {
|
|
1959
2235
|
return ` ${key}: ${generateInlineCode(store.code, store.config || {}, store.env)}`;
|
|
1960
2236
|
}
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
2237
|
+
const codeVar = resolveCodeVar(store);
|
|
2238
|
+
const storeProps = getStepProps(store);
|
|
2239
|
+
const { codeProps, dataProps } = classifyStepProperties(storeProps);
|
|
2240
|
+
const codeEntries = [];
|
|
2241
|
+
codeEntries.push(`code: ${codeVar}`);
|
|
2242
|
+
for (const [propKey, value] of Object.entries(codeProps)) {
|
|
2243
|
+
if (propKey === "code") continue;
|
|
2244
|
+
codeEntries.push(`${propKey}: ${processConfigValue(value)}`);
|
|
2245
|
+
}
|
|
2246
|
+
for (const propKey of Object.keys(dataProps)) {
|
|
2247
|
+
codeEntries.push(`${propKey}: __data.stores.${key}.${propKey}`);
|
|
2248
|
+
}
|
|
2249
|
+
if (Object.keys(dataProps).length > 0) {
|
|
2250
|
+
if (!dataPayloadObj["stores"]) dataPayloadObj["stores"] = {};
|
|
2251
|
+
dataPayloadObj["stores"][key] = dataProps;
|
|
1966
2252
|
}
|
|
1967
|
-
const configStr = store.config ? processConfigValue(store.config) : "{}";
|
|
1968
|
-
const envStr = store.env ? `,
|
|
1969
|
-
env: ${processConfigValue(store.env)}` : "";
|
|
1970
2253
|
return ` ${key}: {
|
|
1971
|
-
|
|
1972
|
-
config: ${configStr}${envStr}
|
|
2254
|
+
${codeEntries.join(",\n ")}
|
|
1973
2255
|
}`;
|
|
1974
2256
|
});
|
|
1975
2257
|
const storesDeclaration = storesEntries.length > 0 ? `const stores = {
|
|
1976
2258
|
${storesEntries.join(",\n")}
|
|
1977
2259
|
};` : "const stores = {};";
|
|
1978
|
-
|
|
1979
|
-
|
|
2260
|
+
let collectorStr = "";
|
|
2261
|
+
if (flowWithProps.collector) {
|
|
2262
|
+
if (containsCodeMarkers(flowWithProps.collector)) {
|
|
2263
|
+
collectorStr = `,
|
|
2264
|
+
...${processConfigValue(flowWithProps.collector)}`;
|
|
2265
|
+
} else {
|
|
2266
|
+
dataPayloadObj["collector"] = flowWithProps.collector;
|
|
2267
|
+
collectorStr = `,
|
|
2268
|
+
...__data.collector`;
|
|
2269
|
+
}
|
|
2270
|
+
}
|
|
1980
2271
|
const transformersStr = transformersEntries.length > 0 ? `,
|
|
1981
2272
|
transformers: {
|
|
1982
2273
|
${transformersEntries.join(",\n")}
|
|
1983
2274
|
}` : "";
|
|
1984
|
-
const
|
|
2275
|
+
const codeConfigObject = `{
|
|
1985
2276
|
sources: {
|
|
1986
2277
|
${sourcesEntries.join(",\n")}
|
|
1987
2278
|
},
|
|
@@ -1990,7 +2281,69 @@ ${destinationsEntries.join(",\n")}
|
|
|
1990
2281
|
}${transformersStr},
|
|
1991
2282
|
stores${collectorStr}
|
|
1992
2283
|
}`;
|
|
1993
|
-
|
|
2284
|
+
const dataPayload = JSON.stringify(dataPayloadObj, null, 2);
|
|
2285
|
+
return { storesDeclaration, codeConfigObject, dataPayload };
|
|
2286
|
+
}
|
|
2287
|
+
function generateSplitWireConfigModule(storesDeclaration, codeConfigObject, userCode) {
|
|
2288
|
+
const codeSection = userCode ? `
|
|
2289
|
+
${userCode}
|
|
2290
|
+
` : "";
|
|
2291
|
+
return `export function wireConfig(__data) {
|
|
2292
|
+
${storesDeclaration}
|
|
2293
|
+
|
|
2294
|
+
const config = ${codeConfigObject};${codeSection}
|
|
2295
|
+
|
|
2296
|
+
return config;
|
|
2297
|
+
}
|
|
2298
|
+
|
|
2299
|
+
export { startFlow };`;
|
|
2300
|
+
}
|
|
2301
|
+
function generateServerEntry(stage1Path, dataPayload) {
|
|
2302
|
+
return `import { startFlow, wireConfig } from '${stage1Path}';
|
|
2303
|
+
|
|
2304
|
+
const __configData = ${dataPayload};
|
|
2305
|
+
|
|
2306
|
+
export default async function(context = {}) {
|
|
2307
|
+
const config = wireConfig(__configData);
|
|
2308
|
+
|
|
2309
|
+
if (context.logger) config.logger = context.logger;
|
|
2310
|
+
|
|
2311
|
+
if (context.sourceSettings && config.sources) {
|
|
2312
|
+
for (const src of Object.values(config.sources)) {
|
|
2313
|
+
if (src.config?.settings) {
|
|
2314
|
+
src.config.settings = { ...src.config.settings, ...context.sourceSettings };
|
|
2315
|
+
}
|
|
2316
|
+
}
|
|
2317
|
+
}
|
|
2318
|
+
|
|
2319
|
+
const result = await startFlow(config);
|
|
2320
|
+
|
|
2321
|
+
const httpSource = Object.values(result.collector.sources || {})
|
|
2322
|
+
.find(s => 'httpHandler' in s && typeof s.httpHandler === 'function');
|
|
2323
|
+
|
|
2324
|
+
return { ...result, httpHandler: httpSource ? httpSource.httpHandler : undefined };
|
|
2325
|
+
}`;
|
|
2326
|
+
}
|
|
2327
|
+
function generateWebEntry(stage1Path, dataPayload, options = {}) {
|
|
2328
|
+
const assignments = [];
|
|
2329
|
+
if (options.windowCollector) {
|
|
2330
|
+
assignments.push(
|
|
2331
|
+
` if (typeof window !== 'undefined') window['${options.windowCollector}'] = collector;`
|
|
2332
|
+
);
|
|
2333
|
+
}
|
|
2334
|
+
if (options.windowElb) {
|
|
2335
|
+
assignments.push(
|
|
2336
|
+
` if (typeof window !== 'undefined') window['${options.windowElb}'] = elb;`
|
|
2337
|
+
);
|
|
2338
|
+
}
|
|
2339
|
+
const assignmentCode = assignments.length > 0 ? "\n" + assignments.join("\n") : "";
|
|
2340
|
+
return `import { startFlow, wireConfig } from '${stage1Path}';
|
|
2341
|
+
|
|
2342
|
+
const __configData = ${dataPayload};
|
|
2343
|
+
|
|
2344
|
+
(async () => {
|
|
2345
|
+
const { collector, elb } = await startFlow(wireConfig(__configData));${assignmentCode}
|
|
2346
|
+
})();`;
|
|
1994
2347
|
}
|
|
1995
2348
|
function processConfigValue(value) {
|
|
1996
2349
|
return serializeWithCode(value, 0);
|
|
@@ -2059,66 +2412,11 @@ ${spaces}}`;
|
|
|
2059
2412
|
}
|
|
2060
2413
|
return JSON.stringify(value);
|
|
2061
2414
|
}
|
|
2062
|
-
function generatePlatformWrapper(storesDeclaration, configObject, userCode, buildOptions) {
|
|
2063
|
-
if (buildOptions.platform === "browser") {
|
|
2064
|
-
const windowAssignments = [];
|
|
2065
|
-
if (buildOptions.windowCollector) {
|
|
2066
|
-
windowAssignments.push(
|
|
2067
|
-
` if (typeof window !== 'undefined') window['${buildOptions.windowCollector}'] = collector;`
|
|
2068
|
-
);
|
|
2069
|
-
}
|
|
2070
|
-
if (buildOptions.windowElb) {
|
|
2071
|
-
windowAssignments.push(
|
|
2072
|
-
` if (typeof window !== 'undefined') window['${buildOptions.windowElb}'] = elb;`
|
|
2073
|
-
);
|
|
2074
|
-
}
|
|
2075
|
-
const assignments = windowAssignments.length > 0 ? "\n" + windowAssignments.join("\n") : "";
|
|
2076
|
-
return `(async () => {
|
|
2077
|
-
${storesDeclaration}
|
|
2078
|
-
|
|
2079
|
-
const config = ${configObject};
|
|
2080
|
-
|
|
2081
|
-
${userCode}
|
|
2082
|
-
|
|
2083
|
-
const { collector, elb } = await startFlow(config);${assignments}
|
|
2084
|
-
})();`;
|
|
2085
|
-
} else {
|
|
2086
|
-
const codeSection = userCode ? `
|
|
2087
|
-
${userCode}
|
|
2088
|
-
` : "";
|
|
2089
|
-
return `export default async function(context = {}) {
|
|
2090
|
-
${storesDeclaration}
|
|
2091
|
-
|
|
2092
|
-
const config = ${configObject};${codeSection}
|
|
2093
|
-
// Apply context overrides (e.g., logger config from CLI)
|
|
2094
|
-
if (context.logger) {
|
|
2095
|
-
config.logger = { ...config.logger, ...context.logger };
|
|
2096
|
-
}
|
|
2097
|
-
|
|
2098
|
-
// When runner provides external server, strip port from sources
|
|
2099
|
-
// so they don't self-listen (runner owns the port)
|
|
2100
|
-
if (context.externalServer && config.sources) {
|
|
2101
|
-
for (const src of Object.values(config.sources)) {
|
|
2102
|
-
if (src.config && src.config.settings && 'port' in src.config.settings) {
|
|
2103
|
-
delete src.config.settings.port;
|
|
2104
|
-
}
|
|
2105
|
-
}
|
|
2106
|
-
}
|
|
2107
|
-
|
|
2108
|
-
const result = await startFlow(config);
|
|
2109
|
-
|
|
2110
|
-
// Discover httpHandler from initialized sources (duck-typing, no source-type coupling)
|
|
2111
|
-
const httpSource = Object.values(result.collector.sources || {})
|
|
2112
|
-
.find(s => 'httpHandler' in s && typeof s.httpHandler === 'function');
|
|
2113
|
-
|
|
2114
|
-
return { ...result, httpHandler: httpSource ? httpSource.httpHandler : undefined };
|
|
2115
|
-
}`;
|
|
2116
|
-
}
|
|
2117
|
-
}
|
|
2118
2415
|
var VALID_JS_IDENTIFIER;
|
|
2119
2416
|
var init_bundler = __esm({
|
|
2120
2417
|
"src/commands/bundle/bundler.ts"() {
|
|
2121
2418
|
"use strict";
|
|
2419
|
+
init_config_classifier();
|
|
2122
2420
|
init_package_manager();
|
|
2123
2421
|
init_tmp();
|
|
2124
2422
|
init_build_cache();
|
|
@@ -2127,12 +2425,12 @@ var init_bundler = __esm({
|
|
|
2127
2425
|
});
|
|
2128
2426
|
|
|
2129
2427
|
// src/commands/bundle/upload.ts
|
|
2130
|
-
import
|
|
2428
|
+
import fs11 from "fs-extra";
|
|
2131
2429
|
function sanitizeUrl(url) {
|
|
2132
2430
|
return url.split("?")[0];
|
|
2133
2431
|
}
|
|
2134
2432
|
async function uploadBundleToUrl(filePath, url, timeoutMs = 3e4) {
|
|
2135
|
-
const bundleContent = await
|
|
2433
|
+
const bundleContent = await fs11.readFile(filePath);
|
|
2136
2434
|
const doUpload = async (attempt) => {
|
|
2137
2435
|
const response = await fetch(url, {
|
|
2138
2436
|
method: "PUT",
|
|
@@ -2211,8 +2509,8 @@ var init_api_client = __esm({
|
|
|
2211
2509
|
});
|
|
2212
2510
|
|
|
2213
2511
|
// src/commands/bundle/dockerfile.ts
|
|
2214
|
-
import
|
|
2215
|
-
import
|
|
2512
|
+
import path12 from "path";
|
|
2513
|
+
import fs12 from "fs-extra";
|
|
2216
2514
|
function buildDockerfileContent(platform, includedFolders) {
|
|
2217
2515
|
const bundleFile = platform === "web" ? "walker.js" : "bundle.mjs";
|
|
2218
2516
|
const lines = [
|
|
@@ -2222,21 +2520,21 @@ function buildDockerfileContent(platform, includedFolders) {
|
|
|
2222
2520
|
`COPY ${bundleFile} /app/flow/${bundleFile}`
|
|
2223
2521
|
];
|
|
2224
2522
|
for (const folder of includedFolders) {
|
|
2225
|
-
const name =
|
|
2523
|
+
const name = path12.basename(folder);
|
|
2226
2524
|
lines.push(`COPY ${name}/ /app/flow/${name}/`);
|
|
2227
2525
|
}
|
|
2228
2526
|
lines.push("", `ENV BUNDLE=/app/flow/${bundleFile}`, "", "EXPOSE 8080", "");
|
|
2229
2527
|
return lines.join("\n");
|
|
2230
2528
|
}
|
|
2231
2529
|
async function generateDockerfile(outputDir, platform, logger, customFile, includedFolders) {
|
|
2232
|
-
const destPath =
|
|
2233
|
-
if (customFile && await
|
|
2234
|
-
await
|
|
2530
|
+
const destPath = path12.join(outputDir, "Dockerfile");
|
|
2531
|
+
if (customFile && await fs12.pathExists(customFile)) {
|
|
2532
|
+
await fs12.copy(customFile, destPath);
|
|
2235
2533
|
logger.info(`Dockerfile: ${destPath} (copied from ${customFile})`);
|
|
2236
2534
|
return;
|
|
2237
2535
|
}
|
|
2238
2536
|
const dockerfile = buildDockerfileContent(platform, includedFolders || []);
|
|
2239
|
-
await
|
|
2537
|
+
await fs12.writeFile(destPath, dockerfile);
|
|
2240
2538
|
logger.info(`Dockerfile: ${destPath}`);
|
|
2241
2539
|
}
|
|
2242
2540
|
var init_dockerfile = __esm({
|
|
@@ -2246,15 +2544,15 @@ var init_dockerfile = __esm({
|
|
|
2246
2544
|
});
|
|
2247
2545
|
|
|
2248
2546
|
// src/commands/bundle/index.ts
|
|
2249
|
-
import
|
|
2250
|
-
import
|
|
2547
|
+
import path13 from "path";
|
|
2548
|
+
import fs13 from "fs-extra";
|
|
2251
2549
|
import { getPlatform as getPlatform2 } from "@walkeros/core";
|
|
2252
2550
|
function resolveOutputPath(output, buildOptions) {
|
|
2253
|
-
const resolved =
|
|
2254
|
-
const ext =
|
|
2255
|
-
if (output.endsWith("/") || output.endsWith(
|
|
2551
|
+
const resolved = path13.resolve(output);
|
|
2552
|
+
const ext = path13.extname(resolved);
|
|
2553
|
+
if (output.endsWith("/") || output.endsWith(path13.sep) || !ext) {
|
|
2256
2554
|
const filename = buildOptions.platform === "browser" ? "walker.js" : "bundle.mjs";
|
|
2257
|
-
return
|
|
2555
|
+
return path13.join(resolved, filename);
|
|
2258
2556
|
}
|
|
2259
2557
|
return resolved;
|
|
2260
2558
|
}
|
|
@@ -2284,7 +2582,7 @@ async function bundleCommand(options) {
|
|
|
2284
2582
|
} catch {
|
|
2285
2583
|
throw new Error("Invalid JSON received on stdin");
|
|
2286
2584
|
}
|
|
2287
|
-
configPath =
|
|
2585
|
+
configPath = path13.resolve(process.cwd(), "stdin.config.json");
|
|
2288
2586
|
} else {
|
|
2289
2587
|
const file = options.config || "bundle.config.json";
|
|
2290
2588
|
configPath = resolveAsset(file, "config");
|
|
@@ -2338,19 +2636,19 @@ async function bundleCommand(options) {
|
|
|
2338
2636
|
if (uploadUrl) {
|
|
2339
2637
|
await uploadBundleToUrl(buildOptions.output, uploadUrl);
|
|
2340
2638
|
logger.info(`Uploaded to: ${sanitizeUrl(uploadUrl)}`);
|
|
2341
|
-
await
|
|
2639
|
+
await fs13.remove(buildOptions.output);
|
|
2342
2640
|
}
|
|
2343
2641
|
if (!options.json && !options.all && options.stats && stats) {
|
|
2344
2642
|
displayStats(stats, logger);
|
|
2345
2643
|
}
|
|
2346
2644
|
if (writingToStdout && !options.json) {
|
|
2347
|
-
const bundleContent = await
|
|
2645
|
+
const bundleContent = await fs13.readFile(buildOptions.output);
|
|
2348
2646
|
await writeResult(bundleContent, {});
|
|
2349
2647
|
}
|
|
2350
2648
|
if (options.dockerfile && options.output) {
|
|
2351
2649
|
const platform = getPlatform2(flowSettings);
|
|
2352
2650
|
if (platform) {
|
|
2353
|
-
const outputDir =
|
|
2651
|
+
const outputDir = path13.dirname(buildOptions.output);
|
|
2354
2652
|
const customFile = typeof options.dockerfile === "string" ? options.dockerfile : void 0;
|
|
2355
2653
|
await generateDockerfile(
|
|
2356
2654
|
outputDir,
|
|
@@ -2369,7 +2667,7 @@ async function bundleCommand(options) {
|
|
|
2369
2667
|
}
|
|
2370
2668
|
}
|
|
2371
2669
|
}
|
|
2372
|
-
const duration = timer.end()
|
|
2670
|
+
const duration = timer.end();
|
|
2373
2671
|
const successCount = results.filter((r2) => r2.success).length;
|
|
2374
2672
|
const failureCount = results.filter((r2) => !r2.success).length;
|
|
2375
2673
|
if (options.json) {
|
|
@@ -2406,7 +2704,7 @@ Build Summary: ${successCount}/${results.length} succeeded`
|
|
|
2406
2704
|
}
|
|
2407
2705
|
process.exit(0);
|
|
2408
2706
|
} catch (error) {
|
|
2409
|
-
const duration = timer.getElapsed()
|
|
2707
|
+
const duration = timer.getElapsed();
|
|
2410
2708
|
const errorMessage = getErrorMessage(error);
|
|
2411
2709
|
if (options.json) {
|
|
2412
2710
|
const jsonError = createErrorOutput(errorMessage, duration);
|
|
@@ -2421,7 +2719,7 @@ Build Summary: ${successCount}/${results.length} succeeded`
|
|
|
2421
2719
|
}
|
|
2422
2720
|
async function bundle(configOrPath, options = {}) {
|
|
2423
2721
|
let rawConfig;
|
|
2424
|
-
let configPath =
|
|
2722
|
+
let configPath = path13.resolve(process.cwd(), "walkeros.config.json");
|
|
2425
2723
|
if (typeof configOrPath === "string") {
|
|
2426
2724
|
configPath = resolveAsset(configOrPath, "config");
|
|
2427
2725
|
rawConfig = await loadJsonConfig(configPath);
|
|
@@ -2477,6 +2775,45 @@ var init_bundle = __esm({
|
|
|
2477
2775
|
}
|
|
2478
2776
|
});
|
|
2479
2777
|
|
|
2778
|
+
// src/commands/push/env-loader.ts
|
|
2779
|
+
var env_loader_exports = {};
|
|
2780
|
+
__export(env_loader_exports, {
|
|
2781
|
+
loadDestinationEnvs: () => loadDestinationEnvs
|
|
2782
|
+
});
|
|
2783
|
+
async function loadDestinationEnvs(destinations, packages, configDir) {
|
|
2784
|
+
const envs = {};
|
|
2785
|
+
const resolveDir = configDir || process.cwd();
|
|
2786
|
+
for (const [destKey, destConfig] of Object.entries(destinations)) {
|
|
2787
|
+
const typedConfig = destConfig;
|
|
2788
|
+
if (!typedConfig.package) {
|
|
2789
|
+
continue;
|
|
2790
|
+
}
|
|
2791
|
+
try {
|
|
2792
|
+
const packageName = typedConfig.package;
|
|
2793
|
+
const isDemoPackage = packageName.includes("-demo");
|
|
2794
|
+
const importPath = isDemoPackage ? resolvePackageImportPath(packageName, packages, resolveDir) : resolvePackageImportPath(packageName, packages, resolveDir, "/dev");
|
|
2795
|
+
const module = await import(importPath);
|
|
2796
|
+
const examplesModule = module.examples || module.default?.examples;
|
|
2797
|
+
const envModule = examplesModule?.env;
|
|
2798
|
+
if (envModule?.push) {
|
|
2799
|
+
envs[destKey] = {
|
|
2800
|
+
init: envModule.init,
|
|
2801
|
+
push: envModule.push,
|
|
2802
|
+
simulation: envModule.simulation || []
|
|
2803
|
+
};
|
|
2804
|
+
}
|
|
2805
|
+
} catch {
|
|
2806
|
+
}
|
|
2807
|
+
}
|
|
2808
|
+
return envs;
|
|
2809
|
+
}
|
|
2810
|
+
var init_env_loader = __esm({
|
|
2811
|
+
"src/commands/push/env-loader.ts"() {
|
|
2812
|
+
"use strict";
|
|
2813
|
+
init_package_path();
|
|
2814
|
+
}
|
|
2815
|
+
});
|
|
2816
|
+
|
|
2480
2817
|
// src/runtime/cache.ts
|
|
2481
2818
|
var cache_exports = {};
|
|
2482
2819
|
__export(cache_exports, {
|
|
@@ -2531,15 +2868,15 @@ __export(utils_exports, {
|
|
|
2531
2868
|
isPreBuiltConfig: () => isPreBuiltConfig,
|
|
2532
2869
|
prepareBundleForRun: () => prepareBundleForRun
|
|
2533
2870
|
});
|
|
2534
|
-
import
|
|
2535
|
-
import
|
|
2871
|
+
import path17 from "path";
|
|
2872
|
+
import fs16 from "fs-extra";
|
|
2536
2873
|
async function prepareBundleForRun(configPath, options) {
|
|
2537
2874
|
const tempDir = getTmpPath(
|
|
2538
2875
|
void 0,
|
|
2539
2876
|
`run-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`
|
|
2540
2877
|
);
|
|
2541
|
-
await
|
|
2542
|
-
const tempPath =
|
|
2878
|
+
await fs16.ensureDir(tempDir);
|
|
2879
|
+
const tempPath = path17.join(tempDir, "bundle.mjs");
|
|
2543
2880
|
await bundle(configPath, {
|
|
2544
2881
|
cache: true,
|
|
2545
2882
|
verbose: options.verbose,
|
|
@@ -2551,7 +2888,12 @@ async function prepareBundleForRun(configPath, options) {
|
|
|
2551
2888
|
platform: "node"
|
|
2552
2889
|
}
|
|
2553
2890
|
});
|
|
2554
|
-
return
|
|
2891
|
+
return {
|
|
2892
|
+
bundlePath: tempPath,
|
|
2893
|
+
cleanup: async () => {
|
|
2894
|
+
await fs16.remove(tempDir);
|
|
2895
|
+
}
|
|
2896
|
+
};
|
|
2555
2897
|
}
|
|
2556
2898
|
function isPreBuiltConfig(configPath) {
|
|
2557
2899
|
return configPath.endsWith(".mjs") || configPath.endsWith(".js") || configPath.endsWith(".cjs");
|
|
@@ -2567,1074 +2909,703 @@ var init_utils3 = __esm({
|
|
|
2567
2909
|
// src/index.ts
|
|
2568
2910
|
init_bundle();
|
|
2569
2911
|
|
|
2570
|
-
// src/commands/
|
|
2571
|
-
import
|
|
2912
|
+
// src/commands/push/index.ts
|
|
2913
|
+
import path16 from "path";
|
|
2914
|
+
import fs15 from "fs-extra";
|
|
2915
|
+
import {
|
|
2916
|
+
createIngest,
|
|
2917
|
+
getPlatform as getPlatform4,
|
|
2918
|
+
compileNext,
|
|
2919
|
+
resolveNext,
|
|
2920
|
+
isRouteArray,
|
|
2921
|
+
buildCacheContext
|
|
2922
|
+
} from "@walkeros/core";
|
|
2572
2923
|
|
|
2573
2924
|
// ../collector/dist/index.mjs
|
|
2574
2925
|
import { assign as o } from "@walkeros/core";
|
|
2575
2926
|
import { assign as r, createLogger as i } from "@walkeros/core";
|
|
2576
|
-
import {
|
|
2577
|
-
import { isArray as
|
|
2578
|
-
import { tryCatch as
|
|
2579
|
-
import {
|
|
2580
|
-
import { isObject as
|
|
2581
|
-
import { assign as
|
|
2582
|
-
import { isObject as
|
|
2583
|
-
import { getGrantedConsent as
|
|
2584
|
-
import { useHooks as
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
}
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
return
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
const t2 = [], o2 = /* @__PURE__ */ new Set();
|
|
2608
|
-
let s2 = n;
|
|
2609
|
-
for (; s2 && e2[s2] && !o2.has(s2); ) {
|
|
2610
|
-
o2.add(s2), t2.push(s2);
|
|
2611
|
-
const n2 = e2[s2].next;
|
|
2612
|
-
if (Array.isArray(n2)) {
|
|
2613
|
-
t2.push(...n2);
|
|
2927
|
+
import { buildCacheContext as a, clone as c, compileCache as u, checkCache as f, storeCache as l, compileNext as d, createIngest as g, debounce as p, getId as m, getGrantedConsent as h, isDefined as y, isFunction as v, isObject as b, isRouteArray as w, processEventMapping as k, resolveNext as C, tryCatchAsync as O, useHooks as j } from "@walkeros/core";
|
|
2928
|
+
import { isArray as A } from "@walkeros/core";
|
|
2929
|
+
import { tryCatch as x, tryCatchAsync as q } from "@walkeros/core";
|
|
2930
|
+
import { createIngest as S, getMappingValue as $, tryCatchAsync as D, compileNext as _, resolveNext as I, isRouteArray as P, compileCache as E, checkCache as M, storeCache as R, applyUpdate as H, buildCacheContext as T } from "@walkeros/core";
|
|
2931
|
+
import { createIngest as G, isObject as N, tryCatchAsync as B, useHooks as U, compileNext as F, resolveNext as W, isRouteArray as L, compileCache as V, checkCache as z, storeCache as J, buildCacheContext as K } from "@walkeros/core";
|
|
2932
|
+
import { assign as ve, getId as be, isFunction as we, isString as ke } from "@walkeros/core";
|
|
2933
|
+
import { isObject as Ce } from "@walkeros/core";
|
|
2934
|
+
import { createIngest as qe, getGrantedConsent as Se, processEventMapping as $e, tryCatchAsync as De, useHooks as _e } from "@walkeros/core";
|
|
2935
|
+
import { useHooks as Pe, tryCatchAsync as Ee } from "@walkeros/core";
|
|
2936
|
+
import { useHooks as Me } from "@walkeros/core";
|
|
2937
|
+
function Q(e, n) {
|
|
2938
|
+
return e.storeId && n.stores[e.storeId] ? n.stores[e.storeId] : n.stores.__cache;
|
|
2939
|
+
}
|
|
2940
|
+
function X(e) {
|
|
2941
|
+
const n = {};
|
|
2942
|
+
for (const [t, o2] of Object.entries(e)) {
|
|
2943
|
+
const e2 = o2.config?.next;
|
|
2944
|
+
e2 && !L(e2) ? n[t] = { next: e2 } : n[t] = {};
|
|
2945
|
+
}
|
|
2946
|
+
return n;
|
|
2947
|
+
}
|
|
2948
|
+
function Z(e, n = {}) {
|
|
2949
|
+
if (!e) return [];
|
|
2950
|
+
if (Array.isArray(e)) return e;
|
|
2951
|
+
const t = [], o2 = /* @__PURE__ */ new Set();
|
|
2952
|
+
let s = e;
|
|
2953
|
+
for (; s && n[s] && !o2.has(s); ) {
|
|
2954
|
+
o2.add(s), t.push(s);
|
|
2955
|
+
const e2 = n[s].next;
|
|
2956
|
+
if (Array.isArray(e2)) {
|
|
2957
|
+
t.push(...e2);
|
|
2614
2958
|
break;
|
|
2615
2959
|
}
|
|
2616
|
-
|
|
2960
|
+
s = e2;
|
|
2617
2961
|
}
|
|
2618
|
-
return
|
|
2962
|
+
return t;
|
|
2619
2963
|
}
|
|
2620
|
-
async function
|
|
2621
|
-
if (
|
|
2622
|
-
const o2 =
|
|
2623
|
-
|
|
2624
|
-
const i2 = await
|
|
2964
|
+
async function ee(e, n, t) {
|
|
2965
|
+
if (n.init && !n.config.init) {
|
|
2966
|
+
const o2 = n.type || "unknown", s = e.logger.scope(`transformer:${o2}`), r2 = { collector: e, logger: s, id: t, ingest: G(t), config: n.config, env: oe(n.config.env) };
|
|
2967
|
+
s.debug("init");
|
|
2968
|
+
const i2 = await U(n.init, "TransformerInit", e.hooks)(r2);
|
|
2625
2969
|
if (false === i2) return false;
|
|
2626
|
-
|
|
2970
|
+
n.config = { ...i2 || n.config, env: i2?.env || n.config.env, init: true }, s.debug("init done");
|
|
2627
2971
|
}
|
|
2628
2972
|
return true;
|
|
2629
2973
|
}
|
|
2630
|
-
async function
|
|
2631
|
-
const i2 =
|
|
2974
|
+
async function ne(e, n, t, o2, s, r2) {
|
|
2975
|
+
const i2 = n.type || "unknown", a2 = e.logger.scope(`transformer:${i2}`), c2 = { collector: e, logger: a2, id: t, ingest: s, config: n.config, env: { ...oe(n.config.env), ...r2 ? { respond: r2 } : {} } };
|
|
2632
2976
|
a2.debug("push", { event: o2.name });
|
|
2633
|
-
const u2 = await
|
|
2977
|
+
const u2 = await U(n.push, "TransformerPush", e.hooks)(o2, c2);
|
|
2634
2978
|
return a2.debug("push done"), u2;
|
|
2635
2979
|
}
|
|
2636
|
-
async function
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2980
|
+
async function te(e, n, t, o2, s, r2, i2) {
|
|
2981
|
+
i2 && s?._meta && (s._meta.chainPath = i2);
|
|
2982
|
+
let a2 = o2, c2 = r2;
|
|
2983
|
+
for (const o3 of t) {
|
|
2984
|
+
const r3 = n[o3];
|
|
2985
|
+
if (!r3) {
|
|
2986
|
+
e.logger.warn(`Transformer not found: ${o3}`);
|
|
2642
2987
|
continue;
|
|
2643
2988
|
}
|
|
2644
|
-
if (
|
|
2645
|
-
|
|
2646
|
-
if (
|
|
2647
|
-
if (
|
|
2648
|
-
const
|
|
2649
|
-
|
|
2650
|
-
const o5 = E(c2, D(e2));
|
|
2651
|
-
return o5.length > 0 ? S(n, e2, o5, t4 || i2, s2, a2) : (n.logger.warn(`Branch target not found: ${JSON.stringify(c2)}`), null);
|
|
2652
|
-
}
|
|
2653
|
-
t4 && (i2 = t4);
|
|
2654
|
-
}
|
|
2655
|
-
}
|
|
2656
|
-
return i2;
|
|
2657
|
-
}
|
|
2658
|
-
function $(n) {
|
|
2659
|
-
return n && C(n) ? n : {};
|
|
2660
|
-
}
|
|
2661
|
-
async function R(n, e2, t2) {
|
|
2662
|
-
const { code: o2, config: s2 = {}, env: r2 = {}, primary: i2, next: a2 } = t2;
|
|
2663
|
-
let c2, u2;
|
|
2664
|
-
const f2 = E(a2, D(n.transformers)), l2 = n.logger.scope("source").scope(e2), g2 = { push: (t3, o3 = {}) => n.push(t3, { ...o3, id: e2, ingest: c2, respond: u2, mapping: s2, preChain: f2 }), command: n.command, sources: n.sources, elb: n.sources.elb.push, logger: l2, ...r2 }, d2 = { collector: n, logger: l2, id: e2, config: s2, env: g2, setIngest: async (e3) => {
|
|
2665
|
-
c2 = s2.ingest ? await k(e3, s2.ingest, { collector: n }) : void 0;
|
|
2666
|
-
}, setRespond: (n2) => {
|
|
2667
|
-
u2 = n2;
|
|
2668
|
-
} }, m2 = await O(o2)(d2);
|
|
2669
|
-
if (!m2) return;
|
|
2670
|
-
const p2 = m2.type || "unknown", h2 = n.logger.scope(p2).scope(e2);
|
|
2671
|
-
return g2.logger = h2, i2 && (m2.config = { ...m2.config, primary: i2 }), m2;
|
|
2672
|
-
}
|
|
2673
|
-
async function T(n, e2 = {}) {
|
|
2674
|
-
const t2 = {};
|
|
2675
|
-
for (const [o2, s2] of Object.entries(e2)) {
|
|
2676
|
-
const { config: e3 = {} } = s2;
|
|
2677
|
-
if (e3.require && e3.require.length > 0) {
|
|
2678
|
-
n.pending.sources[o2] = s2;
|
|
2989
|
+
if (s && s._meta && s._meta.path.length > 256) return e.logger.error(`Max path length exceeded at ${o3}`), { event: null, respond: c2 };
|
|
2990
|
+
s && s._meta && (s._meta.hops++, s._meta.path.push(o3));
|
|
2991
|
+
if (!await B(ee)(e, r3, o3)) return e.logger.error(`Transformer init failed: ${o3}`), { event: null, respond: c2 };
|
|
2992
|
+
if (i2 && void 0 !== r3.config?.chainMocks?.[i2]) {
|
|
2993
|
+
const n2 = r3.config.chainMocks[i2];
|
|
2994
|
+
e.logger.scope(`transformer:${r3.type || "unknown"}`).debug("chainMock", { chain: i2 }), a2 = n2;
|
|
2679
2995
|
continue;
|
|
2680
2996
|
}
|
|
2681
|
-
|
|
2682
|
-
|
|
2997
|
+
if (void 0 !== r3.config?.mock) {
|
|
2998
|
+
e.logger.scope(`transformer:${r3.type || "unknown"}`).debug("mock"), a2 = r3.config.mock;
|
|
2999
|
+
continue;
|
|
3000
|
+
}
|
|
3001
|
+
if (r3.config?.disabled) continue;
|
|
3002
|
+
const u2 = r3.config?.cache, f2 = u2 ? V(u2) : void 0, l2 = f2 ? Q(f2, e) : void 0;
|
|
3003
|
+
let d2;
|
|
3004
|
+
if (f2 && l2) {
|
|
3005
|
+
const e2 = K(s, a2), n2 = z(f2, l2, e2, `t:${o3}`);
|
|
3006
|
+
if ("HIT" === n2?.status && n2.value) {
|
|
3007
|
+
if (a2 = n2.value, f2.full) return { event: a2, respond: c2 };
|
|
3008
|
+
continue;
|
|
3009
|
+
}
|
|
3010
|
+
"MISS" === n2?.status && (d2 = { key: n2.key, ttl: n2.rule.ttl });
|
|
3011
|
+
}
|
|
3012
|
+
const g2 = r3.config.before;
|
|
3013
|
+
if (g2) {
|
|
3014
|
+
const t2 = Z("string" == typeof g2 || Array.isArray(g2) && !L(g2) ? g2 : W(F(g2), K(s, a2)) || void 0, X(n));
|
|
3015
|
+
if (t2.length > 0) {
|
|
3016
|
+
const o4 = await te(e, n, t2, a2, s, c2, i2);
|
|
3017
|
+
if (null === o4.event) return { event: null, respond: o4.respond ?? c2 };
|
|
3018
|
+
o4.respond && (c2 = o4.respond), a2 = Array.isArray(o4.event) ? o4.event[0] : o4.event;
|
|
3019
|
+
}
|
|
3020
|
+
}
|
|
3021
|
+
const p2 = await B(ne, (n2) => (e.logger.scope(`transformer:${r3.type || "unknown"}`).error("Push failed", { error: n2 }), false))(e, r3, o3, a2, s, c2);
|
|
3022
|
+
if (false === p2) return { event: null, respond: c2 };
|
|
3023
|
+
if (Array.isArray(p2)) {
|
|
3024
|
+
const r4 = t.slice(t.indexOf(o3) + 1), u3 = await Promise.all(p2.map(async (t2) => {
|
|
3025
|
+
const o4 = t2.event || a2, u4 = s ? { ...s, _meta: { ...s._meta, path: [...s._meta.path] } } : G("unknown");
|
|
3026
|
+
if (t2.next) {
|
|
3027
|
+
let s2 = t2.next;
|
|
3028
|
+
if (L(t2.next)) {
|
|
3029
|
+
const e2 = F(t2.next);
|
|
3030
|
+
s2 = W(e2, K(u4, o4));
|
|
3031
|
+
}
|
|
3032
|
+
if (s2) {
|
|
3033
|
+
const t3 = Z(s2, X(n));
|
|
3034
|
+
if (t3.length > 0) return te(e, n, t3, o4, u4, c2, i2);
|
|
3035
|
+
}
|
|
3036
|
+
return { event: o4, respond: c2 };
|
|
3037
|
+
}
|
|
3038
|
+
return r4.length > 0 ? te(e, n, r4, o4, u4, c2, i2) : { event: o4, respond: c2 };
|
|
3039
|
+
}));
|
|
3040
|
+
let f3 = c2;
|
|
3041
|
+
const l3 = [];
|
|
3042
|
+
for (const e2 of u3.flat()) if (null !== e2) if (e2 && "object" == typeof e2 && "event" in e2) {
|
|
3043
|
+
const n2 = e2;
|
|
3044
|
+
if (n2.respond && (f3 = n2.respond), null === n2.event) continue;
|
|
3045
|
+
Array.isArray(n2.event) ? l3.push(...n2.event) : l3.push(n2.event);
|
|
3046
|
+
} else l3.push(e2);
|
|
3047
|
+
return 0 === l3.length ? { event: null, respond: f3 } : 1 === l3.length ? { event: l3[0], respond: f3 } : { event: l3, respond: f3 };
|
|
3048
|
+
}
|
|
3049
|
+
if (p2 && "object" == typeof p2) {
|
|
3050
|
+
const { event: t2, respond: o4, next: r4 } = p2;
|
|
3051
|
+
if (o4 && (c2 = o4), r4) {
|
|
3052
|
+
let o5 = r4;
|
|
3053
|
+
if (L(r4)) {
|
|
3054
|
+
const e2 = F(r4);
|
|
3055
|
+
if (o5 = W(e2, K(s, a2)), !o5) {
|
|
3056
|
+
t2 && (a2 = t2);
|
|
3057
|
+
continue;
|
|
3058
|
+
}
|
|
3059
|
+
}
|
|
3060
|
+
const u3 = Z(o5, X(n));
|
|
3061
|
+
return u3.length > 0 ? te(e, n, u3, t2 || a2, s, c2, i2) : (e.logger.warn(`Branch target not found: ${JSON.stringify(r4)}`), { event: null, respond: c2 });
|
|
3062
|
+
}
|
|
3063
|
+
t2 && (a2 = t2);
|
|
3064
|
+
}
|
|
3065
|
+
if (d2 && l2 && J(l2, d2.key, a2, d2.ttl), (!p2 || "object" == typeof p2 && !p2.next) && r3.config.next && L(r3.config.next)) {
|
|
3066
|
+
const t2 = r3.config.next, o4 = F(t2), u3 = W(o4, K(s, a2));
|
|
3067
|
+
if (u3) {
|
|
3068
|
+
const t3 = Z(u3, X(n));
|
|
3069
|
+
if (t3.length > 0) return te(e, n, t3, a2, s, c2, i2);
|
|
3070
|
+
}
|
|
3071
|
+
return { event: a2, respond: c2 };
|
|
3072
|
+
}
|
|
2683
3073
|
}
|
|
2684
|
-
return
|
|
3074
|
+
return { event: a2, respond: c2 };
|
|
2685
3075
|
}
|
|
2686
|
-
|
|
2687
|
-
|
|
2688
|
-
r2.forEach((n2) => {
|
|
2689
|
-
s2.push(n2);
|
|
2690
|
-
}), o2[e2] = s2, await G(n, e2, r2);
|
|
3076
|
+
function oe(e) {
|
|
3077
|
+
return e && N(e) ? e : {};
|
|
2691
3078
|
}
|
|
2692
|
-
function
|
|
2693
|
-
if (
|
|
2694
|
-
|
|
2695
|
-
|
|
3079
|
+
function Te(e) {
|
|
3080
|
+
if (null === e || "object" != typeof e) return e;
|
|
3081
|
+
if (Array.isArray(e)) return e.map(Te);
|
|
3082
|
+
const n = {};
|
|
3083
|
+
for (const [t, o2] of Object.entries(e)) n[t] = "function" == typeof o2 ? o2 : Te(o2);
|
|
3084
|
+
return n;
|
|
2696
3085
|
}
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
case t.Commands.Session:
|
|
2704
|
-
r2 = n.session;
|
|
2705
|
-
break;
|
|
2706
|
-
case t.Commands.User:
|
|
2707
|
-
r2 = s2 || n.user;
|
|
2708
|
-
break;
|
|
2709
|
-
case t.Commands.Custom:
|
|
2710
|
-
r2 = s2 || n.custom;
|
|
2711
|
-
break;
|
|
2712
|
-
case t.Commands.Globals:
|
|
2713
|
-
r2 = s2 || n.globals;
|
|
2714
|
-
break;
|
|
2715
|
-
case t.Commands.Config:
|
|
2716
|
-
r2 = s2 || n.config;
|
|
2717
|
-
break;
|
|
2718
|
-
case t.Commands.Ready:
|
|
2719
|
-
case t.Commands.Run:
|
|
2720
|
-
default:
|
|
2721
|
-
r2 = void 0;
|
|
2722
|
-
}
|
|
2723
|
-
let a2 = false;
|
|
2724
|
-
for (const t2 of Object.values(n.sources)) if (t2.on) {
|
|
2725
|
-
false === await v(t2.on)(e2, r2) && (a2 = true);
|
|
2726
|
-
}
|
|
2727
|
-
if (Object.entries(n.destinations).forEach(([t2, o3]) => {
|
|
2728
|
-
if (o3.on) {
|
|
2729
|
-
if (!o3.config.init) return o3.queueOn = o3.queueOn || [], void o3.queueOn.push({ type: e2, data: r2 });
|
|
2730
|
-
B(n, o3, t2, e2, r2);
|
|
2731
|
-
}
|
|
2732
|
-
}), (Object.keys(n.pending.sources).length > 0 || Object.keys(n.pending.destinations).length > 0) && await (async function(n2, e3) {
|
|
2733
|
-
for (const [t2, o3] of Object.entries(n2.pending.sources)) {
|
|
2734
|
-
if (!n2.pending.sources[t2] || n2.sources[t2]) continue;
|
|
2735
|
-
const s3 = o3.config?.require;
|
|
2736
|
-
if (!s3) continue;
|
|
2737
|
-
const r3 = s3.indexOf(e3);
|
|
2738
|
-
if (-1 === r3) continue;
|
|
2739
|
-
if (s3.splice(r3, 1), s3.length > 0) continue;
|
|
2740
|
-
delete n2.pending.sources[t2];
|
|
2741
|
-
const i3 = await R(n2, t2, o3);
|
|
2742
|
-
i3 && (n2.sources[t2] = i3);
|
|
2743
|
-
}
|
|
2744
|
-
for (const [t2, o3] of Object.entries(n2.pending.destinations)) {
|
|
2745
|
-
if (!n2.pending.destinations[t2] || n2.destinations[t2]) continue;
|
|
2746
|
-
const s3 = o3.config?.require;
|
|
2747
|
-
if (!s3) continue;
|
|
2748
|
-
const r3 = s3.indexOf(e3);
|
|
2749
|
-
if (-1 === r3) continue;
|
|
2750
|
-
if (s3.splice(r3, 1), s3.length > 0) continue;
|
|
2751
|
-
delete n2.pending.destinations[t2];
|
|
2752
|
-
const i3 = M(o3);
|
|
2753
|
-
false !== i3.config.queue && (i3.queuePush = [...n2.queue]), n2.destinations[t2] = i3;
|
|
2754
|
-
}
|
|
2755
|
-
})(n, e2), !i2.length) return !a2;
|
|
2756
|
-
switch (e2) {
|
|
2757
|
-
case t.Commands.Consent:
|
|
2758
|
-
!(function(n2, e3, t2) {
|
|
2759
|
-
const o3 = t2 || n2.consent;
|
|
2760
|
-
e3.forEach((e4) => {
|
|
2761
|
-
Object.keys(o3).filter((n3) => n3 in e4).forEach((t3) => {
|
|
2762
|
-
y(e4[t3])(n2, o3);
|
|
2763
|
-
});
|
|
2764
|
-
});
|
|
2765
|
-
})(n, i2, s2);
|
|
2766
|
-
break;
|
|
2767
|
-
case t.Commands.Ready:
|
|
2768
|
-
case t.Commands.Run:
|
|
2769
|
-
!(function(n2, e3) {
|
|
2770
|
-
n2.allowed && e3.forEach((e4) => {
|
|
2771
|
-
y(e4)(n2);
|
|
2772
|
-
});
|
|
2773
|
-
})(n, i2);
|
|
2774
|
-
break;
|
|
2775
|
-
case t.Commands.Session:
|
|
2776
|
-
!(function(n2, e3) {
|
|
2777
|
-
if (!n2.session) return;
|
|
2778
|
-
e3.forEach((e4) => {
|
|
2779
|
-
y(e4)(n2, n2.session);
|
|
2780
|
-
});
|
|
2781
|
-
})(n, i2);
|
|
2782
|
-
break;
|
|
2783
|
-
default:
|
|
2784
|
-
i2.forEach((e3) => {
|
|
2785
|
-
"function" == typeof e3 && y(e3)(n, r2);
|
|
2786
|
-
});
|
|
2787
|
-
}
|
|
2788
|
-
return !a2;
|
|
2789
|
-
}
|
|
2790
|
-
async function H(n, e2, t2) {
|
|
2791
|
-
const { code: o2, config: s2 = {}, env: r2 = {}, before: i2 } = e2;
|
|
2792
|
-
if (!d(o2.push)) return J({ ok: false, failed: { invalid: { type: "invalid", error: "Destination code must have a push method" } } });
|
|
2793
|
-
const a2 = t2 || s2 || { init: false }, c2 = i2 ? { ...a2, before: i2 } : a2, u2 = { ...o2, config: c2, env: W(o2.env, r2) };
|
|
2794
|
-
let l2 = u2.config.id;
|
|
2795
|
-
if (!l2) do {
|
|
2796
|
-
l2 = f(4);
|
|
2797
|
-
} while (n.destinations[l2]);
|
|
2798
|
-
return n.destinations[l2] = u2, false !== u2.config.queue && (u2.queuePush = [...n.queue]), U(n, void 0, {}, { [l2]: u2 });
|
|
2799
|
-
}
|
|
2800
|
-
async function U(n, e2, t2 = {}, o2) {
|
|
2801
|
-
const { allowed: s2, consent: r2, globals: i2, user: u2 } = n;
|
|
2802
|
-
if (!s2) return J({ ok: false });
|
|
2803
|
-
e2 && (n.queue.push(e2), n.status.in++), o2 || (o2 = n.destinations);
|
|
2804
|
-
const f2 = await Promise.all(Object.entries(o2 || {}).map(async ([o3, s3]) => {
|
|
2805
|
-
let f3 = (s3.queuePush || []).map((n2) => ({ ...n2, consent: r2 }));
|
|
2806
|
-
if (s3.queuePush = [], e2) {
|
|
2807
|
-
const n2 = c(e2);
|
|
2808
|
-
f3.push(n2);
|
|
2809
|
-
}
|
|
2810
|
-
if (!f3.length && !s3.queueOn?.length) return { id: o3, destination: s3, skipped: true };
|
|
2811
|
-
if (!f3.length && s3.queueOn?.length) {
|
|
2812
|
-
const e3 = await h(z)(n, s3, o3);
|
|
2813
|
-
return { id: o3, destination: s3, skipped: !e3 };
|
|
2814
|
-
}
|
|
2815
|
-
const g3 = [], d3 = f3.filter((n2) => {
|
|
2816
|
-
const e3 = l(s3.config.consent, r2, n2.consent);
|
|
2817
|
-
return !e3 || (n2.consent = e3, g3.push(n2), false);
|
|
2818
|
-
});
|
|
2819
|
-
if (s3.queuePush.push(...d3), !g3.length) return { id: o3, destination: s3, queue: f3 };
|
|
2820
|
-
if (!await h(z)(n, s3, o3)) return { id: o3, destination: s3, queue: f3 };
|
|
2821
|
-
let m3, p2;
|
|
2822
|
-
s3.dlq || (s3.dlq = []);
|
|
2823
|
-
const w2 = (function(n2, e3) {
|
|
2824
|
-
const t3 = n2.config.before;
|
|
2825
|
-
return t3 ? E(t3, D(e3)) : [];
|
|
2826
|
-
})(s3, n.transformers);
|
|
2827
|
-
let b2 = 0;
|
|
2828
|
-
return await Promise.all(g3.map(async (e3) => {
|
|
2829
|
-
e3.globals = a(i2, e3.globals), e3.user = a(u2, e3.user);
|
|
2830
|
-
let r3 = e3;
|
|
2831
|
-
if (w2.length > 0 && n.transformers && Object.keys(n.transformers).length > 0) {
|
|
2832
|
-
const o4 = await S(n, n.transformers, w2, e3, t2.ingest, t2.respond);
|
|
2833
|
-
if (null === o4) return e3;
|
|
2834
|
-
r3 = o4;
|
|
2835
|
-
}
|
|
2836
|
-
const c2 = Date.now(), f4 = await h(F, (e4) => {
|
|
2837
|
-
const t3 = s3.type || "unknown";
|
|
2838
|
-
n.logger.scope(t3).error("Push failed", { error: e4, event: r3.name }), m3 = e4, s3.dlq.push([r3, e4]);
|
|
2839
|
-
})(n, s3, o3, r3, t2.ingest, t2.respond);
|
|
2840
|
-
return b2 += Date.now() - c2, void 0 !== f4 && (p2 = f4), e3;
|
|
2841
|
-
})), { id: o3, destination: s3, error: m3, response: p2, totalDuration: b2 };
|
|
2842
|
-
})), g2 = {}, d2 = {}, m2 = {};
|
|
2843
|
-
for (const e3 of f2) {
|
|
2844
|
-
if (e3.skipped) continue;
|
|
2845
|
-
const t3 = { type: e3.destination.type || "unknown", data: e3.response };
|
|
2846
|
-
n.status.destinations[e3.id] || (n.status.destinations[e3.id] = { count: 0, failed: 0, duration: 0 });
|
|
2847
|
-
const o3 = n.status.destinations[e3.id], s3 = Date.now();
|
|
2848
|
-
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++);
|
|
2849
|
-
}
|
|
2850
|
-
return J({ event: e2, ...Object.keys(g2).length && { done: g2 }, ...Object.keys(d2).length && { queued: d2 }, ...Object.keys(m2).length && { failed: m2 } });
|
|
2851
|
-
}
|
|
2852
|
-
async function z(n, e2, t2) {
|
|
2853
|
-
if (e2.init && !e2.config.init) {
|
|
2854
|
-
const o2 = e2.type || "unknown", s2 = n.logger.scope(o2), r2 = { collector: n, logger: s2, id: t2, config: e2.config, env: W(e2.env, e2.config.env) };
|
|
2855
|
-
s2.debug("init");
|
|
2856
|
-
const i2 = await w(e2.init, "DestinationInit", n.hooks)(r2);
|
|
2857
|
-
if (false === i2) return i2;
|
|
2858
|
-
if (e2.config = { ...i2 || e2.config, init: true }, e2.queueOn?.length) {
|
|
2859
|
-
const o3 = e2.queueOn;
|
|
2860
|
-
e2.queueOn = [];
|
|
2861
|
-
for (const { type: s3, data: r3 } of o3) B(n, e2, t2, s3, r3);
|
|
2862
|
-
}
|
|
2863
|
-
s2.debug("init done");
|
|
2864
|
-
}
|
|
2865
|
-
return true;
|
|
2866
|
-
}
|
|
2867
|
-
async function F(n, e2, t2, o2, s2, r2) {
|
|
2868
|
-
const { config: i2 } = e2, a2 = await p(o2, i2, n);
|
|
2869
|
-
if (a2.ignore) return false;
|
|
2870
|
-
const c2 = e2.type || "unknown", f2 = n.logger.scope(c2), l2 = { collector: n, logger: f2, id: t2, config: i2, data: a2.data, rule: a2.mapping, ingest: s2, env: { ...W(e2.env, i2.env), ...r2 ? { respond: r2 } : {} } }, d2 = a2.mapping, m2 = a2.mappingKey || "* *";
|
|
2871
|
-
if (!d2?.batch || !e2.pushBatch) {
|
|
2872
|
-
f2.debug("push", { event: a2.event.name });
|
|
2873
|
-
const t3 = await w(e2.push, "DestinationPush", n.hooks)(a2.event, l2);
|
|
2874
|
-
return f2.debug("push done"), t3;
|
|
2875
|
-
}
|
|
2876
|
-
{
|
|
2877
|
-
if (e2.batches = e2.batches || {}, !e2.batches[m2]) {
|
|
2878
|
-
const o4 = { key: m2, events: [], data: [] };
|
|
2879
|
-
e2.batches[m2] = { batched: o4, batchFn: u(() => {
|
|
2880
|
-
const o5 = e2.batches[m2].batched, a3 = { collector: n, logger: f2, id: t2, config: i2, data: void 0, rule: d2, ingest: s2, env: { ...W(e2.env, i2.env), ...r2 ? { respond: r2 } : {} } };
|
|
2881
|
-
f2.debug("push batch", { events: o5.events.length }), w(e2.pushBatch, "DestinationPushBatch", n.hooks)(o5, a3), f2.debug("push batch done"), o5.events = [], o5.data = [];
|
|
2882
|
-
}, d2.batch) };
|
|
2883
|
-
}
|
|
2884
|
-
const o3 = e2.batches[m2];
|
|
2885
|
-
o3.batched.events.push(a2.event), g(a2.data) && o3.batched.data.push(a2.data), o3.batchFn();
|
|
2886
|
-
}
|
|
2887
|
-
return true;
|
|
2888
|
-
}
|
|
2889
|
-
function J(n) {
|
|
2890
|
-
return { ok: !n?.failed, ...n };
|
|
2891
|
-
}
|
|
2892
|
-
function M(n) {
|
|
2893
|
-
const { code: e2, config: t2 = {}, env: o2 = {} } = n, { config: s2 } = A(n, "before"), r2 = { ...e2.config, ...t2, ...s2 }, i2 = W(e2.env, o2);
|
|
2894
|
-
return { ...e2, config: r2, env: i2 };
|
|
2895
|
-
}
|
|
2896
|
-
async function N(n, e2 = {}) {
|
|
2897
|
-
const t2 = {};
|
|
2898
|
-
for (const [o2, s2] of Object.entries(e2)) s2.config?.require?.length ? n.pending.destinations[o2] = s2 : t2[o2] = M(s2);
|
|
2899
|
-
return t2;
|
|
2900
|
-
}
|
|
2901
|
-
function W(n, e2) {
|
|
2902
|
-
return n || e2 ? e2 ? n && m(n) && m(e2) ? { ...n, ...e2 } : e2 : n : {};
|
|
2903
|
-
}
|
|
2904
|
-
async function X(n, e2, t2) {
|
|
2905
|
-
const o2 = Object.entries(n).map(async ([n2, o3]) => {
|
|
2906
|
-
const s2 = o3.destroy;
|
|
2907
|
-
if (!s2) return;
|
|
2908
|
-
const r2 = o3.type || "unknown", i2 = t2.scope(r2), a2 = { id: n2, config: o3.config, env: o3.env ?? {}, logger: i2 };
|
|
2909
|
-
try {
|
|
2910
|
-
await Promise.race([s2(a2), new Promise((t3, o4) => setTimeout(() => o4(new Error(`${e2} '${n2}' destroy timed out`)), 5e3))]);
|
|
2911
|
-
} catch (t3) {
|
|
2912
|
-
i2.error(`${e2} '${n2}' destroy failed: ${t3}`);
|
|
2913
|
-
}
|
|
2914
|
-
});
|
|
2915
|
-
await Promise.allSettled(o2);
|
|
2916
|
-
}
|
|
2917
|
-
async function Y(n, e2, o2, r2) {
|
|
2918
|
-
let i2, a2, c2 = false, u2 = false;
|
|
2919
|
-
switch (e2) {
|
|
2920
|
-
case t.Commands.Config:
|
|
2921
|
-
K(o2) && (L(n.config, o2, { shallow: false }), a2 = o2, c2 = true);
|
|
2922
|
-
break;
|
|
2923
|
-
case t.Commands.Consent:
|
|
2924
|
-
if (K(o2)) {
|
|
2925
|
-
const { update: e3, runQueue: t2 } = s(n, o2);
|
|
2926
|
-
a2 = e3, c2 = true, u2 = t2;
|
|
2927
|
-
}
|
|
2928
|
-
break;
|
|
2929
|
-
case t.Commands.Custom:
|
|
2930
|
-
K(o2) && (n.custom = L(n.custom, o2), a2 = o2, c2 = true);
|
|
2931
|
-
break;
|
|
2932
|
-
case t.Commands.Destination:
|
|
2933
|
-
K(o2) && ("code" in o2 && K(o2.code) ? i2 = await H(n, o2, r2) : V(o2.push) && (i2 = await H(n, { code: o2 }, r2)));
|
|
2934
|
-
break;
|
|
2935
|
-
case t.Commands.Globals:
|
|
2936
|
-
K(o2) && (n.globals = L(n.globals, o2), a2 = o2, c2 = true);
|
|
2937
|
-
break;
|
|
2938
|
-
case t.Commands.On:
|
|
2939
|
-
_(o2) && await I(n, o2, r2);
|
|
2940
|
-
break;
|
|
2941
|
-
case t.Commands.Ready:
|
|
2942
|
-
c2 = true;
|
|
2943
|
-
break;
|
|
2944
|
-
case t.Commands.Run:
|
|
2945
|
-
i2 = await nn(n, o2), c2 = true;
|
|
2946
|
-
break;
|
|
2947
|
-
case t.Commands.Session:
|
|
2948
|
-
c2 = true;
|
|
2949
|
-
break;
|
|
2950
|
-
case t.Commands.Shutdown:
|
|
2951
|
-
await (async function(n2) {
|
|
2952
|
-
const e3 = n2.logger;
|
|
2953
|
-
await X(n2.sources, "source", e3), await X(n2.destinations, "destination", e3), await X(n2.transformers, "transformer", e3), await X(n2.stores, "store", e3);
|
|
2954
|
-
})(n);
|
|
2955
|
-
break;
|
|
2956
|
-
case t.Commands.User:
|
|
2957
|
-
K(o2) && (L(n.user, o2, { shallow: false }), a2 = o2, c2 = true);
|
|
2958
|
-
}
|
|
2959
|
-
return c2 && await G(n, e2, void 0, a2), u2 && (i2 = await U(n)), i2 || J({ ok: true });
|
|
2960
|
-
}
|
|
2961
|
-
function Z(n, e2) {
|
|
2962
|
-
if (!e2.name) throw new Error("Event name is required");
|
|
2963
|
-
const [t2, o2] = e2.name.split(" ");
|
|
2964
|
-
if (!t2 || !o2) throw new Error("Event name is invalid");
|
|
2965
|
-
++n.count;
|
|
2966
|
-
const { timestamp: s2 = Date.now(), group: r2 = n.group, count: i2 = n.count } = e2, { name: a2 = `${t2} ${o2}`, data: c2 = {}, context: u2 = {}, globals: f2 = n.globals, custom: l2 = {}, user: g2 = n.user, nested: d2 = [], consent: m2 = n.consent, id: p2 = `${s2}-${r2}-${i2}`, trigger: h2 = "", entity: w2 = t2, action: b2 = o2, timing: y2 = 0, version: v2 = { source: n.version, tagging: n.config.tagging || 0 }, source: k2 = { type: "collector", id: "", previous_id: "" } } = e2;
|
|
2967
|
-
return { name: a2, data: c2, context: u2, globals: f2, custom: l2, user: g2, nested: d2, consent: m2, id: p2, trigger: h2, entity: w2, action: b2, timestamp: s2, timing: y2, group: r2, count: i2, version: v2, source: k2 };
|
|
2968
|
-
}
|
|
2969
|
-
async function nn(n, e2) {
|
|
2970
|
-
n.allowed = true, n.count = 0, n.group = Q(), n.timing = Date.now(), e2 && (e2.consent && (n.consent = L(n.consent, e2.consent)), e2.user && (n.user = L(n.user, e2.user)), e2.globals && (n.globals = L(n.config.globalsStatic || {}, e2.globals)), e2.custom && (n.custom = L(n.custom, e2.custom))), Object.values(n.destinations).forEach((n2) => {
|
|
2971
|
-
n2.queuePush = [];
|
|
2972
|
-
}), n.queue = [], n.round++;
|
|
2973
|
-
return await U(n);
|
|
2974
|
-
}
|
|
2975
|
-
function rn(n, e2) {
|
|
2976
|
-
return sn(async (t2, o2 = {}) => await on(async () => {
|
|
2977
|
-
const s2 = Date.now(), { id: r2, ingest: i2, respond: a2, mapping: c2, preChain: u2 } = o2;
|
|
2978
|
-
let f2 = t2;
|
|
2979
|
-
const l2 = i2 ? Object.freeze(i2) : void 0;
|
|
2980
|
-
if (c2) {
|
|
2981
|
-
const e3 = await tn(f2, c2, n);
|
|
2982
|
-
if (e3.ignore) return J({ ok: true });
|
|
2983
|
-
if (c2.consent) {
|
|
2984
|
-
if (!en(c2.consent, n.consent, e3.event.consent)) return J({ ok: true });
|
|
2985
|
-
}
|
|
2986
|
-
f2 = e3.event;
|
|
2987
|
-
}
|
|
2988
|
-
if (u2?.length && n.transformers && Object.keys(n.transformers).length > 0) {
|
|
2989
|
-
const e3 = await S(n, n.transformers, u2, f2, l2, a2);
|
|
2990
|
-
if (null === e3) return J({ ok: true });
|
|
2991
|
-
f2 = e3;
|
|
2992
|
-
}
|
|
2993
|
-
const g2 = e2(f2), d2 = Z(n, g2), m2 = await U(n, d2, { id: r2, ingest: l2, respond: a2 });
|
|
2994
|
-
if (r2) {
|
|
2995
|
-
n.status.sources[r2] || (n.status.sources[r2] = { count: 0, duration: 0 });
|
|
2996
|
-
const e3 = n.status.sources[r2];
|
|
2997
|
-
e3.count++, e3.lastAt = Date.now(), e3.duration += Date.now() - s2;
|
|
2998
|
-
}
|
|
2999
|
-
return m2;
|
|
3000
|
-
}, () => J({ ok: false }))(), "Push", n.hooks);
|
|
3001
|
-
}
|
|
3002
|
-
async function un(n) {
|
|
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 };
|
|
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) {
|
|
3005
|
-
return an(async (t3, o3, s3) => await cn(async () => await e3(n2, t3, o3, s3), () => J({ ok: false }))(), "Command", n2.hooks);
|
|
3006
|
-
})(a2, Y);
|
|
3007
|
-
const c2 = n.stores || {};
|
|
3008
|
-
return a2.stores = await (async function(n2, e3 = {}) {
|
|
3009
|
-
const t3 = {};
|
|
3010
|
-
for (const [o3, s3] of Object.entries(e3)) {
|
|
3011
|
-
const { code: e4, config: r2 = {}, env: i2 = {} } = s3, a3 = n2.logger.scope("store").scope(o3), c3 = { collector: n2, logger: a3, id: o3, config: r2, env: i2 }, u2 = await e4(c3);
|
|
3012
|
-
t3[o3] = u2;
|
|
3013
|
-
}
|
|
3014
|
-
return t3;
|
|
3015
|
-
})(a2, c2), (function(n2, e3, t3) {
|
|
3016
|
-
const o3 = /* @__PURE__ */ new Map();
|
|
3017
|
-
for (const [t4, s4] of Object.entries(n2)) e3[t4] && o3.set(s4, e3[t4]);
|
|
3018
|
-
if (0 !== o3.size) {
|
|
3019
|
-
for (const n3 of [t3.transformers, t3.destinations, t3.sources]) if (n3) for (const e4 of Object.values(n3)) s3(e4.env);
|
|
3020
|
-
}
|
|
3021
|
-
function s3(n3) {
|
|
3022
|
-
if (n3) {
|
|
3023
|
-
for (const [e4, t4] of Object.entries(n3)) if ("object" == typeof t4 && null !== t4) {
|
|
3024
|
-
const s4 = o3.get(t4);
|
|
3025
|
-
s4 && (n3[e4] = s4);
|
|
3026
|
-
}
|
|
3027
|
-
}
|
|
3028
|
-
}
|
|
3029
|
-
})(c2, a2.stores, n), a2.destinations = await N(a2, n.destinations || {}), a2.transformers = await (async function(n2, e3 = {}) {
|
|
3030
|
-
const t3 = {};
|
|
3031
|
-
for (const [o3, s3] of Object.entries(e3)) {
|
|
3032
|
-
const { code: e4, env: r2 = {} } = s3, { config: i2 } = A(s3, "next"), a3 = Object.keys(r2).length > 0 ? { ...i2, env: r2 } : i2, c3 = n2.logger.scope("transformer").scope(o3), u2 = { collector: n2, logger: c3, id: o3, config: a3, env: r2 }, f2 = await e4(u2);
|
|
3033
|
-
t3[o3] = f2;
|
|
3034
|
-
}
|
|
3035
|
-
return t3;
|
|
3036
|
-
})(a2, n.transformers || {}), a2;
|
|
3037
|
-
}
|
|
3038
|
-
async function fn(n) {
|
|
3039
|
-
n = n || {};
|
|
3040
|
-
const e2 = await un(n), t2 = (o2 = e2, { type: "elb", config: {}, push: async (n2, e3, t3, s3, r3, i3) => {
|
|
3041
|
-
if ("string" == typeof n2 && n2.startsWith("walker ")) {
|
|
3042
|
-
const s4 = n2.replace("walker ", "");
|
|
3043
|
-
return o2.command(s4, e3, t3);
|
|
3044
|
-
}
|
|
3045
|
-
let a3;
|
|
3046
|
-
if ("string" == typeof n2) a3 = { name: n2 }, e3 && "object" == typeof e3 && !Array.isArray(e3) && (a3.data = e3);
|
|
3047
|
-
else {
|
|
3048
|
-
if (!n2 || "object" != typeof n2) return J({ ok: false });
|
|
3049
|
-
a3 = n2, e3 && "object" == typeof e3 && !Array.isArray(e3) && (a3.data = { ...a3.data || {}, ...e3 });
|
|
3050
|
-
}
|
|
3051
|
-
return s3 && "object" == typeof s3 && (a3.context = s3), r3 && Array.isArray(r3) && (a3.nested = r3), i3 && "object" == typeof i3 && (a3.custom = i3), o2.push(a3);
|
|
3052
|
-
} });
|
|
3053
|
-
var o2;
|
|
3054
|
-
e2.sources.elb = t2;
|
|
3055
|
-
const s2 = await T(e2, n.sources || {});
|
|
3056
|
-
Object.assign(e2.sources, s2);
|
|
3057
|
-
const { consent: r2, user: i2, globals: a2, custom: c2 } = n;
|
|
3058
|
-
r2 && await e2.command("consent", r2), i2 && await e2.command("user", i2), a2 && Object.assign(e2.globals, a2), c2 && Object.assign(e2.custom, c2), e2.config.run && await e2.command("run");
|
|
3059
|
-
let u2 = t2.push;
|
|
3060
|
-
const f2 = Object.values(e2.sources).filter((n2) => "elb" !== n2.type), l2 = f2.find((n2) => n2.config.primary);
|
|
3061
|
-
return l2 ? u2 = l2.push : f2.length > 0 && (u2 = f2[0].push), { collector: e2, elb: u2 };
|
|
3062
|
-
}
|
|
3063
|
-
function ln(n) {
|
|
3064
|
-
if (null === n || "object" != typeof n) return n;
|
|
3065
|
-
if (Array.isArray(n)) return n.map(ln);
|
|
3066
|
-
const e2 = {};
|
|
3067
|
-
for (const [t2, o2] of Object.entries(n)) e2[t2] = "function" == typeof o2 ? o2 : ln(o2);
|
|
3068
|
-
return e2;
|
|
3069
|
-
}
|
|
3070
|
-
function gn(n) {
|
|
3071
|
-
const e2 = [], { simulation: t2, ...o2 } = n, s2 = ln(o2);
|
|
3072
|
-
for (const n2 of t2) {
|
|
3073
|
-
const t3 = n2.startsWith("call:") ? n2.slice(5) : n2, o3 = t3.split(".");
|
|
3074
|
-
let r2 = s2;
|
|
3075
|
-
for (let n3 = 0; n3 < o3.length - 1 && null != r2[o3[n3]]; n3++) r2 = r2[o3[n3]];
|
|
3086
|
+
function Ge(e) {
|
|
3087
|
+
const n = [], { simulation: t, ...o2 } = e, s = Te(o2);
|
|
3088
|
+
for (const e2 of t) {
|
|
3089
|
+
const t2 = e2.startsWith("call:") ? e2.slice(5) : e2, o3 = t2.split(".");
|
|
3090
|
+
let r2 = s;
|
|
3091
|
+
for (let e3 = 0; e3 < o3.length - 1 && null != r2[o3[e3]]; e3++) r2 = r2[o3[e3]];
|
|
3076
3092
|
const i2 = o3[o3.length - 1];
|
|
3077
3093
|
if (null == r2 || !(i2 in r2)) continue;
|
|
3078
3094
|
const a2 = r2[i2];
|
|
3079
|
-
"function" == typeof a2 && (r2[i2] = function(...
|
|
3080
|
-
return
|
|
3095
|
+
"function" == typeof a2 && (r2[i2] = function(...e3) {
|
|
3096
|
+
return n.push({ fn: t2, args: e3, ts: Date.now() }), a2.apply(this, e3);
|
|
3081
3097
|
});
|
|
3082
3098
|
}
|
|
3083
|
-
return { wrappedEnv:
|
|
3084
|
-
}
|
|
3085
|
-
async function dn(n) {
|
|
3086
|
-
const e2 = Date.now();
|
|
3087
|
-
try {
|
|
3088
|
-
switch (n.step) {
|
|
3089
|
-
case "transformer":
|
|
3090
|
-
return await (async function(n2, e3) {
|
|
3091
|
-
const { code: t2, config: o2 = {}, event: s2 } = n2, { collector: r2 } = await fn({ transformers: { sim: { code: t2, config: o2 } } }), i2 = r2.transformers?.sim;
|
|
3092
|
-
if (!i2) throw new Error("Transformer failed to initialize");
|
|
3093
|
-
const a2 = await i2.push(s2, { collector: r2, logger: r2.logger.scope("transformer").scope("sim"), id: "sim", config: i2.config, env: i2.config?.env || {} });
|
|
3094
|
-
let c2;
|
|
3095
|
-
c2 = false === a2 ? [] : null == a2 ? [s2] : [a2.event || s2];
|
|
3096
|
-
return { step: "transformer", name: n2.name, events: c2, calls: [], duration: Date.now() - e3 };
|
|
3097
|
-
})(n, e2);
|
|
3098
|
-
case "source":
|
|
3099
|
-
return await (async function(n2, e3) {
|
|
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);
|
|
3102
|
-
return { step: "source", name: n2.name, events: f2, calls: [], duration: Date.now() - e3 };
|
|
3103
|
-
})(n, e2);
|
|
3104
|
-
case "destination":
|
|
3105
|
-
return await (async function(n2, e3) {
|
|
3106
|
-
const { code: t2, config: o2 = {}, event: s2, consent: r2, env: i2, track: a2 } = n2, c2 = { functional: true, marketing: true, analytics: true };
|
|
3107
|
-
let u2 = [], f2 = i2;
|
|
3108
|
-
if (i2 && a2 && a2.length > 0) {
|
|
3109
|
-
const n3 = gn({ ...i2, simulation: a2 });
|
|
3110
|
-
f2 = n3.wrappedEnv, u2 = n3.calls;
|
|
3111
|
-
}
|
|
3112
|
-
const l2 = { ...o2 };
|
|
3113
|
-
f2 && (l2.env = f2);
|
|
3114
|
-
const { collector: g2 } = await fn({ consent: r2 || c2, destinations: { sim: { code: t2, config: l2 } } });
|
|
3115
|
-
return await g2.push(s2), { step: "destination", name: n2.name, events: [], calls: u2, duration: Date.now() - e3 };
|
|
3116
|
-
})(n, e2);
|
|
3117
|
-
}
|
|
3118
|
-
} catch (t2) {
|
|
3119
|
-
return { step: n.step, name: n.name, events: [], calls: [], duration: Date.now() - e2, error: t2 instanceof Error ? t2 : new Error(String(t2)) };
|
|
3120
|
-
}
|
|
3099
|
+
return { wrappedEnv: s, calls: n };
|
|
3121
3100
|
}
|
|
3122
3101
|
|
|
3123
|
-
// src/commands/
|
|
3102
|
+
// src/commands/push/index.ts
|
|
3124
3103
|
init_cli_logger();
|
|
3125
3104
|
init_core();
|
|
3126
|
-
init_config();
|
|
3127
3105
|
init_tmp();
|
|
3106
|
+
init_config();
|
|
3107
|
+
init_utils();
|
|
3108
|
+
init_bundler();
|
|
3128
3109
|
|
|
3129
|
-
// src/commands/
|
|
3130
|
-
|
|
3131
|
-
const
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
|
|
3135
|
-
continue;
|
|
3136
|
-
}
|
|
3137
|
-
try {
|
|
3138
|
-
const packageName = typedConfig.package;
|
|
3139
|
-
const isDemoPackage = packageName.includes("-demo");
|
|
3140
|
-
const importPath = isDemoPackage ? packageName : `${packageName}/dev`;
|
|
3141
|
-
const module = await import(importPath);
|
|
3142
|
-
const examplesModule = module.examples || module.default?.examples;
|
|
3143
|
-
const envModule = examplesModule?.env;
|
|
3144
|
-
if (envModule?.push) {
|
|
3145
|
-
envs[destKey] = {
|
|
3146
|
-
init: envModule.init,
|
|
3147
|
-
push: envModule.push,
|
|
3148
|
-
simulation: envModule.simulation || []
|
|
3149
|
-
};
|
|
3150
|
-
}
|
|
3151
|
-
} catch {
|
|
3152
|
-
}
|
|
3153
|
-
}
|
|
3154
|
-
return envs;
|
|
3155
|
-
}
|
|
3156
|
-
|
|
3157
|
-
// src/commands/simulate/simulator.ts
|
|
3158
|
-
function callsToUsage(destName, calls) {
|
|
3159
|
-
if (!calls.length) return {};
|
|
3160
|
-
return {
|
|
3161
|
-
[destName]: calls.map((c2) => ({
|
|
3162
|
-
type: "call",
|
|
3163
|
-
path: c2.fn,
|
|
3164
|
-
args: c2.args,
|
|
3165
|
-
timestamp: c2.ts
|
|
3166
|
-
}))
|
|
3167
|
-
};
|
|
3168
|
-
}
|
|
3169
|
-
async function simulateCore(inputPath, event, options = {}) {
|
|
3170
|
-
const logger = createCLILogger({
|
|
3171
|
-
verbose: options.verbose || false,
|
|
3172
|
-
silent: options.silent || false,
|
|
3173
|
-
json: options.json || false
|
|
3174
|
-
});
|
|
3175
|
-
try {
|
|
3176
|
-
logger.debug(`Simulating event: ${JSON.stringify(event)}`);
|
|
3177
|
-
const result = await executeSimulation(event, inputPath, options.platform, {
|
|
3178
|
-
flow: options.flow,
|
|
3179
|
-
step: options.step,
|
|
3180
|
-
verbose: options.verbose
|
|
3181
|
-
});
|
|
3182
|
-
return result;
|
|
3183
|
-
} catch (error) {
|
|
3184
|
-
const errorMessage = getErrorMessage(error);
|
|
3185
|
-
return {
|
|
3186
|
-
success: false,
|
|
3187
|
-
error: errorMessage
|
|
3188
|
-
};
|
|
3189
|
-
}
|
|
3190
|
-
}
|
|
3191
|
-
function formatSimulationResult(result, options = {}) {
|
|
3192
|
-
if (options.json) {
|
|
3193
|
-
const output = {
|
|
3194
|
-
result: result.elbResult,
|
|
3195
|
-
usage: result.usage,
|
|
3196
|
-
duration: result.duration
|
|
3197
|
-
};
|
|
3198
|
-
if (result.capturedEvents) {
|
|
3199
|
-
output.capturedEvents = result.capturedEvents;
|
|
3200
|
-
}
|
|
3201
|
-
return JSON.stringify(output, null, 2);
|
|
3202
|
-
}
|
|
3203
|
-
const lines = [];
|
|
3204
|
-
if (result.success) {
|
|
3205
|
-
lines.push("Simulation completed");
|
|
3206
|
-
} else {
|
|
3207
|
-
lines.push(`Simulation failed: ${result.error}`);
|
|
3110
|
+
// src/commands/push/overrides.ts
|
|
3111
|
+
function buildOverrides(flags, flowConfig) {
|
|
3112
|
+
const simulateFlags = flags.simulate ?? [];
|
|
3113
|
+
const mockFlags = flags.mock ?? [];
|
|
3114
|
+
if (simulateFlags.length === 0 && mockFlags.length === 0) {
|
|
3115
|
+
return {};
|
|
3208
3116
|
}
|
|
3209
|
-
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
|
|
3213
|
-
|
|
3117
|
+
const simulateNames = /* @__PURE__ */ new Set();
|
|
3118
|
+
const sourceSimulateNames = /* @__PURE__ */ new Set();
|
|
3119
|
+
const mockNames = /* @__PURE__ */ new Set();
|
|
3120
|
+
const overrides = {};
|
|
3121
|
+
for (const step of simulateFlags) {
|
|
3122
|
+
const { type, name } = parseStep(step);
|
|
3123
|
+
if (type === "destination") {
|
|
3124
|
+
simulateNames.add(name);
|
|
3125
|
+
if (!overrides.destinations) overrides.destinations = {};
|
|
3126
|
+
overrides.destinations[name] = { simulate: true };
|
|
3127
|
+
} else if (type === "transformer") {
|
|
3128
|
+
if (!overrides.transformers) overrides.transformers = {};
|
|
3129
|
+
overrides.transformers[name] = { simulate: true };
|
|
3130
|
+
} else {
|
|
3131
|
+
sourceSimulateNames.add(name);
|
|
3132
|
+
if (!overrides.sources) overrides.sources = {};
|
|
3133
|
+
overrides.sources[name] = { simulate: true };
|
|
3134
|
+
}
|
|
3135
|
+
}
|
|
3136
|
+
const hasSource = sourceSimulateNames.size > 0;
|
|
3137
|
+
const hasTransformer = overrides.transformers && Object.keys(overrides.transformers).length > 0;
|
|
3138
|
+
const hasDestination = simulateNames.size > 0;
|
|
3139
|
+
const simulatedTypes = [
|
|
3140
|
+
hasSource && "source",
|
|
3141
|
+
hasTransformer && "transformer",
|
|
3142
|
+
hasDestination && "destination"
|
|
3143
|
+
].filter(Boolean);
|
|
3144
|
+
if (simulatedTypes.length > 1) {
|
|
3145
|
+
throw new Error(
|
|
3146
|
+
`Cannot simulate both ${simulatedTypes.join(" and ")} in the same invocation. Run separate commands for each step type.`
|
|
3147
|
+
);
|
|
3214
3148
|
}
|
|
3215
|
-
|
|
3216
|
-
|
|
3217
|
-
|
|
3218
|
-
const startTime = Date.now();
|
|
3219
|
-
const tempDir = getTmpPath();
|
|
3220
|
-
try {
|
|
3221
|
-
await fs12.ensureDir(tempDir);
|
|
3222
|
-
const detected = await detectInput(inputPath, platformOverride);
|
|
3223
|
-
if (!isObject(event) || !("name" in event) || typeof event.name !== "string") {
|
|
3149
|
+
for (const step of mockFlags) {
|
|
3150
|
+
const eqIndex = step.indexOf("=");
|
|
3151
|
+
if (eqIndex === -1) {
|
|
3224
3152
|
throw new Error(
|
|
3225
|
-
|
|
3153
|
+
`Invalid --mock format: "${step}". Expected destination.NAME=VALUE`
|
|
3226
3154
|
);
|
|
3227
3155
|
}
|
|
3228
|
-
const
|
|
3229
|
-
|
|
3156
|
+
const stepPart = step.slice(0, eqIndex);
|
|
3157
|
+
const valuePart = step.slice(eqIndex + 1);
|
|
3158
|
+
const parsed = parseStep(stepPart);
|
|
3159
|
+
if (parsed.type === "source") {
|
|
3230
3160
|
throw new Error(
|
|
3231
|
-
|
|
3161
|
+
`--mock is not supported for sources. Use --simulate source.${parsed.name}`
|
|
3232
3162
|
);
|
|
3233
3163
|
}
|
|
3234
|
-
|
|
3235
|
-
|
|
3236
|
-
|
|
3237
|
-
|
|
3238
|
-
tempDir,
|
|
3239
|
-
startTime,
|
|
3240
|
-
options.flow,
|
|
3241
|
-
options.step
|
|
3242
|
-
);
|
|
3243
|
-
} catch (error) {
|
|
3244
|
-
const duration = Date.now() - startTime;
|
|
3245
|
-
return {
|
|
3246
|
-
success: false,
|
|
3247
|
-
error: getErrorMessage(error),
|
|
3248
|
-
duration
|
|
3249
|
-
};
|
|
3250
|
-
} finally {
|
|
3251
|
-
if (tempDir) {
|
|
3252
|
-
await fs12.remove(tempDir).catch(() => {
|
|
3253
|
-
});
|
|
3164
|
+
if (parsed.type === "transformer" && !parsed.chainType) {
|
|
3165
|
+
throw new Error(
|
|
3166
|
+
`Use --mock destination.NAME.before.${parsed.name}=VALUE for path-specific transformer mocks`
|
|
3167
|
+
);
|
|
3254
3168
|
}
|
|
3255
|
-
|
|
3256
|
-
|
|
3257
|
-
|
|
3258
|
-
|
|
3259
|
-
|
|
3260
|
-
|
|
3261
|
-
|
|
3262
|
-
const
|
|
3263
|
-
|
|
3264
|
-
if (!
|
|
3265
|
-
|
|
3169
|
+
let parsedValue;
|
|
3170
|
+
try {
|
|
3171
|
+
parsedValue = JSON.parse(valuePart);
|
|
3172
|
+
} catch {
|
|
3173
|
+
parsedValue = valuePart;
|
|
3174
|
+
}
|
|
3175
|
+
if (parsed.chainType && parsed.transformerId) {
|
|
3176
|
+
const chainPath = `destination.${parsed.name}.${parsed.chainType}`;
|
|
3177
|
+
if (!overrides.transformerMocks) overrides.transformerMocks = {};
|
|
3178
|
+
if (!overrides.transformerMocks[chainPath])
|
|
3179
|
+
overrides.transformerMocks[chainPath] = {};
|
|
3180
|
+
overrides.transformerMocks[chainPath][parsed.transformerId] = parsedValue;
|
|
3181
|
+
} else {
|
|
3182
|
+
if (simulateNames.has(parsed.name)) {
|
|
3183
|
+
throw new Error(
|
|
3184
|
+
`Destination "${parsed.name}" cannot be in both --simulate and --mock`
|
|
3185
|
+
);
|
|
3186
|
+
}
|
|
3187
|
+
mockNames.add(parsed.name);
|
|
3188
|
+
if (!overrides.destinations) overrides.destinations = {};
|
|
3189
|
+
overrides.destinations[parsed.name] = { config: { mock: parsedValue } };
|
|
3190
|
+
}
|
|
3191
|
+
}
|
|
3192
|
+
const allDestinations = Object.keys(flowConfig.destinations ?? {});
|
|
3193
|
+
const targetedNames = /* @__PURE__ */ new Set([...simulateNames, ...mockNames]);
|
|
3194
|
+
if (targetedNames.size > 0) {
|
|
3195
|
+
if (!overrides.destinations) overrides.destinations = {};
|
|
3196
|
+
for (const destName of allDestinations) {
|
|
3197
|
+
if (!targetedNames.has(destName)) {
|
|
3198
|
+
overrides.destinations[destName] = { config: { disabled: true } };
|
|
3266
3199
|
}
|
|
3267
|
-
return { type, name, config: section[name] };
|
|
3268
3200
|
}
|
|
3269
3201
|
}
|
|
3270
|
-
|
|
3271
|
-
if (destinations) {
|
|
3272
|
-
const [name, config] = Object.entries(destinations)[0];
|
|
3273
|
-
return {
|
|
3274
|
-
type: "destination",
|
|
3275
|
-
name,
|
|
3276
|
-
config
|
|
3277
|
-
};
|
|
3278
|
-
}
|
|
3279
|
-
throw new Error("No destination found in flow config");
|
|
3202
|
+
return overrides;
|
|
3280
3203
|
}
|
|
3281
|
-
|
|
3282
|
-
const
|
|
3283
|
-
|
|
3284
|
-
|
|
3285
|
-
|
|
3286
|
-
|
|
3287
|
-
flowSettings
|
|
3288
|
-
);
|
|
3289
|
-
if (step.type === "destination") {
|
|
3290
|
-
const packageName = step.config.package;
|
|
3291
|
-
if (!packageName) {
|
|
3292
|
-
throw new Error(`Destination "${step.name}" has no package field`);
|
|
3293
|
-
}
|
|
3294
|
-
const destModule = await import(packageName);
|
|
3295
|
-
const code = destModule.default || Object.values(destModule)[0];
|
|
3296
|
-
const destinations = flowSettings.destinations;
|
|
3297
|
-
const envs = await loadDestinationEnvs(destinations || {});
|
|
3298
|
-
const destEnv = envs[step.name];
|
|
3299
|
-
const result = await dn({
|
|
3300
|
-
step: "destination",
|
|
3301
|
-
name: step.name,
|
|
3302
|
-
code,
|
|
3303
|
-
event: typedEvent,
|
|
3304
|
-
config: step.config.config,
|
|
3305
|
-
env: destEnv?.push,
|
|
3306
|
-
track: destEnv?.simulation
|
|
3307
|
-
});
|
|
3308
|
-
const duration = Date.now() - startTime;
|
|
3309
|
-
return {
|
|
3310
|
-
success: !result.error,
|
|
3311
|
-
error: result.error?.message,
|
|
3312
|
-
usage: callsToUsage(step.name, result.calls),
|
|
3313
|
-
duration,
|
|
3314
|
-
logs: []
|
|
3315
|
-
};
|
|
3316
|
-
}
|
|
3317
|
-
if (step.type === "transformer") {
|
|
3318
|
-
const packageName = step.config.package;
|
|
3319
|
-
if (!packageName) {
|
|
3320
|
-
throw new Error(`Transformer "${step.name}" has no package field`);
|
|
3321
|
-
}
|
|
3322
|
-
const mod = await import(packageName);
|
|
3323
|
-
const code = mod.default || Object.values(mod)[0];
|
|
3324
|
-
const result = await dn({
|
|
3325
|
-
step: "transformer",
|
|
3326
|
-
name: step.name,
|
|
3327
|
-
code,
|
|
3328
|
-
event: typedEvent,
|
|
3329
|
-
config: step.config.config
|
|
3330
|
-
});
|
|
3331
|
-
const duration = Date.now() - startTime;
|
|
3332
|
-
return {
|
|
3333
|
-
success: !result.error,
|
|
3334
|
-
error: result.error?.message,
|
|
3335
|
-
capturedEvents: result.events,
|
|
3336
|
-
duration,
|
|
3337
|
-
usage: {},
|
|
3338
|
-
logs: []
|
|
3339
|
-
};
|
|
3204
|
+
function parseStep(step) {
|
|
3205
|
+
const parts = step.split(".");
|
|
3206
|
+
if (parts.length < 2) {
|
|
3207
|
+
throw new Error(
|
|
3208
|
+
`Invalid step format: "${step}". Expected "source.NAME" or "destination.NAME"`
|
|
3209
|
+
);
|
|
3340
3210
|
}
|
|
3341
|
-
|
|
3342
|
-
|
|
3343
|
-
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
async function loadSourcePackage(packageName) {
|
|
3347
|
-
const mainModule = await import(packageName);
|
|
3348
|
-
const code = mainModule.default || Object.values(mainModule)[0];
|
|
3349
|
-
if (!code || typeof code !== "function") {
|
|
3350
|
-
throw new Error(`Package ${packageName} missing source init function`);
|
|
3211
|
+
const prefix = parts[0];
|
|
3212
|
+
if (prefix !== "source" && prefix !== "destination" && prefix !== "transformer") {
|
|
3213
|
+
throw new Error(
|
|
3214
|
+
`Unsupported step type: "${prefix}". Use "source", "destination", or "transformer"`
|
|
3215
|
+
);
|
|
3351
3216
|
}
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
-
|
|
3356
|
-
|
|
3357
|
-
createTrigger = examples.createTrigger;
|
|
3358
|
-
}
|
|
3359
|
-
} catch {
|
|
3217
|
+
const name = parts[1];
|
|
3218
|
+
if (!name) {
|
|
3219
|
+
throw new Error(
|
|
3220
|
+
`Invalid step format: "${step}". Missing name after "${prefix}."`
|
|
3221
|
+
);
|
|
3360
3222
|
}
|
|
3361
|
-
|
|
3362
|
-
|
|
3363
|
-
|
|
3364
|
-
const startTime = Date.now();
|
|
3365
|
-
try {
|
|
3366
|
-
const sources = flowConfig.sources;
|
|
3367
|
-
if (!sources) {
|
|
3368
|
-
throw new Error("Flow config has no sources");
|
|
3369
|
-
}
|
|
3370
|
-
const sourceConfig = sources[options.sourceStep];
|
|
3371
|
-
if (!sourceConfig) {
|
|
3372
|
-
const available = Object.keys(sources).join(", ");
|
|
3223
|
+
if (parts.length >= 4) {
|
|
3224
|
+
const chainType = parts[2];
|
|
3225
|
+
if (chainType !== "before" && chainType !== "next") {
|
|
3373
3226
|
throw new Error(
|
|
3374
|
-
`
|
|
3227
|
+
`Invalid chain type: "${chainType}". Use "before" or "next"`
|
|
3375
3228
|
);
|
|
3376
3229
|
}
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
}
|
|
3380
|
-
const { code, createTrigger } = await loadSourcePackage(
|
|
3381
|
-
sourceConfig.package
|
|
3382
|
-
);
|
|
3383
|
-
if (!createTrigger) {
|
|
3230
|
+
const transformerId = parts[3];
|
|
3231
|
+
if (!transformerId) {
|
|
3384
3232
|
throw new Error(
|
|
3385
|
-
`
|
|
3233
|
+
`Invalid step format: "${step}". Missing transformer name after "${chainType}."`
|
|
3386
3234
|
);
|
|
3387
3235
|
}
|
|
3388
|
-
|
|
3389
|
-
step: "source",
|
|
3390
|
-
name: options.sourceStep,
|
|
3391
|
-
code,
|
|
3392
|
-
config: sourceConfig.config || {},
|
|
3393
|
-
createTrigger,
|
|
3394
|
-
input: sourceInput || { content: void 0 }
|
|
3395
|
-
});
|
|
3396
|
-
return {
|
|
3397
|
-
success: !result.error,
|
|
3398
|
-
error: result.error?.message,
|
|
3399
|
-
capturedEvents: result.events,
|
|
3400
|
-
duration: Date.now() - startTime
|
|
3401
|
-
};
|
|
3402
|
-
} catch (error) {
|
|
3403
|
-
return {
|
|
3404
|
-
success: false,
|
|
3405
|
-
error: getErrorMessage(error),
|
|
3406
|
-
duration: Date.now() - startTime
|
|
3407
|
-
};
|
|
3408
|
-
}
|
|
3409
|
-
}
|
|
3410
|
-
|
|
3411
|
-
// src/commands/simulate/index.ts
|
|
3412
|
-
init_cli_logger();
|
|
3413
|
-
init_core();
|
|
3414
|
-
init_config();
|
|
3415
|
-
init_validators();
|
|
3416
|
-
|
|
3417
|
-
// src/commands/simulate/example-loader.ts
|
|
3418
|
-
function findExample(config, exampleName, stepTarget) {
|
|
3419
|
-
if (stepTarget) {
|
|
3420
|
-
return findExampleInStep(config, exampleName, stepTarget);
|
|
3421
|
-
}
|
|
3422
|
-
return findExampleAcrossSteps(config, exampleName);
|
|
3423
|
-
}
|
|
3424
|
-
function findExampleInStep(config, exampleName, stepTarget) {
|
|
3425
|
-
const dotIndex = stepTarget.indexOf(".");
|
|
3426
|
-
if (dotIndex === -1) {
|
|
3427
|
-
throw new Error(
|
|
3428
|
-
`Invalid --step format: "${stepTarget}". Expected "type.name" (e.g. "destination.gtag")`
|
|
3429
|
-
);
|
|
3430
|
-
}
|
|
3431
|
-
const type = stepTarget.substring(0, dotIndex);
|
|
3432
|
-
const name = stepTarget.substring(dotIndex + 1);
|
|
3433
|
-
const stepMap = getStepMap(config, type);
|
|
3434
|
-
if (!stepMap) {
|
|
3435
|
-
throw new Error(`No ${type}s found in flow config`);
|
|
3236
|
+
return { type: prefix, name, chainType, transformerId };
|
|
3436
3237
|
}
|
|
3437
|
-
|
|
3438
|
-
if (!step) {
|
|
3439
|
-
const available = Object.keys(stepMap).join(", ");
|
|
3440
|
-
throw new Error(`${type} "${name}" not found. Available: ${available}`);
|
|
3441
|
-
}
|
|
3442
|
-
const examples = step.examples;
|
|
3443
|
-
if (!examples || !examples[exampleName]) {
|
|
3444
|
-
const available = examples ? Object.keys(examples).join(", ") : "none";
|
|
3238
|
+
if (parts.length === 3) {
|
|
3445
3239
|
throw new Error(
|
|
3446
|
-
`
|
|
3240
|
+
`Invalid step format: "${step}". Specify a transformer: "${step}.TRANSFORMER_NAME"`
|
|
3447
3241
|
);
|
|
3448
3242
|
}
|
|
3449
|
-
return {
|
|
3450
|
-
stepType: type,
|
|
3451
|
-
stepName: name,
|
|
3452
|
-
exampleName,
|
|
3453
|
-
example: examples[exampleName]
|
|
3454
|
-
};
|
|
3243
|
+
return { type: prefix, name };
|
|
3455
3244
|
}
|
|
3456
|
-
|
|
3457
|
-
|
|
3458
|
-
|
|
3459
|
-
|
|
3460
|
-
const
|
|
3461
|
-
if (
|
|
3462
|
-
|
|
3463
|
-
|
|
3464
|
-
|
|
3465
|
-
|
|
3466
|
-
|
|
3467
|
-
|
|
3468
|
-
|
|
3469
|
-
|
|
3470
|
-
|
|
3245
|
+
|
|
3246
|
+
// src/commands/push/apply-overrides.ts
|
|
3247
|
+
function applyOverrides(config, overrides) {
|
|
3248
|
+
if (overrides.destinations) {
|
|
3249
|
+
const destinations = config.destinations;
|
|
3250
|
+
if (destinations) {
|
|
3251
|
+
for (const [id, override] of Object.entries(overrides.destinations)) {
|
|
3252
|
+
const dest = destinations[id];
|
|
3253
|
+
if (!dest) continue;
|
|
3254
|
+
if (!dest.config) dest.config = {};
|
|
3255
|
+
const destConfig = dest.config;
|
|
3256
|
+
if (override.config?.disabled) destConfig.disabled = true;
|
|
3257
|
+
if (override.config?.mock !== void 0)
|
|
3258
|
+
destConfig.mock = override.config.mock;
|
|
3259
|
+
if (override.env) {
|
|
3260
|
+
destConfig.env = override.env;
|
|
3261
|
+
}
|
|
3471
3262
|
}
|
|
3472
3263
|
}
|
|
3473
3264
|
}
|
|
3474
|
-
if (
|
|
3475
|
-
|
|
3476
|
-
|
|
3477
|
-
|
|
3478
|
-
|
|
3479
|
-
|
|
3480
|
-
|
|
3481
|
-
|
|
3482
|
-
|
|
3483
|
-
|
|
3484
|
-
|
|
3485
|
-
|
|
3486
|
-
|
|
3487
|
-
|
|
3488
|
-
|
|
3489
|
-
|
|
3490
|
-
return config.transformers;
|
|
3491
|
-
case "destination":
|
|
3492
|
-
return config.destinations;
|
|
3493
|
-
default:
|
|
3494
|
-
throw new Error(
|
|
3495
|
-
`Invalid step type: "${type}". Must be "source", "transformer", or "destination"`
|
|
3496
|
-
);
|
|
3265
|
+
if (overrides.transformerMocks) {
|
|
3266
|
+
const transformers = config.transformers;
|
|
3267
|
+
if (transformers) {
|
|
3268
|
+
for (const [chainPath, mocks] of Object.entries(
|
|
3269
|
+
overrides.transformerMocks
|
|
3270
|
+
)) {
|
|
3271
|
+
for (const [transformerId, mockValue] of Object.entries(mocks)) {
|
|
3272
|
+
const transformer = transformers[transformerId];
|
|
3273
|
+
if (!transformer) continue;
|
|
3274
|
+
if (!transformer.config) transformer.config = {};
|
|
3275
|
+
const tConfig = transformer.config;
|
|
3276
|
+
if (!tConfig.chainMocks) tConfig.chainMocks = {};
|
|
3277
|
+
tConfig.chainMocks[chainPath] = mockValue;
|
|
3278
|
+
}
|
|
3279
|
+
}
|
|
3280
|
+
}
|
|
3497
3281
|
}
|
|
3498
3282
|
}
|
|
3499
3283
|
|
|
3500
|
-
// src/commands/
|
|
3501
|
-
|
|
3502
|
-
|
|
3503
|
-
|
|
3504
|
-
|
|
3505
|
-
|
|
3284
|
+
// src/commands/push/index.ts
|
|
3285
|
+
init_package_path();
|
|
3286
|
+
|
|
3287
|
+
// src/commands/push/flow-context.ts
|
|
3288
|
+
init_utils2();
|
|
3289
|
+
import path14 from "path";
|
|
3290
|
+
import { pathToFileURL } from "url";
|
|
3291
|
+
import { JSDOM, VirtualConsole } from "jsdom";
|
|
3292
|
+
|
|
3293
|
+
// src/commands/push/async-drain.ts
|
|
3294
|
+
function installTimerInterception(options = {}) {
|
|
3295
|
+
let nextId = 1;
|
|
3296
|
+
const pending = /* @__PURE__ */ new Map();
|
|
3297
|
+
const realSetTimeout = globalThis.setTimeout.bind(globalThis);
|
|
3298
|
+
const targets = [];
|
|
3299
|
+
function patchTarget(target) {
|
|
3300
|
+
targets.push({
|
|
3301
|
+
target,
|
|
3302
|
+
setTimeout: target.setTimeout,
|
|
3303
|
+
clearTimeout: target.clearTimeout,
|
|
3304
|
+
setInterval: target.setInterval,
|
|
3305
|
+
clearInterval: target.clearInterval
|
|
3306
|
+
});
|
|
3307
|
+
target.setTimeout = (callback, delay, ...args) => {
|
|
3308
|
+
if (typeof callback !== "function") return 0;
|
|
3309
|
+
const id = nextId++;
|
|
3310
|
+
pending.set(id, { id, callback, delay: delay ?? 0, type: "timeout", args, cleared: false });
|
|
3311
|
+
return id;
|
|
3312
|
+
};
|
|
3313
|
+
target.clearTimeout = (id) => {
|
|
3314
|
+
if (id == null) return;
|
|
3315
|
+
const numId = typeof id === "number" ? id : Number(id);
|
|
3316
|
+
const entry = pending.get(numId);
|
|
3317
|
+
if (entry) entry.cleared = true;
|
|
3318
|
+
};
|
|
3319
|
+
target.setInterval = (callback, delay, ...args) => {
|
|
3320
|
+
if (typeof callback !== "function") return 0;
|
|
3321
|
+
const id = nextId++;
|
|
3322
|
+
pending.set(id, { id, callback, delay: delay ?? 0, type: "interval", args, cleared: false });
|
|
3323
|
+
return id;
|
|
3324
|
+
};
|
|
3325
|
+
target.clearInterval = target.clearTimeout;
|
|
3326
|
+
}
|
|
3327
|
+
patchTarget(globalThis);
|
|
3328
|
+
if (options.domWindow && options.domWindow !== globalThis) {
|
|
3329
|
+
patchTarget(options.domWindow);
|
|
3330
|
+
}
|
|
3331
|
+
const drainMicrotasks = () => new Promise((resolve3) => realSetTimeout(resolve3, 0));
|
|
3332
|
+
async function flush(wallTimeout = 5e3) {
|
|
3333
|
+
const deadline = Date.now() + wallTimeout;
|
|
3334
|
+
const maxIterations = 100;
|
|
3335
|
+
let iterations = 0;
|
|
3336
|
+
while (iterations < maxIterations) {
|
|
3337
|
+
await drainMicrotasks();
|
|
3338
|
+
const ready = Array.from(pending.values()).filter((t) => !t.cleared).sort((a2, b2) => a2.delay - b2.delay);
|
|
3339
|
+
if (ready.length === 0) break;
|
|
3340
|
+
for (const timer of ready) {
|
|
3341
|
+
if (timer.cleared) continue;
|
|
3342
|
+
pending.delete(timer.id);
|
|
3343
|
+
if (timer.type === "interval") {
|
|
3344
|
+
timer.cleared = true;
|
|
3345
|
+
const newId = nextId++;
|
|
3346
|
+
pending.set(newId, { ...timer, id: newId, cleared: false });
|
|
3347
|
+
}
|
|
3348
|
+
try {
|
|
3349
|
+
timer.callback(...timer.args);
|
|
3350
|
+
} catch (err) {
|
|
3351
|
+
console.warn("[async-drain] Timer callback error:", err);
|
|
3352
|
+
}
|
|
3353
|
+
}
|
|
3354
|
+
await drainMicrotasks();
|
|
3355
|
+
if (Date.now() > deadline) {
|
|
3356
|
+
break;
|
|
3357
|
+
}
|
|
3358
|
+
iterations++;
|
|
3359
|
+
}
|
|
3360
|
+
pending.clear();
|
|
3506
3361
|
}
|
|
3507
|
-
|
|
3508
|
-
|
|
3509
|
-
|
|
3510
|
-
|
|
3511
|
-
|
|
3512
|
-
|
|
3513
|
-
|
|
3514
|
-
|
|
3515
|
-
|
|
3516
|
-
|
|
3362
|
+
function countPending() {
|
|
3363
|
+
return Array.from(pending.values()).filter((t) => !t.cleared).length;
|
|
3364
|
+
}
|
|
3365
|
+
function restore() {
|
|
3366
|
+
for (const saved of targets) {
|
|
3367
|
+
saved.target.setTimeout = saved.setTimeout;
|
|
3368
|
+
saved.target.clearTimeout = saved.clearTimeout;
|
|
3369
|
+
saved.target.setInterval = saved.setInterval;
|
|
3370
|
+
saved.target.clearInterval = saved.clearInterval;
|
|
3371
|
+
}
|
|
3372
|
+
pending.clear();
|
|
3373
|
+
}
|
|
3374
|
+
return { flush, countPending, restore };
|
|
3517
3375
|
}
|
|
3518
3376
|
|
|
3519
|
-
// src/commands/
|
|
3520
|
-
async function
|
|
3521
|
-
const logger
|
|
3377
|
+
// src/commands/push/flow-context.ts
|
|
3378
|
+
async function withFlowContext(options, fn) {
|
|
3379
|
+
const { esmPath, platform, logger, snapshotCode, timeout, networkCalls, asyncDrain } = options;
|
|
3522
3380
|
const startTime = Date.now();
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
|
|
3526
|
-
|
|
3527
|
-
|
|
3528
|
-
|
|
3529
|
-
|
|
3530
|
-
|
|
3531
|
-
|
|
3532
|
-
|
|
3533
|
-
|
|
3534
|
-
|
|
3535
|
-
}
|
|
3536
|
-
const result = await simulate(config, options.event, {
|
|
3537
|
-
flow: options.flow,
|
|
3538
|
-
json: options.json,
|
|
3539
|
-
verbose: options.verbose,
|
|
3540
|
-
silent: options.silent,
|
|
3541
|
-
platform: options.platform,
|
|
3542
|
-
step: options.step
|
|
3381
|
+
const g2 = global;
|
|
3382
|
+
let savedWindow, savedDocument, savedNavigator;
|
|
3383
|
+
let savedFetch;
|
|
3384
|
+
let dom;
|
|
3385
|
+
let timerControl;
|
|
3386
|
+
if (platform === "web") {
|
|
3387
|
+
const virtualConsole = new VirtualConsole();
|
|
3388
|
+
dom = new JSDOM("<!DOCTYPE html><html><body></body></html>", {
|
|
3389
|
+
url: "http://localhost",
|
|
3390
|
+
runScripts: "dangerously",
|
|
3391
|
+
resources: "usable",
|
|
3392
|
+
virtualConsole
|
|
3543
3393
|
});
|
|
3544
|
-
|
|
3545
|
-
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
|
|
3549
|
-
|
|
3394
|
+
savedWindow = g2.window;
|
|
3395
|
+
savedDocument = g2.document;
|
|
3396
|
+
savedNavigator = g2.navigator;
|
|
3397
|
+
g2.window = dom.window;
|
|
3398
|
+
g2.document = dom.window.document;
|
|
3399
|
+
Object.defineProperty(global, "navigator", {
|
|
3400
|
+
value: dom.window.navigator,
|
|
3401
|
+
configurable: true,
|
|
3402
|
+
writable: true
|
|
3550
3403
|
});
|
|
3551
|
-
|
|
3552
|
-
|
|
3553
|
-
|
|
3554
|
-
|
|
3555
|
-
if (options.json) {
|
|
3556
|
-
const errorOutput = JSON.stringify(
|
|
3557
|
-
{
|
|
3558
|
-
success: false,
|
|
3559
|
-
error: errorMessage,
|
|
3560
|
-
duration: (Date.now() - startTime) / 1e3
|
|
3561
|
-
},
|
|
3562
|
-
null,
|
|
3563
|
-
2
|
|
3564
|
-
);
|
|
3565
|
-
await writeResult(errorOutput + "\n", { output: options.output });
|
|
3566
|
-
} else {
|
|
3567
|
-
logger.error(`Error: ${errorMessage}`);
|
|
3404
|
+
if (networkCalls) {
|
|
3405
|
+
savedFetch = global.fetch;
|
|
3406
|
+
applyNetworkPolyfills(dom, networkCalls);
|
|
3407
|
+
global.fetch = dom.window.fetch;
|
|
3568
3408
|
}
|
|
3569
|
-
process.exit(1);
|
|
3570
3409
|
}
|
|
3571
|
-
|
|
3572
|
-
|
|
3573
|
-
|
|
3574
|
-
|
|
3575
|
-
"simulate() currently only supports config file paths. Please provide a path to a configuration file."
|
|
3576
|
-
);
|
|
3410
|
+
if (asyncDrain) {
|
|
3411
|
+
timerControl = installTimerInterception({
|
|
3412
|
+
domWindow: platform === "web" && dom ? dom.window : void 0
|
|
3413
|
+
});
|
|
3577
3414
|
}
|
|
3578
|
-
|
|
3579
|
-
|
|
3580
|
-
|
|
3581
|
-
|
|
3582
|
-
|
|
3583
|
-
|
|
3584
|
-
|
|
3585
|
-
|
|
3586
|
-
|
|
3587
|
-
|
|
3588
|
-
const flowName = options.flow || (flowNames.length === 1 ? flowNames[0] : void 0);
|
|
3589
|
-
if (!flowName) {
|
|
3590
|
-
throw new Error(
|
|
3591
|
-
`Multiple flows found. Use --flow to specify which flow.
|
|
3592
|
-
Available: ${flowNames.join(", ")}`
|
|
3593
|
-
);
|
|
3415
|
+
try {
|
|
3416
|
+
if (snapshotCode) {
|
|
3417
|
+
if (platform === "web" && dom) {
|
|
3418
|
+
logger.debug("Evaluating snapshot in JSDOM");
|
|
3419
|
+
dom.window.eval(snapshotCode);
|
|
3420
|
+
} else {
|
|
3421
|
+
logger.debug("Evaluating snapshot in Node");
|
|
3422
|
+
const vm = await import("vm");
|
|
3423
|
+
vm.runInThisContext(snapshotCode);
|
|
3424
|
+
}
|
|
3594
3425
|
}
|
|
3595
|
-
const
|
|
3596
|
-
|
|
3426
|
+
const fileUrl = pathToFileURL(path14.resolve(esmPath)).href;
|
|
3427
|
+
const module = await import(`${fileUrl}?t=${Date.now()}`);
|
|
3428
|
+
const { wireConfig, startFlow } = module;
|
|
3429
|
+
if (typeof wireConfig !== "function" || typeof startFlow !== "function") {
|
|
3597
3430
|
throw new Error(
|
|
3598
|
-
|
|
3431
|
+
"Invalid ESM bundle: missing wireConfig or startFlow exports"
|
|
3599
3432
|
);
|
|
3600
3433
|
}
|
|
3601
|
-
const
|
|
3602
|
-
|
|
3603
|
-
|
|
3604
|
-
|
|
3605
|
-
|
|
3606
|
-
|
|
3607
|
-
|
|
3608
|
-
|
|
3609
|
-
|
|
3610
|
-
|
|
3434
|
+
const flowModule = {
|
|
3435
|
+
wireConfig,
|
|
3436
|
+
startFlow,
|
|
3437
|
+
__configData: module.__configData
|
|
3438
|
+
};
|
|
3439
|
+
if (timerControl) {
|
|
3440
|
+
const result = await fn(flowModule);
|
|
3441
|
+
await timerControl.flush(asyncDrain?.timeout ?? 5e3);
|
|
3442
|
+
return result;
|
|
3443
|
+
} else if (timeout) {
|
|
3444
|
+
const timeoutPromise = new Promise((_2, reject) => {
|
|
3445
|
+
setTimeout(
|
|
3446
|
+
() => reject(new Error(`Push timeout after ${timeout}ms`)),
|
|
3447
|
+
timeout
|
|
3448
|
+
);
|
|
3449
|
+
});
|
|
3450
|
+
return await Promise.race([fn(flowModule), timeoutPromise]);
|
|
3451
|
+
}
|
|
3452
|
+
return await fn(flowModule);
|
|
3453
|
+
} catch (error) {
|
|
3454
|
+
return {
|
|
3455
|
+
success: false,
|
|
3456
|
+
duration: Date.now() - startTime,
|
|
3457
|
+
error: getErrorMessage(error)
|
|
3458
|
+
};
|
|
3459
|
+
} finally {
|
|
3460
|
+
if (timerControl) timerControl.restore();
|
|
3461
|
+
if (savedFetch !== void 0) {
|
|
3462
|
+
cleanupNetworkPolyfills(savedFetch);
|
|
3463
|
+
}
|
|
3464
|
+
if (platform === "web") {
|
|
3465
|
+
if (savedWindow !== void 0) g2.window = savedWindow;
|
|
3466
|
+
else delete g2.window;
|
|
3467
|
+
if (savedDocument !== void 0) g2.document = savedDocument;
|
|
3468
|
+
else delete g2.document;
|
|
3469
|
+
if (savedNavigator !== void 0) {
|
|
3470
|
+
Object.defineProperty(global, "navigator", {
|
|
3471
|
+
value: savedNavigator,
|
|
3472
|
+
configurable: true,
|
|
3473
|
+
writable: true
|
|
3474
|
+
});
|
|
3475
|
+
} else {
|
|
3476
|
+
delete g2.navigator;
|
|
3611
3477
|
}
|
|
3612
|
-
|
|
3613
|
-
} else {
|
|
3614
|
-
result = await simulateCore(configOrPath, resolvedEvent, {
|
|
3615
|
-
json: options.json ?? false,
|
|
3616
|
-
verbose: options.verbose ?? false,
|
|
3617
|
-
silent: options.silent ?? false,
|
|
3618
|
-
flow: options.flow,
|
|
3619
|
-
platform: options.platform,
|
|
3620
|
-
step: options.step
|
|
3621
|
-
});
|
|
3478
|
+
}
|
|
3622
3479
|
}
|
|
3623
|
-
|
|
3480
|
+
}
|
|
3481
|
+
function applyNetworkPolyfills(dom, networkCalls) {
|
|
3482
|
+
dom.window.fetch = (async (input, init) => {
|
|
3483
|
+
const url = typeof input === "string" ? input : input.toString();
|
|
3484
|
+
const method = init?.method || "GET";
|
|
3485
|
+
const body = init?.body !== void 0 && init?.body !== null ? String(init.body) : null;
|
|
3486
|
+
const headers = {};
|
|
3487
|
+
if (init?.headers) {
|
|
3488
|
+
if (init.headers instanceof Headers) {
|
|
3489
|
+
init.headers.forEach((v2, k2) => {
|
|
3490
|
+
headers[k2] = v2;
|
|
3491
|
+
});
|
|
3492
|
+
} else if (typeof init.headers === "object") {
|
|
3493
|
+
Object.entries(init.headers).forEach(
|
|
3494
|
+
([k2, v2]) => {
|
|
3495
|
+
headers[k2] = v2;
|
|
3496
|
+
}
|
|
3497
|
+
);
|
|
3498
|
+
}
|
|
3499
|
+
}
|
|
3500
|
+
networkCalls.push({
|
|
3501
|
+
type: "fetch",
|
|
3502
|
+
url,
|
|
3503
|
+
method,
|
|
3504
|
+
body,
|
|
3505
|
+
headers,
|
|
3506
|
+
timestamp: Date.now()
|
|
3507
|
+
});
|
|
3508
|
+
return new Response("", { status: 200, statusText: "OK" });
|
|
3509
|
+
});
|
|
3510
|
+
dom.window.navigator.sendBeacon = (url, data) => {
|
|
3511
|
+
const body = data !== void 0 && data !== null ? String(data) : null;
|
|
3512
|
+
networkCalls.push({ type: "beacon", url, body, timestamp: Date.now() });
|
|
3513
|
+
return true;
|
|
3514
|
+
};
|
|
3515
|
+
}
|
|
3516
|
+
function cleanupNetworkPolyfills(savedFetch) {
|
|
3517
|
+
global.fetch = savedFetch;
|
|
3624
3518
|
}
|
|
3625
3519
|
|
|
3626
|
-
// src/commands/push/
|
|
3520
|
+
// src/commands/push/prepare.ts
|
|
3627
3521
|
init_cli_logger();
|
|
3628
|
-
init_core();
|
|
3629
3522
|
init_tmp();
|
|
3630
3523
|
init_config();
|
|
3631
3524
|
init_bundler();
|
|
3632
|
-
import
|
|
3633
|
-
import
|
|
3634
|
-
import fs13 from "fs-extra";
|
|
3525
|
+
import path15 from "path";
|
|
3526
|
+
import fs14 from "fs-extra";
|
|
3635
3527
|
import { getPlatform as getPlatform3 } from "@walkeros/core";
|
|
3636
|
-
|
|
3637
|
-
|
|
3528
|
+
async function prepareFlow(options) {
|
|
3529
|
+
const logger = createCLILogger({
|
|
3530
|
+
silent: options.silent,
|
|
3531
|
+
verbose: options.verbose
|
|
3532
|
+
});
|
|
3533
|
+
logger.debug("Loading flow configuration");
|
|
3534
|
+
const { flowSettings, buildOptions } = await loadFlowConfig(
|
|
3535
|
+
options.configPath,
|
|
3536
|
+
{
|
|
3537
|
+
flowName: options.flow,
|
|
3538
|
+
logger
|
|
3539
|
+
}
|
|
3540
|
+
);
|
|
3541
|
+
const platform = getPlatform3(flowSettings);
|
|
3542
|
+
const configDir = buildOptions.configDir || process.cwd();
|
|
3543
|
+
const overrides = buildOverrides(
|
|
3544
|
+
{ simulate: options.simulate, mock: options.mock },
|
|
3545
|
+
flowSettings
|
|
3546
|
+
);
|
|
3547
|
+
if (overrides.destinations) {
|
|
3548
|
+
const { loadDestinationEnvs: loadDestinationEnvs2 } = await Promise.resolve().then(() => (init_env_loader(), env_loader_exports));
|
|
3549
|
+
const envs = await loadDestinationEnvs2(
|
|
3550
|
+
flowSettings.destinations ?? {},
|
|
3551
|
+
flowSettings.packages,
|
|
3552
|
+
configDir
|
|
3553
|
+
);
|
|
3554
|
+
for (const [destId, env] of Object.entries(envs)) {
|
|
3555
|
+
if (overrides.destinations[destId] && env.push) {
|
|
3556
|
+
overrides.destinations[destId].env = env.push;
|
|
3557
|
+
if (env.simulation && env.simulation.length > 0) {
|
|
3558
|
+
overrides.destinations[destId].simulation = env.simulation;
|
|
3559
|
+
}
|
|
3560
|
+
}
|
|
3561
|
+
}
|
|
3562
|
+
}
|
|
3563
|
+
logger.debug("Bundling flow configuration");
|
|
3564
|
+
const tempDir = getTmpPath(
|
|
3565
|
+
void 0,
|
|
3566
|
+
`push-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`
|
|
3567
|
+
);
|
|
3568
|
+
await fs14.ensureDir(tempDir);
|
|
3569
|
+
const bundlePath = path15.join(tempDir, "bundle.mjs");
|
|
3570
|
+
const pushBuildOptions = {
|
|
3571
|
+
...buildOptions,
|
|
3572
|
+
output: bundlePath,
|
|
3573
|
+
format: "esm",
|
|
3574
|
+
platform: platform === "web" ? "browser" : "node",
|
|
3575
|
+
skipWrapper: true
|
|
3576
|
+
// CLI imports ESM directly -- no platform wrapper
|
|
3577
|
+
};
|
|
3578
|
+
await bundleCore(flowSettings, pushBuildOptions, logger, false);
|
|
3579
|
+
logger.debug(`Bundle created: ${bundlePath}`);
|
|
3580
|
+
return {
|
|
3581
|
+
bundlePath,
|
|
3582
|
+
platform,
|
|
3583
|
+
overrides,
|
|
3584
|
+
flowSettings,
|
|
3585
|
+
configDir,
|
|
3586
|
+
cleanup: async () => {
|
|
3587
|
+
await fs14.remove(tempDir).catch(() => {
|
|
3588
|
+
});
|
|
3589
|
+
}
|
|
3590
|
+
};
|
|
3591
|
+
}
|
|
3592
|
+
|
|
3593
|
+
// src/commands/push/index.ts
|
|
3594
|
+
import { schemas as schemas3 } from "@walkeros/core/dev";
|
|
3595
|
+
function resolveBeforeChain(before, transformers, ingest, event) {
|
|
3596
|
+
if (!before) return [];
|
|
3597
|
+
const next = before;
|
|
3598
|
+
if (isRouteArray(next)) {
|
|
3599
|
+
const compiled = compileNext(next);
|
|
3600
|
+
const resolved = resolveNext(compiled, buildCacheContext(ingest, event));
|
|
3601
|
+
if (!resolved) return [];
|
|
3602
|
+
return Z(resolved, X(transformers));
|
|
3603
|
+
}
|
|
3604
|
+
return Z(
|
|
3605
|
+
next,
|
|
3606
|
+
X(transformers)
|
|
3607
|
+
);
|
|
3608
|
+
}
|
|
3638
3609
|
async function pushCore(inputPath, event, options = {}) {
|
|
3639
3610
|
const logger = createCLILogger({
|
|
3640
3611
|
silent: options.silent,
|
|
@@ -3643,53 +3614,45 @@ async function pushCore(inputPath, event, options = {}) {
|
|
|
3643
3614
|
const startTime = Date.now();
|
|
3644
3615
|
let tempDir;
|
|
3645
3616
|
try {
|
|
3646
|
-
const eventResult = schemas2.PartialEventSchema.safeParse(event);
|
|
3647
|
-
if (!eventResult.success) {
|
|
3648
|
-
const errors = eventResult.error.issues.map((issue) => `${String(issue.path.join("."))}: ${issue.message}`).join(", ");
|
|
3649
|
-
throw new Error(`Invalid event: ${errors}`);
|
|
3650
|
-
}
|
|
3651
|
-
const parsedEvent = eventResult.data;
|
|
3652
|
-
if (!parsedEvent.name) {
|
|
3653
|
-
throw new Error('Invalid event: Missing required "name" property');
|
|
3654
|
-
}
|
|
3655
|
-
const validatedEvent = {
|
|
3656
|
-
name: parsedEvent.name,
|
|
3657
|
-
data: parsedEvent.data || {}
|
|
3658
|
-
};
|
|
3659
|
-
if (!validatedEvent.name.includes(" ")) {
|
|
3660
|
-
logger.info(
|
|
3661
|
-
`Warning: Event name "${validatedEvent.name}" should follow "ENTITY ACTION" format (e.g., "page view")`
|
|
3662
|
-
);
|
|
3663
|
-
}
|
|
3664
3617
|
logger.debug("Detecting input type");
|
|
3665
3618
|
const detected = await detectInput(
|
|
3666
3619
|
inputPath,
|
|
3667
3620
|
options.platform
|
|
3668
3621
|
);
|
|
3669
3622
|
let result;
|
|
3623
|
+
let snapshotCode;
|
|
3624
|
+
if (options.snapshot) {
|
|
3625
|
+
snapshotCode = await loadConfig(options.snapshot, {
|
|
3626
|
+
json: false
|
|
3627
|
+
});
|
|
3628
|
+
logger.debug(`Snapshot loaded (${snapshotCode.length} bytes)`);
|
|
3629
|
+
}
|
|
3670
3630
|
if (detected.type === "config") {
|
|
3671
3631
|
result = await executeConfigPush(
|
|
3672
3632
|
{
|
|
3673
3633
|
config: inputPath,
|
|
3674
3634
|
flow: options.flow,
|
|
3675
|
-
verbose: options.verbose
|
|
3635
|
+
verbose: options.verbose,
|
|
3636
|
+
mock: options.mock
|
|
3676
3637
|
},
|
|
3677
|
-
|
|
3638
|
+
event,
|
|
3678
3639
|
logger,
|
|
3679
3640
|
(dir) => {
|
|
3680
3641
|
tempDir = dir;
|
|
3681
|
-
}
|
|
3642
|
+
},
|
|
3643
|
+
snapshotCode
|
|
3682
3644
|
);
|
|
3683
3645
|
} else {
|
|
3684
3646
|
result = await executeBundlePush(
|
|
3685
3647
|
detected.content,
|
|
3686
3648
|
detected.platform,
|
|
3687
|
-
|
|
3649
|
+
event,
|
|
3688
3650
|
logger,
|
|
3689
3651
|
(dir) => {
|
|
3690
3652
|
tempDir = dir;
|
|
3691
3653
|
},
|
|
3692
|
-
|
|
3654
|
+
void 0,
|
|
3655
|
+
snapshotCode
|
|
3693
3656
|
);
|
|
3694
3657
|
}
|
|
3695
3658
|
return result;
|
|
@@ -3701,7 +3664,7 @@ async function pushCore(inputPath, event, options = {}) {
|
|
|
3701
3664
|
};
|
|
3702
3665
|
} finally {
|
|
3703
3666
|
if (tempDir) {
|
|
3704
|
-
await
|
|
3667
|
+
await fs15.remove(tempDir).catch(() => {
|
|
3705
3668
|
});
|
|
3706
3669
|
}
|
|
3707
3670
|
}
|
|
@@ -3712,21 +3675,63 @@ async function pushCommand(options) {
|
|
|
3712
3675
|
try {
|
|
3713
3676
|
let config;
|
|
3714
3677
|
if (isStdinPiped() && !options.config) {
|
|
3715
|
-
|
|
3716
|
-
const tmpPath = getTmpPath(void 0, "stdin-push.json");
|
|
3717
|
-
await fs13.ensureDir(path12.dirname(tmpPath));
|
|
3718
|
-
await fs13.writeFile(tmpPath, stdinContent, "utf-8");
|
|
3719
|
-
config = tmpPath;
|
|
3678
|
+
config = await readStdinToTempFile("push");
|
|
3720
3679
|
} else {
|
|
3721
3680
|
config = options.config || "bundle.config.json";
|
|
3722
3681
|
}
|
|
3723
|
-
|
|
3724
|
-
|
|
3725
|
-
|
|
3726
|
-
|
|
3727
|
-
|
|
3728
|
-
|
|
3729
|
-
|
|
3682
|
+
let resolvedEvent = options.event;
|
|
3683
|
+
if (typeof options.event === "string") {
|
|
3684
|
+
resolvedEvent = await loadJsonFromSource(options.event, {
|
|
3685
|
+
name: "event"
|
|
3686
|
+
});
|
|
3687
|
+
}
|
|
3688
|
+
const simulateFlag = options.simulate?.[0];
|
|
3689
|
+
let result;
|
|
3690
|
+
if (simulateFlag?.startsWith("source.")) {
|
|
3691
|
+
result = await simulateSource(config, resolvedEvent, {
|
|
3692
|
+
sourceId: simulateFlag.replace("source.", ""),
|
|
3693
|
+
flow: options.flow,
|
|
3694
|
+
silent: options.silent,
|
|
3695
|
+
verbose: options.verbose,
|
|
3696
|
+
snapshot: options.snapshot
|
|
3697
|
+
});
|
|
3698
|
+
} else if (simulateFlag?.startsWith("transformer.")) {
|
|
3699
|
+
result = await simulateTransformer(
|
|
3700
|
+
config,
|
|
3701
|
+
resolvedEvent,
|
|
3702
|
+
{
|
|
3703
|
+
transformerId: simulateFlag.replace("transformer.", ""),
|
|
3704
|
+
flow: options.flow,
|
|
3705
|
+
mock: options.mock,
|
|
3706
|
+
silent: options.silent,
|
|
3707
|
+
verbose: options.verbose,
|
|
3708
|
+
snapshot: options.snapshot
|
|
3709
|
+
}
|
|
3710
|
+
);
|
|
3711
|
+
} else if (simulateFlag?.startsWith("destination.")) {
|
|
3712
|
+
result = await simulateDestination(
|
|
3713
|
+
config,
|
|
3714
|
+
resolvedEvent,
|
|
3715
|
+
{
|
|
3716
|
+
destinationId: simulateFlag.replace("destination.", ""),
|
|
3717
|
+
flow: options.flow,
|
|
3718
|
+
mock: options.mock,
|
|
3719
|
+
silent: options.silent,
|
|
3720
|
+
verbose: options.verbose,
|
|
3721
|
+
snapshot: options.snapshot
|
|
3722
|
+
}
|
|
3723
|
+
);
|
|
3724
|
+
} else {
|
|
3725
|
+
result = await push(config, resolvedEvent, {
|
|
3726
|
+
flow: options.flow,
|
|
3727
|
+
json: options.json,
|
|
3728
|
+
verbose: options.verbose,
|
|
3729
|
+
silent: options.silent,
|
|
3730
|
+
platform: options.platform,
|
|
3731
|
+
mock: options.mock,
|
|
3732
|
+
snapshot: options.snapshot
|
|
3733
|
+
});
|
|
3734
|
+
}
|
|
3730
3735
|
const duration = Date.now() - startTime;
|
|
3731
3736
|
let output;
|
|
3732
3737
|
if (options.json) {
|
|
@@ -3782,158 +3787,438 @@ async function push(configOrPath, event, options = {}) {
|
|
|
3782
3787
|
"push() currently only supports config file paths. Config object support will be added in a future version. Please provide a path to a configuration file."
|
|
3783
3788
|
);
|
|
3784
3789
|
}
|
|
3785
|
-
|
|
3786
|
-
if (
|
|
3787
|
-
|
|
3790
|
+
const parsed = schemas3.PartialEventSchema.safeParse(event);
|
|
3791
|
+
if (!parsed.success) {
|
|
3792
|
+
return {
|
|
3793
|
+
success: false,
|
|
3794
|
+
duration: 0,
|
|
3795
|
+
error: `Invalid event: ${parsed.error.issues.map((i2) => `${i2.path.join(".")}: ${i2.message}`).join(", ")}`
|
|
3796
|
+
};
|
|
3788
3797
|
}
|
|
3789
|
-
return
|
|
3798
|
+
return pushCore(configOrPath, event, {
|
|
3790
3799
|
json: options.json ?? false,
|
|
3791
3800
|
verbose: options.verbose ?? false,
|
|
3792
3801
|
silent: options.silent ?? false,
|
|
3793
3802
|
flow: options.flow,
|
|
3794
|
-
platform: options.platform
|
|
3803
|
+
platform: options.platform,
|
|
3804
|
+
mock: options.mock,
|
|
3805
|
+
snapshot: options.snapshot
|
|
3795
3806
|
});
|
|
3796
3807
|
}
|
|
3797
|
-
async function executeConfigPush(options, validatedEvent, logger, setTempDir) {
|
|
3808
|
+
async function executeConfigPush(options, validatedEvent, logger, setTempDir, snapshotCode) {
|
|
3798
3809
|
logger.debug("Loading flow configuration");
|
|
3799
3810
|
const { flowSettings, buildOptions } = await loadFlowConfig(options.config, {
|
|
3800
3811
|
flowName: options.flow,
|
|
3801
3812
|
logger
|
|
3802
3813
|
});
|
|
3803
|
-
const platform =
|
|
3814
|
+
const platform = getPlatform4(flowSettings);
|
|
3815
|
+
const overrides = buildOverrides(
|
|
3816
|
+
{ mock: options.mock },
|
|
3817
|
+
flowSettings
|
|
3818
|
+
);
|
|
3819
|
+
if (overrides.destinations) {
|
|
3820
|
+
const { loadDestinationEnvs: loadDestinationEnvs2 } = await Promise.resolve().then(() => (init_env_loader(), env_loader_exports));
|
|
3821
|
+
const configDir = buildOptions.configDir || process.cwd();
|
|
3822
|
+
const envs = await loadDestinationEnvs2(
|
|
3823
|
+
flowSettings.destinations ?? {},
|
|
3824
|
+
flowSettings.packages,
|
|
3825
|
+
configDir
|
|
3826
|
+
);
|
|
3827
|
+
for (const [destId, env] of Object.entries(envs)) {
|
|
3828
|
+
if (overrides.destinations[destId] && env.push) {
|
|
3829
|
+
overrides.destinations[destId].env = env.push;
|
|
3830
|
+
if (env.simulation && env.simulation.length > 0) {
|
|
3831
|
+
overrides.destinations[destId].simulation = env.simulation;
|
|
3832
|
+
}
|
|
3833
|
+
}
|
|
3834
|
+
}
|
|
3835
|
+
}
|
|
3804
3836
|
logger.debug("Bundling flow configuration");
|
|
3805
|
-
const configDir = buildOptions.configDir || process.cwd();
|
|
3806
3837
|
const tempDir = getTmpPath(
|
|
3807
3838
|
void 0,
|
|
3808
3839
|
`push-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`
|
|
3809
3840
|
);
|
|
3810
3841
|
setTempDir(tempDir);
|
|
3811
|
-
await
|
|
3812
|
-
const tempPath =
|
|
3813
|
-
tempDir,
|
|
3814
|
-
`bundle.${platform === "web" ? "js" : "mjs"}`
|
|
3815
|
-
);
|
|
3842
|
+
await fs15.ensureDir(tempDir);
|
|
3843
|
+
const tempPath = path16.join(tempDir, "bundle.mjs");
|
|
3816
3844
|
const pushBuildOptions = {
|
|
3817
3845
|
...buildOptions,
|
|
3818
3846
|
output: tempPath,
|
|
3819
|
-
format:
|
|
3847
|
+
format: "esm",
|
|
3820
3848
|
platform: platform === "web" ? "browser" : "node",
|
|
3821
|
-
|
|
3822
|
-
|
|
3823
|
-
windowElb: "elb"
|
|
3824
|
-
}
|
|
3849
|
+
skipWrapper: true
|
|
3850
|
+
// CLI imports ESM directly — no platform wrapper
|
|
3825
3851
|
};
|
|
3826
3852
|
await bundleCore(flowSettings, pushBuildOptions, logger, false);
|
|
3827
3853
|
logger.debug(`Bundle created: ${tempPath}`);
|
|
3828
|
-
|
|
3829
|
-
|
|
3830
|
-
|
|
3831
|
-
|
|
3832
|
-
|
|
3833
|
-
|
|
3834
|
-
|
|
3835
|
-
|
|
3836
|
-
|
|
3837
|
-
|
|
3838
|
-
|
|
3854
|
+
logger.debug(
|
|
3855
|
+
`Executing in ${platform} environment (${platform === "web" ? "JSDOM" : "Node.js"})`
|
|
3856
|
+
);
|
|
3857
|
+
return executeDestinationPush(
|
|
3858
|
+
tempPath,
|
|
3859
|
+
validatedEvent,
|
|
3860
|
+
logger,
|
|
3861
|
+
platform,
|
|
3862
|
+
overrides,
|
|
3863
|
+
snapshotCode,
|
|
3864
|
+
platform === "server" ? 6e4 : void 0
|
|
3865
|
+
);
|
|
3839
3866
|
}
|
|
3840
|
-
async function executeBundlePush(bundleContent, platform, validatedEvent, logger, setTempDir,
|
|
3867
|
+
async function executeBundlePush(bundleContent, platform, validatedEvent, logger, setTempDir, overrides = {}, snapshotCode) {
|
|
3841
3868
|
const tempDir = getTmpPath(
|
|
3842
3869
|
void 0,
|
|
3843
3870
|
`push-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`
|
|
3844
3871
|
);
|
|
3845
3872
|
setTempDir(tempDir);
|
|
3846
|
-
await
|
|
3847
|
-
const tempPath =
|
|
3848
|
-
|
|
3849
|
-
`bundle.${platform === "server" ? "mjs" : "js"}`
|
|
3850
|
-
);
|
|
3851
|
-
await fs13.writeFile(tempPath, bundleContent, "utf8");
|
|
3873
|
+
await fs15.ensureDir(tempDir);
|
|
3874
|
+
const tempPath = path16.join(tempDir, "bundle.mjs");
|
|
3875
|
+
await fs15.writeFile(tempPath, bundleContent, "utf8");
|
|
3852
3876
|
logger.debug(`Bundle written to: ${tempPath}`);
|
|
3853
|
-
|
|
3854
|
-
|
|
3855
|
-
|
|
3856
|
-
|
|
3857
|
-
|
|
3858
|
-
|
|
3877
|
+
logger.debug(
|
|
3878
|
+
`Executing in ${platform} environment (${platform === "web" ? "JSDOM" : "Node.js"})`
|
|
3879
|
+
);
|
|
3880
|
+
return executeDestinationPush(
|
|
3881
|
+
tempPath,
|
|
3882
|
+
validatedEvent,
|
|
3883
|
+
logger,
|
|
3884
|
+
platform,
|
|
3885
|
+
overrides,
|
|
3886
|
+
snapshotCode,
|
|
3887
|
+
platform === "server" ? 6e4 : void 0
|
|
3888
|
+
);
|
|
3889
|
+
}
|
|
3890
|
+
async function executeDestinationPush(esmPath, event, logger, platform, overrides, snapshotCode, timeout) {
|
|
3891
|
+
const startTime = Date.now();
|
|
3892
|
+
const networkCalls = [];
|
|
3893
|
+
return withFlowContext(
|
|
3894
|
+
{ esmPath, platform, logger, snapshotCode, timeout, networkCalls, asyncDrain: { timeout: 5e3 } },
|
|
3895
|
+
async (module) => {
|
|
3896
|
+
const config = module.wireConfig(module.__configData ?? void 0);
|
|
3897
|
+
applyOverrides(config, overrides || {});
|
|
3898
|
+
const result = await module.startFlow(config);
|
|
3899
|
+
if (!result?.collector?.push)
|
|
3900
|
+
throw new Error("Invalid bundle: collector missing push");
|
|
3901
|
+
const collector = result.collector;
|
|
3902
|
+
logger.info(`Pushing event: ${event.name}`);
|
|
3903
|
+
const elbResult = await collector.push(event);
|
|
3904
|
+
await collector.command("shutdown");
|
|
3905
|
+
return {
|
|
3906
|
+
success: true,
|
|
3907
|
+
elbResult,
|
|
3908
|
+
...networkCalls.length > 0 ? { networkCalls } : {},
|
|
3909
|
+
duration: Date.now() - startTime
|
|
3910
|
+
};
|
|
3911
|
+
}
|
|
3912
|
+
);
|
|
3913
|
+
}
|
|
3914
|
+
async function simulateSource(configPath, input, options) {
|
|
3915
|
+
const startTime = Date.now();
|
|
3916
|
+
const prepared = await prepareFlow({
|
|
3917
|
+
configPath,
|
|
3918
|
+
flow: options.flow,
|
|
3919
|
+
simulate: ["source." + options.sourceId],
|
|
3920
|
+
silent: options.silent,
|
|
3921
|
+
verbose: options.verbose
|
|
3922
|
+
});
|
|
3923
|
+
try {
|
|
3924
|
+
const logger = createCLILogger({
|
|
3925
|
+
silent: options.silent,
|
|
3926
|
+
verbose: options.verbose
|
|
3927
|
+
});
|
|
3928
|
+
const sourceConfig = (prepared.flowSettings.sources ?? {})[options.sourceId];
|
|
3929
|
+
if (!sourceConfig?.package) {
|
|
3930
|
+
throw new Error(
|
|
3931
|
+
`Source "${options.sourceId}" has no package defined`
|
|
3932
|
+
);
|
|
3933
|
+
}
|
|
3934
|
+
const devPath = resolvePackageImportPath(
|
|
3935
|
+
sourceConfig.package,
|
|
3936
|
+
prepared.flowSettings.packages,
|
|
3937
|
+
prepared.configDir,
|
|
3938
|
+
"/dev"
|
|
3939
|
+
);
|
|
3940
|
+
const devModule = await import(devPath);
|
|
3941
|
+
const createTrigger = devModule.examples?.createTrigger || devModule.default?.examples?.createTrigger;
|
|
3942
|
+
if (!createTrigger) {
|
|
3943
|
+
throw new Error(
|
|
3944
|
+
`Source package "${sourceConfig.package}" has no createTrigger in /dev export`
|
|
3945
|
+
);
|
|
3946
|
+
}
|
|
3947
|
+
let snapshotCode;
|
|
3948
|
+
if (options.snapshot) {
|
|
3949
|
+
snapshotCode = await loadConfig(options.snapshot, {
|
|
3950
|
+
json: false
|
|
3951
|
+
});
|
|
3952
|
+
logger.debug(`Snapshot loaded (${snapshotCode.length} bytes)`);
|
|
3953
|
+
}
|
|
3954
|
+
const networkCalls = [];
|
|
3955
|
+
return await withFlowContext(
|
|
3956
|
+
{
|
|
3957
|
+
esmPath: prepared.bundlePath,
|
|
3958
|
+
platform: prepared.platform,
|
|
3959
|
+
logger,
|
|
3960
|
+
snapshotCode,
|
|
3961
|
+
networkCalls
|
|
3962
|
+
},
|
|
3963
|
+
async (module) => {
|
|
3964
|
+
const config = module.wireConfig(module.__configData ?? void 0);
|
|
3965
|
+
applyOverrides(config, prepared.overrides);
|
|
3966
|
+
const captured = [];
|
|
3967
|
+
config.hooks = {
|
|
3968
|
+
...config.hooks || {},
|
|
3969
|
+
prePush: ({ fn }, event) => {
|
|
3970
|
+
captured.push({ event, timestamp: Date.now() });
|
|
3971
|
+
return { ok: true };
|
|
3972
|
+
}
|
|
3973
|
+
};
|
|
3974
|
+
const instance = await createTrigger(config, { sourceId: options.sourceId });
|
|
3975
|
+
const { trigger } = instance;
|
|
3976
|
+
logger.info("Simulating source");
|
|
3977
|
+
const inputRecord = input ?? {};
|
|
3978
|
+
const content = inputRecord.content ?? input;
|
|
3979
|
+
const triggerOpts = inputRecord.trigger;
|
|
3980
|
+
await trigger(triggerOpts?.type, triggerOpts?.options)(content);
|
|
3981
|
+
if (instance.flow?.collector?.command) {
|
|
3982
|
+
await instance.flow.collector.command("shutdown");
|
|
3983
|
+
}
|
|
3984
|
+
return {
|
|
3985
|
+
success: true,
|
|
3986
|
+
...captured.length > 0 ? { captured } : {},
|
|
3987
|
+
...networkCalls.length > 0 ? { networkCalls } : {},
|
|
3988
|
+
duration: Date.now() - startTime
|
|
3989
|
+
};
|
|
3990
|
+
}
|
|
3991
|
+
);
|
|
3992
|
+
} catch (error) {
|
|
3993
|
+
return {
|
|
3994
|
+
success: false,
|
|
3995
|
+
duration: Date.now() - startTime,
|
|
3996
|
+
error: getErrorMessage(error)
|
|
3997
|
+
};
|
|
3998
|
+
} finally {
|
|
3999
|
+
await prepared.cleanup();
|
|
3859
4000
|
}
|
|
3860
4001
|
}
|
|
3861
|
-
async function
|
|
4002
|
+
async function simulateTransformer(configPath, event, options) {
|
|
3862
4003
|
const startTime = Date.now();
|
|
4004
|
+
const parsed = schemas3.PartialEventSchema.safeParse(event);
|
|
4005
|
+
if (!parsed.success) {
|
|
4006
|
+
return {
|
|
4007
|
+
success: false,
|
|
4008
|
+
duration: 0,
|
|
4009
|
+
error: parsed.error.message
|
|
4010
|
+
};
|
|
4011
|
+
}
|
|
4012
|
+
const prepared = await prepareFlow({
|
|
4013
|
+
configPath,
|
|
4014
|
+
flow: options.flow,
|
|
4015
|
+
simulate: ["transformer." + options.transformerId],
|
|
4016
|
+
mock: options.mock,
|
|
4017
|
+
silent: options.silent,
|
|
4018
|
+
verbose: options.verbose
|
|
4019
|
+
});
|
|
3863
4020
|
try {
|
|
3864
|
-
const
|
|
3865
|
-
|
|
3866
|
-
|
|
3867
|
-
runScripts: "dangerously",
|
|
3868
|
-
resources: "usable",
|
|
3869
|
-
virtualConsole
|
|
4021
|
+
const logger = createCLILogger({
|
|
4022
|
+
silent: options.silent,
|
|
4023
|
+
verbose: options.verbose
|
|
3870
4024
|
});
|
|
3871
|
-
|
|
3872
|
-
|
|
3873
|
-
|
|
3874
|
-
|
|
3875
|
-
|
|
3876
|
-
|
|
3877
|
-
|
|
3878
|
-
|
|
3879
|
-
|
|
4025
|
+
let snapshotCode;
|
|
4026
|
+
if (options.snapshot) {
|
|
4027
|
+
snapshotCode = await loadConfig(options.snapshot, {
|
|
4028
|
+
json: false
|
|
4029
|
+
});
|
|
4030
|
+
logger.debug(`Snapshot loaded (${snapshotCode.length} bytes)`);
|
|
4031
|
+
}
|
|
4032
|
+
const networkCalls = [];
|
|
4033
|
+
return await withFlowContext(
|
|
4034
|
+
{
|
|
4035
|
+
esmPath: prepared.bundlePath,
|
|
4036
|
+
platform: prepared.platform,
|
|
4037
|
+
logger,
|
|
4038
|
+
snapshotCode,
|
|
4039
|
+
networkCalls
|
|
4040
|
+
},
|
|
4041
|
+
async (module) => {
|
|
4042
|
+
const config = module.wireConfig(module.__configData ?? void 0);
|
|
4043
|
+
applyOverrides(config, prepared.overrides);
|
|
4044
|
+
if (config.sources) config.sources = {};
|
|
4045
|
+
if (config.destinations) config.destinations = {};
|
|
4046
|
+
const result = await module.startFlow(config);
|
|
4047
|
+
if (!result?.collector)
|
|
4048
|
+
throw new Error("Invalid bundle: collector not available");
|
|
4049
|
+
const collector = result.collector;
|
|
4050
|
+
const transformer = collector.transformers?.[options.transformerId];
|
|
4051
|
+
if (!transformer) {
|
|
4052
|
+
throw new Error(
|
|
4053
|
+
`Transformer "${options.transformerId}" not found in collector. Available: ${Object.keys(collector.transformers || {}).join(", ") || "none"}`
|
|
4054
|
+
);
|
|
4055
|
+
}
|
|
4056
|
+
const initialized = await ee(
|
|
4057
|
+
collector,
|
|
4058
|
+
transformer,
|
|
4059
|
+
options.transformerId
|
|
4060
|
+
);
|
|
4061
|
+
if (!initialized) {
|
|
4062
|
+
throw new Error(
|
|
4063
|
+
`Transformer "${options.transformerId}" failed to initialize`
|
|
4064
|
+
);
|
|
4065
|
+
}
|
|
4066
|
+
const inputEvent = event;
|
|
4067
|
+
const ingest = createIngest(options.transformerId);
|
|
4068
|
+
const captured = [];
|
|
4069
|
+
captured.push({ event: { ...inputEvent }, timestamp: Date.now() });
|
|
4070
|
+
logger.info(`Simulating transformer: ${options.transformerId}`);
|
|
4071
|
+
let processedEvent = inputEvent;
|
|
4072
|
+
const before = transformer.config.before;
|
|
4073
|
+
if (before && collector.transformers) {
|
|
4074
|
+
const beforeChainIds = resolveBeforeChain(
|
|
4075
|
+
before,
|
|
4076
|
+
collector.transformers,
|
|
4077
|
+
ingest,
|
|
4078
|
+
processedEvent
|
|
4079
|
+
);
|
|
4080
|
+
if (beforeChainIds.length > 0) {
|
|
4081
|
+
const beforeResult = await te(
|
|
4082
|
+
collector,
|
|
4083
|
+
collector.transformers,
|
|
4084
|
+
beforeChainIds,
|
|
4085
|
+
processedEvent,
|
|
4086
|
+
ingest,
|
|
4087
|
+
void 0,
|
|
4088
|
+
`transformer.${options.transformerId}.before`
|
|
4089
|
+
);
|
|
4090
|
+
if (beforeResult === null) {
|
|
4091
|
+
captured.push({ event: null, timestamp: Date.now() });
|
|
4092
|
+
await collector.command("shutdown");
|
|
4093
|
+
return {
|
|
4094
|
+
success: true,
|
|
4095
|
+
captured,
|
|
4096
|
+
duration: Date.now() - startTime
|
|
4097
|
+
};
|
|
4098
|
+
}
|
|
4099
|
+
processedEvent = Array.isArray(beforeResult) ? beforeResult[0] : beforeResult;
|
|
4100
|
+
}
|
|
4101
|
+
}
|
|
4102
|
+
const pushResult = await ne(
|
|
4103
|
+
collector,
|
|
4104
|
+
transformer,
|
|
4105
|
+
options.transformerId,
|
|
4106
|
+
processedEvent,
|
|
4107
|
+
ingest
|
|
4108
|
+
);
|
|
4109
|
+
if (pushResult === false) {
|
|
4110
|
+
captured.push({ event: null, timestamp: Date.now() });
|
|
4111
|
+
} else if (Array.isArray(pushResult)) {
|
|
4112
|
+
for (const r2 of pushResult) {
|
|
4113
|
+
captured.push({
|
|
4114
|
+
event: r2.event || processedEvent,
|
|
4115
|
+
timestamp: Date.now()
|
|
4116
|
+
});
|
|
4117
|
+
}
|
|
4118
|
+
} else if (pushResult && typeof pushResult === "object" && pushResult.event) {
|
|
4119
|
+
captured.push({ event: pushResult.event, timestamp: Date.now() });
|
|
4120
|
+
} else {
|
|
4121
|
+
captured.push({ event: processedEvent, timestamp: Date.now() });
|
|
4122
|
+
}
|
|
4123
|
+
await collector.command("shutdown");
|
|
4124
|
+
return {
|
|
4125
|
+
success: true,
|
|
4126
|
+
captured,
|
|
4127
|
+
...networkCalls.length > 0 ? { networkCalls } : {},
|
|
4128
|
+
duration: Date.now() - startTime
|
|
4129
|
+
};
|
|
4130
|
+
}
|
|
3880
4131
|
);
|
|
3881
|
-
const windowObj = window;
|
|
3882
|
-
const collector = windowObj.collector;
|
|
3883
|
-
logger.info(`Pushing event: ${event.name}`);
|
|
3884
|
-
const elbResult = await collector.push({
|
|
3885
|
-
name: event.name,
|
|
3886
|
-
data: event.data
|
|
3887
|
-
});
|
|
3888
|
-
return {
|
|
3889
|
-
success: true,
|
|
3890
|
-
elbResult,
|
|
3891
|
-
duration: Date.now() - startTime
|
|
3892
|
-
};
|
|
3893
4132
|
} catch (error) {
|
|
3894
4133
|
return {
|
|
3895
4134
|
success: false,
|
|
3896
4135
|
duration: Date.now() - startTime,
|
|
3897
4136
|
error: getErrorMessage(error)
|
|
3898
4137
|
};
|
|
4138
|
+
} finally {
|
|
4139
|
+
await prepared.cleanup();
|
|
3899
4140
|
}
|
|
3900
4141
|
}
|
|
3901
|
-
async function
|
|
4142
|
+
async function simulateDestination(configPath, event, options) {
|
|
3902
4143
|
const startTime = Date.now();
|
|
3903
|
-
|
|
4144
|
+
const parsed = schemas3.PartialEventSchema.safeParse(event);
|
|
4145
|
+
if (!parsed.success) {
|
|
4146
|
+
return {
|
|
4147
|
+
success: false,
|
|
4148
|
+
duration: 0,
|
|
4149
|
+
error: parsed.error.message
|
|
4150
|
+
};
|
|
4151
|
+
}
|
|
4152
|
+
const prepared = await prepareFlow({
|
|
4153
|
+
configPath,
|
|
4154
|
+
flow: options.flow,
|
|
4155
|
+
simulate: ["destination." + options.destinationId],
|
|
4156
|
+
mock: options.mock,
|
|
4157
|
+
silent: options.silent,
|
|
4158
|
+
verbose: options.verbose
|
|
4159
|
+
});
|
|
3904
4160
|
try {
|
|
3905
|
-
const
|
|
3906
|
-
|
|
3907
|
-
|
|
3908
|
-
timeout
|
|
3909
|
-
);
|
|
4161
|
+
const logger = createCLILogger({
|
|
4162
|
+
silent: options.silent,
|
|
4163
|
+
verbose: options.verbose
|
|
3910
4164
|
});
|
|
3911
|
-
|
|
3912
|
-
|
|
3913
|
-
|
|
3914
|
-
|
|
3915
|
-
throw new Error("Bundle does not export default factory function");
|
|
3916
|
-
}
|
|
3917
|
-
logger.debug("Calling factory function...");
|
|
3918
|
-
const result = await flowModule.default(context);
|
|
3919
|
-
if (!result || !result.collector || typeof result.collector.push !== "function") {
|
|
3920
|
-
throw new Error(
|
|
3921
|
-
"Factory function did not return valid result with collector"
|
|
3922
|
-
);
|
|
3923
|
-
}
|
|
3924
|
-
const { collector } = result;
|
|
3925
|
-
logger.info(`Pushing event: ${event.name}`);
|
|
3926
|
-
const elbResult = await collector.push({
|
|
3927
|
-
name: event.name,
|
|
3928
|
-
data: event.data
|
|
4165
|
+
let snapshotCode;
|
|
4166
|
+
if (options.snapshot) {
|
|
4167
|
+
snapshotCode = await loadConfig(options.snapshot, {
|
|
4168
|
+
json: false
|
|
3929
4169
|
});
|
|
3930
|
-
|
|
3931
|
-
|
|
3932
|
-
|
|
3933
|
-
|
|
3934
|
-
|
|
3935
|
-
|
|
3936
|
-
|
|
4170
|
+
}
|
|
4171
|
+
const networkCalls = [];
|
|
4172
|
+
return await withFlowContext(
|
|
4173
|
+
{
|
|
4174
|
+
esmPath: prepared.bundlePath,
|
|
4175
|
+
platform: prepared.platform,
|
|
4176
|
+
logger,
|
|
4177
|
+
snapshotCode,
|
|
4178
|
+
networkCalls
|
|
4179
|
+
},
|
|
4180
|
+
async (module) => {
|
|
4181
|
+
const config = module.wireConfig(module.__configData ?? void 0);
|
|
4182
|
+
applyOverrides(config, prepared.overrides);
|
|
4183
|
+
const destOverride = prepared.overrides.destinations?.[options.destinationId];
|
|
4184
|
+
let trackedCalls = [];
|
|
4185
|
+
if (destOverride?.simulation?.length) {
|
|
4186
|
+
const destinations = config.destinations;
|
|
4187
|
+
const destConfig = destinations[options.destinationId]?.config;
|
|
4188
|
+
if (destConfig?.env) {
|
|
4189
|
+
const combined = {
|
|
4190
|
+
...destConfig.env,
|
|
4191
|
+
simulation: destOverride.simulation
|
|
4192
|
+
};
|
|
4193
|
+
const { wrappedEnv, calls } = Ge(combined);
|
|
4194
|
+
destConfig.env = wrappedEnv;
|
|
4195
|
+
trackedCalls = calls;
|
|
4196
|
+
}
|
|
4197
|
+
}
|
|
4198
|
+
if (config.sources) config.sources = {};
|
|
4199
|
+
const result = await module.startFlow(config);
|
|
4200
|
+
if (!result?.collector)
|
|
4201
|
+
throw new Error("Invalid bundle: collector not available");
|
|
4202
|
+
const collector = result.collector;
|
|
4203
|
+
if (!collector.destinations[options.destinationId] && !collector.pending.destinations[options.destinationId]) {
|
|
4204
|
+
throw new Error(
|
|
4205
|
+
`Destination "${options.destinationId}" not found in collector. Available: ${Object.keys(collector.destinations || {}).join(", ") || "none"}`
|
|
4206
|
+
);
|
|
4207
|
+
}
|
|
4208
|
+
logger.info(`Simulating destination: ${options.destinationId}`);
|
|
4209
|
+
const elbResult = await collector.push(event, {
|
|
4210
|
+
include: [options.destinationId]
|
|
4211
|
+
});
|
|
4212
|
+
await collector.command("shutdown");
|
|
4213
|
+
return {
|
|
4214
|
+
success: true,
|
|
4215
|
+
elbResult,
|
|
4216
|
+
...trackedCalls.length > 0 ? { usage: { [options.destinationId]: trackedCalls } } : {},
|
|
4217
|
+
...networkCalls.length > 0 ? { networkCalls } : {},
|
|
4218
|
+
duration: Date.now() - startTime
|
|
4219
|
+
};
|
|
4220
|
+
}
|
|
4221
|
+
);
|
|
3937
4222
|
} catch (error) {
|
|
3938
4223
|
return {
|
|
3939
4224
|
success: false,
|
|
@@ -3941,35 +4226,17 @@ async function executeServerPush(bundlePath, event, logger, timeout = 6e4, conte
|
|
|
3941
4226
|
error: getErrorMessage(error)
|
|
3942
4227
|
};
|
|
3943
4228
|
} finally {
|
|
3944
|
-
|
|
4229
|
+
await prepared.cleanup();
|
|
3945
4230
|
}
|
|
3946
4231
|
}
|
|
3947
|
-
function waitForWindowProperty(window, prop, timeout = 5e3) {
|
|
3948
|
-
return new Promise((resolve2, reject) => {
|
|
3949
|
-
const start = Date.now();
|
|
3950
|
-
const check = () => {
|
|
3951
|
-
if (window[prop] !== void 0) {
|
|
3952
|
-
resolve2();
|
|
3953
|
-
} else if (Date.now() - start > timeout) {
|
|
3954
|
-
reject(
|
|
3955
|
-
new Error(
|
|
3956
|
-
`Timeout waiting for window.${prop}. IIFE may have failed to execute.`
|
|
3957
|
-
)
|
|
3958
|
-
);
|
|
3959
|
-
} else {
|
|
3960
|
-
setImmediate(check);
|
|
3961
|
-
}
|
|
3962
|
-
};
|
|
3963
|
-
check();
|
|
3964
|
-
});
|
|
3965
|
-
}
|
|
3966
4232
|
|
|
3967
4233
|
// src/commands/run/index.ts
|
|
3968
4234
|
init_cli_logger();
|
|
3969
4235
|
init_core();
|
|
4236
|
+
init_tmp();
|
|
3970
4237
|
init_config_file();
|
|
3971
4238
|
init_auth();
|
|
3972
|
-
import
|
|
4239
|
+
import path18 from "path";
|
|
3973
4240
|
import { writeFileSync as writeFileSync5 } from "fs";
|
|
3974
4241
|
import { homedir as homedir2 } from "os";
|
|
3975
4242
|
import { join as join4 } from "path";
|
|
@@ -4017,12 +4284,12 @@ async function resolveBundle(bundleEnv) {
|
|
|
4017
4284
|
return { path: bundleEnv, source: "file" };
|
|
4018
4285
|
}
|
|
4019
4286
|
if (isUrl2(bundleEnv)) {
|
|
4020
|
-
const
|
|
4021
|
-
return { path:
|
|
4287
|
+
const path19 = await fetchBundle(bundleEnv, writePath);
|
|
4288
|
+
return { path: path19, source: "url" };
|
|
4022
4289
|
}
|
|
4023
4290
|
if (isStdinPiped()) {
|
|
4024
|
-
const
|
|
4025
|
-
return { path:
|
|
4291
|
+
const path19 = await readBundleFromStdin(writePath);
|
|
4292
|
+
return { path: path19, source: "stdin" };
|
|
4026
4293
|
}
|
|
4027
4294
|
return { path: bundleEnv, source: "file" };
|
|
4028
4295
|
}
|
|
@@ -4186,12 +4453,14 @@ function validatePort(port) {
|
|
|
4186
4453
|
init_utils3();
|
|
4187
4454
|
|
|
4188
4455
|
// src/commands/run/pipeline.ts
|
|
4456
|
+
init_tmp();
|
|
4189
4457
|
import { writeFileSync as writeFileSync4 } from "fs";
|
|
4458
|
+
import fs17 from "fs-extra";
|
|
4190
4459
|
|
|
4191
4460
|
// src/runtime/health-server.ts
|
|
4192
4461
|
import http from "http";
|
|
4193
4462
|
function createHealthServer(port, logger) {
|
|
4194
|
-
return new Promise((
|
|
4463
|
+
return new Promise((resolve3, reject) => {
|
|
4195
4464
|
let flowHandler = null;
|
|
4196
4465
|
const server = http.createServer((req, res) => {
|
|
4197
4466
|
if (req.url === "/health" && req.method === "GET") {
|
|
@@ -4218,7 +4487,7 @@ function createHealthServer(port, logger) {
|
|
|
4218
4487
|
server.headersTimeout = 1e4;
|
|
4219
4488
|
server.listen(port, "0.0.0.0", () => {
|
|
4220
4489
|
logger.info(`Health server listening on port ${port}`);
|
|
4221
|
-
|
|
4490
|
+
resolve3({
|
|
4222
4491
|
server,
|
|
4223
4492
|
setFlowHandler(handler) {
|
|
4224
4493
|
flowHandler = handler;
|
|
@@ -4233,28 +4502,45 @@ function createHealthServer(port, logger) {
|
|
|
4233
4502
|
}
|
|
4234
4503
|
|
|
4235
4504
|
// src/runtime/runner.ts
|
|
4236
|
-
import {
|
|
4237
|
-
|
|
4238
|
-
|
|
4505
|
+
import { resolve as resolve2, dirname as dirname2 } from "path";
|
|
4506
|
+
|
|
4507
|
+
// src/runtime/load-bundle.ts
|
|
4508
|
+
import { resolve } from "path";
|
|
4509
|
+
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
4510
|
+
async function loadBundle(file, context, logger) {
|
|
4239
4511
|
const absolutePath = resolve(file);
|
|
4240
|
-
const
|
|
4241
|
-
|
|
4242
|
-
const fileUrl = pathToFileURL(absolutePath).href;
|
|
4512
|
+
const fileUrl = pathToFileURL2(absolutePath).href;
|
|
4513
|
+
logger?.debug?.(`Importing bundle: ${absolutePath}`);
|
|
4243
4514
|
const module = await import(`${fileUrl}?t=${Date.now()}`);
|
|
4244
4515
|
if (!module.default || typeof module.default !== "function") {
|
|
4245
4516
|
throw new Error(
|
|
4246
|
-
`Invalid
|
|
4517
|
+
`Invalid bundle: ${file} must export a default factory function`
|
|
4247
4518
|
);
|
|
4248
4519
|
}
|
|
4520
|
+
logger?.debug?.("Calling factory function...");
|
|
4521
|
+
const result = await module.default(context ?? {});
|
|
4522
|
+
if (!result || !result.collector || typeof result.collector.push !== "function") {
|
|
4523
|
+
throw new Error(
|
|
4524
|
+
`Invalid bundle: factory must return { collector } with a push function`
|
|
4525
|
+
);
|
|
4526
|
+
}
|
|
4527
|
+
return {
|
|
4528
|
+
collector: result.collector,
|
|
4529
|
+
...typeof result.httpHandler === "function" ? { httpHandler: result.httpHandler } : {}
|
|
4530
|
+
};
|
|
4531
|
+
}
|
|
4532
|
+
|
|
4533
|
+
// src/runtime/runner.ts
|
|
4534
|
+
async function loadFlow(file, config, logger, loggerConfig, healthServer) {
|
|
4535
|
+
const absolutePath = resolve2(file);
|
|
4536
|
+
const flowDir = dirname2(absolutePath);
|
|
4537
|
+
process.chdir(flowDir);
|
|
4249
4538
|
const flowContext = {
|
|
4250
4539
|
...config,
|
|
4251
4540
|
...loggerConfig ? { logger: loggerConfig } : {},
|
|
4252
|
-
...healthServer ? {
|
|
4541
|
+
...healthServer ? { sourceSettings: { port: void 0 } } : {}
|
|
4253
4542
|
};
|
|
4254
|
-
const result = await
|
|
4255
|
-
if (!result || !result.collector) {
|
|
4256
|
-
throw new Error(`Invalid flow bundle: ${file} must return { collector }`);
|
|
4257
|
-
}
|
|
4543
|
+
const result = await loadBundle(absolutePath, flowContext, logger);
|
|
4258
4544
|
if (healthServer && typeof result.httpHandler === "function") {
|
|
4259
4545
|
healthServer.setFlowHandler(result.httpHandler);
|
|
4260
4546
|
}
|
|
@@ -4520,6 +4806,8 @@ async function runPipeline(options) {
|
|
|
4520
4806
|
logger.info(`Port: ${port}`);
|
|
4521
4807
|
let heartbeat = null;
|
|
4522
4808
|
let poller = null;
|
|
4809
|
+
let currentBundleCleanup;
|
|
4810
|
+
let currentConfigPath;
|
|
4523
4811
|
if (api) {
|
|
4524
4812
|
heartbeat = createHeartbeat(
|
|
4525
4813
|
{
|
|
@@ -4554,28 +4842,44 @@ async function runPipeline(options) {
|
|
|
4554
4842
|
);
|
|
4555
4843
|
return;
|
|
4556
4844
|
}
|
|
4557
|
-
const tmpConfigPath =
|
|
4845
|
+
const tmpConfigPath = getTmpPath(
|
|
4846
|
+
void 0,
|
|
4847
|
+
`walkeros-flow-${Date.now()}.json`
|
|
4848
|
+
);
|
|
4558
4849
|
writeFileSync4(
|
|
4559
4850
|
tmpConfigPath,
|
|
4560
4851
|
JSON.stringify(content, null, 2),
|
|
4561
4852
|
"utf-8"
|
|
4562
4853
|
);
|
|
4563
|
-
const
|
|
4854
|
+
const newBundleResult = await api.prepareBundleForRun(tmpConfigPath, {
|
|
4564
4855
|
verbose: false,
|
|
4565
4856
|
silent: true,
|
|
4566
4857
|
flowName: api.flowName
|
|
4567
4858
|
});
|
|
4568
4859
|
handle = await swapFlow(
|
|
4569
4860
|
handle,
|
|
4570
|
-
|
|
4861
|
+
newBundleResult.bundlePath,
|
|
4571
4862
|
runtimeConfig,
|
|
4572
4863
|
logger,
|
|
4573
4864
|
loggerConfig,
|
|
4574
4865
|
healthServer
|
|
4575
4866
|
);
|
|
4576
|
-
writeCache(
|
|
4867
|
+
writeCache(
|
|
4868
|
+
api.cacheDir,
|
|
4869
|
+
newBundleResult.bundlePath,
|
|
4870
|
+
JSON.stringify(content),
|
|
4871
|
+
version
|
|
4872
|
+
);
|
|
4577
4873
|
configVersion = version;
|
|
4578
4874
|
if (heartbeat) heartbeat.updateConfigVersion(version);
|
|
4875
|
+
if (currentBundleCleanup)
|
|
4876
|
+
await currentBundleCleanup().catch(() => {
|
|
4877
|
+
});
|
|
4878
|
+
if (currentConfigPath)
|
|
4879
|
+
await fs17.remove(currentConfigPath).catch(() => {
|
|
4880
|
+
});
|
|
4881
|
+
currentBundleCleanup = newBundleResult.cleanup;
|
|
4882
|
+
currentConfigPath = tmpConfigPath;
|
|
4579
4883
|
logger.info(`Hot-swapped to version ${version}`);
|
|
4580
4884
|
}
|
|
4581
4885
|
},
|
|
@@ -4597,6 +4901,10 @@ async function runPipeline(options) {
|
|
|
4597
4901
|
await handle.collector.command("shutdown");
|
|
4598
4902
|
}
|
|
4599
4903
|
await healthServer.close();
|
|
4904
|
+
if (currentBundleCleanup) await currentBundleCleanup().catch(() => {
|
|
4905
|
+
});
|
|
4906
|
+
if (currentConfigPath) await fs17.remove(currentConfigPath).catch(() => {
|
|
4907
|
+
});
|
|
4600
4908
|
logger.info("Shutdown complete");
|
|
4601
4909
|
clearTimeout(forceTimer);
|
|
4602
4910
|
process.exit(0);
|
|
@@ -4745,15 +5053,16 @@ async function resolveBundlePath(configInput, apiConfig, logger) {
|
|
|
4745
5053
|
logger.info(`Bundle: ${resolved.path}`);
|
|
4746
5054
|
}
|
|
4747
5055
|
if (isPreBuiltConfig(resolved.path)) {
|
|
4748
|
-
return
|
|
5056
|
+
return path18.resolve(resolved.path);
|
|
4749
5057
|
}
|
|
4750
5058
|
const flowFile = validateFlowFile(resolved.path);
|
|
4751
5059
|
logger.debug("Building flow bundle");
|
|
4752
|
-
|
|
5060
|
+
const result = await lazyPrepareBundleForRun(flowFile, {
|
|
4753
5061
|
verbose: false,
|
|
4754
5062
|
silent: true,
|
|
4755
5063
|
flowName: apiConfig?.flowName
|
|
4756
5064
|
});
|
|
5065
|
+
return result.bundlePath;
|
|
4757
5066
|
}
|
|
4758
5067
|
if (apiConfig) {
|
|
4759
5068
|
logger.info("Fetching config from API...");
|
|
@@ -4765,7 +5074,10 @@ async function resolveBundlePath(configInput, apiConfig, logger) {
|
|
|
4765
5074
|
flowId: apiConfig.flowId
|
|
4766
5075
|
});
|
|
4767
5076
|
if (result.changed) {
|
|
4768
|
-
const tmpConfigPath =
|
|
5077
|
+
const tmpConfigPath = getTmpPath(
|
|
5078
|
+
void 0,
|
|
5079
|
+
`walkeros-flow-${Date.now()}.json`
|
|
5080
|
+
);
|
|
4769
5081
|
writeFileSync5(
|
|
4770
5082
|
tmpConfigPath,
|
|
4771
5083
|
JSON.stringify(result.content, null, 2),
|
|
@@ -4773,7 +5085,7 @@ async function resolveBundlePath(configInput, apiConfig, logger) {
|
|
|
4773
5085
|
);
|
|
4774
5086
|
logger.info(`Config version: ${result.version}`);
|
|
4775
5087
|
logger.info("Building flow...");
|
|
4776
|
-
const
|
|
5088
|
+
const bundleResult = await lazyPrepareBundleForRun(tmpConfigPath, {
|
|
4777
5089
|
verbose: false,
|
|
4778
5090
|
silent: true,
|
|
4779
5091
|
flowName: apiConfig.flowName
|
|
@@ -4782,14 +5094,14 @@ async function resolveBundlePath(configInput, apiConfig, logger) {
|
|
|
4782
5094
|
const { writeCache: writeCache2 } = await Promise.resolve().then(() => (init_cache(), cache_exports));
|
|
4783
5095
|
writeCache2(
|
|
4784
5096
|
apiConfig.cacheDir,
|
|
4785
|
-
bundlePath,
|
|
5097
|
+
bundleResult.bundlePath,
|
|
4786
5098
|
JSON.stringify(result.content),
|
|
4787
5099
|
result.version
|
|
4788
5100
|
);
|
|
4789
5101
|
} catch {
|
|
4790
5102
|
logger.debug("Cache write failed (non-critical)");
|
|
4791
5103
|
}
|
|
4792
|
-
return bundlePath;
|
|
5104
|
+
return bundleResult.bundlePath;
|
|
4793
5105
|
}
|
|
4794
5106
|
} catch (error) {
|
|
4795
5107
|
logger.error(
|
|
@@ -4807,7 +5119,7 @@ async function resolveBundlePath(configInput, apiConfig, logger) {
|
|
|
4807
5119
|
}
|
|
4808
5120
|
const defaultFile = "server-collect.mjs";
|
|
4809
5121
|
logger.debug(`No config specified, using default: ${defaultFile}`);
|
|
4810
|
-
return
|
|
5122
|
+
return path18.resolve(defaultFile);
|
|
4811
5123
|
}
|
|
4812
5124
|
async function run(options) {
|
|
4813
5125
|
const startTime = Date.now();
|
|
@@ -4998,73 +5310,15 @@ function validateEntityActions(obj, prefix, errors) {
|
|
|
4998
5310
|
}
|
|
4999
5311
|
|
|
5000
5312
|
// src/commands/validate/validators/event.ts
|
|
5001
|
-
|
|
5002
|
-
|
|
5003
|
-
|
|
5004
|
-
const errors = [];
|
|
5005
|
-
const warnings = [];
|
|
5006
|
-
const details = {};
|
|
5007
|
-
const event = typeof input === "object" && input !== null ? input : {};
|
|
5008
|
-
if (!("name" in event) || event.name === void 0) {
|
|
5009
|
-
errors.push({
|
|
5010
|
-
path: "name",
|
|
5011
|
-
message: "Event must have a name field",
|
|
5012
|
-
code: "MISSING_EVENT_NAME"
|
|
5013
|
-
});
|
|
5014
|
-
} else if (typeof event.name !== "string" || event.name.trim() === "") {
|
|
5015
|
-
errors.push({
|
|
5016
|
-
path: "name",
|
|
5017
|
-
message: "Event name cannot be empty",
|
|
5018
|
-
value: event.name,
|
|
5019
|
-
code: "EMPTY_EVENT_NAME"
|
|
5020
|
-
});
|
|
5021
|
-
} else {
|
|
5022
|
-
const name = event.name;
|
|
5023
|
-
if (!name.includes(" ")) {
|
|
5024
|
-
errors.push({
|
|
5025
|
-
path: "name",
|
|
5026
|
-
message: 'Event name must be "entity action" format with space (e.g., "page view")',
|
|
5027
|
-
value: name,
|
|
5028
|
-
code: "INVALID_EVENT_NAME"
|
|
5029
|
-
});
|
|
5030
|
-
details.entity = null;
|
|
5031
|
-
details.action = null;
|
|
5032
|
-
} else {
|
|
5033
|
-
const parts = name.trim().split(/\s+/);
|
|
5034
|
-
const action = parts.pop();
|
|
5035
|
-
const entity = parts.join(" ");
|
|
5036
|
-
details.entity = entity;
|
|
5037
|
-
details.action = action;
|
|
5038
|
-
}
|
|
5039
|
-
}
|
|
5040
|
-
const zodResult = PartialEventSchema.safeParse(input);
|
|
5041
|
-
if (!zodResult.success) {
|
|
5042
|
-
for (const issue of zodResult.error.issues) {
|
|
5043
|
-
const path15 = issue.path.join(".");
|
|
5044
|
-
if (path15 === "name") continue;
|
|
5045
|
-
errors.push({
|
|
5046
|
-
path: path15 || "root",
|
|
5047
|
-
message: issue.message,
|
|
5048
|
-
code: "SCHEMA_VALIDATION"
|
|
5049
|
-
});
|
|
5050
|
-
}
|
|
5051
|
-
}
|
|
5052
|
-
if (!event.consent) {
|
|
5053
|
-
warnings.push({
|
|
5054
|
-
path: "consent",
|
|
5055
|
-
message: "No consent object provided",
|
|
5056
|
-
suggestion: "Consider adding a consent object for GDPR/privacy compliance"
|
|
5057
|
-
});
|
|
5058
|
-
}
|
|
5059
|
-
details.hasConsent = !!event.consent;
|
|
5060
|
-
details.hasData = !!event.data;
|
|
5061
|
-
details.hasContext = !!event.context;
|
|
5313
|
+
init_event_validation();
|
|
5314
|
+
function validateEvent2(input) {
|
|
5315
|
+
const result = validateEvent(input, "strict");
|
|
5062
5316
|
return {
|
|
5063
|
-
valid:
|
|
5317
|
+
valid: result.valid,
|
|
5064
5318
|
type: "event",
|
|
5065
|
-
errors,
|
|
5066
|
-
warnings,
|
|
5067
|
-
details
|
|
5319
|
+
errors: result.errors,
|
|
5320
|
+
warnings: result.warnings,
|
|
5321
|
+
details: result.details
|
|
5068
5322
|
};
|
|
5069
5323
|
}
|
|
5070
5324
|
|
|
@@ -5251,10 +5505,10 @@ function buildConnectionGraph(config) {
|
|
|
5251
5505
|
function checkCompatibility(conn, errors, warnings) {
|
|
5252
5506
|
const fromOuts = Object.entries(conn.from.examples).filter(([, ex]) => ex.out !== void 0 && ex.out !== false).map(([name, ex]) => ({ name, value: ex.out }));
|
|
5253
5507
|
const toIns = Object.entries(conn.to.examples).filter(([, ex]) => ex.in !== void 0).map(([name, ex]) => ({ name, value: ex.in }));
|
|
5254
|
-
const
|
|
5508
|
+
const path19 = `${conn.from.type}.${conn.from.name} \u2192 ${conn.to.type}.${conn.to.name}`;
|
|
5255
5509
|
if (fromOuts.length === 0 || toIns.length === 0) {
|
|
5256
5510
|
warnings.push({
|
|
5257
|
-
path:
|
|
5511
|
+
path: path19,
|
|
5258
5512
|
message: "Cannot check compatibility: missing out or in examples",
|
|
5259
5513
|
suggestion: "Add out examples to the source step or in examples to the target step"
|
|
5260
5514
|
});
|
|
@@ -5272,7 +5526,7 @@ function checkCompatibility(conn, errors, warnings) {
|
|
|
5272
5526
|
}
|
|
5273
5527
|
if (!hasMatch) {
|
|
5274
5528
|
errors.push({
|
|
5275
|
-
path:
|
|
5529
|
+
path: path19,
|
|
5276
5530
|
message: "No compatible out/in pair found between connected steps",
|
|
5277
5531
|
code: "INCOMPATIBLE_EXAMPLES"
|
|
5278
5532
|
});
|
|
@@ -5368,13 +5622,13 @@ function validateMapping(input) {
|
|
|
5368
5622
|
import Ajv from "ajv";
|
|
5369
5623
|
import { fetchPackageSchema } from "@walkeros/core";
|
|
5370
5624
|
var SECTIONS = ["destinations", "sources", "transformers"];
|
|
5371
|
-
function resolveEntry(
|
|
5625
|
+
function resolveEntry(path19, flowConfig) {
|
|
5372
5626
|
const flows = flowConfig.flows;
|
|
5373
5627
|
if (!flows || typeof flows !== "object") return "No flows found in config";
|
|
5374
5628
|
const flowName = Object.keys(flows)[0];
|
|
5375
5629
|
const flow = flows[flowName];
|
|
5376
5630
|
if (!flow) return `Flow "${flowName}" is empty`;
|
|
5377
|
-
const parts =
|
|
5631
|
+
const parts = path19.split(".");
|
|
5378
5632
|
if (parts.length === 2) {
|
|
5379
5633
|
const [section, key] = parts;
|
|
5380
5634
|
if (!SECTIONS.includes(section)) {
|
|
@@ -5411,15 +5665,15 @@ function resolveEntry(path15, flowConfig) {
|
|
|
5411
5665
|
}
|
|
5412
5666
|
return { section: matches[0].section, key, entry: matches[0].entry };
|
|
5413
5667
|
}
|
|
5414
|
-
return `Invalid path "${
|
|
5668
|
+
return `Invalid path "${path19}". Use "section.key" or just "key"`;
|
|
5415
5669
|
}
|
|
5416
|
-
async function validateEntry(
|
|
5417
|
-
const resolved = resolveEntry(
|
|
5670
|
+
async function validateEntry(path19, flowConfig) {
|
|
5671
|
+
const resolved = resolveEntry(path19, flowConfig);
|
|
5418
5672
|
if (typeof resolved === "string") {
|
|
5419
5673
|
return {
|
|
5420
5674
|
valid: false,
|
|
5421
5675
|
type: "entry",
|
|
5422
|
-
errors: [{ path:
|
|
5676
|
+
errors: [{ path: path19, message: resolved, code: "ENTRY_VALIDATION" }],
|
|
5423
5677
|
warnings: [],
|
|
5424
5678
|
details: {}
|
|
5425
5679
|
};
|
|
@@ -5450,7 +5704,7 @@ async function validateEntry(path15, flowConfig) {
|
|
|
5450
5704
|
type: "entry",
|
|
5451
5705
|
errors: [
|
|
5452
5706
|
{
|
|
5453
|
-
path:
|
|
5707
|
+
path: path19,
|
|
5454
5708
|
message: error instanceof Error ? error.message : "Unknown error",
|
|
5455
5709
|
code: "ENTRY_VALIDATION"
|
|
5456
5710
|
}
|
|
@@ -5475,10 +5729,10 @@ async function validateEntry(path15, flowConfig) {
|
|
|
5475
5729
|
const validate2 = ajv.compile(settingsSchema);
|
|
5476
5730
|
const isValid = validate2(settings || {});
|
|
5477
5731
|
if (!isValid) {
|
|
5478
|
-
const errors = (validate2.errors || []).map((
|
|
5479
|
-
path:
|
|
5480
|
-
message:
|
|
5481
|
-
code:
|
|
5732
|
+
const errors = (validate2.errors || []).map((e) => ({
|
|
5733
|
+
path: e.instancePath || "/",
|
|
5734
|
+
message: e.message || "Unknown error",
|
|
5735
|
+
code: e.keyword
|
|
5482
5736
|
}));
|
|
5483
5737
|
return {
|
|
5484
5738
|
valid: false,
|
|
@@ -5513,7 +5767,7 @@ async function validate(type, input, options = {}) {
|
|
|
5513
5767
|
case "contract":
|
|
5514
5768
|
return validateContract(resolved);
|
|
5515
5769
|
case "event":
|
|
5516
|
-
return
|
|
5770
|
+
return validateEvent2(resolved);
|
|
5517
5771
|
case "flow":
|
|
5518
5772
|
return validateFlow(resolved, { flow: options.flow });
|
|
5519
5773
|
case "mapping":
|
|
@@ -5798,10 +6052,10 @@ async function deleteProject(options = {}) {
|
|
|
5798
6052
|
throw new Error(error.error?.message || "Failed to delete project");
|
|
5799
6053
|
return data ?? { success: true };
|
|
5800
6054
|
}
|
|
5801
|
-
async function handleResult(
|
|
6055
|
+
async function handleResult(fn, options) {
|
|
5802
6056
|
const logger = createCLILogger(options);
|
|
5803
6057
|
try {
|
|
5804
|
-
const result = await
|
|
6058
|
+
const result = await fn();
|
|
5805
6059
|
await writeResult(JSON.stringify(result, null, 2), options);
|
|
5806
6060
|
} catch (error) {
|
|
5807
6061
|
logger.error(error instanceof Error ? error.message : String(error));
|
|
@@ -5957,10 +6211,10 @@ async function duplicateFlow(options) {
|
|
|
5957
6211
|
if (error) throwApiError(error, "Failed to duplicate flow");
|
|
5958
6212
|
return data;
|
|
5959
6213
|
}
|
|
5960
|
-
async function handleResult2(
|
|
6214
|
+
async function handleResult2(fn, options) {
|
|
5961
6215
|
const logger = createCLILogger(options);
|
|
5962
6216
|
try {
|
|
5963
|
-
const result = await
|
|
6217
|
+
const result = await fn();
|
|
5964
6218
|
await writeResult(JSON.stringify(result, null, 2), options);
|
|
5965
6219
|
} catch (error) {
|
|
5966
6220
|
logger.error(error instanceof Error ? error.message : String(error));
|
|
@@ -6119,8 +6373,8 @@ async function deploy(options) {
|
|
|
6119
6373
|
if (error) {
|
|
6120
6374
|
try {
|
|
6121
6375
|
throwApiError(error, "Failed to start deployment");
|
|
6122
|
-
} catch (
|
|
6123
|
-
if (
|
|
6376
|
+
} catch (e) {
|
|
6377
|
+
if (e instanceof ApiError && e.code === "AMBIGUOUS_CONFIG") {
|
|
6124
6378
|
const names = await getAvailableFlowNames({
|
|
6125
6379
|
flowId: options.flowId,
|
|
6126
6380
|
projectId
|
|
@@ -6131,7 +6385,7 @@ Available: ${names.join(", ")}`,
|
|
|
6131
6385
|
{ code: "AMBIGUOUS_CONFIG" }
|
|
6132
6386
|
);
|
|
6133
6387
|
}
|
|
6134
|
-
throw
|
|
6388
|
+
throw e;
|
|
6135
6389
|
}
|
|
6136
6390
|
}
|
|
6137
6391
|
if (!options.wait) return data;
|
|
@@ -6268,7 +6522,7 @@ async function getDeploymentCommand(flowId, options) {
|
|
|
6268
6522
|
// src/commands/deployments/index.ts
|
|
6269
6523
|
init_auth();
|
|
6270
6524
|
init_http();
|
|
6271
|
-
import { getPlatform as
|
|
6525
|
+
import { getPlatform as getPlatform5 } from "@walkeros/core";
|
|
6272
6526
|
init_cli_logger();
|
|
6273
6527
|
init_output();
|
|
6274
6528
|
init_loader();
|
|
@@ -6324,10 +6578,10 @@ async function deleteDeployment(options) {
|
|
|
6324
6578
|
const data = await response.json().catch(() => null);
|
|
6325
6579
|
return data ?? { success: true };
|
|
6326
6580
|
}
|
|
6327
|
-
async function handleResult3(
|
|
6581
|
+
async function handleResult3(fn, options) {
|
|
6328
6582
|
const logger = createCLILogger(options);
|
|
6329
6583
|
try {
|
|
6330
|
-
const result = await
|
|
6584
|
+
const result = await fn();
|
|
6331
6585
|
await writeResult(JSON.stringify(result, null, 2), options);
|
|
6332
6586
|
} catch (error) {
|
|
6333
6587
|
logger.error(error instanceof Error ? error.message : String(error));
|
|
@@ -6401,7 +6655,7 @@ async function createDeployCommand(config, options) {
|
|
|
6401
6655
|
const result2 = await loadFlowConfig(config, {
|
|
6402
6656
|
flowName: options.flow
|
|
6403
6657
|
});
|
|
6404
|
-
type =
|
|
6658
|
+
type = getPlatform5(result2.flowSettings);
|
|
6405
6659
|
}
|
|
6406
6660
|
const deployment = await createDeployment({
|
|
6407
6661
|
type,
|
|
@@ -6502,14 +6756,14 @@ async function feedbackCommand(text) {
|
|
|
6502
6756
|
}
|
|
6503
6757
|
}
|
|
6504
6758
|
function promptUser(question) {
|
|
6505
|
-
return new Promise((
|
|
6759
|
+
return new Promise((resolve3) => {
|
|
6506
6760
|
const rl = createInterface({
|
|
6507
6761
|
input: process.stdin,
|
|
6508
6762
|
output: process.stderr
|
|
6509
6763
|
});
|
|
6510
6764
|
rl.question(question, (answer) => {
|
|
6511
6765
|
rl.close();
|
|
6512
|
-
|
|
6766
|
+
resolve3(answer);
|
|
6513
6767
|
});
|
|
6514
6768
|
});
|
|
6515
6769
|
}
|
|
@@ -6522,6 +6776,108 @@ init_api_client();
|
|
|
6522
6776
|
init_config_file();
|
|
6523
6777
|
init_sse();
|
|
6524
6778
|
init_utils();
|
|
6779
|
+
|
|
6780
|
+
// src/commands/simulate/example-loader.ts
|
|
6781
|
+
function findExample(config, exampleName, stepTarget) {
|
|
6782
|
+
if (stepTarget) {
|
|
6783
|
+
return findExampleInStep(config, exampleName, stepTarget);
|
|
6784
|
+
}
|
|
6785
|
+
return findExampleAcrossSteps(config, exampleName);
|
|
6786
|
+
}
|
|
6787
|
+
function findExampleInStep(config, exampleName, stepTarget) {
|
|
6788
|
+
const dotIndex = stepTarget.indexOf(".");
|
|
6789
|
+
if (dotIndex === -1) {
|
|
6790
|
+
throw new Error(
|
|
6791
|
+
`Invalid --step format: "${stepTarget}". Expected "type.name" (e.g. "destination.gtag")`
|
|
6792
|
+
);
|
|
6793
|
+
}
|
|
6794
|
+
const type = stepTarget.substring(0, dotIndex);
|
|
6795
|
+
const name = stepTarget.substring(dotIndex + 1);
|
|
6796
|
+
const stepMap = getStepMap(config, type);
|
|
6797
|
+
if (!stepMap) {
|
|
6798
|
+
throw new Error(`No ${type}s found in flow config`);
|
|
6799
|
+
}
|
|
6800
|
+
const step = stepMap[name];
|
|
6801
|
+
if (!step) {
|
|
6802
|
+
const available = Object.keys(stepMap).join(", ");
|
|
6803
|
+
throw new Error(`${type} "${name}" not found. Available: ${available}`);
|
|
6804
|
+
}
|
|
6805
|
+
const examples = step.examples;
|
|
6806
|
+
if (!examples || !examples[exampleName]) {
|
|
6807
|
+
const available = examples ? Object.keys(examples).join(", ") : "none";
|
|
6808
|
+
throw new Error(
|
|
6809
|
+
`Example "${exampleName}" not found in ${type} "${name}". Available: ${available}`
|
|
6810
|
+
);
|
|
6811
|
+
}
|
|
6812
|
+
return {
|
|
6813
|
+
stepType: type,
|
|
6814
|
+
stepName: name,
|
|
6815
|
+
exampleName,
|
|
6816
|
+
example: examples[exampleName]
|
|
6817
|
+
};
|
|
6818
|
+
}
|
|
6819
|
+
function findExampleAcrossSteps(config, exampleName) {
|
|
6820
|
+
const matches = [];
|
|
6821
|
+
const stepTypes = ["source", "transformer", "destination"];
|
|
6822
|
+
for (const type of stepTypes) {
|
|
6823
|
+
const stepMap = getStepMap(config, type);
|
|
6824
|
+
if (!stepMap) continue;
|
|
6825
|
+
for (const [name, step] of Object.entries(stepMap)) {
|
|
6826
|
+
const examples = step.examples;
|
|
6827
|
+
if (examples && examples[exampleName]) {
|
|
6828
|
+
matches.push({
|
|
6829
|
+
stepType: type,
|
|
6830
|
+
stepName: name,
|
|
6831
|
+
exampleName,
|
|
6832
|
+
example: examples[exampleName]
|
|
6833
|
+
});
|
|
6834
|
+
}
|
|
6835
|
+
}
|
|
6836
|
+
}
|
|
6837
|
+
if (matches.length === 0) {
|
|
6838
|
+
throw new Error(`Example "${exampleName}" not found in any step`);
|
|
6839
|
+
}
|
|
6840
|
+
if (matches.length > 1) {
|
|
6841
|
+
const locations = matches.map((m2) => `${m2.stepType}.${m2.stepName}`).join(", ");
|
|
6842
|
+
throw new Error(
|
|
6843
|
+
`Example "${exampleName}" found in multiple steps: ${locations}. Use --step to disambiguate.`
|
|
6844
|
+
);
|
|
6845
|
+
}
|
|
6846
|
+
return matches[0];
|
|
6847
|
+
}
|
|
6848
|
+
function getStepMap(config, type) {
|
|
6849
|
+
switch (type) {
|
|
6850
|
+
case "source":
|
|
6851
|
+
return config.sources;
|
|
6852
|
+
case "transformer":
|
|
6853
|
+
return config.transformers;
|
|
6854
|
+
case "destination":
|
|
6855
|
+
return config.destinations;
|
|
6856
|
+
default:
|
|
6857
|
+
throw new Error(
|
|
6858
|
+
`Invalid step type: "${type}". Must be "source", "transformer", or "destination"`
|
|
6859
|
+
);
|
|
6860
|
+
}
|
|
6861
|
+
}
|
|
6862
|
+
|
|
6863
|
+
// src/commands/simulate/compare.ts
|
|
6864
|
+
function compareOutput(expected, actual) {
|
|
6865
|
+
const expectedStr = JSON.stringify(expected, null, 2);
|
|
6866
|
+
const actualStr = JSON.stringify(actual, null, 2);
|
|
6867
|
+
if (expectedStr === actualStr) {
|
|
6868
|
+
return { expected, actual, match: true };
|
|
6869
|
+
}
|
|
6870
|
+
return {
|
|
6871
|
+
expected,
|
|
6872
|
+
actual,
|
|
6873
|
+
match: false,
|
|
6874
|
+
diff: `Expected:
|
|
6875
|
+
${expectedStr}
|
|
6876
|
+
|
|
6877
|
+
Actual:
|
|
6878
|
+
${actualStr}`
|
|
6879
|
+
};
|
|
6880
|
+
}
|
|
6525
6881
|
export {
|
|
6526
6882
|
ApiError,
|
|
6527
6883
|
apiFetch,
|
|
@@ -6567,6 +6923,7 @@ export {
|
|
|
6567
6923
|
listFlowsCommand,
|
|
6568
6924
|
listProjects,
|
|
6569
6925
|
listProjectsCommand,
|
|
6926
|
+
loadConfig,
|
|
6570
6927
|
loadJsonConfig,
|
|
6571
6928
|
loginCommand,
|
|
6572
6929
|
logoutCommand,
|
|
@@ -6579,8 +6936,9 @@ export {
|
|
|
6579
6936
|
requireProjectId,
|
|
6580
6937
|
run,
|
|
6581
6938
|
runCommand,
|
|
6582
|
-
|
|
6583
|
-
|
|
6939
|
+
simulateDestination,
|
|
6940
|
+
simulateSource,
|
|
6941
|
+
simulateTransformer,
|
|
6584
6942
|
throwApiError,
|
|
6585
6943
|
updateFlow,
|
|
6586
6944
|
updateFlowCommand,
|