@walkeros/cli 3.1.1 → 3.2.0
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 +66 -0
- package/README.md +50 -52
- package/dist/cli.js +2817 -2501
- 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 +2112 -1754
- 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 +3 -3
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,7 @@ function detectPlatformFromPath(inputPath) {
|
|
|
505
500
|
}
|
|
506
501
|
async function loadContent(inputPath) {
|
|
507
502
|
if (isUrl(inputPath)) {
|
|
508
|
-
|
|
509
|
-
const response = await fetch(inputPath, {
|
|
510
|
-
headers: mergeAuthHeaders(token)
|
|
511
|
-
});
|
|
512
|
-
if (!response.ok) {
|
|
513
|
-
throw new Error(`Failed to fetch ${inputPath}: ${response.status}`);
|
|
514
|
-
}
|
|
515
|
-
return response.text();
|
|
503
|
+
return fetchContentString(inputPath);
|
|
516
504
|
}
|
|
517
505
|
const trimmed = inputPath.trim();
|
|
518
506
|
if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
|
|
@@ -524,12 +512,12 @@ var init_input_detector = __esm({
|
|
|
524
512
|
"src/core/input-detector.ts"() {
|
|
525
513
|
"use strict";
|
|
526
514
|
init_utils();
|
|
527
|
-
init_http();
|
|
528
|
-
init_config_file();
|
|
529
515
|
}
|
|
530
516
|
});
|
|
531
517
|
|
|
532
518
|
// src/core/stdin.ts
|
|
519
|
+
import fs5 from "fs-extra";
|
|
520
|
+
import path6 from "path";
|
|
533
521
|
function isStdinPiped() {
|
|
534
522
|
return !process.stdin.isTTY;
|
|
535
523
|
}
|
|
@@ -544,9 +532,17 @@ async function readStdin() {
|
|
|
544
532
|
}
|
|
545
533
|
return content;
|
|
546
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
|
+
}
|
|
547
542
|
var init_stdin = __esm({
|
|
548
543
|
"src/core/stdin.ts"() {
|
|
549
544
|
"use strict";
|
|
545
|
+
init_tmp();
|
|
550
546
|
}
|
|
551
547
|
});
|
|
552
548
|
|
|
@@ -603,6 +599,129 @@ var init_sse = __esm({
|
|
|
603
599
|
}
|
|
604
600
|
});
|
|
605
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
|
+
|
|
606
725
|
// src/core/index.ts
|
|
607
726
|
var init_core = __esm({
|
|
608
727
|
"src/core/index.ts"() {
|
|
@@ -619,20 +738,19 @@ var init_core = __esm({
|
|
|
619
738
|
init_auth();
|
|
620
739
|
init_http();
|
|
621
740
|
init_sse();
|
|
741
|
+
init_event_validation();
|
|
742
|
+
init_package_path();
|
|
622
743
|
}
|
|
623
744
|
});
|
|
624
745
|
|
|
625
746
|
// src/config/validators.ts
|
|
626
|
-
import { schemas } from "@walkeros/core/dev";
|
|
627
|
-
function isObject(value) {
|
|
628
|
-
return typeof value === "object" && value !== null && !Array.isArray(value) && Object.prototype.toString.call(value) === "[object Object]";
|
|
629
|
-
}
|
|
747
|
+
import { schemas as schemas2 } from "@walkeros/core/dev";
|
|
630
748
|
function validateFlowConfig(data) {
|
|
631
749
|
const result = safeParseConfig(data);
|
|
632
750
|
if (!result.success) {
|
|
633
751
|
const errors = result.error.issues.map((issue) => {
|
|
634
|
-
const
|
|
635
|
-
return ` - ${
|
|
752
|
+
const path19 = issue.path.length > 0 ? issue.path.map(String).join(".") : "root";
|
|
753
|
+
return ` - ${path19}: ${issue.message}`;
|
|
636
754
|
}).join("\n");
|
|
637
755
|
throw new Error(`Invalid configuration:
|
|
638
756
|
${errors}`);
|
|
@@ -646,7 +764,7 @@ var safeParseConfig;
|
|
|
646
764
|
var init_validators = __esm({
|
|
647
765
|
"src/config/validators.ts"() {
|
|
648
766
|
"use strict";
|
|
649
|
-
({ safeParseConfig } =
|
|
767
|
+
({ safeParseConfig } = schemas2);
|
|
650
768
|
}
|
|
651
769
|
});
|
|
652
770
|
|
|
@@ -668,7 +786,7 @@ var init_build_defaults = __esm({
|
|
|
668
786
|
minify: true,
|
|
669
787
|
sourcemap: false,
|
|
670
788
|
cache: true,
|
|
671
|
-
windowCollector: "
|
|
789
|
+
windowCollector: "walkerOS",
|
|
672
790
|
windowElb: "elb"
|
|
673
791
|
};
|
|
674
792
|
SERVER_BUILD_DEFAULTS = {
|
|
@@ -687,8 +805,8 @@ var init_build_defaults = __esm({
|
|
|
687
805
|
});
|
|
688
806
|
|
|
689
807
|
// src/config/loader.ts
|
|
690
|
-
import
|
|
691
|
-
import
|
|
808
|
+
import path8 from "path";
|
|
809
|
+
import fs7 from "fs-extra";
|
|
692
810
|
import { getFlowSettings, getPlatform } from "@walkeros/core";
|
|
693
811
|
function loadBundleConfig(rawConfig, options) {
|
|
694
812
|
const config = validateFlowConfig(rawConfig);
|
|
@@ -707,11 +825,11 @@ function loadBundleConfig(rawConfig, options) {
|
|
|
707
825
|
const buildDefaults = getBuildDefaults(platform);
|
|
708
826
|
const packages = flowSettings.packages || {};
|
|
709
827
|
const output = options.buildOverrides?.output || getDefaultOutput(platform);
|
|
710
|
-
const configDir = isUrl(options.configPath) ? process.cwd() :
|
|
828
|
+
const configDir = isUrl(options.configPath) ? process.cwd() : path8.dirname(options.configPath);
|
|
711
829
|
let includes = config.include;
|
|
712
830
|
if (!includes) {
|
|
713
|
-
const defaultIncludePath =
|
|
714
|
-
if (
|
|
831
|
+
const defaultIncludePath = path8.resolve(configDir, DEFAULT_INCLUDE_FOLDER);
|
|
832
|
+
if (fs7.pathExistsSync(defaultIncludePath)) {
|
|
715
833
|
includes = [DEFAULT_INCLUDE_FOLDER];
|
|
716
834
|
}
|
|
717
835
|
}
|
|
@@ -796,6 +914,43 @@ var init_config = __esm({
|
|
|
796
914
|
}
|
|
797
915
|
});
|
|
798
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
|
+
|
|
799
954
|
// src/core/cache-utils.ts
|
|
800
955
|
import { getHashServer } from "@walkeros/server-core";
|
|
801
956
|
import semver from "semver";
|
|
@@ -836,8 +991,8 @@ var init_cache_utils = __esm({
|
|
|
836
991
|
|
|
837
992
|
// src/commands/bundle/package-manager.ts
|
|
838
993
|
import pacote from "pacote";
|
|
839
|
-
import
|
|
840
|
-
import
|
|
994
|
+
import path9 from "path";
|
|
995
|
+
import fs8 from "fs-extra";
|
|
841
996
|
import semver2 from "semver";
|
|
842
997
|
async function withTimeout(promise, ms, errorMessage) {
|
|
843
998
|
let timer;
|
|
@@ -851,7 +1006,7 @@ async function withTimeout(promise, ms, errorMessage) {
|
|
|
851
1006
|
}
|
|
852
1007
|
}
|
|
853
1008
|
function getPackageDirectory(baseDir, packageName) {
|
|
854
|
-
return
|
|
1009
|
+
return path9.join(baseDir, "node_modules", packageName);
|
|
855
1010
|
}
|
|
856
1011
|
async function collectAllSpecs(packages, logger, configDir) {
|
|
857
1012
|
const allSpecs = /* @__PURE__ */ new Map();
|
|
@@ -877,7 +1032,47 @@ async function collectAllSpecs(packages, logger, configDir) {
|
|
|
877
1032
|
optional: item.optional,
|
|
878
1033
|
localPath: item.localPath
|
|
879
1034
|
});
|
|
880
|
-
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
|
+
}
|
|
881
1076
|
let manifest;
|
|
882
1077
|
try {
|
|
883
1078
|
manifest = await withTimeout(
|
|
@@ -924,7 +1119,7 @@ async function collectAllSpecs(packages, logger, configDir) {
|
|
|
924
1119
|
function resolveVersionConflicts(allSpecs, logger) {
|
|
925
1120
|
const resolved = /* @__PURE__ */ new Map();
|
|
926
1121
|
for (const [name, specs] of allSpecs) {
|
|
927
|
-
const localSpec = specs.find((
|
|
1122
|
+
const localSpec = specs.find((s) => s.localPath);
|
|
928
1123
|
if (localSpec) {
|
|
929
1124
|
resolved.set(name, {
|
|
930
1125
|
name,
|
|
@@ -933,13 +1128,13 @@ function resolveVersionConflicts(allSpecs, logger) {
|
|
|
933
1128
|
});
|
|
934
1129
|
continue;
|
|
935
1130
|
}
|
|
936
|
-
const nonPeerSpecs = specs.filter((
|
|
937
|
-
const peerSpecs = specs.filter((
|
|
1131
|
+
const nonPeerSpecs = specs.filter((s) => s.source !== "peerDependency");
|
|
1132
|
+
const peerSpecs = specs.filter((s) => s.source === "peerDependency");
|
|
938
1133
|
let activeSpecs;
|
|
939
1134
|
if (nonPeerSpecs.length > 0) {
|
|
940
1135
|
activeSpecs = nonPeerSpecs;
|
|
941
1136
|
} else {
|
|
942
|
-
const requiredPeers = peerSpecs.filter((
|
|
1137
|
+
const requiredPeers = peerSpecs.filter((s) => !s.optional);
|
|
943
1138
|
if (requiredPeers.length === 0) {
|
|
944
1139
|
logger.debug(`Skipping optional peer dependency: ${name}`);
|
|
945
1140
|
continue;
|
|
@@ -949,19 +1144,19 @@ function resolveVersionConflicts(allSpecs, logger) {
|
|
|
949
1144
|
activeSpecs.sort(
|
|
950
1145
|
(a2, b2) => SOURCE_PRIORITY[a2.source] - SOURCE_PRIORITY[b2.source]
|
|
951
1146
|
);
|
|
952
|
-
const directSpecs = activeSpecs.filter((
|
|
953
|
-
const directExact = directSpecs.find((
|
|
1147
|
+
const directSpecs = activeSpecs.filter((s) => s.source === "direct");
|
|
1148
|
+
const directExact = directSpecs.find((s) => semver2.valid(s.spec) !== null);
|
|
954
1149
|
let chosenVersion;
|
|
955
1150
|
if (directExact) {
|
|
956
1151
|
chosenVersion = directExact.spec;
|
|
957
1152
|
} else if (directSpecs.length > 0) {
|
|
958
1153
|
chosenVersion = directSpecs[0].spec;
|
|
959
1154
|
} else {
|
|
960
|
-
const exactVersions = activeSpecs.filter((
|
|
1155
|
+
const exactVersions = activeSpecs.filter((s) => semver2.valid(s.spec) !== null).map((s) => s.spec);
|
|
961
1156
|
const uniqueExact = [...new Set(exactVersions)];
|
|
962
1157
|
if (uniqueExact.length > 1) {
|
|
963
1158
|
throw new Error(
|
|
964
|
-
`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(", ")})`
|
|
965
1160
|
);
|
|
966
1161
|
} else if (uniqueExact.length === 1) {
|
|
967
1162
|
chosenVersion = uniqueExact[0];
|
|
@@ -1008,7 +1203,7 @@ async function downloadPackages(packages, targetDir, logger, useCache = true, co
|
|
|
1008
1203
|
logger.debug("Resolving dependencies");
|
|
1009
1204
|
const allSpecs = await collectAllSpecs(packages, logger, configDir);
|
|
1010
1205
|
const resolved = resolveVersionConflicts(allSpecs, logger);
|
|
1011
|
-
await
|
|
1206
|
+
await fs8.ensureDir(targetDir);
|
|
1012
1207
|
const localPackageMap = /* @__PURE__ */ new Map();
|
|
1013
1208
|
for (const pkg of packages) {
|
|
1014
1209
|
if (pkg.path) localPackageMap.set(pkg.name, pkg.path);
|
|
@@ -1037,8 +1232,8 @@ async function downloadPackages(packages, targetDir, logger, useCache = true, co
|
|
|
1037
1232
|
logger.debug(`Downloading ${packageSpec} (cached)`);
|
|
1038
1233
|
}
|
|
1039
1234
|
try {
|
|
1040
|
-
await
|
|
1041
|
-
await
|
|
1235
|
+
await fs8.ensureDir(path9.dirname(packageDir));
|
|
1236
|
+
await fs8.copy(cachedPath, packageDir);
|
|
1042
1237
|
packagePaths.set(name, packageDir);
|
|
1043
1238
|
continue;
|
|
1044
1239
|
} catch {
|
|
@@ -1046,7 +1241,7 @@ async function downloadPackages(packages, targetDir, logger, useCache = true, co
|
|
|
1046
1241
|
}
|
|
1047
1242
|
}
|
|
1048
1243
|
try {
|
|
1049
|
-
await
|
|
1244
|
+
await fs8.ensureDir(path9.dirname(packageDir));
|
|
1050
1245
|
const cacheDir = process.env.NPM_CACHE_DIR || getTmpPath(tmpDir, "cache", "npm");
|
|
1051
1246
|
await withTimeout(
|
|
1052
1247
|
pacote.extract(packageSpec, packageDir, {
|
|
@@ -1061,8 +1256,8 @@ async function downloadPackages(packages, targetDir, logger, useCache = true, co
|
|
|
1061
1256
|
}
|
|
1062
1257
|
if (useCache) {
|
|
1063
1258
|
try {
|
|
1064
|
-
await
|
|
1065
|
-
await
|
|
1259
|
+
await fs8.ensureDir(path9.dirname(cachedPath));
|
|
1260
|
+
await fs8.copy(packageDir, cachedPath);
|
|
1066
1261
|
} catch {
|
|
1067
1262
|
}
|
|
1068
1263
|
}
|
|
@@ -1076,11 +1271,11 @@ async function downloadPackages(packages, targetDir, logger, useCache = true, co
|
|
|
1076
1271
|
async function getCachedPackagePath(pkg, tmpDir) {
|
|
1077
1272
|
const cacheDir = getTmpPath(tmpDir, "cache", "packages");
|
|
1078
1273
|
const cacheKey = await getPackageCacheKey(pkg.name, pkg.version);
|
|
1079
|
-
return
|
|
1274
|
+
return path9.join(cacheDir, cacheKey);
|
|
1080
1275
|
}
|
|
1081
1276
|
async function isPackageCached(pkg, tmpDir) {
|
|
1082
1277
|
const cachedPath = await getCachedPackagePath(pkg, tmpDir);
|
|
1083
|
-
return
|
|
1278
|
+
return fs8.pathExists(cachedPath);
|
|
1084
1279
|
}
|
|
1085
1280
|
function validateNoDuplicatePackages(packages) {
|
|
1086
1281
|
const packageMap = /* @__PURE__ */ new Map();
|
|
@@ -1126,29 +1321,57 @@ var init_package_manager = __esm({
|
|
|
1126
1321
|
});
|
|
1127
1322
|
|
|
1128
1323
|
// src/core/build-cache.ts
|
|
1129
|
-
import
|
|
1130
|
-
import
|
|
1324
|
+
import fs9 from "fs-extra";
|
|
1325
|
+
import path10 from "path";
|
|
1326
|
+
import { getHashServer as getHashServer2 } from "@walkeros/server-core";
|
|
1131
1327
|
async function getBuildCachePath(configContent, tmpDir) {
|
|
1132
1328
|
const cacheDir = getTmpPath(tmpDir, "cache", "builds");
|
|
1133
1329
|
const cacheKey = await getFlowSettingsCacheKey(configContent);
|
|
1134
|
-
return
|
|
1330
|
+
return path10.join(cacheDir, `${cacheKey}.js`);
|
|
1135
1331
|
}
|
|
1136
1332
|
async function isBuildCached(configContent, tmpDir) {
|
|
1137
1333
|
const cachePath = await getBuildCachePath(configContent, tmpDir);
|
|
1138
|
-
return
|
|
1334
|
+
return fs9.pathExists(cachePath);
|
|
1139
1335
|
}
|
|
1140
1336
|
async function cacheBuild(configContent, buildOutput, tmpDir) {
|
|
1141
1337
|
const cachePath = await getBuildCachePath(configContent, tmpDir);
|
|
1142
|
-
await
|
|
1143
|
-
await
|
|
1338
|
+
await fs9.ensureDir(path10.dirname(cachePath));
|
|
1339
|
+
await fs9.writeFile(cachePath, buildOutput, "utf-8");
|
|
1144
1340
|
}
|
|
1145
1341
|
async function getCachedBuild(configContent, tmpDir) {
|
|
1146
1342
|
const cachePath = await getBuildCachePath(configContent, tmpDir);
|
|
1147
|
-
if (await
|
|
1148
|
-
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");
|
|
1149
1362
|
}
|
|
1150
1363
|
return null;
|
|
1151
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
|
+
}
|
|
1152
1375
|
var init_build_cache = __esm({
|
|
1153
1376
|
"src/core/build-cache.ts"() {
|
|
1154
1377
|
"use strict";
|
|
@@ -1158,19 +1381,23 @@ var init_build_cache = __esm({
|
|
|
1158
1381
|
});
|
|
1159
1382
|
|
|
1160
1383
|
// src/commands/bundle/bundler.ts
|
|
1161
|
-
import
|
|
1384
|
+
import crypto from "crypto";
|
|
1162
1385
|
import esbuild from "esbuild";
|
|
1163
1386
|
import { builtinModules } from "module";
|
|
1164
|
-
import
|
|
1165
|
-
import
|
|
1387
|
+
import path11 from "path";
|
|
1388
|
+
import fs10 from "fs-extra";
|
|
1166
1389
|
import { packageNameToVariable, ENV_MARKER_PREFIX } from "@walkeros/core";
|
|
1167
1390
|
function isInlineCode(code) {
|
|
1168
1391
|
return code !== null && typeof code === "object" && !Array.isArray(code) && "push" in code;
|
|
1169
1392
|
}
|
|
1393
|
+
function hasCodeReference(code) {
|
|
1394
|
+
return isInlineCode(code) || typeof code === "string";
|
|
1395
|
+
}
|
|
1170
1396
|
function validateReference(type, name, ref) {
|
|
1171
1397
|
const hasPackage = !!ref.package;
|
|
1172
|
-
const
|
|
1173
|
-
|
|
1398
|
+
const hasInlineCode = isInlineCode(ref.code);
|
|
1399
|
+
const hasCode = hasCodeReference(ref.code);
|
|
1400
|
+
if (hasPackage && hasInlineCode) {
|
|
1174
1401
|
throw new Error(
|
|
1175
1402
|
`${type} "${name}": Cannot specify both package and code. Use one or the other.`
|
|
1176
1403
|
);
|
|
@@ -1211,18 +1438,18 @@ function generateInlineCode(inline, config, env, chain, chainPropertyName, isDes
|
|
|
1211
1438
|
}
|
|
1212
1439
|
async function copyIncludes(includes, sourceDir, outputDir, logger) {
|
|
1213
1440
|
for (const include of includes) {
|
|
1214
|
-
const sourcePath =
|
|
1215
|
-
const folderName =
|
|
1216
|
-
const destPath =
|
|
1217
|
-
const resolvedOutput =
|
|
1218
|
-
const resolvedSource =
|
|
1219
|
-
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)) {
|
|
1220
1447
|
throw new Error(
|
|
1221
1448
|
`Circular include detected: "${include}" resolves to "${resolvedSource}" which overlaps with output directory "${resolvedOutput}"`
|
|
1222
1449
|
);
|
|
1223
1450
|
}
|
|
1224
|
-
if (await
|
|
1225
|
-
await
|
|
1451
|
+
if (await fs10.pathExists(sourcePath)) {
|
|
1452
|
+
await fs10.copy(sourcePath, destPath);
|
|
1226
1453
|
logger.debug(`Copied ${include} to output`);
|
|
1227
1454
|
} else {
|
|
1228
1455
|
logger.warn(`Include folder not found: ${include}`);
|
|
@@ -1283,7 +1510,7 @@ async function bundleCore(flowSettings, buildOptions, logger, showStats = false)
|
|
|
1283
1510
|
if (hasDeprecatedFeatures) {
|
|
1284
1511
|
logger.warn("Skipping deprecated code: true entries from bundle.");
|
|
1285
1512
|
}
|
|
1286
|
-
const buildId =
|
|
1513
|
+
const buildId = crypto.randomUUID();
|
|
1287
1514
|
const TEMP_DIR = buildOptions.tempDir || getTmpPath(void 0, `walkeros-build-${buildId}`);
|
|
1288
1515
|
const CACHE_DIR = buildOptions.tempDir || getTmpPath();
|
|
1289
1516
|
if (buildOptions.cache !== false) {
|
|
@@ -1293,14 +1520,14 @@ async function bundleCore(flowSettings, buildOptions, logger, showStats = false)
|
|
|
1293
1520
|
const cachedBuild = await getCachedBuild(configContent, CACHE_DIR);
|
|
1294
1521
|
if (cachedBuild) {
|
|
1295
1522
|
logger.debug("Using cached build");
|
|
1296
|
-
const outputPath =
|
|
1297
|
-
await
|
|
1298
|
-
await
|
|
1299
|
-
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);
|
|
1300
1527
|
const sizeKB = (stats.size / 1024).toFixed(1);
|
|
1301
1528
|
logger.info(`Output: ${outputPath} (${sizeKB} KB, cached)`);
|
|
1302
1529
|
if (showStats) {
|
|
1303
|
-
const stats2 = await
|
|
1530
|
+
const stats2 = await fs10.stat(outputPath);
|
|
1304
1531
|
const packageStats = Object.entries(buildOptions.packages).map(
|
|
1305
1532
|
([name, pkg]) => ({
|
|
1306
1533
|
name: `${name}@${pkg.version || "latest"}`,
|
|
@@ -1323,7 +1550,7 @@ async function bundleCore(flowSettings, buildOptions, logger, showStats = false)
|
|
|
1323
1550
|
}
|
|
1324
1551
|
}
|
|
1325
1552
|
try {
|
|
1326
|
-
await
|
|
1553
|
+
await fs10.ensureDir(TEMP_DIR);
|
|
1327
1554
|
const hasSourcesOrDests = Object.keys(
|
|
1328
1555
|
flowSettings.sources || {}
|
|
1329
1556
|
).length > 0 || Object.keys(
|
|
@@ -1332,9 +1559,28 @@ async function bundleCore(flowSettings, buildOptions, logger, showStats = false)
|
|
|
1332
1559
|
if (hasSourcesOrDests && !buildOptions.packages["@walkeros/collector"]) {
|
|
1333
1560
|
buildOptions.packages["@walkeros/collector"] = {};
|
|
1334
1561
|
}
|
|
1335
|
-
const stepPackages =
|
|
1562
|
+
const stepPackages = collectAllStepPackages(flowSettings);
|
|
1336
1563
|
for (const pkg of stepPackages) {
|
|
1337
|
-
|
|
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]) {
|
|
1338
1584
|
buildOptions.packages[pkg] = {};
|
|
1339
1585
|
}
|
|
1340
1586
|
}
|
|
@@ -1358,8 +1604,8 @@ async function bundleCore(flowSettings, buildOptions, logger, showStats = false)
|
|
|
1358
1604
|
);
|
|
1359
1605
|
for (const [pkgName, pkgPath] of packagePaths.entries()) {
|
|
1360
1606
|
if (pkgName.startsWith("@walkeros/")) {
|
|
1361
|
-
const pkgJsonPath =
|
|
1362
|
-
const pkgJson = await
|
|
1607
|
+
const pkgJsonPath = path11.join(pkgPath, "package.json");
|
|
1608
|
+
const pkgJson = await fs10.readJSON(pkgJsonPath);
|
|
1363
1609
|
if (!pkgJson.exports && pkgJson.module) {
|
|
1364
1610
|
pkgJson.exports = {
|
|
1365
1611
|
".": {
|
|
@@ -1367,67 +1613,135 @@ async function bundleCore(flowSettings, buildOptions, logger, showStats = false)
|
|
|
1367
1613
|
require: pkgJson.main
|
|
1368
1614
|
}
|
|
1369
1615
|
};
|
|
1370
|
-
await
|
|
1616
|
+
await fs10.writeJSON(pkgJsonPath, pkgJson, { spaces: 2 });
|
|
1371
1617
|
}
|
|
1372
1618
|
}
|
|
1373
1619
|
}
|
|
1374
|
-
const packageJsonPath =
|
|
1375
|
-
await
|
|
1620
|
+
const packageJsonPath = path11.join(TEMP_DIR, "package.json");
|
|
1621
|
+
await fs10.writeFile(
|
|
1376
1622
|
packageJsonPath,
|
|
1377
1623
|
JSON.stringify({ type: "module" }, null, 2)
|
|
1378
1624
|
);
|
|
1379
1625
|
logger.debug("Creating entry point");
|
|
1380
|
-
const
|
|
1626
|
+
const { codeEntry, dataPayload, hasFlow } = await createEntryPoint(
|
|
1381
1627
|
flowSettings,
|
|
1382
1628
|
buildOptions,
|
|
1383
1629
|
packagePaths
|
|
1384
1630
|
);
|
|
1385
|
-
const
|
|
1386
|
-
await
|
|
1387
|
-
|
|
1388
|
-
`Running esbuild (target: ${buildOptions.target || "es2018"}, format: ${buildOptions.format})`
|
|
1389
|
-
);
|
|
1390
|
-
const outputPath = path9.resolve(buildOptions.output);
|
|
1391
|
-
await fs8.ensureDir(path9.dirname(outputPath));
|
|
1392
|
-
const esbuildOptions = createEsbuildOptions(
|
|
1393
|
-
buildOptions,
|
|
1394
|
-
entryPath,
|
|
1395
|
-
outputPath,
|
|
1396
|
-
TEMP_DIR,
|
|
1397
|
-
packagePaths,
|
|
1398
|
-
logger
|
|
1399
|
-
);
|
|
1400
|
-
try {
|
|
1401
|
-
await esbuild.build(esbuildOptions);
|
|
1402
|
-
} catch (buildError) {
|
|
1403
|
-
throw createBuildError(
|
|
1404
|
-
buildError,
|
|
1405
|
-
buildOptions.code || ""
|
|
1406
|
-
);
|
|
1407
|
-
} finally {
|
|
1408
|
-
await esbuild.stop();
|
|
1409
|
-
}
|
|
1410
|
-
const outputStats = await fs8.stat(outputPath);
|
|
1411
|
-
const sizeKB = (outputStats.size / 1024).toFixed(1);
|
|
1412
|
-
const buildTime = ((Date.now() - bundleStartTime) / 1e3).toFixed(1);
|
|
1413
|
-
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;
|
|
1414
1634
|
if (buildOptions.cache !== false) {
|
|
1415
|
-
|
|
1416
|
-
const buildOutput = await fs8.readFile(outputPath, "utf-8");
|
|
1417
|
-
await cacheBuild(configContent, buildOutput, CACHE_DIR);
|
|
1418
|
-
logger.debug("Build cached for future use");
|
|
1635
|
+
compiledCode = await getCachedCode(codeEntry, CACHE_DIR);
|
|
1419
1636
|
}
|
|
1420
|
-
|
|
1421
|
-
|
|
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;
|
|
1735
|
+
if (showStats) {
|
|
1422
1736
|
stats = await collectBundleStats(
|
|
1423
1737
|
outputPath,
|
|
1424
1738
|
buildOptions.packages,
|
|
1425
1739
|
bundleStartTime,
|
|
1426
|
-
|
|
1740
|
+
codeEntry
|
|
1427
1741
|
);
|
|
1428
1742
|
}
|
|
1429
1743
|
if (buildOptions.include && buildOptions.include.length > 0) {
|
|
1430
|
-
const outputDir =
|
|
1744
|
+
const outputDir = path11.dirname(outputPath);
|
|
1431
1745
|
await copyIncludes(
|
|
1432
1746
|
buildOptions.include,
|
|
1433
1747
|
buildOptions.configDir || process.cwd(),
|
|
@@ -1440,13 +1754,13 @@ async function bundleCore(flowSettings, buildOptions, logger, showStats = false)
|
|
|
1440
1754
|
throw error;
|
|
1441
1755
|
} finally {
|
|
1442
1756
|
if (!buildOptions.tempDir) {
|
|
1443
|
-
|
|
1757
|
+
fs10.remove(TEMP_DIR).catch(() => {
|
|
1444
1758
|
});
|
|
1445
1759
|
}
|
|
1446
1760
|
}
|
|
1447
1761
|
}
|
|
1448
1762
|
async function collectBundleStats(outputPath, packages, startTime, entryContent) {
|
|
1449
|
-
const stats = await
|
|
1763
|
+
const stats = await fs10.stat(outputPath);
|
|
1450
1764
|
const totalSize = stats.size;
|
|
1451
1765
|
const buildTime = Date.now() - startTime;
|
|
1452
1766
|
const packageStats = Object.entries(packages).map(([name, pkg]) => {
|
|
@@ -1477,7 +1791,8 @@ function createEsbuildOptions(buildOptions, entryPath, outputPath, tempDir, pack
|
|
|
1477
1791
|
const baseOptions = {
|
|
1478
1792
|
entryPoints: [entryPath],
|
|
1479
1793
|
bundle: true,
|
|
1480
|
-
format:
|
|
1794
|
+
format: "esm",
|
|
1795
|
+
// Always ESM — platform wrapper handles final format
|
|
1481
1796
|
platform: buildOptions.platform,
|
|
1482
1797
|
outfile: outputPath,
|
|
1483
1798
|
absWorkingDir: tempDir,
|
|
@@ -1510,11 +1825,6 @@ function createEsbuildOptions(buildOptions, entryPath, outputPath, tempDir, pack
|
|
|
1510
1825
|
} else if (buildOptions.platform === "node") {
|
|
1511
1826
|
const nodeExternals = getNodeExternals();
|
|
1512
1827
|
baseOptions.external = buildOptions.external ? [...nodeExternals, ...buildOptions.external] : nodeExternals;
|
|
1513
|
-
if (buildOptions.format === "esm") {
|
|
1514
|
-
baseOptions.banner = {
|
|
1515
|
-
js: `import { createRequire } from 'module';const require = createRequire(import.meta.url);`
|
|
1516
|
-
};
|
|
1517
|
-
}
|
|
1518
1828
|
}
|
|
1519
1829
|
if (buildOptions.target) {
|
|
1520
1830
|
baseOptions.target = buildOptions.target;
|
|
@@ -1525,64 +1835,19 @@ function createEsbuildOptions(buildOptions, entryPath, outputPath, tempDir, pack
|
|
|
1525
1835
|
}
|
|
1526
1836
|
return baseOptions;
|
|
1527
1837
|
}
|
|
1528
|
-
function
|
|
1529
|
-
const
|
|
1530
|
-
const
|
|
1531
|
-
if (
|
|
1532
|
-
for (const [
|
|
1533
|
-
if (typeof
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
destinationPackages.add(destConfig.package);
|
|
1538
|
-
}
|
|
1539
|
-
}
|
|
1540
|
-
}
|
|
1541
|
-
return destinationPackages;
|
|
1542
|
-
}
|
|
1543
|
-
function detectSourcePackages(flowSettings) {
|
|
1544
|
-
const sourcePackages = /* @__PURE__ */ new Set();
|
|
1545
|
-
const sources = flowSettings.sources;
|
|
1546
|
-
if (sources) {
|
|
1547
|
-
for (const [sourceKey, sourceConfig] of Object.entries(sources)) {
|
|
1548
|
-
if (typeof sourceConfig === "object" && sourceConfig !== null && "code" in sourceConfig && sourceConfig.code === true) {
|
|
1549
|
-
continue;
|
|
1550
|
-
}
|
|
1551
|
-
if (typeof sourceConfig === "object" && sourceConfig !== null && "package" in sourceConfig && typeof sourceConfig.package === "string") {
|
|
1552
|
-
sourcePackages.add(sourceConfig.package);
|
|
1553
|
-
}
|
|
1554
|
-
}
|
|
1555
|
-
}
|
|
1556
|
-
return sourcePackages;
|
|
1557
|
-
}
|
|
1558
|
-
function detectTransformerPackages(flowSettings) {
|
|
1559
|
-
const transformerPackages = /* @__PURE__ */ new Set();
|
|
1560
|
-
const transformers = flowSettings.transformers;
|
|
1561
|
-
if (transformers) {
|
|
1562
|
-
for (const [transformerKey, transformerConfig] of Object.entries(
|
|
1563
|
-
transformers
|
|
1564
|
-
)) {
|
|
1565
|
-
if (typeof transformerConfig === "object" && transformerConfig !== null && "code" in transformerConfig && transformerConfig.code === true) {
|
|
1566
|
-
continue;
|
|
1567
|
-
}
|
|
1568
|
-
if (typeof transformerConfig === "object" && transformerConfig !== null && "package" in transformerConfig && typeof transformerConfig.package === "string") {
|
|
1569
|
-
transformerPackages.add(transformerConfig.package);
|
|
1570
|
-
}
|
|
1571
|
-
}
|
|
1572
|
-
}
|
|
1573
|
-
return transformerPackages;
|
|
1574
|
-
}
|
|
1575
|
-
function detectStorePackages(flowSettings) {
|
|
1576
|
-
const storePackages = /* @__PURE__ */ new Set();
|
|
1577
|
-
const stores = flowSettings.stores;
|
|
1578
|
-
if (stores) {
|
|
1579
|
-
for (const [, storeConfig] of Object.entries(stores)) {
|
|
1580
|
-
if (typeof storeConfig === "object" && storeConfig !== null && "package" in storeConfig && typeof storeConfig.package === "string") {
|
|
1581
|
-
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);
|
|
1582
1847
|
}
|
|
1583
1848
|
}
|
|
1584
1849
|
}
|
|
1585
|
-
return
|
|
1850
|
+
return packages;
|
|
1586
1851
|
}
|
|
1587
1852
|
function getNodeExternals() {
|
|
1588
1853
|
const externals = [];
|
|
@@ -1592,27 +1857,20 @@ function getNodeExternals() {
|
|
|
1592
1857
|
}
|
|
1593
1858
|
return externals;
|
|
1594
1859
|
}
|
|
1595
|
-
function
|
|
1860
|
+
function collectAllStepPackages(flowSettings) {
|
|
1596
1861
|
const allPackages = /* @__PURE__ */ new Set();
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
for (const
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
for (const pkg of detectStorePackages(flowSettings)) {
|
|
1607
|
-
allPackages.add(pkg);
|
|
1608
|
-
}
|
|
1609
|
-
const npmPackages = /* @__PURE__ */ new Set();
|
|
1610
|
-
for (const pkg of allPackages) {
|
|
1611
|
-
if (!pkg.startsWith(".") && !pkg.startsWith("/")) {
|
|
1612
|
-
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);
|
|
1613
1871
|
}
|
|
1614
1872
|
}
|
|
1615
|
-
return
|
|
1873
|
+
return allPackages;
|
|
1616
1874
|
}
|
|
1617
1875
|
function detectExplicitCodeImports(flowSettings) {
|
|
1618
1876
|
const explicitCodeImports = /* @__PURE__ */ new Map();
|
|
@@ -1759,12 +2017,12 @@ function validateComponentNames(components, section) {
|
|
|
1759
2017
|
}
|
|
1760
2018
|
function validateStoreReferences(flowSettings, storeIds) {
|
|
1761
2019
|
const refs = [];
|
|
1762
|
-
function collectRefs(obj,
|
|
2020
|
+
function collectRefs(obj, path19) {
|
|
1763
2021
|
if (typeof obj === "string" && obj.startsWith("$store:")) {
|
|
1764
|
-
refs.push({ ref: obj.slice(7), location:
|
|
2022
|
+
refs.push({ ref: obj.slice(7), location: path19 });
|
|
1765
2023
|
} else if (obj && typeof obj === "object") {
|
|
1766
2024
|
for (const [key, val] of Object.entries(obj)) {
|
|
1767
|
-
collectRefs(val, `${
|
|
2025
|
+
collectRefs(val, `${path19}.${key}`);
|
|
1768
2026
|
}
|
|
1769
2027
|
}
|
|
1770
2028
|
}
|
|
@@ -1789,10 +2047,10 @@ function validateStoreReferences(flowSettings, storeIds) {
|
|
|
1789
2047
|
}
|
|
1790
2048
|
}
|
|
1791
2049
|
async function createEntryPoint(flowSettings, buildOptions, packagePaths) {
|
|
1792
|
-
const
|
|
1793
|
-
const
|
|
1794
|
-
const transformerPackages =
|
|
1795
|
-
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");
|
|
1796
2054
|
const explicitCodeImports = detectExplicitCodeImports(flowSettings);
|
|
1797
2055
|
const storeIds = new Set(
|
|
1798
2056
|
Object.keys(
|
|
@@ -1819,29 +2077,30 @@ async function createEntryPoint(flowSettings, buildOptions, packagePaths) {
|
|
|
1819
2077
|
);
|
|
1820
2078
|
const importsCode = importStatements.join("\n");
|
|
1821
2079
|
const hasFlow = Object.values(flowSettings.sources || {}).some(
|
|
1822
|
-
(
|
|
2080
|
+
(s) => s.package || hasCodeReference(s.code)
|
|
1823
2081
|
) || Object.values(flowSettings.destinations || {}).some(
|
|
1824
|
-
(d2) => d2.package ||
|
|
2082
|
+
(d2) => d2.package || hasCodeReference(d2.code)
|
|
1825
2083
|
);
|
|
1826
2084
|
if (!hasFlow) {
|
|
1827
2085
|
const userCode = buildOptions.code || "";
|
|
1828
|
-
return
|
|
2086
|
+
return {
|
|
2087
|
+
codeEntry: importsCode ? `${importsCode}
|
|
1829
2088
|
|
|
1830
|
-
${userCode}` : userCode
|
|
2089
|
+
${userCode}` : userCode,
|
|
2090
|
+
dataPayload: "{}",
|
|
2091
|
+
hasFlow: false
|
|
2092
|
+
};
|
|
1831
2093
|
}
|
|
1832
|
-
const { storesDeclaration,
|
|
1833
|
-
|
|
1834
|
-
explicitCodeImports
|
|
1835
|
-
);
|
|
1836
|
-
const wrappedCode = generatePlatformWrapper(
|
|
2094
|
+
const { storesDeclaration, codeConfigObject, dataPayload } = buildSplitConfigObject(flowSettings, explicitCodeImports);
|
|
2095
|
+
const wireConfigModule = generateSplitWireConfigModule(
|
|
1837
2096
|
storesDeclaration,
|
|
1838
|
-
|
|
1839
|
-
buildOptions.code || ""
|
|
1840
|
-
buildOptions
|
|
2097
|
+
codeConfigObject,
|
|
2098
|
+
buildOptions.code || ""
|
|
1841
2099
|
);
|
|
1842
|
-
|
|
2100
|
+
const codeEntry = importsCode ? `${importsCode}
|
|
1843
2101
|
|
|
1844
|
-
${
|
|
2102
|
+
${wireConfigModule}` : wireConfigModule;
|
|
2103
|
+
return { codeEntry, dataPayload, hasFlow: true };
|
|
1845
2104
|
}
|
|
1846
2105
|
function createBuildError(buildError, code) {
|
|
1847
2106
|
if (!buildError.errors || buildError.errors.length === 0) {
|
|
@@ -1866,12 +2125,55 @@ ${firstError.text}`
|
|
|
1866
2125
|
` + (location ? ` at ${location.file}:${location.line}:${location.column}` : "")
|
|
1867
2126
|
);
|
|
1868
2127
|
}
|
|
1869
|
-
function
|
|
2128
|
+
function buildSplitConfigObject(flowSettings, explicitCodeImports) {
|
|
1870
2129
|
const flowWithProps = flowSettings;
|
|
1871
2130
|
const sources = flowWithProps.sources || {};
|
|
1872
2131
|
const destinations = flowWithProps.destinations || {};
|
|
1873
2132
|
const transformers = flowWithProps.transformers || {};
|
|
1874
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
|
+
}
|
|
1875
2177
|
Object.entries(sources).forEach(([name, source]) => {
|
|
1876
2178
|
if (source.code !== true) {
|
|
1877
2179
|
validateReference("Source", name, source);
|
|
@@ -1888,104 +2190,89 @@ function buildConfigObject(flowSettings, explicitCodeImports) {
|
|
|
1888
2190
|
}
|
|
1889
2191
|
});
|
|
1890
2192
|
const sourcesEntries = Object.entries(sources).filter(
|
|
1891
|
-
([, source]) => source.code !== true && (source.package ||
|
|
2193
|
+
([, source]) => source.code !== true && (source.package || hasCodeReference(source.code))
|
|
1892
2194
|
).map(([key, source]) => {
|
|
1893
2195
|
if (isInlineCode(source.code)) {
|
|
1894
2196
|
return ` ${key}: ${generateInlineCode(source.code, source.config || {}, source.env, source.next, "next")}`;
|
|
1895
2197
|
}
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
}
|
|
1902
|
-
const configStr = source.config ? processConfigValue(source.config) : "{}";
|
|
1903
|
-
const envStr = source.env ? `,
|
|
1904
|
-
env: ${processConfigValue(source.env)}` : "";
|
|
1905
|
-
const nextStr = source.next ? `,
|
|
1906
|
-
next: ${JSON.stringify(source.next)}` : "";
|
|
1907
|
-
return ` ${key}: {
|
|
1908
|
-
code: ${codeVar},
|
|
1909
|
-
config: ${configStr}${envStr}${nextStr}
|
|
1910
|
-
}`;
|
|
2198
|
+
return buildSplitStepEntry(
|
|
2199
|
+
"sources",
|
|
2200
|
+
key,
|
|
2201
|
+
source
|
|
2202
|
+
);
|
|
1911
2203
|
});
|
|
1912
2204
|
const destinationsEntries = Object.entries(destinations).filter(
|
|
1913
|
-
([, dest]) => dest.code !== true && (dest.package ||
|
|
2205
|
+
([, dest]) => dest.code !== true && (dest.package || hasCodeReference(dest.code))
|
|
1914
2206
|
).map(([key, dest]) => {
|
|
1915
2207
|
if (isInlineCode(dest.code)) {
|
|
1916
2208
|
return ` ${key}: ${generateInlineCode(dest.code, dest.config || {}, dest.env, dest.before, "before", true)}`;
|
|
1917
2209
|
}
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
}
|
|
1924
|
-
const configStr = dest.config ? processConfigValue(dest.config) : "{}";
|
|
1925
|
-
const envStr = dest.env ? `,
|
|
1926
|
-
env: ${processConfigValue(dest.env)}` : "";
|
|
1927
|
-
const beforeStr = dest.before ? `,
|
|
1928
|
-
before: ${JSON.stringify(dest.before)}` : "";
|
|
1929
|
-
return ` ${key}: {
|
|
1930
|
-
code: ${codeVar},
|
|
1931
|
-
config: ${configStr}${envStr}${beforeStr}
|
|
1932
|
-
}`;
|
|
2210
|
+
return buildSplitStepEntry(
|
|
2211
|
+
"destinations",
|
|
2212
|
+
key,
|
|
2213
|
+
dest
|
|
2214
|
+
);
|
|
1933
2215
|
});
|
|
1934
2216
|
const transformersEntries = Object.entries(transformers).filter(
|
|
1935
|
-
([, transformer]) => transformer.code !== true && (transformer.package ||
|
|
2217
|
+
([, transformer]) => transformer.code !== true && (transformer.package || hasCodeReference(transformer.code))
|
|
1936
2218
|
).map(([key, transformer]) => {
|
|
1937
2219
|
if (isInlineCode(transformer.code)) {
|
|
1938
2220
|
return ` ${key}: ${generateInlineCode(transformer.code, transformer.config || {}, transformer.env, transformer.next, "next")}`;
|
|
1939
2221
|
}
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
}
|
|
1946
|
-
const configStr = transformer.config ? processConfigValue(transformer.config) : "{}";
|
|
1947
|
-
const envStr = transformer.env ? `,
|
|
1948
|
-
env: ${processConfigValue(transformer.env)}` : "";
|
|
1949
|
-
const nextStr = transformer.next ? `,
|
|
1950
|
-
next: ${JSON.stringify(transformer.next)}` : "";
|
|
1951
|
-
return ` ${key}: {
|
|
1952
|
-
code: ${codeVar},
|
|
1953
|
-
config: ${configStr}${envStr}${nextStr}
|
|
1954
|
-
}`;
|
|
2222
|
+
return buildSplitStepEntry(
|
|
2223
|
+
"transformers",
|
|
2224
|
+
key,
|
|
2225
|
+
transformer
|
|
2226
|
+
);
|
|
1955
2227
|
});
|
|
1956
2228
|
Object.entries(stores).forEach(([name, store]) => {
|
|
1957
|
-
if (store.package ||
|
|
2229
|
+
if (store.package || hasCodeReference(store.code)) {
|
|
1958
2230
|
validateReference("Store", name, store);
|
|
1959
2231
|
}
|
|
1960
2232
|
});
|
|
1961
|
-
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]) => {
|
|
1962
2234
|
if (isInlineCode(store.code)) {
|
|
1963
2235
|
return ` ${key}: ${generateInlineCode(store.code, store.config || {}, store.env)}`;
|
|
1964
2236
|
}
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
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;
|
|
1970
2252
|
}
|
|
1971
|
-
const configStr = store.config ? processConfigValue(store.config) : "{}";
|
|
1972
|
-
const envStr = store.env ? `,
|
|
1973
|
-
env: ${processConfigValue(store.env)}` : "";
|
|
1974
2253
|
return ` ${key}: {
|
|
1975
|
-
|
|
1976
|
-
config: ${configStr}${envStr}
|
|
2254
|
+
${codeEntries.join(",\n ")}
|
|
1977
2255
|
}`;
|
|
1978
2256
|
});
|
|
1979
2257
|
const storesDeclaration = storesEntries.length > 0 ? `const stores = {
|
|
1980
2258
|
${storesEntries.join(",\n")}
|
|
1981
2259
|
};` : "const stores = {};";
|
|
1982
|
-
|
|
1983
|
-
|
|
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
|
+
}
|
|
1984
2271
|
const transformersStr = transformersEntries.length > 0 ? `,
|
|
1985
2272
|
transformers: {
|
|
1986
2273
|
${transformersEntries.join(",\n")}
|
|
1987
2274
|
}` : "";
|
|
1988
|
-
const
|
|
2275
|
+
const codeConfigObject = `{
|
|
1989
2276
|
sources: {
|
|
1990
2277
|
${sourcesEntries.join(",\n")}
|
|
1991
2278
|
},
|
|
@@ -1994,7 +2281,69 @@ ${destinationsEntries.join(",\n")}
|
|
|
1994
2281
|
}${transformersStr},
|
|
1995
2282
|
stores${collectorStr}
|
|
1996
2283
|
}`;
|
|
1997
|
-
|
|
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
|
+
})();`;
|
|
1998
2347
|
}
|
|
1999
2348
|
function processConfigValue(value) {
|
|
2000
2349
|
return serializeWithCode(value, 0);
|
|
@@ -2063,66 +2412,11 @@ ${spaces}}`;
|
|
|
2063
2412
|
}
|
|
2064
2413
|
return JSON.stringify(value);
|
|
2065
2414
|
}
|
|
2066
|
-
function generatePlatformWrapper(storesDeclaration, configObject, userCode, buildOptions) {
|
|
2067
|
-
if (buildOptions.platform === "browser") {
|
|
2068
|
-
const windowAssignments = [];
|
|
2069
|
-
if (buildOptions.windowCollector) {
|
|
2070
|
-
windowAssignments.push(
|
|
2071
|
-
` if (typeof window !== 'undefined') window['${buildOptions.windowCollector}'] = collector;`
|
|
2072
|
-
);
|
|
2073
|
-
}
|
|
2074
|
-
if (buildOptions.windowElb) {
|
|
2075
|
-
windowAssignments.push(
|
|
2076
|
-
` if (typeof window !== 'undefined') window['${buildOptions.windowElb}'] = elb;`
|
|
2077
|
-
);
|
|
2078
|
-
}
|
|
2079
|
-
const assignments = windowAssignments.length > 0 ? "\n" + windowAssignments.join("\n") : "";
|
|
2080
|
-
return `(async () => {
|
|
2081
|
-
${storesDeclaration}
|
|
2082
|
-
|
|
2083
|
-
const config = ${configObject};
|
|
2084
|
-
|
|
2085
|
-
${userCode}
|
|
2086
|
-
|
|
2087
|
-
const { collector, elb } = await startFlow(config);${assignments}
|
|
2088
|
-
})();`;
|
|
2089
|
-
} else {
|
|
2090
|
-
const codeSection = userCode ? `
|
|
2091
|
-
${userCode}
|
|
2092
|
-
` : "";
|
|
2093
|
-
return `export default async function(context = {}) {
|
|
2094
|
-
${storesDeclaration}
|
|
2095
|
-
|
|
2096
|
-
const config = ${configObject};${codeSection}
|
|
2097
|
-
// Apply context overrides (e.g., logger config from CLI)
|
|
2098
|
-
if (context.logger) {
|
|
2099
|
-
config.logger = { ...config.logger, ...context.logger };
|
|
2100
|
-
}
|
|
2101
|
-
|
|
2102
|
-
// When runner provides external server, strip port from sources
|
|
2103
|
-
// so they don't self-listen (runner owns the port)
|
|
2104
|
-
if (context.externalServer && config.sources) {
|
|
2105
|
-
for (const src of Object.values(config.sources)) {
|
|
2106
|
-
if (src.config && src.config.settings && 'port' in src.config.settings) {
|
|
2107
|
-
delete src.config.settings.port;
|
|
2108
|
-
}
|
|
2109
|
-
}
|
|
2110
|
-
}
|
|
2111
|
-
|
|
2112
|
-
const result = await startFlow(config);
|
|
2113
|
-
|
|
2114
|
-
// Discover httpHandler from initialized sources (duck-typing, no source-type coupling)
|
|
2115
|
-
const httpSource = Object.values(result.collector.sources || {})
|
|
2116
|
-
.find(s => 'httpHandler' in s && typeof s.httpHandler === 'function');
|
|
2117
|
-
|
|
2118
|
-
return { ...result, httpHandler: httpSource ? httpSource.httpHandler : undefined };
|
|
2119
|
-
}`;
|
|
2120
|
-
}
|
|
2121
|
-
}
|
|
2122
2415
|
var VALID_JS_IDENTIFIER;
|
|
2123
2416
|
var init_bundler = __esm({
|
|
2124
2417
|
"src/commands/bundle/bundler.ts"() {
|
|
2125
2418
|
"use strict";
|
|
2419
|
+
init_config_classifier();
|
|
2126
2420
|
init_package_manager();
|
|
2127
2421
|
init_tmp();
|
|
2128
2422
|
init_build_cache();
|
|
@@ -2131,12 +2425,12 @@ var init_bundler = __esm({
|
|
|
2131
2425
|
});
|
|
2132
2426
|
|
|
2133
2427
|
// src/commands/bundle/upload.ts
|
|
2134
|
-
import
|
|
2428
|
+
import fs11 from "fs-extra";
|
|
2135
2429
|
function sanitizeUrl(url) {
|
|
2136
2430
|
return url.split("?")[0];
|
|
2137
2431
|
}
|
|
2138
2432
|
async function uploadBundleToUrl(filePath, url, timeoutMs = 3e4) {
|
|
2139
|
-
const bundleContent = await
|
|
2433
|
+
const bundleContent = await fs11.readFile(filePath);
|
|
2140
2434
|
const doUpload = async (attempt) => {
|
|
2141
2435
|
const response = await fetch(url, {
|
|
2142
2436
|
method: "PUT",
|
|
@@ -2215,8 +2509,8 @@ var init_api_client = __esm({
|
|
|
2215
2509
|
});
|
|
2216
2510
|
|
|
2217
2511
|
// src/commands/bundle/dockerfile.ts
|
|
2218
|
-
import
|
|
2219
|
-
import
|
|
2512
|
+
import path12 from "path";
|
|
2513
|
+
import fs12 from "fs-extra";
|
|
2220
2514
|
function buildDockerfileContent(platform, includedFolders) {
|
|
2221
2515
|
const bundleFile = platform === "web" ? "walker.js" : "bundle.mjs";
|
|
2222
2516
|
const lines = [
|
|
@@ -2226,21 +2520,21 @@ function buildDockerfileContent(platform, includedFolders) {
|
|
|
2226
2520
|
`COPY ${bundleFile} /app/flow/${bundleFile}`
|
|
2227
2521
|
];
|
|
2228
2522
|
for (const folder of includedFolders) {
|
|
2229
|
-
const name =
|
|
2523
|
+
const name = path12.basename(folder);
|
|
2230
2524
|
lines.push(`COPY ${name}/ /app/flow/${name}/`);
|
|
2231
2525
|
}
|
|
2232
2526
|
lines.push("", `ENV BUNDLE=/app/flow/${bundleFile}`, "", "EXPOSE 8080", "");
|
|
2233
2527
|
return lines.join("\n");
|
|
2234
2528
|
}
|
|
2235
2529
|
async function generateDockerfile(outputDir, platform, logger, customFile, includedFolders) {
|
|
2236
|
-
const destPath =
|
|
2237
|
-
if (customFile && await
|
|
2238
|
-
await
|
|
2530
|
+
const destPath = path12.join(outputDir, "Dockerfile");
|
|
2531
|
+
if (customFile && await fs12.pathExists(customFile)) {
|
|
2532
|
+
await fs12.copy(customFile, destPath);
|
|
2239
2533
|
logger.info(`Dockerfile: ${destPath} (copied from ${customFile})`);
|
|
2240
2534
|
return;
|
|
2241
2535
|
}
|
|
2242
2536
|
const dockerfile = buildDockerfileContent(platform, includedFolders || []);
|
|
2243
|
-
await
|
|
2537
|
+
await fs12.writeFile(destPath, dockerfile);
|
|
2244
2538
|
logger.info(`Dockerfile: ${destPath}`);
|
|
2245
2539
|
}
|
|
2246
2540
|
var init_dockerfile = __esm({
|
|
@@ -2250,15 +2544,15 @@ var init_dockerfile = __esm({
|
|
|
2250
2544
|
});
|
|
2251
2545
|
|
|
2252
2546
|
// src/commands/bundle/index.ts
|
|
2253
|
-
import
|
|
2254
|
-
import
|
|
2547
|
+
import path13 from "path";
|
|
2548
|
+
import fs13 from "fs-extra";
|
|
2255
2549
|
import { getPlatform as getPlatform2 } from "@walkeros/core";
|
|
2256
2550
|
function resolveOutputPath(output, buildOptions) {
|
|
2257
|
-
const resolved =
|
|
2258
|
-
const ext =
|
|
2259
|
-
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) {
|
|
2260
2554
|
const filename = buildOptions.platform === "browser" ? "walker.js" : "bundle.mjs";
|
|
2261
|
-
return
|
|
2555
|
+
return path13.join(resolved, filename);
|
|
2262
2556
|
}
|
|
2263
2557
|
return resolved;
|
|
2264
2558
|
}
|
|
@@ -2288,7 +2582,7 @@ async function bundleCommand(options) {
|
|
|
2288
2582
|
} catch {
|
|
2289
2583
|
throw new Error("Invalid JSON received on stdin");
|
|
2290
2584
|
}
|
|
2291
|
-
configPath =
|
|
2585
|
+
configPath = path13.resolve(process.cwd(), "stdin.config.json");
|
|
2292
2586
|
} else {
|
|
2293
2587
|
const file = options.config || "bundle.config.json";
|
|
2294
2588
|
configPath = resolveAsset(file, "config");
|
|
@@ -2342,19 +2636,19 @@ async function bundleCommand(options) {
|
|
|
2342
2636
|
if (uploadUrl) {
|
|
2343
2637
|
await uploadBundleToUrl(buildOptions.output, uploadUrl);
|
|
2344
2638
|
logger.info(`Uploaded to: ${sanitizeUrl(uploadUrl)}`);
|
|
2345
|
-
await
|
|
2639
|
+
await fs13.remove(buildOptions.output);
|
|
2346
2640
|
}
|
|
2347
2641
|
if (!options.json && !options.all && options.stats && stats) {
|
|
2348
2642
|
displayStats(stats, logger);
|
|
2349
2643
|
}
|
|
2350
2644
|
if (writingToStdout && !options.json) {
|
|
2351
|
-
const bundleContent = await
|
|
2645
|
+
const bundleContent = await fs13.readFile(buildOptions.output);
|
|
2352
2646
|
await writeResult(bundleContent, {});
|
|
2353
2647
|
}
|
|
2354
2648
|
if (options.dockerfile && options.output) {
|
|
2355
2649
|
const platform = getPlatform2(flowSettings);
|
|
2356
2650
|
if (platform) {
|
|
2357
|
-
const outputDir =
|
|
2651
|
+
const outputDir = path13.dirname(buildOptions.output);
|
|
2358
2652
|
const customFile = typeof options.dockerfile === "string" ? options.dockerfile : void 0;
|
|
2359
2653
|
await generateDockerfile(
|
|
2360
2654
|
outputDir,
|
|
@@ -2373,7 +2667,7 @@ async function bundleCommand(options) {
|
|
|
2373
2667
|
}
|
|
2374
2668
|
}
|
|
2375
2669
|
}
|
|
2376
|
-
const duration = timer.end()
|
|
2670
|
+
const duration = timer.end();
|
|
2377
2671
|
const successCount = results.filter((r2) => r2.success).length;
|
|
2378
2672
|
const failureCount = results.filter((r2) => !r2.success).length;
|
|
2379
2673
|
if (options.json) {
|
|
@@ -2410,7 +2704,7 @@ Build Summary: ${successCount}/${results.length} succeeded`
|
|
|
2410
2704
|
}
|
|
2411
2705
|
process.exit(0);
|
|
2412
2706
|
} catch (error) {
|
|
2413
|
-
const duration = timer.getElapsed()
|
|
2707
|
+
const duration = timer.getElapsed();
|
|
2414
2708
|
const errorMessage = getErrorMessage(error);
|
|
2415
2709
|
if (options.json) {
|
|
2416
2710
|
const jsonError = createErrorOutput(errorMessage, duration);
|
|
@@ -2425,7 +2719,7 @@ Build Summary: ${successCount}/${results.length} succeeded`
|
|
|
2425
2719
|
}
|
|
2426
2720
|
async function bundle(configOrPath, options = {}) {
|
|
2427
2721
|
let rawConfig;
|
|
2428
|
-
let configPath =
|
|
2722
|
+
let configPath = path13.resolve(process.cwd(), "walkeros.config.json");
|
|
2429
2723
|
if (typeof configOrPath === "string") {
|
|
2430
2724
|
configPath = resolveAsset(configOrPath, "config");
|
|
2431
2725
|
rawConfig = await loadJsonConfig(configPath);
|
|
@@ -2481,6 +2775,45 @@ var init_bundle = __esm({
|
|
|
2481
2775
|
}
|
|
2482
2776
|
});
|
|
2483
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
|
+
|
|
2484
2817
|
// src/runtime/cache.ts
|
|
2485
2818
|
var cache_exports = {};
|
|
2486
2819
|
__export(cache_exports, {
|
|
@@ -2535,15 +2868,15 @@ __export(utils_exports, {
|
|
|
2535
2868
|
isPreBuiltConfig: () => isPreBuiltConfig,
|
|
2536
2869
|
prepareBundleForRun: () => prepareBundleForRun
|
|
2537
2870
|
});
|
|
2538
|
-
import
|
|
2539
|
-
import
|
|
2871
|
+
import path17 from "path";
|
|
2872
|
+
import fs16 from "fs-extra";
|
|
2540
2873
|
async function prepareBundleForRun(configPath, options) {
|
|
2541
2874
|
const tempDir = getTmpPath(
|
|
2542
2875
|
void 0,
|
|
2543
2876
|
`run-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`
|
|
2544
2877
|
);
|
|
2545
|
-
await
|
|
2546
|
-
const tempPath =
|
|
2878
|
+
await fs16.ensureDir(tempDir);
|
|
2879
|
+
const tempPath = path17.join(tempDir, "bundle.mjs");
|
|
2547
2880
|
await bundle(configPath, {
|
|
2548
2881
|
cache: true,
|
|
2549
2882
|
verbose: options.verbose,
|
|
@@ -2555,7 +2888,12 @@ async function prepareBundleForRun(configPath, options) {
|
|
|
2555
2888
|
platform: "node"
|
|
2556
2889
|
}
|
|
2557
2890
|
});
|
|
2558
|
-
return
|
|
2891
|
+
return {
|
|
2892
|
+
bundlePath: tempPath,
|
|
2893
|
+
cleanup: async () => {
|
|
2894
|
+
await fs16.remove(tempDir);
|
|
2895
|
+
}
|
|
2896
|
+
};
|
|
2559
2897
|
}
|
|
2560
2898
|
function isPreBuiltConfig(configPath) {
|
|
2561
2899
|
return configPath.endsWith(".mjs") || configPath.endsWith(".js") || configPath.endsWith(".cjs");
|
|
@@ -2571,1062 +2909,703 @@ var init_utils3 = __esm({
|
|
|
2571
2909
|
// src/index.ts
|
|
2572
2910
|
init_bundle();
|
|
2573
2911
|
|
|
2574
|
-
// src/commands/
|
|
2575
|
-
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";
|
|
2576
2923
|
|
|
2577
2924
|
// ../collector/dist/index.mjs
|
|
2578
2925
|
import { assign as o } from "@walkeros/core";
|
|
2579
2926
|
import { assign as r, createLogger as i } from "@walkeros/core";
|
|
2580
|
-
import {
|
|
2581
|
-
import { isArray as
|
|
2582
|
-
import { tryCatch as
|
|
2583
|
-
import {
|
|
2584
|
-
import { isObject as
|
|
2585
|
-
import { assign as
|
|
2586
|
-
import { isObject as
|
|
2587
|
-
import { getGrantedConsent as
|
|
2588
|
-
import { useHooks as
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
}
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
return
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
const t2 = [], o2 = /* @__PURE__ */ new Set();
|
|
2612
|
-
let s2 = n;
|
|
2613
|
-
for (; s2 && e2[s2] && !o2.has(s2); ) {
|
|
2614
|
-
o2.add(s2), t2.push(s2);
|
|
2615
|
-
const n2 = e2[s2].next;
|
|
2616
|
-
if (Array.isArray(n2)) {
|
|
2617
|
-
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);
|
|
2618
2958
|
break;
|
|
2619
2959
|
}
|
|
2620
|
-
|
|
2960
|
+
s = e2;
|
|
2621
2961
|
}
|
|
2622
|
-
return
|
|
2962
|
+
return t;
|
|
2623
2963
|
}
|
|
2624
|
-
async function
|
|
2625
|
-
if (
|
|
2626
|
-
const o2 =
|
|
2627
|
-
|
|
2628
|
-
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);
|
|
2629
2969
|
if (false === i2) return false;
|
|
2630
|
-
|
|
2970
|
+
n.config = { ...i2 || n.config, env: i2?.env || n.config.env, init: true }, s.debug("init done");
|
|
2631
2971
|
}
|
|
2632
2972
|
return true;
|
|
2633
2973
|
}
|
|
2634
|
-
async function
|
|
2635
|
-
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 } : {} } };
|
|
2636
2976
|
a2.debug("push", { event: o2.name });
|
|
2637
|
-
const u2 = await
|
|
2977
|
+
const u2 = await U(n.push, "TransformerPush", e.hooks)(o2, c2);
|
|
2638
2978
|
return a2.debug("push done"), u2;
|
|
2639
2979
|
}
|
|
2640
|
-
async function
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
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}`);
|
|
2646
2987
|
continue;
|
|
2647
2988
|
}
|
|
2648
|
-
if (
|
|
2649
|
-
|
|
2650
|
-
if (
|
|
2651
|
-
if (
|
|
2652
|
-
const
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
}
|
|
2659
|
-
}
|
|
2660
|
-
return i2;
|
|
2661
|
-
}
|
|
2662
|
-
function $(n) {
|
|
2663
|
-
return n && C(n) ? n : {};
|
|
2664
|
-
}
|
|
2665
|
-
async function R(n, e2, t2) {
|
|
2666
|
-
const { code: o2, config: s2 = {}, env: r2 = {}, primary: i2, next: a2 } = t2;
|
|
2667
|
-
let c2, u2;
|
|
2668
|
-
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) => {
|
|
2669
|
-
c2 = s2.ingest ? await k(e3, s2.ingest, { collector: n }) : void 0;
|
|
2670
|
-
}, setRespond: (n2) => {
|
|
2671
|
-
u2 = n2;
|
|
2672
|
-
} }, m2 = await O(o2)(d2);
|
|
2673
|
-
if (!m2) return;
|
|
2674
|
-
const p2 = m2.type || "unknown", h2 = n.logger.scope(p2).scope(e2);
|
|
2675
|
-
return g2.logger = h2, i2 && (m2.config = { ...m2.config, primary: i2 }), m2;
|
|
2676
|
-
}
|
|
2677
|
-
async function T(n, e2 = {}) {
|
|
2678
|
-
const t2 = {};
|
|
2679
|
-
for (const [o2, s2] of Object.entries(e2)) {
|
|
2680
|
-
const { config: e3 = {} } = s2;
|
|
2681
|
-
if (e3.require && e3.require.length > 0) {
|
|
2682
|
-
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;
|
|
2995
|
+
continue;
|
|
2996
|
+
}
|
|
2997
|
+
if (void 0 !== r3.config?.mock) {
|
|
2998
|
+
e.logger.scope(`transformer:${r3.type || "unknown"}`).debug("mock"), a2 = r3.config.mock;
|
|
2683
2999
|
continue;
|
|
2684
3000
|
}
|
|
2685
|
-
|
|
2686
|
-
|
|
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
|
+
}
|
|
2687
3073
|
}
|
|
2688
|
-
return
|
|
3074
|
+
return { event: a2, respond: c2 };
|
|
2689
3075
|
}
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
r2.forEach((n2) => {
|
|
2693
|
-
s2.push(n2);
|
|
2694
|
-
}), o2[e2] = s2, await G(n, e2, r2);
|
|
3076
|
+
function oe(e) {
|
|
3077
|
+
return e && N(e) ? e : {};
|
|
2695
3078
|
}
|
|
2696
|
-
function
|
|
2697
|
-
if (
|
|
2698
|
-
|
|
2699
|
-
|
|
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;
|
|
2700
3085
|
}
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
case t.Commands.Session:
|
|
2708
|
-
r2 = n.session;
|
|
2709
|
-
break;
|
|
2710
|
-
case t.Commands.User:
|
|
2711
|
-
r2 = s2 || n.user;
|
|
2712
|
-
break;
|
|
2713
|
-
case t.Commands.Custom:
|
|
2714
|
-
r2 = s2 || n.custom;
|
|
2715
|
-
break;
|
|
2716
|
-
case t.Commands.Globals:
|
|
2717
|
-
r2 = s2 || n.globals;
|
|
2718
|
-
break;
|
|
2719
|
-
case t.Commands.Config:
|
|
2720
|
-
r2 = s2 || n.config;
|
|
2721
|
-
break;
|
|
2722
|
-
case t.Commands.Ready:
|
|
2723
|
-
case t.Commands.Run:
|
|
2724
|
-
default:
|
|
2725
|
-
r2 = void 0;
|
|
2726
|
-
}
|
|
2727
|
-
let a2 = false;
|
|
2728
|
-
for (const t2 of Object.values(n.sources)) if (t2.on) {
|
|
2729
|
-
false === await v(t2.on)(e2, r2) && (a2 = true);
|
|
2730
|
-
}
|
|
2731
|
-
if (Object.entries(n.destinations).forEach(([t2, o3]) => {
|
|
2732
|
-
if (o3.on) {
|
|
2733
|
-
if (!o3.config.init) return o3.queueOn = o3.queueOn || [], void o3.queueOn.push({ type: e2, data: r2 });
|
|
2734
|
-
B(n, o3, t2, e2, r2);
|
|
2735
|
-
}
|
|
2736
|
-
}), (Object.keys(n.pending.sources).length > 0 || Object.keys(n.pending.destinations).length > 0) && await (async function(n2, e3) {
|
|
2737
|
-
for (const [t2, o3] of Object.entries(n2.pending.sources)) {
|
|
2738
|
-
if (!n2.pending.sources[t2] || n2.sources[t2]) continue;
|
|
2739
|
-
const s3 = o3.config?.require;
|
|
2740
|
-
if (!s3) continue;
|
|
2741
|
-
const r3 = s3.indexOf(e3);
|
|
2742
|
-
if (-1 === r3) continue;
|
|
2743
|
-
if (s3.splice(r3, 1), s3.length > 0) continue;
|
|
2744
|
-
delete n2.pending.sources[t2];
|
|
2745
|
-
const i3 = await R(n2, t2, o3);
|
|
2746
|
-
i3 && (n2.sources[t2] = i3);
|
|
2747
|
-
}
|
|
2748
|
-
for (const [t2, o3] of Object.entries(n2.pending.destinations)) {
|
|
2749
|
-
if (!n2.pending.destinations[t2] || n2.destinations[t2]) continue;
|
|
2750
|
-
const s3 = o3.config?.require;
|
|
2751
|
-
if (!s3) continue;
|
|
2752
|
-
const r3 = s3.indexOf(e3);
|
|
2753
|
-
if (-1 === r3) continue;
|
|
2754
|
-
if (s3.splice(r3, 1), s3.length > 0) continue;
|
|
2755
|
-
delete n2.pending.destinations[t2];
|
|
2756
|
-
const i3 = M(o3);
|
|
2757
|
-
false !== i3.config.queue && (i3.queuePush = [...n2.queue]), n2.destinations[t2] = i3;
|
|
2758
|
-
}
|
|
2759
|
-
})(n, e2), !i2.length) return !a2;
|
|
2760
|
-
switch (e2) {
|
|
2761
|
-
case t.Commands.Consent:
|
|
2762
|
-
!(function(n2, e3, t2) {
|
|
2763
|
-
const o3 = t2 || n2.consent;
|
|
2764
|
-
e3.forEach((e4) => {
|
|
2765
|
-
Object.keys(o3).filter((n3) => n3 in e4).forEach((t3) => {
|
|
2766
|
-
y(e4[t3])(n2, o3);
|
|
2767
|
-
});
|
|
2768
|
-
});
|
|
2769
|
-
})(n, i2, s2);
|
|
2770
|
-
break;
|
|
2771
|
-
case t.Commands.Ready:
|
|
2772
|
-
case t.Commands.Run:
|
|
2773
|
-
!(function(n2, e3) {
|
|
2774
|
-
n2.allowed && e3.forEach((e4) => {
|
|
2775
|
-
y(e4)(n2);
|
|
2776
|
-
});
|
|
2777
|
-
})(n, i2);
|
|
2778
|
-
break;
|
|
2779
|
-
case t.Commands.Session:
|
|
2780
|
-
!(function(n2, e3) {
|
|
2781
|
-
if (!n2.session) return;
|
|
2782
|
-
e3.forEach((e4) => {
|
|
2783
|
-
y(e4)(n2, n2.session);
|
|
2784
|
-
});
|
|
2785
|
-
})(n, i2);
|
|
2786
|
-
break;
|
|
2787
|
-
default:
|
|
2788
|
-
i2.forEach((e3) => {
|
|
2789
|
-
"function" == typeof e3 && y(e3)(n, r2);
|
|
2790
|
-
});
|
|
2791
|
-
}
|
|
2792
|
-
return !a2;
|
|
2793
|
-
}
|
|
2794
|
-
async function H(n, e2, t2) {
|
|
2795
|
-
const { code: o2, config: s2 = {}, env: r2 = {}, before: i2 } = e2;
|
|
2796
|
-
if (!d(o2.push)) return J({ ok: false, failed: { invalid: { type: "invalid", error: "Destination code must have a push method" } } });
|
|
2797
|
-
const a2 = t2 || s2 || { init: false }, c2 = i2 ? { ...a2, before: i2 } : a2, u2 = { ...o2, config: c2, env: W(o2.env, r2) };
|
|
2798
|
-
let l2 = u2.config.id;
|
|
2799
|
-
if (!l2) do {
|
|
2800
|
-
l2 = f(4);
|
|
2801
|
-
} while (n.destinations[l2]);
|
|
2802
|
-
return n.destinations[l2] = u2, false !== u2.config.queue && (u2.queuePush = [...n.queue]), U(n, void 0, {}, { [l2]: u2 });
|
|
2803
|
-
}
|
|
2804
|
-
async function U(n, e2, t2 = {}, o2) {
|
|
2805
|
-
const { allowed: s2, consent: r2, globals: i2, user: u2 } = n;
|
|
2806
|
-
if (!s2) return J({ ok: false });
|
|
2807
|
-
e2 && (n.queue.push(e2), n.status.in++), o2 || (o2 = n.destinations);
|
|
2808
|
-
const f2 = await Promise.all(Object.entries(o2 || {}).map(async ([o3, s3]) => {
|
|
2809
|
-
let f3 = (s3.queuePush || []).map((n2) => ({ ...n2, consent: r2 }));
|
|
2810
|
-
if (s3.queuePush = [], e2) {
|
|
2811
|
-
const n2 = c(e2);
|
|
2812
|
-
f3.push(n2);
|
|
2813
|
-
}
|
|
2814
|
-
if (!f3.length && !s3.queueOn?.length) return { id: o3, destination: s3, skipped: true };
|
|
2815
|
-
if (!f3.length && s3.queueOn?.length) {
|
|
2816
|
-
const e3 = await h(z)(n, s3, o3);
|
|
2817
|
-
return { id: o3, destination: s3, skipped: !e3 };
|
|
2818
|
-
}
|
|
2819
|
-
const g3 = [], d3 = f3.filter((n2) => {
|
|
2820
|
-
const e3 = l(s3.config.consent, r2, n2.consent);
|
|
2821
|
-
return !e3 || (n2.consent = e3, g3.push(n2), false);
|
|
2822
|
-
});
|
|
2823
|
-
if (s3.queuePush.push(...d3), !g3.length) return { id: o3, destination: s3, queue: f3 };
|
|
2824
|
-
if (!await h(z)(n, s3, o3)) return { id: o3, destination: s3, queue: f3 };
|
|
2825
|
-
let m3, p2;
|
|
2826
|
-
s3.dlq || (s3.dlq = []);
|
|
2827
|
-
const w2 = (function(n2, e3) {
|
|
2828
|
-
const t3 = n2.config.before;
|
|
2829
|
-
return t3 ? E(t3, D(e3)) : [];
|
|
2830
|
-
})(s3, n.transformers);
|
|
2831
|
-
let b2 = 0;
|
|
2832
|
-
return await Promise.all(g3.map(async (e3) => {
|
|
2833
|
-
e3.globals = a(i2, e3.globals), e3.user = a(u2, e3.user);
|
|
2834
|
-
let r3 = e3;
|
|
2835
|
-
if (w2.length > 0 && n.transformers && Object.keys(n.transformers).length > 0) {
|
|
2836
|
-
const o4 = await S(n, n.transformers, w2, e3, t2.ingest, t2.respond);
|
|
2837
|
-
if (null === o4) return e3;
|
|
2838
|
-
r3 = o4;
|
|
2839
|
-
}
|
|
2840
|
-
const c2 = Date.now(), f4 = await h(F, (e4) => {
|
|
2841
|
-
const t3 = s3.type || "unknown";
|
|
2842
|
-
n.logger.scope(t3).error("Push failed", { error: e4, event: r3.name }), m3 = e4, s3.dlq.push([r3, e4]);
|
|
2843
|
-
})(n, s3, o3, r3, t2.ingest, t2.respond);
|
|
2844
|
-
return b2 += Date.now() - c2, void 0 !== f4 && (p2 = f4), e3;
|
|
2845
|
-
})), { id: o3, destination: s3, error: m3, response: p2, totalDuration: b2 };
|
|
2846
|
-
})), g2 = {}, d2 = {}, m2 = {};
|
|
2847
|
-
for (const e3 of f2) {
|
|
2848
|
-
if (e3.skipped) continue;
|
|
2849
|
-
const t3 = { type: e3.destination.type || "unknown", data: e3.response };
|
|
2850
|
-
n.status.destinations[e3.id] || (n.status.destinations[e3.id] = { count: 0, failed: 0, duration: 0 });
|
|
2851
|
-
const o3 = n.status.destinations[e3.id], s3 = Date.now();
|
|
2852
|
-
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++);
|
|
2853
|
-
}
|
|
2854
|
-
return J({ event: e2, ...Object.keys(g2).length && { done: g2 }, ...Object.keys(d2).length && { queued: d2 }, ...Object.keys(m2).length && { failed: m2 } });
|
|
2855
|
-
}
|
|
2856
|
-
async function z(n, e2, t2) {
|
|
2857
|
-
if (e2.init && !e2.config.init) {
|
|
2858
|
-
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) };
|
|
2859
|
-
s2.debug("init");
|
|
2860
|
-
const i2 = await w(e2.init, "DestinationInit", n.hooks)(r2);
|
|
2861
|
-
if (false === i2) return i2;
|
|
2862
|
-
if (e2.config = { ...i2 || e2.config, init: true }, e2.queueOn?.length) {
|
|
2863
|
-
const o3 = e2.queueOn;
|
|
2864
|
-
e2.queueOn = [];
|
|
2865
|
-
for (const { type: s3, data: r3 } of o3) B(n, e2, t2, s3, r3);
|
|
2866
|
-
}
|
|
2867
|
-
s2.debug("init done");
|
|
2868
|
-
}
|
|
2869
|
-
return true;
|
|
2870
|
-
}
|
|
2871
|
-
async function F(n, e2, t2, o2, s2, r2) {
|
|
2872
|
-
const { config: i2 } = e2, a2 = await p(o2, i2, n);
|
|
2873
|
-
if (a2.ignore) return false;
|
|
2874
|
-
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 || "* *";
|
|
2875
|
-
if (!d2?.batch || !e2.pushBatch) {
|
|
2876
|
-
f2.debug("push", { event: a2.event.name });
|
|
2877
|
-
const t3 = await w(e2.push, "DestinationPush", n.hooks)(a2.event, l2);
|
|
2878
|
-
return f2.debug("push done"), t3;
|
|
2879
|
-
}
|
|
2880
|
-
{
|
|
2881
|
-
if (e2.batches = e2.batches || {}, !e2.batches[m2]) {
|
|
2882
|
-
const o4 = { key: m2, events: [], data: [] };
|
|
2883
|
-
e2.batches[m2] = { batched: o4, batchFn: u(() => {
|
|
2884
|
-
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 } : {} } };
|
|
2885
|
-
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 = [];
|
|
2886
|
-
}, d2.batch) };
|
|
2887
|
-
}
|
|
2888
|
-
const o3 = e2.batches[m2];
|
|
2889
|
-
o3.batched.events.push(a2.event), g(a2.data) && o3.batched.data.push(a2.data), o3.batchFn();
|
|
2890
|
-
}
|
|
2891
|
-
return true;
|
|
2892
|
-
}
|
|
2893
|
-
function J(n) {
|
|
2894
|
-
return { ok: !n?.failed, ...n };
|
|
2895
|
-
}
|
|
2896
|
-
function M(n) {
|
|
2897
|
-
const { code: e2, config: t2 = {}, env: o2 = {} } = n, { config: s2 } = A(n, "before"), r2 = { ...e2.config, ...t2, ...s2 }, i2 = W(e2.env, o2);
|
|
2898
|
-
return { ...e2, config: r2, env: i2 };
|
|
2899
|
-
}
|
|
2900
|
-
async function N(n, e2 = {}) {
|
|
2901
|
-
const t2 = {};
|
|
2902
|
-
for (const [o2, s2] of Object.entries(e2)) s2.config?.require?.length ? n.pending.destinations[o2] = s2 : t2[o2] = M(s2);
|
|
2903
|
-
return t2;
|
|
2904
|
-
}
|
|
2905
|
-
function W(n, e2) {
|
|
2906
|
-
return n || e2 ? e2 ? n && m(n) && m(e2) ? { ...n, ...e2 } : e2 : n : {};
|
|
2907
|
-
}
|
|
2908
|
-
async function X(n, e2, t2) {
|
|
2909
|
-
const o2 = Object.entries(n).map(async ([n2, o3]) => {
|
|
2910
|
-
const s2 = o3.destroy;
|
|
2911
|
-
if (!s2) return;
|
|
2912
|
-
const r2 = o3.type || "unknown", i2 = t2.scope(r2), a2 = { id: n2, config: o3.config, env: o3.env ?? {}, logger: i2 };
|
|
2913
|
-
try {
|
|
2914
|
-
await Promise.race([s2(a2), new Promise((t3, o4) => setTimeout(() => o4(new Error(`${e2} '${n2}' destroy timed out`)), 5e3))]);
|
|
2915
|
-
} catch (t3) {
|
|
2916
|
-
i2.error(`${e2} '${n2}' destroy failed: ${t3}`);
|
|
2917
|
-
}
|
|
2918
|
-
});
|
|
2919
|
-
await Promise.allSettled(o2);
|
|
2920
|
-
}
|
|
2921
|
-
async function Y(n, e2, o2, r2) {
|
|
2922
|
-
let i2, a2, c2 = false, u2 = false;
|
|
2923
|
-
switch (e2) {
|
|
2924
|
-
case t.Commands.Config:
|
|
2925
|
-
K(o2) && (L(n.config, o2, { shallow: false }), a2 = o2, c2 = true);
|
|
2926
|
-
break;
|
|
2927
|
-
case t.Commands.Consent:
|
|
2928
|
-
if (K(o2)) {
|
|
2929
|
-
const { update: e3, runQueue: t2 } = s(n, o2);
|
|
2930
|
-
a2 = e3, c2 = true, u2 = t2;
|
|
2931
|
-
}
|
|
2932
|
-
break;
|
|
2933
|
-
case t.Commands.Custom:
|
|
2934
|
-
K(o2) && (n.custom = L(n.custom, o2), a2 = o2, c2 = true);
|
|
2935
|
-
break;
|
|
2936
|
-
case t.Commands.Destination:
|
|
2937
|
-
K(o2) && ("code" in o2 && K(o2.code) ? i2 = await H(n, o2, r2) : V(o2.push) && (i2 = await H(n, { code: o2 }, r2)));
|
|
2938
|
-
break;
|
|
2939
|
-
case t.Commands.Globals:
|
|
2940
|
-
K(o2) && (n.globals = L(n.globals, o2), a2 = o2, c2 = true);
|
|
2941
|
-
break;
|
|
2942
|
-
case t.Commands.On:
|
|
2943
|
-
_(o2) && await I(n, o2, r2);
|
|
2944
|
-
break;
|
|
2945
|
-
case t.Commands.Ready:
|
|
2946
|
-
c2 = true;
|
|
2947
|
-
break;
|
|
2948
|
-
case t.Commands.Run:
|
|
2949
|
-
i2 = await nn(n, o2), c2 = true;
|
|
2950
|
-
break;
|
|
2951
|
-
case t.Commands.Session:
|
|
2952
|
-
c2 = true;
|
|
2953
|
-
break;
|
|
2954
|
-
case t.Commands.Shutdown:
|
|
2955
|
-
await (async function(n2) {
|
|
2956
|
-
const e3 = n2.logger;
|
|
2957
|
-
await X(n2.sources, "source", e3), await X(n2.destinations, "destination", e3), await X(n2.transformers, "transformer", e3), await X(n2.stores, "store", e3);
|
|
2958
|
-
})(n);
|
|
2959
|
-
break;
|
|
2960
|
-
case t.Commands.User:
|
|
2961
|
-
K(o2) && (L(n.user, o2, { shallow: false }), a2 = o2, c2 = true);
|
|
2962
|
-
}
|
|
2963
|
-
return c2 && await G(n, e2, void 0, a2), u2 && (i2 = await U(n)), i2 || J({ ok: true });
|
|
2964
|
-
}
|
|
2965
|
-
function Z(n, e2) {
|
|
2966
|
-
if (!e2.name) throw new Error("Event name is required");
|
|
2967
|
-
const [t2, o2] = e2.name.split(" ");
|
|
2968
|
-
if (!t2 || !o2) throw new Error("Event name is invalid");
|
|
2969
|
-
++n.count;
|
|
2970
|
-
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;
|
|
2971
|
-
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 };
|
|
2972
|
-
}
|
|
2973
|
-
async function nn(n, e2) {
|
|
2974
|
-
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) => {
|
|
2975
|
-
n2.queuePush = [];
|
|
2976
|
-
}), n.queue = [], n.round++;
|
|
2977
|
-
return await U(n);
|
|
2978
|
-
}
|
|
2979
|
-
function rn(n, e2) {
|
|
2980
|
-
return sn(async (t2, o2 = {}) => await on(async () => {
|
|
2981
|
-
const s2 = Date.now(), { id: r2, ingest: i2, respond: a2, mapping: c2, preChain: u2 } = o2;
|
|
2982
|
-
let f2 = t2;
|
|
2983
|
-
const l2 = i2 ? Object.freeze(i2) : void 0;
|
|
2984
|
-
if (c2) {
|
|
2985
|
-
const e3 = await tn(f2, c2, n);
|
|
2986
|
-
if (e3.ignore) return J({ ok: true });
|
|
2987
|
-
if (c2.consent) {
|
|
2988
|
-
if (!en(c2.consent, n.consent, e3.event.consent)) return J({ ok: true });
|
|
2989
|
-
}
|
|
2990
|
-
f2 = e3.event;
|
|
2991
|
-
}
|
|
2992
|
-
if (u2?.length && n.transformers && Object.keys(n.transformers).length > 0) {
|
|
2993
|
-
const e3 = await S(n, n.transformers, u2, f2, l2, a2);
|
|
2994
|
-
if (null === e3) return J({ ok: true });
|
|
2995
|
-
f2 = e3;
|
|
2996
|
-
}
|
|
2997
|
-
const g2 = e2(f2), d2 = Z(n, g2), m2 = await U(n, d2, { id: r2, ingest: l2, respond: a2 });
|
|
2998
|
-
if (r2) {
|
|
2999
|
-
n.status.sources[r2] || (n.status.sources[r2] = { count: 0, duration: 0 });
|
|
3000
|
-
const e3 = n.status.sources[r2];
|
|
3001
|
-
e3.count++, e3.lastAt = Date.now(), e3.duration += Date.now() - s2;
|
|
3002
|
-
}
|
|
3003
|
-
return m2;
|
|
3004
|
-
}, () => J({ ok: false }))(), "Push", n.hooks);
|
|
3005
|
-
}
|
|
3006
|
-
async function un(n) {
|
|
3007
|
-
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.1.0", sources: {}, pending: { sources: {}, destinations: {} }, push: void 0, command: void 0 };
|
|
3008
|
-
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) {
|
|
3009
|
-
return an(async (t3, o3, s3) => await cn(async () => await e3(n2, t3, o3, s3), () => J({ ok: false }))(), "Command", n2.hooks);
|
|
3010
|
-
})(a2, Y);
|
|
3011
|
-
const c2 = n.stores || {};
|
|
3012
|
-
return a2.stores = await (async function(n2, e3 = {}) {
|
|
3013
|
-
const t3 = {};
|
|
3014
|
-
for (const [o3, s3] of Object.entries(e3)) {
|
|
3015
|
-
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);
|
|
3016
|
-
t3[o3] = u2;
|
|
3017
|
-
}
|
|
3018
|
-
return t3;
|
|
3019
|
-
})(a2, c2), (function(n2, e3, t3) {
|
|
3020
|
-
const o3 = /* @__PURE__ */ new Map();
|
|
3021
|
-
for (const [t4, s4] of Object.entries(n2)) e3[t4] && o3.set(s4, e3[t4]);
|
|
3022
|
-
if (0 !== o3.size) {
|
|
3023
|
-
for (const n3 of [t3.transformers, t3.destinations, t3.sources]) if (n3) for (const e4 of Object.values(n3)) s3(e4.env);
|
|
3024
|
-
}
|
|
3025
|
-
function s3(n3) {
|
|
3026
|
-
if (n3) {
|
|
3027
|
-
for (const [e4, t4] of Object.entries(n3)) if ("object" == typeof t4 && null !== t4) {
|
|
3028
|
-
const s4 = o3.get(t4);
|
|
3029
|
-
s4 && (n3[e4] = s4);
|
|
3030
|
-
}
|
|
3031
|
-
}
|
|
3032
|
-
}
|
|
3033
|
-
})(c2, a2.stores, n), a2.destinations = await N(a2, n.destinations || {}), a2.transformers = await (async function(n2, e3 = {}) {
|
|
3034
|
-
const t3 = {};
|
|
3035
|
-
for (const [o3, s3] of Object.entries(e3)) {
|
|
3036
|
-
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);
|
|
3037
|
-
t3[o3] = f2;
|
|
3038
|
-
}
|
|
3039
|
-
return t3;
|
|
3040
|
-
})(a2, n.transformers || {}), a2;
|
|
3041
|
-
}
|
|
3042
|
-
async function fn(n) {
|
|
3043
|
-
n = n || {};
|
|
3044
|
-
const e2 = await un(n), t2 = (o2 = e2, { type: "elb", config: {}, push: async (n2, e3, t3, s3, r3, i3) => {
|
|
3045
|
-
if ("string" == typeof n2 && n2.startsWith("walker ")) {
|
|
3046
|
-
const s4 = n2.replace("walker ", "");
|
|
3047
|
-
return o2.command(s4, e3, t3);
|
|
3048
|
-
}
|
|
3049
|
-
let a3;
|
|
3050
|
-
if ("string" == typeof n2) a3 = { name: n2 }, e3 && "object" == typeof e3 && !Array.isArray(e3) && (a3.data = e3);
|
|
3051
|
-
else {
|
|
3052
|
-
if (!n2 || "object" != typeof n2) return J({ ok: false });
|
|
3053
|
-
a3 = n2, e3 && "object" == typeof e3 && !Array.isArray(e3) && (a3.data = { ...a3.data || {}, ...e3 });
|
|
3054
|
-
}
|
|
3055
|
-
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);
|
|
3056
|
-
} });
|
|
3057
|
-
var o2;
|
|
3058
|
-
e2.sources.elb = t2;
|
|
3059
|
-
const s2 = await T(e2, n.sources || {});
|
|
3060
|
-
Object.assign(e2.sources, s2);
|
|
3061
|
-
const { consent: r2, user: i2, globals: a2, custom: c2 } = n;
|
|
3062
|
-
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");
|
|
3063
|
-
let u2 = t2.push;
|
|
3064
|
-
const f2 = Object.values(e2.sources).filter((n2) => "elb" !== n2.type), l2 = f2.find((n2) => n2.config.primary);
|
|
3065
|
-
return l2 ? u2 = l2.push : f2.length > 0 && (u2 = f2[0].push), { collector: e2, elb: u2 };
|
|
3066
|
-
}
|
|
3067
|
-
function ln(n) {
|
|
3068
|
-
if (null === n || "object" != typeof n) return n;
|
|
3069
|
-
if (Array.isArray(n)) return n.map(ln);
|
|
3070
|
-
const e2 = {};
|
|
3071
|
-
for (const [t2, o2] of Object.entries(n)) e2[t2] = "function" == typeof o2 ? o2 : ln(o2);
|
|
3072
|
-
return e2;
|
|
3073
|
-
}
|
|
3074
|
-
function gn(n) {
|
|
3075
|
-
const e2 = [], { simulation: t2, ...o2 } = n, s2 = ln(o2);
|
|
3076
|
-
for (const n2 of t2) {
|
|
3077
|
-
const t3 = n2.startsWith("call:") ? n2.slice(5) : n2, o3 = t3.split(".");
|
|
3078
|
-
let r2 = s2;
|
|
3079
|
-
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]];
|
|
3080
3092
|
const i2 = o3[o3.length - 1];
|
|
3081
3093
|
if (null == r2 || !(i2 in r2)) continue;
|
|
3082
3094
|
const a2 = r2[i2];
|
|
3083
|
-
"function" == typeof a2 && (r2[i2] = function(...
|
|
3084
|
-
return
|
|
3095
|
+
"function" == typeof a2 && (r2[i2] = function(...e3) {
|
|
3096
|
+
return n.push({ fn: t2, args: e3, ts: Date.now() }), a2.apply(this, e3);
|
|
3085
3097
|
});
|
|
3086
3098
|
}
|
|
3087
|
-
return { wrappedEnv:
|
|
3088
|
-
}
|
|
3089
|
-
async function dn(n) {
|
|
3090
|
-
const e2 = Date.now();
|
|
3091
|
-
try {
|
|
3092
|
-
switch (n.step) {
|
|
3093
|
-
case "transformer":
|
|
3094
|
-
return await (async function(n2, e3) {
|
|
3095
|
-
const { code: t2, config: o2 = {}, event: s2 } = n2, { collector: r2 } = await fn({ transformers: { sim: { code: t2, config: o2 } } }), i2 = r2.transformers?.sim;
|
|
3096
|
-
if (!i2) throw new Error("Transformer failed to initialize");
|
|
3097
|
-
const a2 = await i2.push(s2, { collector: r2, logger: r2.logger.scope("transformer").scope("sim"), id: "sim", config: i2.config, env: i2.config?.env || {} });
|
|
3098
|
-
let c2;
|
|
3099
|
-
c2 = false === a2 ? [] : null == a2 ? [s2] : [a2.event || s2];
|
|
3100
|
-
return { step: "transformer", name: n2.name, events: c2, calls: [], duration: Date.now() - e3 };
|
|
3101
|
-
})(n, e2);
|
|
3102
|
-
case "source":
|
|
3103
|
-
return await (async function(n2, e3) {
|
|
3104
|
-
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);
|
|
3105
|
-
void 0 !== a2 && await g2(c2?.type, c2?.options)(a2);
|
|
3106
|
-
return { step: "source", name: n2.name, events: f2, calls: [], duration: Date.now() - e3 };
|
|
3107
|
-
})(n, e2);
|
|
3108
|
-
case "destination":
|
|
3109
|
-
return await (async function(n2, e3) {
|
|
3110
|
-
const { code: t2, config: o2 = {}, event: s2, consent: r2, env: i2, track: a2 } = n2, c2 = { functional: true, marketing: true, analytics: true };
|
|
3111
|
-
let u2 = [], f2 = i2;
|
|
3112
|
-
if (i2 && a2 && a2.length > 0) {
|
|
3113
|
-
const n3 = gn({ ...i2, simulation: a2 });
|
|
3114
|
-
f2 = n3.wrappedEnv, u2 = n3.calls;
|
|
3115
|
-
}
|
|
3116
|
-
const l2 = { ...o2 };
|
|
3117
|
-
f2 && (l2.env = f2);
|
|
3118
|
-
const { collector: g2 } = await fn({ consent: r2 || c2, destinations: { sim: { code: t2, config: l2 } } });
|
|
3119
|
-
return await g2.push(s2), { step: "destination", name: n2.name, events: [], calls: u2, duration: Date.now() - e3 };
|
|
3120
|
-
})(n, e2);
|
|
3121
|
-
}
|
|
3122
|
-
} catch (t2) {
|
|
3123
|
-
return { step: n.step, name: n.name, events: [], calls: [], duration: Date.now() - e2, error: t2 instanceof Error ? t2 : new Error(String(t2)) };
|
|
3124
|
-
}
|
|
3099
|
+
return { wrappedEnv: s, calls: n };
|
|
3125
3100
|
}
|
|
3126
3101
|
|
|
3127
|
-
// src/commands/
|
|
3102
|
+
// src/commands/push/index.ts
|
|
3128
3103
|
init_cli_logger();
|
|
3129
3104
|
init_core();
|
|
3130
|
-
init_config();
|
|
3131
3105
|
init_tmp();
|
|
3106
|
+
init_config();
|
|
3107
|
+
init_utils();
|
|
3108
|
+
init_bundler();
|
|
3132
3109
|
|
|
3133
|
-
// src/commands/
|
|
3134
|
-
|
|
3135
|
-
const
|
|
3136
|
-
|
|
3137
|
-
|
|
3138
|
-
|
|
3139
|
-
continue;
|
|
3140
|
-
}
|
|
3141
|
-
try {
|
|
3142
|
-
const packageName = typedConfig.package;
|
|
3143
|
-
const isDemoPackage = packageName.includes("-demo");
|
|
3144
|
-
const importPath = isDemoPackage ? packageName : `${packageName}/dev`;
|
|
3145
|
-
const module = await import(importPath);
|
|
3146
|
-
const examplesModule = module.examples || module.default?.examples;
|
|
3147
|
-
const envModule = examplesModule?.env;
|
|
3148
|
-
if (envModule?.push) {
|
|
3149
|
-
envs[destKey] = {
|
|
3150
|
-
init: envModule.init,
|
|
3151
|
-
push: envModule.push,
|
|
3152
|
-
simulation: envModule.simulation || []
|
|
3153
|
-
};
|
|
3154
|
-
}
|
|
3155
|
-
} catch {
|
|
3156
|
-
}
|
|
3157
|
-
}
|
|
3158
|
-
return envs;
|
|
3159
|
-
}
|
|
3160
|
-
|
|
3161
|
-
// src/commands/simulate/simulator.ts
|
|
3162
|
-
function callsToUsage(destName, calls) {
|
|
3163
|
-
if (!calls.length) return {};
|
|
3164
|
-
return {
|
|
3165
|
-
[destName]: calls.map((c2) => ({
|
|
3166
|
-
type: "call",
|
|
3167
|
-
path: c2.fn,
|
|
3168
|
-
args: c2.args,
|
|
3169
|
-
timestamp: c2.ts
|
|
3170
|
-
}))
|
|
3171
|
-
};
|
|
3172
|
-
}
|
|
3173
|
-
async function simulateCore(inputPath, event, options = {}) {
|
|
3174
|
-
const logger = createCLILogger({
|
|
3175
|
-
verbose: options.verbose || false,
|
|
3176
|
-
silent: options.silent || false,
|
|
3177
|
-
json: options.json || false
|
|
3178
|
-
});
|
|
3179
|
-
try {
|
|
3180
|
-
logger.debug(`Simulating event: ${JSON.stringify(event)}`);
|
|
3181
|
-
const result = await executeSimulation(event, inputPath, options.platform, {
|
|
3182
|
-
flow: options.flow,
|
|
3183
|
-
step: options.step,
|
|
3184
|
-
verbose: options.verbose
|
|
3185
|
-
});
|
|
3186
|
-
return result;
|
|
3187
|
-
} catch (error) {
|
|
3188
|
-
const errorMessage = getErrorMessage(error);
|
|
3189
|
-
return {
|
|
3190
|
-
success: false,
|
|
3191
|
-
error: errorMessage
|
|
3192
|
-
};
|
|
3193
|
-
}
|
|
3194
|
-
}
|
|
3195
|
-
function formatSimulationResult(result, options = {}) {
|
|
3196
|
-
if (options.json) {
|
|
3197
|
-
const output = {
|
|
3198
|
-
result: result.elbResult,
|
|
3199
|
-
usage: result.usage,
|
|
3200
|
-
duration: result.duration
|
|
3201
|
-
};
|
|
3202
|
-
if (result.capturedEvents) {
|
|
3203
|
-
output.capturedEvents = result.capturedEvents;
|
|
3204
|
-
}
|
|
3205
|
-
return JSON.stringify(output, null, 2);
|
|
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 {};
|
|
3206
3116
|
}
|
|
3207
|
-
const
|
|
3208
|
-
|
|
3209
|
-
|
|
3210
|
-
|
|
3211
|
-
|
|
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
|
+
);
|
|
3212
3148
|
}
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
|
|
3149
|
+
for (const step of mockFlags) {
|
|
3150
|
+
const eqIndex = step.indexOf("=");
|
|
3151
|
+
if (eqIndex === -1) {
|
|
3152
|
+
throw new Error(
|
|
3153
|
+
`Invalid --mock format: "${step}". Expected destination.NAME=VALUE`
|
|
3154
|
+
);
|
|
3217
3155
|
}
|
|
3218
|
-
|
|
3219
|
-
|
|
3220
|
-
|
|
3221
|
-
|
|
3222
|
-
const startTime = Date.now();
|
|
3223
|
-
const tempDir = getTmpPath();
|
|
3224
|
-
try {
|
|
3225
|
-
await fs12.ensureDir(tempDir);
|
|
3226
|
-
const { flowSettings } = await loadFlowConfig(inputPath, {
|
|
3227
|
-
flowName: options.flow
|
|
3228
|
-
});
|
|
3229
|
-
if (!isObject(event) || !("name" in event) || typeof event.name !== "string") {
|
|
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.step
|
|
3241
|
-
);
|
|
3242
|
-
} catch (error) {
|
|
3243
|
-
const duration = Date.now() - startTime;
|
|
3244
|
-
return {
|
|
3245
|
-
success: false,
|
|
3246
|
-
error: getErrorMessage(error),
|
|
3247
|
-
duration
|
|
3248
|
-
};
|
|
3249
|
-
} finally {
|
|
3250
|
-
if (tempDir) {
|
|
3251
|
-
await fs12.remove(tempDir).catch(() => {
|
|
3252
|
-
});
|
|
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
|
+
);
|
|
3253
3168
|
}
|
|
3254
|
-
|
|
3255
|
-
|
|
3256
|
-
|
|
3257
|
-
|
|
3258
|
-
|
|
3259
|
-
|
|
3260
|
-
|
|
3261
|
-
const
|
|
3262
|
-
|
|
3263
|
-
if (!
|
|
3264
|
-
|
|
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 } };
|
|
3265
3199
|
}
|
|
3266
|
-
return { type, name, config: section[name] };
|
|
3267
3200
|
}
|
|
3268
3201
|
}
|
|
3269
|
-
|
|
3270
|
-
const [name, config] = Object.entries(flowSettings.destinations)[0];
|
|
3271
|
-
return {
|
|
3272
|
-
type: "destination",
|
|
3273
|
-
name,
|
|
3274
|
-
config
|
|
3275
|
-
};
|
|
3276
|
-
}
|
|
3277
|
-
throw new Error("No destination found in flow config");
|
|
3278
|
-
}
|
|
3279
|
-
async function executeConfigSimulation(flowSettings, typedEvent, tempDir, startTime, stepTarget) {
|
|
3280
|
-
const step = parseStepTarget(stepTarget, flowSettings);
|
|
3281
|
-
if (step.type === "destination") {
|
|
3282
|
-
const packageName = step.config.package;
|
|
3283
|
-
if (!packageName) {
|
|
3284
|
-
throw new Error(`Destination "${step.name}" has no package field`);
|
|
3285
|
-
}
|
|
3286
|
-
const destModule = await import(packageName);
|
|
3287
|
-
const code = destModule.default || Object.values(destModule)[0];
|
|
3288
|
-
const destinations = flowSettings.destinations;
|
|
3289
|
-
const envs = await loadDestinationEnvs(destinations || {});
|
|
3290
|
-
const destEnv = envs[step.name];
|
|
3291
|
-
const result = await dn({
|
|
3292
|
-
step: "destination",
|
|
3293
|
-
name: step.name,
|
|
3294
|
-
code,
|
|
3295
|
-
event: typedEvent,
|
|
3296
|
-
config: step.config.config,
|
|
3297
|
-
env: destEnv?.push,
|
|
3298
|
-
track: destEnv?.simulation
|
|
3299
|
-
});
|
|
3300
|
-
const duration = Date.now() - startTime;
|
|
3301
|
-
return {
|
|
3302
|
-
success: !result.error,
|
|
3303
|
-
error: result.error?.message,
|
|
3304
|
-
usage: callsToUsage(step.name, result.calls),
|
|
3305
|
-
duration,
|
|
3306
|
-
logs: []
|
|
3307
|
-
};
|
|
3308
|
-
}
|
|
3309
|
-
if (step.type === "transformer") {
|
|
3310
|
-
const packageName = step.config.package;
|
|
3311
|
-
if (!packageName) {
|
|
3312
|
-
throw new Error(`Transformer "${step.name}" has no package field`);
|
|
3313
|
-
}
|
|
3314
|
-
const mod = await import(packageName);
|
|
3315
|
-
const code = mod.default || Object.values(mod)[0];
|
|
3316
|
-
const result = await dn({
|
|
3317
|
-
step: "transformer",
|
|
3318
|
-
name: step.name,
|
|
3319
|
-
code,
|
|
3320
|
-
event: typedEvent,
|
|
3321
|
-
config: step.config.config
|
|
3322
|
-
});
|
|
3323
|
-
const duration = Date.now() - startTime;
|
|
3324
|
-
return {
|
|
3325
|
-
success: !result.error,
|
|
3326
|
-
error: result.error?.message,
|
|
3327
|
-
capturedEvents: result.events,
|
|
3328
|
-
duration,
|
|
3329
|
-
usage: {},
|
|
3330
|
-
logs: []
|
|
3331
|
-
};
|
|
3332
|
-
}
|
|
3333
|
-
throw new Error(`Unknown step type: ${step.type}`);
|
|
3202
|
+
return overrides;
|
|
3334
3203
|
}
|
|
3335
|
-
|
|
3336
|
-
|
|
3337
|
-
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
|
|
3341
|
-
if (!code || typeof code !== "function") {
|
|
3342
|
-
throw new Error(`Package ${packageName} missing source init function`);
|
|
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
|
+
);
|
|
3343
3210
|
}
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
createTrigger = examples.createTrigger;
|
|
3350
|
-
}
|
|
3351
|
-
} catch {
|
|
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
|
+
);
|
|
3352
3216
|
}
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
-
|
|
3356
|
-
|
|
3357
|
-
|
|
3358
|
-
|
|
3359
|
-
|
|
3360
|
-
|
|
3361
|
-
|
|
3362
|
-
const sourceConfig = sources[options.sourceStep];
|
|
3363
|
-
if (!sourceConfig) {
|
|
3364
|
-
const available = Object.keys(sources).join(", ");
|
|
3217
|
+
const name = parts[1];
|
|
3218
|
+
if (!name) {
|
|
3219
|
+
throw new Error(
|
|
3220
|
+
`Invalid step format: "${step}". Missing name after "${prefix}."`
|
|
3221
|
+
);
|
|
3222
|
+
}
|
|
3223
|
+
if (parts.length >= 4) {
|
|
3224
|
+
const chainType = parts[2];
|
|
3225
|
+
if (chainType !== "before" && chainType !== "next") {
|
|
3365
3226
|
throw new Error(
|
|
3366
|
-
`
|
|
3227
|
+
`Invalid chain type: "${chainType}". Use "before" or "next"`
|
|
3367
3228
|
);
|
|
3368
3229
|
}
|
|
3369
|
-
|
|
3370
|
-
|
|
3371
|
-
}
|
|
3372
|
-
const { code, createTrigger } = await loadSourcePackage(
|
|
3373
|
-
sourceConfig.package
|
|
3374
|
-
);
|
|
3375
|
-
if (!createTrigger) {
|
|
3230
|
+
const transformerId = parts[3];
|
|
3231
|
+
if (!transformerId) {
|
|
3376
3232
|
throw new Error(
|
|
3377
|
-
`
|
|
3233
|
+
`Invalid step format: "${step}". Missing transformer name after "${chainType}."`
|
|
3378
3234
|
);
|
|
3379
3235
|
}
|
|
3380
|
-
|
|
3381
|
-
step: "source",
|
|
3382
|
-
name: options.sourceStep,
|
|
3383
|
-
code,
|
|
3384
|
-
config: sourceConfig.config || {},
|
|
3385
|
-
createTrigger,
|
|
3386
|
-
input: sourceInput || { content: void 0 }
|
|
3387
|
-
});
|
|
3388
|
-
return {
|
|
3389
|
-
success: !result.error,
|
|
3390
|
-
error: result.error?.message,
|
|
3391
|
-
capturedEvents: result.events,
|
|
3392
|
-
duration: Date.now() - startTime
|
|
3393
|
-
};
|
|
3394
|
-
} catch (error) {
|
|
3395
|
-
return {
|
|
3396
|
-
success: false,
|
|
3397
|
-
error: getErrorMessage(error),
|
|
3398
|
-
duration: Date.now() - startTime
|
|
3399
|
-
};
|
|
3236
|
+
return { type: prefix, name, chainType, transformerId };
|
|
3400
3237
|
}
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
// src/commands/simulate/index.ts
|
|
3404
|
-
init_cli_logger();
|
|
3405
|
-
init_core();
|
|
3406
|
-
init_config();
|
|
3407
|
-
init_validators();
|
|
3408
|
-
|
|
3409
|
-
// src/commands/simulate/example-loader.ts
|
|
3410
|
-
function findExample(config, exampleName, stepTarget) {
|
|
3411
|
-
if (stepTarget) {
|
|
3412
|
-
return findExampleInStep(config, exampleName, stepTarget);
|
|
3413
|
-
}
|
|
3414
|
-
return findExampleAcrossSteps(config, exampleName);
|
|
3415
|
-
}
|
|
3416
|
-
function findExampleInStep(config, exampleName, stepTarget) {
|
|
3417
|
-
const dotIndex = stepTarget.indexOf(".");
|
|
3418
|
-
if (dotIndex === -1) {
|
|
3419
|
-
throw new Error(
|
|
3420
|
-
`Invalid --step format: "${stepTarget}". Expected "type.name" (e.g. "destination.gtag")`
|
|
3421
|
-
);
|
|
3422
|
-
}
|
|
3423
|
-
const type = stepTarget.substring(0, dotIndex);
|
|
3424
|
-
const name = stepTarget.substring(dotIndex + 1);
|
|
3425
|
-
const stepMap = getStepMap(config, type);
|
|
3426
|
-
if (!stepMap) {
|
|
3427
|
-
throw new Error(`No ${type}s found in flow config`);
|
|
3428
|
-
}
|
|
3429
|
-
const step = stepMap[name];
|
|
3430
|
-
if (!step) {
|
|
3431
|
-
const available = Object.keys(stepMap).join(", ");
|
|
3432
|
-
throw new Error(`${type} "${name}" not found. Available: ${available}`);
|
|
3433
|
-
}
|
|
3434
|
-
const examples = step.examples;
|
|
3435
|
-
if (!examples || !examples[exampleName]) {
|
|
3436
|
-
const available = examples ? Object.keys(examples).join(", ") : "none";
|
|
3238
|
+
if (parts.length === 3) {
|
|
3437
3239
|
throw new Error(
|
|
3438
|
-
`
|
|
3240
|
+
`Invalid step format: "${step}". Specify a transformer: "${step}.TRANSFORMER_NAME"`
|
|
3439
3241
|
);
|
|
3440
3242
|
}
|
|
3441
|
-
return {
|
|
3442
|
-
stepType: type,
|
|
3443
|
-
stepName: name,
|
|
3444
|
-
exampleName,
|
|
3445
|
-
example: examples[exampleName]
|
|
3446
|
-
};
|
|
3243
|
+
return { type: prefix, name };
|
|
3447
3244
|
}
|
|
3448
|
-
|
|
3449
|
-
|
|
3450
|
-
|
|
3451
|
-
|
|
3452
|
-
const
|
|
3453
|
-
if (
|
|
3454
|
-
|
|
3455
|
-
|
|
3456
|
-
|
|
3457
|
-
|
|
3458
|
-
|
|
3459
|
-
|
|
3460
|
-
|
|
3461
|
-
|
|
3462
|
-
|
|
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
|
+
}
|
|
3463
3262
|
}
|
|
3464
3263
|
}
|
|
3465
3264
|
}
|
|
3466
|
-
if (
|
|
3467
|
-
|
|
3468
|
-
|
|
3469
|
-
|
|
3470
|
-
|
|
3471
|
-
|
|
3472
|
-
|
|
3473
|
-
|
|
3474
|
-
|
|
3475
|
-
|
|
3476
|
-
|
|
3477
|
-
|
|
3478
|
-
|
|
3479
|
-
|
|
3480
|
-
|
|
3481
|
-
|
|
3482
|
-
return config.transformers;
|
|
3483
|
-
case "destination":
|
|
3484
|
-
return config.destinations;
|
|
3485
|
-
default:
|
|
3486
|
-
throw new Error(
|
|
3487
|
-
`Invalid step type: "${type}". Must be "source", "transformer", or "destination"`
|
|
3488
|
-
);
|
|
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
|
+
}
|
|
3489
3281
|
}
|
|
3490
3282
|
}
|
|
3491
3283
|
|
|
3492
|
-
// src/commands/
|
|
3493
|
-
|
|
3494
|
-
|
|
3495
|
-
|
|
3496
|
-
|
|
3497
|
-
|
|
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();
|
|
3361
|
+
}
|
|
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();
|
|
3498
3373
|
}
|
|
3499
|
-
return {
|
|
3500
|
-
expected,
|
|
3501
|
-
actual,
|
|
3502
|
-
match: false,
|
|
3503
|
-
diff: `Expected:
|
|
3504
|
-
${expectedStr}
|
|
3505
|
-
|
|
3506
|
-
Actual:
|
|
3507
|
-
${actualStr}`
|
|
3508
|
-
};
|
|
3374
|
+
return { flush, countPending, restore };
|
|
3509
3375
|
}
|
|
3510
3376
|
|
|
3511
|
-
// src/commands/
|
|
3512
|
-
async function
|
|
3513
|
-
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;
|
|
3514
3380
|
const startTime = Date.now();
|
|
3515
|
-
|
|
3516
|
-
|
|
3517
|
-
|
|
3518
|
-
|
|
3519
|
-
|
|
3520
|
-
|
|
3521
|
-
|
|
3522
|
-
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
|
|
3526
|
-
|
|
3527
|
-
}
|
|
3528
|
-
const result = await simulate(config, options.event, {
|
|
3529
|
-
flow: options.flow,
|
|
3530
|
-
json: options.json,
|
|
3531
|
-
verbose: options.verbose,
|
|
3532
|
-
silent: options.silent,
|
|
3533
|
-
platform: options.platform,
|
|
3534
|
-
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
|
|
3535
3393
|
});
|
|
3536
|
-
|
|
3537
|
-
|
|
3538
|
-
|
|
3539
|
-
|
|
3540
|
-
|
|
3541
|
-
|
|
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
|
|
3542
3403
|
});
|
|
3543
|
-
|
|
3544
|
-
|
|
3545
|
-
|
|
3546
|
-
|
|
3547
|
-
if (options.json) {
|
|
3548
|
-
const errorOutput = JSON.stringify(
|
|
3549
|
-
{
|
|
3550
|
-
success: false,
|
|
3551
|
-
error: errorMessage,
|
|
3552
|
-
duration: (Date.now() - startTime) / 1e3
|
|
3553
|
-
},
|
|
3554
|
-
null,
|
|
3555
|
-
2
|
|
3556
|
-
);
|
|
3557
|
-
await writeResult(errorOutput + "\n", { output: options.output });
|
|
3558
|
-
} else {
|
|
3559
|
-
logger.error(`Error: ${errorMessage}`);
|
|
3404
|
+
if (networkCalls) {
|
|
3405
|
+
savedFetch = global.fetch;
|
|
3406
|
+
applyNetworkPolyfills(dom, networkCalls);
|
|
3407
|
+
global.fetch = dom.window.fetch;
|
|
3560
3408
|
}
|
|
3561
|
-
process.exit(1);
|
|
3562
3409
|
}
|
|
3563
|
-
|
|
3564
|
-
|
|
3565
|
-
|
|
3566
|
-
|
|
3567
|
-
"simulate() currently only supports config file paths. Please provide a path to a configuration file."
|
|
3568
|
-
);
|
|
3410
|
+
if (asyncDrain) {
|
|
3411
|
+
timerControl = installTimerInterception({
|
|
3412
|
+
domWindow: platform === "web" && dom ? dom.window : void 0
|
|
3413
|
+
});
|
|
3569
3414
|
}
|
|
3570
|
-
|
|
3571
|
-
|
|
3572
|
-
|
|
3573
|
-
|
|
3574
|
-
|
|
3575
|
-
|
|
3576
|
-
|
|
3577
|
-
|
|
3578
|
-
|
|
3579
|
-
|
|
3580
|
-
const flowName = options.flow || (flowNames.length === 1 ? flowNames[0] : void 0);
|
|
3581
|
-
if (!flowName) {
|
|
3582
|
-
throw new Error(
|
|
3583
|
-
`Multiple flows found. Use --flow to specify which flow.
|
|
3584
|
-
Available: ${flowNames.join(", ")}`
|
|
3585
|
-
);
|
|
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
|
+
}
|
|
3586
3425
|
}
|
|
3587
|
-
const
|
|
3588
|
-
|
|
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") {
|
|
3589
3430
|
throw new Error(
|
|
3590
|
-
|
|
3431
|
+
"Invalid ESM bundle: missing wireConfig or startFlow exports"
|
|
3591
3432
|
);
|
|
3592
3433
|
}
|
|
3593
|
-
const
|
|
3594
|
-
|
|
3595
|
-
|
|
3596
|
-
|
|
3597
|
-
|
|
3598
|
-
|
|
3599
|
-
|
|
3600
|
-
|
|
3601
|
-
|
|
3602
|
-
|
|
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;
|
|
3603
3477
|
}
|
|
3604
|
-
|
|
3605
|
-
} else {
|
|
3606
|
-
result = await simulateCore(configOrPath, resolvedEvent, {
|
|
3607
|
-
json: options.json ?? false,
|
|
3608
|
-
verbose: options.verbose ?? false,
|
|
3609
|
-
silent: options.silent ?? false,
|
|
3610
|
-
flow: options.flow,
|
|
3611
|
-
platform: options.platform,
|
|
3612
|
-
step: options.step
|
|
3613
|
-
});
|
|
3478
|
+
}
|
|
3614
3479
|
}
|
|
3615
|
-
|
|
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;
|
|
3616
3518
|
}
|
|
3617
3519
|
|
|
3618
|
-
// src/commands/push/
|
|
3520
|
+
// src/commands/push/prepare.ts
|
|
3619
3521
|
init_cli_logger();
|
|
3620
|
-
init_core();
|
|
3621
3522
|
init_tmp();
|
|
3622
3523
|
init_config();
|
|
3623
3524
|
init_bundler();
|
|
3624
|
-
import
|
|
3625
|
-
import
|
|
3626
|
-
import fs13 from "fs-extra";
|
|
3525
|
+
import path15 from "path";
|
|
3526
|
+
import fs14 from "fs-extra";
|
|
3627
3527
|
import { getPlatform as getPlatform3 } from "@walkeros/core";
|
|
3628
|
-
|
|
3629
|
-
|
|
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
|
+
}
|
|
3630
3609
|
async function pushCore(inputPath, event, options = {}) {
|
|
3631
3610
|
const logger = createCLILogger({
|
|
3632
3611
|
silent: options.silent,
|
|
@@ -3635,53 +3614,45 @@ async function pushCore(inputPath, event, options = {}) {
|
|
|
3635
3614
|
const startTime = Date.now();
|
|
3636
3615
|
let tempDir;
|
|
3637
3616
|
try {
|
|
3638
|
-
const eventResult = schemas2.PartialEventSchema.safeParse(event);
|
|
3639
|
-
if (!eventResult.success) {
|
|
3640
|
-
const errors = eventResult.error.issues.map((issue) => `${String(issue.path.join("."))}: ${issue.message}`).join(", ");
|
|
3641
|
-
throw new Error(`Invalid event: ${errors}`);
|
|
3642
|
-
}
|
|
3643
|
-
const parsedEvent = eventResult.data;
|
|
3644
|
-
if (!parsedEvent.name) {
|
|
3645
|
-
throw new Error('Invalid event: Missing required "name" property');
|
|
3646
|
-
}
|
|
3647
|
-
const validatedEvent = {
|
|
3648
|
-
name: parsedEvent.name,
|
|
3649
|
-
data: parsedEvent.data || {}
|
|
3650
|
-
};
|
|
3651
|
-
if (!validatedEvent.name.includes(" ")) {
|
|
3652
|
-
logger.info(
|
|
3653
|
-
`Warning: Event name "${validatedEvent.name}" should follow "ENTITY ACTION" format (e.g., "page view")`
|
|
3654
|
-
);
|
|
3655
|
-
}
|
|
3656
3617
|
logger.debug("Detecting input type");
|
|
3657
3618
|
const detected = await detectInput(
|
|
3658
3619
|
inputPath,
|
|
3659
3620
|
options.platform
|
|
3660
3621
|
);
|
|
3661
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
|
+
}
|
|
3662
3630
|
if (detected.type === "config") {
|
|
3663
3631
|
result = await executeConfigPush(
|
|
3664
3632
|
{
|
|
3665
3633
|
config: inputPath,
|
|
3666
3634
|
flow: options.flow,
|
|
3667
|
-
verbose: options.verbose
|
|
3635
|
+
verbose: options.verbose,
|
|
3636
|
+
mock: options.mock
|
|
3668
3637
|
},
|
|
3669
|
-
|
|
3638
|
+
event,
|
|
3670
3639
|
logger,
|
|
3671
3640
|
(dir) => {
|
|
3672
3641
|
tempDir = dir;
|
|
3673
|
-
}
|
|
3642
|
+
},
|
|
3643
|
+
snapshotCode
|
|
3674
3644
|
);
|
|
3675
3645
|
} else {
|
|
3676
3646
|
result = await executeBundlePush(
|
|
3677
3647
|
detected.content,
|
|
3678
3648
|
detected.platform,
|
|
3679
|
-
|
|
3649
|
+
event,
|
|
3680
3650
|
logger,
|
|
3681
3651
|
(dir) => {
|
|
3682
3652
|
tempDir = dir;
|
|
3683
3653
|
},
|
|
3684
|
-
|
|
3654
|
+
void 0,
|
|
3655
|
+
snapshotCode
|
|
3685
3656
|
);
|
|
3686
3657
|
}
|
|
3687
3658
|
return result;
|
|
@@ -3693,7 +3664,7 @@ async function pushCore(inputPath, event, options = {}) {
|
|
|
3693
3664
|
};
|
|
3694
3665
|
} finally {
|
|
3695
3666
|
if (tempDir) {
|
|
3696
|
-
await
|
|
3667
|
+
await fs15.remove(tempDir).catch(() => {
|
|
3697
3668
|
});
|
|
3698
3669
|
}
|
|
3699
3670
|
}
|
|
@@ -3704,33 +3675,67 @@ async function pushCommand(options) {
|
|
|
3704
3675
|
try {
|
|
3705
3676
|
let config;
|
|
3706
3677
|
if (isStdinPiped() && !options.config) {
|
|
3707
|
-
|
|
3708
|
-
const tmpPath = getTmpPath(void 0, "stdin-push.json");
|
|
3709
|
-
await fs13.ensureDir(path12.dirname(tmpPath));
|
|
3710
|
-
await fs13.writeFile(tmpPath, stdinContent, "utf-8");
|
|
3711
|
-
config = tmpPath;
|
|
3678
|
+
config = await readStdinToTempFile("push");
|
|
3712
3679
|
} else {
|
|
3713
3680
|
config = options.config || "bundle.config.json";
|
|
3714
3681
|
}
|
|
3715
|
-
|
|
3716
|
-
|
|
3717
|
-
|
|
3718
|
-
|
|
3719
|
-
|
|
3720
|
-
|
|
3721
|
-
|
|
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
|
+
}
|
|
3722
3735
|
const duration = Date.now() - startTime;
|
|
3723
3736
|
let output;
|
|
3724
3737
|
if (options.json) {
|
|
3725
|
-
output = JSON.stringify(
|
|
3726
|
-
{
|
|
3727
|
-
success: result.success,
|
|
3728
|
-
event: result.elbResult,
|
|
3729
|
-
duration
|
|
3730
|
-
},
|
|
3731
|
-
null,
|
|
3732
|
-
2
|
|
3733
|
-
);
|
|
3738
|
+
output = JSON.stringify({ ...result, duration }, null, 2);
|
|
3734
3739
|
} else {
|
|
3735
3740
|
const lines = [];
|
|
3736
3741
|
if (result.success) {
|
|
@@ -3774,158 +3779,438 @@ async function push(configOrPath, event, options = {}) {
|
|
|
3774
3779
|
"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."
|
|
3775
3780
|
);
|
|
3776
3781
|
}
|
|
3777
|
-
|
|
3778
|
-
if (
|
|
3779
|
-
|
|
3782
|
+
const parsed = schemas3.PartialEventSchema.safeParse(event);
|
|
3783
|
+
if (!parsed.success) {
|
|
3784
|
+
return {
|
|
3785
|
+
success: false,
|
|
3786
|
+
duration: 0,
|
|
3787
|
+
error: `Invalid event: ${parsed.error.issues.map((i2) => `${i2.path.join(".")}: ${i2.message}`).join(", ")}`
|
|
3788
|
+
};
|
|
3780
3789
|
}
|
|
3781
|
-
return
|
|
3790
|
+
return pushCore(configOrPath, event, {
|
|
3782
3791
|
json: options.json ?? false,
|
|
3783
3792
|
verbose: options.verbose ?? false,
|
|
3784
3793
|
silent: options.silent ?? false,
|
|
3785
3794
|
flow: options.flow,
|
|
3786
|
-
platform: options.platform
|
|
3795
|
+
platform: options.platform,
|
|
3796
|
+
mock: options.mock,
|
|
3797
|
+
snapshot: options.snapshot
|
|
3787
3798
|
});
|
|
3788
3799
|
}
|
|
3789
|
-
async function executeConfigPush(options, validatedEvent, logger, setTempDir) {
|
|
3800
|
+
async function executeConfigPush(options, validatedEvent, logger, setTempDir, snapshotCode) {
|
|
3790
3801
|
logger.debug("Loading flow configuration");
|
|
3791
3802
|
const { flowSettings, buildOptions } = await loadFlowConfig(options.config, {
|
|
3792
3803
|
flowName: options.flow,
|
|
3793
3804
|
logger
|
|
3794
3805
|
});
|
|
3795
|
-
const platform =
|
|
3806
|
+
const platform = getPlatform4(flowSettings);
|
|
3807
|
+
const overrides = buildOverrides(
|
|
3808
|
+
{ mock: options.mock },
|
|
3809
|
+
flowSettings
|
|
3810
|
+
);
|
|
3811
|
+
if (overrides.destinations) {
|
|
3812
|
+
const { loadDestinationEnvs: loadDestinationEnvs2 } = await Promise.resolve().then(() => (init_env_loader(), env_loader_exports));
|
|
3813
|
+
const configDir = buildOptions.configDir || process.cwd();
|
|
3814
|
+
const envs = await loadDestinationEnvs2(
|
|
3815
|
+
flowSettings.destinations ?? {},
|
|
3816
|
+
flowSettings.packages,
|
|
3817
|
+
configDir
|
|
3818
|
+
);
|
|
3819
|
+
for (const [destId, env] of Object.entries(envs)) {
|
|
3820
|
+
if (overrides.destinations[destId] && env.push) {
|
|
3821
|
+
overrides.destinations[destId].env = env.push;
|
|
3822
|
+
if (env.simulation && env.simulation.length > 0) {
|
|
3823
|
+
overrides.destinations[destId].simulation = env.simulation;
|
|
3824
|
+
}
|
|
3825
|
+
}
|
|
3826
|
+
}
|
|
3827
|
+
}
|
|
3796
3828
|
logger.debug("Bundling flow configuration");
|
|
3797
|
-
const configDir = buildOptions.configDir || process.cwd();
|
|
3798
3829
|
const tempDir = getTmpPath(
|
|
3799
3830
|
void 0,
|
|
3800
3831
|
`push-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`
|
|
3801
3832
|
);
|
|
3802
3833
|
setTempDir(tempDir);
|
|
3803
|
-
await
|
|
3804
|
-
const tempPath =
|
|
3805
|
-
tempDir,
|
|
3806
|
-
`bundle.${platform === "web" ? "js" : "mjs"}`
|
|
3807
|
-
);
|
|
3834
|
+
await fs15.ensureDir(tempDir);
|
|
3835
|
+
const tempPath = path16.join(tempDir, "bundle.mjs");
|
|
3808
3836
|
const pushBuildOptions = {
|
|
3809
3837
|
...buildOptions,
|
|
3810
3838
|
output: tempPath,
|
|
3811
|
-
format:
|
|
3839
|
+
format: "esm",
|
|
3812
3840
|
platform: platform === "web" ? "browser" : "node",
|
|
3813
|
-
|
|
3814
|
-
|
|
3815
|
-
windowElb: "elb"
|
|
3816
|
-
}
|
|
3841
|
+
skipWrapper: true
|
|
3842
|
+
// CLI imports ESM directly — no platform wrapper
|
|
3817
3843
|
};
|
|
3818
3844
|
await bundleCore(flowSettings, pushBuildOptions, logger, false);
|
|
3819
3845
|
logger.debug(`Bundle created: ${tempPath}`);
|
|
3820
|
-
|
|
3821
|
-
|
|
3822
|
-
|
|
3823
|
-
|
|
3824
|
-
|
|
3825
|
-
|
|
3826
|
-
|
|
3827
|
-
|
|
3828
|
-
|
|
3829
|
-
|
|
3830
|
-
|
|
3846
|
+
logger.debug(
|
|
3847
|
+
`Executing in ${platform} environment (${platform === "web" ? "JSDOM" : "Node.js"})`
|
|
3848
|
+
);
|
|
3849
|
+
return executeDestinationPush(
|
|
3850
|
+
tempPath,
|
|
3851
|
+
validatedEvent,
|
|
3852
|
+
logger,
|
|
3853
|
+
platform,
|
|
3854
|
+
overrides,
|
|
3855
|
+
snapshotCode,
|
|
3856
|
+
platform === "server" ? 6e4 : void 0
|
|
3857
|
+
);
|
|
3831
3858
|
}
|
|
3832
|
-
async function executeBundlePush(bundleContent, platform, validatedEvent, logger, setTempDir,
|
|
3859
|
+
async function executeBundlePush(bundleContent, platform, validatedEvent, logger, setTempDir, overrides = {}, snapshotCode) {
|
|
3833
3860
|
const tempDir = getTmpPath(
|
|
3834
3861
|
void 0,
|
|
3835
3862
|
`push-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`
|
|
3836
3863
|
);
|
|
3837
3864
|
setTempDir(tempDir);
|
|
3838
|
-
await
|
|
3839
|
-
const tempPath =
|
|
3840
|
-
|
|
3841
|
-
`bundle.${platform === "server" ? "mjs" : "js"}`
|
|
3842
|
-
);
|
|
3843
|
-
await fs13.writeFile(tempPath, bundleContent, "utf8");
|
|
3865
|
+
await fs15.ensureDir(tempDir);
|
|
3866
|
+
const tempPath = path16.join(tempDir, "bundle.mjs");
|
|
3867
|
+
await fs15.writeFile(tempPath, bundleContent, "utf8");
|
|
3844
3868
|
logger.debug(`Bundle written to: ${tempPath}`);
|
|
3845
|
-
|
|
3846
|
-
|
|
3847
|
-
|
|
3848
|
-
|
|
3849
|
-
|
|
3850
|
-
|
|
3869
|
+
logger.debug(
|
|
3870
|
+
`Executing in ${platform} environment (${platform === "web" ? "JSDOM" : "Node.js"})`
|
|
3871
|
+
);
|
|
3872
|
+
return executeDestinationPush(
|
|
3873
|
+
tempPath,
|
|
3874
|
+
validatedEvent,
|
|
3875
|
+
logger,
|
|
3876
|
+
platform,
|
|
3877
|
+
overrides,
|
|
3878
|
+
snapshotCode,
|
|
3879
|
+
platform === "server" ? 6e4 : void 0
|
|
3880
|
+
);
|
|
3881
|
+
}
|
|
3882
|
+
async function executeDestinationPush(esmPath, event, logger, platform, overrides, snapshotCode, timeout) {
|
|
3883
|
+
const startTime = Date.now();
|
|
3884
|
+
const networkCalls = [];
|
|
3885
|
+
return withFlowContext(
|
|
3886
|
+
{ esmPath, platform, logger, snapshotCode, timeout, networkCalls, asyncDrain: { timeout: 5e3 } },
|
|
3887
|
+
async (module) => {
|
|
3888
|
+
const config = module.wireConfig(module.__configData ?? void 0);
|
|
3889
|
+
applyOverrides(config, overrides || {});
|
|
3890
|
+
const result = await module.startFlow(config);
|
|
3891
|
+
if (!result?.collector?.push)
|
|
3892
|
+
throw new Error("Invalid bundle: collector missing push");
|
|
3893
|
+
const collector = result.collector;
|
|
3894
|
+
logger.info(`Pushing event: ${event.name}`);
|
|
3895
|
+
const elbResult = await collector.push(event);
|
|
3896
|
+
await collector.command("shutdown");
|
|
3897
|
+
return {
|
|
3898
|
+
success: true,
|
|
3899
|
+
elbResult,
|
|
3900
|
+
...networkCalls.length > 0 ? { networkCalls } : {},
|
|
3901
|
+
duration: Date.now() - startTime
|
|
3902
|
+
};
|
|
3903
|
+
}
|
|
3904
|
+
);
|
|
3905
|
+
}
|
|
3906
|
+
async function simulateSource(configPath, input, options) {
|
|
3907
|
+
const startTime = Date.now();
|
|
3908
|
+
const prepared = await prepareFlow({
|
|
3909
|
+
configPath,
|
|
3910
|
+
flow: options.flow,
|
|
3911
|
+
simulate: ["source." + options.sourceId],
|
|
3912
|
+
silent: options.silent,
|
|
3913
|
+
verbose: options.verbose
|
|
3914
|
+
});
|
|
3915
|
+
try {
|
|
3916
|
+
const logger = createCLILogger({
|
|
3917
|
+
silent: options.silent,
|
|
3918
|
+
verbose: options.verbose
|
|
3919
|
+
});
|
|
3920
|
+
const sourceConfig = (prepared.flowSettings.sources ?? {})[options.sourceId];
|
|
3921
|
+
if (!sourceConfig?.package) {
|
|
3922
|
+
throw new Error(
|
|
3923
|
+
`Source "${options.sourceId}" has no package defined`
|
|
3924
|
+
);
|
|
3925
|
+
}
|
|
3926
|
+
const devPath = resolvePackageImportPath(
|
|
3927
|
+
sourceConfig.package,
|
|
3928
|
+
prepared.flowSettings.packages,
|
|
3929
|
+
prepared.configDir,
|
|
3930
|
+
"/dev"
|
|
3931
|
+
);
|
|
3932
|
+
const devModule = await import(devPath);
|
|
3933
|
+
const createTrigger = devModule.examples?.createTrigger || devModule.default?.examples?.createTrigger;
|
|
3934
|
+
if (!createTrigger) {
|
|
3935
|
+
throw new Error(
|
|
3936
|
+
`Source package "${sourceConfig.package}" has no createTrigger in /dev export`
|
|
3937
|
+
);
|
|
3938
|
+
}
|
|
3939
|
+
let snapshotCode;
|
|
3940
|
+
if (options.snapshot) {
|
|
3941
|
+
snapshotCode = await loadConfig(options.snapshot, {
|
|
3942
|
+
json: false
|
|
3943
|
+
});
|
|
3944
|
+
logger.debug(`Snapshot loaded (${snapshotCode.length} bytes)`);
|
|
3945
|
+
}
|
|
3946
|
+
const networkCalls = [];
|
|
3947
|
+
return await withFlowContext(
|
|
3948
|
+
{
|
|
3949
|
+
esmPath: prepared.bundlePath,
|
|
3950
|
+
platform: prepared.platform,
|
|
3951
|
+
logger,
|
|
3952
|
+
snapshotCode,
|
|
3953
|
+
networkCalls
|
|
3954
|
+
},
|
|
3955
|
+
async (module) => {
|
|
3956
|
+
const config = module.wireConfig(module.__configData ?? void 0);
|
|
3957
|
+
applyOverrides(config, prepared.overrides);
|
|
3958
|
+
const captured = [];
|
|
3959
|
+
config.hooks = {
|
|
3960
|
+
...config.hooks || {},
|
|
3961
|
+
prePush: ({ fn }, event) => {
|
|
3962
|
+
captured.push({ event, timestamp: Date.now() });
|
|
3963
|
+
return { ok: true };
|
|
3964
|
+
}
|
|
3965
|
+
};
|
|
3966
|
+
const instance = await createTrigger(config, { sourceId: options.sourceId });
|
|
3967
|
+
const { trigger } = instance;
|
|
3968
|
+
logger.info("Simulating source");
|
|
3969
|
+
const inputRecord = input ?? {};
|
|
3970
|
+
const content = inputRecord.content ?? input;
|
|
3971
|
+
const triggerOpts = inputRecord.trigger;
|
|
3972
|
+
await trigger(triggerOpts?.type, triggerOpts?.options)(content);
|
|
3973
|
+
if (instance.flow?.collector?.command) {
|
|
3974
|
+
await instance.flow.collector.command("shutdown");
|
|
3975
|
+
}
|
|
3976
|
+
return {
|
|
3977
|
+
success: true,
|
|
3978
|
+
...captured.length > 0 ? { captured } : {},
|
|
3979
|
+
...networkCalls.length > 0 ? { networkCalls } : {},
|
|
3980
|
+
duration: Date.now() - startTime
|
|
3981
|
+
};
|
|
3982
|
+
}
|
|
3983
|
+
);
|
|
3984
|
+
} catch (error) {
|
|
3985
|
+
return {
|
|
3986
|
+
success: false,
|
|
3987
|
+
duration: Date.now() - startTime,
|
|
3988
|
+
error: getErrorMessage(error)
|
|
3989
|
+
};
|
|
3990
|
+
} finally {
|
|
3991
|
+
await prepared.cleanup();
|
|
3851
3992
|
}
|
|
3852
3993
|
}
|
|
3853
|
-
async function
|
|
3994
|
+
async function simulateTransformer(configPath, event, options) {
|
|
3854
3995
|
const startTime = Date.now();
|
|
3996
|
+
const parsed = schemas3.PartialEventSchema.safeParse(event);
|
|
3997
|
+
if (!parsed.success) {
|
|
3998
|
+
return {
|
|
3999
|
+
success: false,
|
|
4000
|
+
duration: 0,
|
|
4001
|
+
error: parsed.error.message
|
|
4002
|
+
};
|
|
4003
|
+
}
|
|
4004
|
+
const prepared = await prepareFlow({
|
|
4005
|
+
configPath,
|
|
4006
|
+
flow: options.flow,
|
|
4007
|
+
simulate: ["transformer." + options.transformerId],
|
|
4008
|
+
mock: options.mock,
|
|
4009
|
+
silent: options.silent,
|
|
4010
|
+
verbose: options.verbose
|
|
4011
|
+
});
|
|
3855
4012
|
try {
|
|
3856
|
-
const
|
|
3857
|
-
|
|
3858
|
-
|
|
3859
|
-
runScripts: "dangerously",
|
|
3860
|
-
resources: "usable",
|
|
3861
|
-
virtualConsole
|
|
4013
|
+
const logger = createCLILogger({
|
|
4014
|
+
silent: options.silent,
|
|
4015
|
+
verbose: options.verbose
|
|
3862
4016
|
});
|
|
3863
|
-
|
|
3864
|
-
|
|
3865
|
-
|
|
3866
|
-
|
|
3867
|
-
|
|
3868
|
-
|
|
3869
|
-
|
|
3870
|
-
|
|
3871
|
-
|
|
4017
|
+
let snapshotCode;
|
|
4018
|
+
if (options.snapshot) {
|
|
4019
|
+
snapshotCode = await loadConfig(options.snapshot, {
|
|
4020
|
+
json: false
|
|
4021
|
+
});
|
|
4022
|
+
logger.debug(`Snapshot loaded (${snapshotCode.length} bytes)`);
|
|
4023
|
+
}
|
|
4024
|
+
const networkCalls = [];
|
|
4025
|
+
return await withFlowContext(
|
|
4026
|
+
{
|
|
4027
|
+
esmPath: prepared.bundlePath,
|
|
4028
|
+
platform: prepared.platform,
|
|
4029
|
+
logger,
|
|
4030
|
+
snapshotCode,
|
|
4031
|
+
networkCalls
|
|
4032
|
+
},
|
|
4033
|
+
async (module) => {
|
|
4034
|
+
const config = module.wireConfig(module.__configData ?? void 0);
|
|
4035
|
+
applyOverrides(config, prepared.overrides);
|
|
4036
|
+
if (config.sources) config.sources = {};
|
|
4037
|
+
if (config.destinations) config.destinations = {};
|
|
4038
|
+
const result = await module.startFlow(config);
|
|
4039
|
+
if (!result?.collector)
|
|
4040
|
+
throw new Error("Invalid bundle: collector not available");
|
|
4041
|
+
const collector = result.collector;
|
|
4042
|
+
const transformer = collector.transformers?.[options.transformerId];
|
|
4043
|
+
if (!transformer) {
|
|
4044
|
+
throw new Error(
|
|
4045
|
+
`Transformer "${options.transformerId}" not found in collector. Available: ${Object.keys(collector.transformers || {}).join(", ") || "none"}`
|
|
4046
|
+
);
|
|
4047
|
+
}
|
|
4048
|
+
const initialized = await ee(
|
|
4049
|
+
collector,
|
|
4050
|
+
transformer,
|
|
4051
|
+
options.transformerId
|
|
4052
|
+
);
|
|
4053
|
+
if (!initialized) {
|
|
4054
|
+
throw new Error(
|
|
4055
|
+
`Transformer "${options.transformerId}" failed to initialize`
|
|
4056
|
+
);
|
|
4057
|
+
}
|
|
4058
|
+
const inputEvent = event;
|
|
4059
|
+
const ingest = createIngest(options.transformerId);
|
|
4060
|
+
const captured = [];
|
|
4061
|
+
captured.push({ event: { ...inputEvent }, timestamp: Date.now() });
|
|
4062
|
+
logger.info(`Simulating transformer: ${options.transformerId}`);
|
|
4063
|
+
let processedEvent = inputEvent;
|
|
4064
|
+
const before = transformer.config.before;
|
|
4065
|
+
if (before && collector.transformers) {
|
|
4066
|
+
const beforeChainIds = resolveBeforeChain(
|
|
4067
|
+
before,
|
|
4068
|
+
collector.transformers,
|
|
4069
|
+
ingest,
|
|
4070
|
+
processedEvent
|
|
4071
|
+
);
|
|
4072
|
+
if (beforeChainIds.length > 0) {
|
|
4073
|
+
const beforeResult = await te(
|
|
4074
|
+
collector,
|
|
4075
|
+
collector.transformers,
|
|
4076
|
+
beforeChainIds,
|
|
4077
|
+
processedEvent,
|
|
4078
|
+
ingest,
|
|
4079
|
+
void 0,
|
|
4080
|
+
`transformer.${options.transformerId}.before`
|
|
4081
|
+
);
|
|
4082
|
+
if (beforeResult === null) {
|
|
4083
|
+
captured.push({ event: null, timestamp: Date.now() });
|
|
4084
|
+
await collector.command("shutdown");
|
|
4085
|
+
return {
|
|
4086
|
+
success: true,
|
|
4087
|
+
captured,
|
|
4088
|
+
duration: Date.now() - startTime
|
|
4089
|
+
};
|
|
4090
|
+
}
|
|
4091
|
+
processedEvent = Array.isArray(beforeResult) ? beforeResult[0] : beforeResult;
|
|
4092
|
+
}
|
|
4093
|
+
}
|
|
4094
|
+
const pushResult = await ne(
|
|
4095
|
+
collector,
|
|
4096
|
+
transformer,
|
|
4097
|
+
options.transformerId,
|
|
4098
|
+
processedEvent,
|
|
4099
|
+
ingest
|
|
4100
|
+
);
|
|
4101
|
+
if (pushResult === false) {
|
|
4102
|
+
captured.push({ event: null, timestamp: Date.now() });
|
|
4103
|
+
} else if (Array.isArray(pushResult)) {
|
|
4104
|
+
for (const r2 of pushResult) {
|
|
4105
|
+
captured.push({
|
|
4106
|
+
event: r2.event || processedEvent,
|
|
4107
|
+
timestamp: Date.now()
|
|
4108
|
+
});
|
|
4109
|
+
}
|
|
4110
|
+
} else if (pushResult && typeof pushResult === "object" && pushResult.event) {
|
|
4111
|
+
captured.push({ event: pushResult.event, timestamp: Date.now() });
|
|
4112
|
+
} else {
|
|
4113
|
+
captured.push({ event: processedEvent, timestamp: Date.now() });
|
|
4114
|
+
}
|
|
4115
|
+
await collector.command("shutdown");
|
|
4116
|
+
return {
|
|
4117
|
+
success: true,
|
|
4118
|
+
captured,
|
|
4119
|
+
...networkCalls.length > 0 ? { networkCalls } : {},
|
|
4120
|
+
duration: Date.now() - startTime
|
|
4121
|
+
};
|
|
4122
|
+
}
|
|
3872
4123
|
);
|
|
3873
|
-
const windowObj = window;
|
|
3874
|
-
const collector = windowObj.collector;
|
|
3875
|
-
logger.info(`Pushing event: ${event.name}`);
|
|
3876
|
-
const elbResult = await collector.push({
|
|
3877
|
-
name: event.name,
|
|
3878
|
-
data: event.data
|
|
3879
|
-
});
|
|
3880
|
-
return {
|
|
3881
|
-
success: true,
|
|
3882
|
-
elbResult,
|
|
3883
|
-
duration: Date.now() - startTime
|
|
3884
|
-
};
|
|
3885
4124
|
} catch (error) {
|
|
3886
4125
|
return {
|
|
3887
4126
|
success: false,
|
|
3888
4127
|
duration: Date.now() - startTime,
|
|
3889
4128
|
error: getErrorMessage(error)
|
|
3890
4129
|
};
|
|
4130
|
+
} finally {
|
|
4131
|
+
await prepared.cleanup();
|
|
3891
4132
|
}
|
|
3892
4133
|
}
|
|
3893
|
-
async function
|
|
4134
|
+
async function simulateDestination(configPath, event, options) {
|
|
3894
4135
|
const startTime = Date.now();
|
|
3895
|
-
|
|
4136
|
+
const parsed = schemas3.PartialEventSchema.safeParse(event);
|
|
4137
|
+
if (!parsed.success) {
|
|
4138
|
+
return {
|
|
4139
|
+
success: false,
|
|
4140
|
+
duration: 0,
|
|
4141
|
+
error: parsed.error.message
|
|
4142
|
+
};
|
|
4143
|
+
}
|
|
4144
|
+
const prepared = await prepareFlow({
|
|
4145
|
+
configPath,
|
|
4146
|
+
flow: options.flow,
|
|
4147
|
+
simulate: ["destination." + options.destinationId],
|
|
4148
|
+
mock: options.mock,
|
|
4149
|
+
silent: options.silent,
|
|
4150
|
+
verbose: options.verbose
|
|
4151
|
+
});
|
|
3896
4152
|
try {
|
|
3897
|
-
const
|
|
3898
|
-
|
|
3899
|
-
|
|
3900
|
-
timeout
|
|
3901
|
-
);
|
|
4153
|
+
const logger = createCLILogger({
|
|
4154
|
+
silent: options.silent,
|
|
4155
|
+
verbose: options.verbose
|
|
3902
4156
|
});
|
|
3903
|
-
|
|
3904
|
-
|
|
3905
|
-
|
|
3906
|
-
|
|
3907
|
-
throw new Error("Bundle does not export default factory function");
|
|
3908
|
-
}
|
|
3909
|
-
logger.debug("Calling factory function...");
|
|
3910
|
-
const result = await flowModule.default(context);
|
|
3911
|
-
if (!result || !result.collector || typeof result.collector.push !== "function") {
|
|
3912
|
-
throw new Error(
|
|
3913
|
-
"Factory function did not return valid result with collector"
|
|
3914
|
-
);
|
|
3915
|
-
}
|
|
3916
|
-
const { collector } = result;
|
|
3917
|
-
logger.info(`Pushing event: ${event.name}`);
|
|
3918
|
-
const elbResult = await collector.push({
|
|
3919
|
-
name: event.name,
|
|
3920
|
-
data: event.data
|
|
4157
|
+
let snapshotCode;
|
|
4158
|
+
if (options.snapshot) {
|
|
4159
|
+
snapshotCode = await loadConfig(options.snapshot, {
|
|
4160
|
+
json: false
|
|
3921
4161
|
});
|
|
3922
|
-
|
|
3923
|
-
|
|
3924
|
-
|
|
3925
|
-
|
|
3926
|
-
|
|
3927
|
-
|
|
3928
|
-
|
|
4162
|
+
}
|
|
4163
|
+
const networkCalls = [];
|
|
4164
|
+
return await withFlowContext(
|
|
4165
|
+
{
|
|
4166
|
+
esmPath: prepared.bundlePath,
|
|
4167
|
+
platform: prepared.platform,
|
|
4168
|
+
logger,
|
|
4169
|
+
snapshotCode,
|
|
4170
|
+
networkCalls
|
|
4171
|
+
},
|
|
4172
|
+
async (module) => {
|
|
4173
|
+
const config = module.wireConfig(module.__configData ?? void 0);
|
|
4174
|
+
applyOverrides(config, prepared.overrides);
|
|
4175
|
+
const destOverride = prepared.overrides.destinations?.[options.destinationId];
|
|
4176
|
+
let trackedCalls = [];
|
|
4177
|
+
if (destOverride?.simulation?.length) {
|
|
4178
|
+
const destinations = config.destinations;
|
|
4179
|
+
const destConfig = destinations[options.destinationId]?.config;
|
|
4180
|
+
if (destConfig?.env) {
|
|
4181
|
+
const combined = {
|
|
4182
|
+
...destConfig.env,
|
|
4183
|
+
simulation: destOverride.simulation
|
|
4184
|
+
};
|
|
4185
|
+
const { wrappedEnv, calls } = Ge(combined);
|
|
4186
|
+
destConfig.env = wrappedEnv;
|
|
4187
|
+
trackedCalls = calls;
|
|
4188
|
+
}
|
|
4189
|
+
}
|
|
4190
|
+
if (config.sources) config.sources = {};
|
|
4191
|
+
const result = await module.startFlow(config);
|
|
4192
|
+
if (!result?.collector)
|
|
4193
|
+
throw new Error("Invalid bundle: collector not available");
|
|
4194
|
+
const collector = result.collector;
|
|
4195
|
+
if (!collector.destinations[options.destinationId] && !collector.pending.destinations[options.destinationId]) {
|
|
4196
|
+
throw new Error(
|
|
4197
|
+
`Destination "${options.destinationId}" not found in collector. Available: ${Object.keys(collector.destinations || {}).join(", ") || "none"}`
|
|
4198
|
+
);
|
|
4199
|
+
}
|
|
4200
|
+
logger.info(`Simulating destination: ${options.destinationId}`);
|
|
4201
|
+
const elbResult = await collector.push(event, {
|
|
4202
|
+
include: [options.destinationId]
|
|
4203
|
+
});
|
|
4204
|
+
await collector.command("shutdown");
|
|
4205
|
+
return {
|
|
4206
|
+
success: true,
|
|
4207
|
+
elbResult,
|
|
4208
|
+
...trackedCalls.length > 0 ? { usage: { [options.destinationId]: trackedCalls } } : {},
|
|
4209
|
+
...networkCalls.length > 0 ? { networkCalls } : {},
|
|
4210
|
+
duration: Date.now() - startTime
|
|
4211
|
+
};
|
|
4212
|
+
}
|
|
4213
|
+
);
|
|
3929
4214
|
} catch (error) {
|
|
3930
4215
|
return {
|
|
3931
4216
|
success: false,
|
|
@@ -3933,35 +4218,17 @@ async function executeServerPush(bundlePath, event, logger, timeout = 6e4, conte
|
|
|
3933
4218
|
error: getErrorMessage(error)
|
|
3934
4219
|
};
|
|
3935
4220
|
} finally {
|
|
3936
|
-
|
|
4221
|
+
await prepared.cleanup();
|
|
3937
4222
|
}
|
|
3938
4223
|
}
|
|
3939
|
-
function waitForWindowProperty(window, prop, timeout = 5e3) {
|
|
3940
|
-
return new Promise((resolve2, reject) => {
|
|
3941
|
-
const start = Date.now();
|
|
3942
|
-
const check = () => {
|
|
3943
|
-
if (window[prop] !== void 0) {
|
|
3944
|
-
resolve2();
|
|
3945
|
-
} else if (Date.now() - start > timeout) {
|
|
3946
|
-
reject(
|
|
3947
|
-
new Error(
|
|
3948
|
-
`Timeout waiting for window.${prop}. IIFE may have failed to execute.`
|
|
3949
|
-
)
|
|
3950
|
-
);
|
|
3951
|
-
} else {
|
|
3952
|
-
setImmediate(check);
|
|
3953
|
-
}
|
|
3954
|
-
};
|
|
3955
|
-
check();
|
|
3956
|
-
});
|
|
3957
|
-
}
|
|
3958
4224
|
|
|
3959
4225
|
// src/commands/run/index.ts
|
|
3960
4226
|
init_cli_logger();
|
|
3961
4227
|
init_core();
|
|
4228
|
+
init_tmp();
|
|
3962
4229
|
init_config_file();
|
|
3963
4230
|
init_auth();
|
|
3964
|
-
import
|
|
4231
|
+
import path18 from "path";
|
|
3965
4232
|
import { writeFileSync as writeFileSync5 } from "fs";
|
|
3966
4233
|
import { homedir as homedir2 } from "os";
|
|
3967
4234
|
import { join as join4 } from "path";
|
|
@@ -4009,12 +4276,12 @@ async function resolveBundle(bundleEnv) {
|
|
|
4009
4276
|
return { path: bundleEnv, source: "file" };
|
|
4010
4277
|
}
|
|
4011
4278
|
if (isUrl2(bundleEnv)) {
|
|
4012
|
-
const
|
|
4013
|
-
return { path:
|
|
4279
|
+
const path19 = await fetchBundle(bundleEnv, writePath);
|
|
4280
|
+
return { path: path19, source: "url" };
|
|
4014
4281
|
}
|
|
4015
4282
|
if (isStdinPiped()) {
|
|
4016
|
-
const
|
|
4017
|
-
return { path:
|
|
4283
|
+
const path19 = await readBundleFromStdin(writePath);
|
|
4284
|
+
return { path: path19, source: "stdin" };
|
|
4018
4285
|
}
|
|
4019
4286
|
return { path: bundleEnv, source: "file" };
|
|
4020
4287
|
}
|
|
@@ -4178,12 +4445,14 @@ function validatePort(port) {
|
|
|
4178
4445
|
init_utils3();
|
|
4179
4446
|
|
|
4180
4447
|
// src/commands/run/pipeline.ts
|
|
4448
|
+
init_tmp();
|
|
4181
4449
|
import { writeFileSync as writeFileSync4 } from "fs";
|
|
4450
|
+
import fs17 from "fs-extra";
|
|
4182
4451
|
|
|
4183
4452
|
// src/runtime/health-server.ts
|
|
4184
4453
|
import http from "http";
|
|
4185
4454
|
function createHealthServer(port, logger) {
|
|
4186
|
-
return new Promise((
|
|
4455
|
+
return new Promise((resolve3, reject) => {
|
|
4187
4456
|
let flowHandler = null;
|
|
4188
4457
|
const server = http.createServer((req, res) => {
|
|
4189
4458
|
if (req.url === "/health" && req.method === "GET") {
|
|
@@ -4210,7 +4479,7 @@ function createHealthServer(port, logger) {
|
|
|
4210
4479
|
server.headersTimeout = 1e4;
|
|
4211
4480
|
server.listen(port, "0.0.0.0", () => {
|
|
4212
4481
|
logger.info(`Health server listening on port ${port}`);
|
|
4213
|
-
|
|
4482
|
+
resolve3({
|
|
4214
4483
|
server,
|
|
4215
4484
|
setFlowHandler(handler) {
|
|
4216
4485
|
flowHandler = handler;
|
|
@@ -4225,28 +4494,45 @@ function createHealthServer(port, logger) {
|
|
|
4225
4494
|
}
|
|
4226
4495
|
|
|
4227
4496
|
// src/runtime/runner.ts
|
|
4228
|
-
import {
|
|
4229
|
-
|
|
4230
|
-
|
|
4497
|
+
import { resolve as resolve2, dirname as dirname2 } from "path";
|
|
4498
|
+
|
|
4499
|
+
// src/runtime/load-bundle.ts
|
|
4500
|
+
import { resolve } from "path";
|
|
4501
|
+
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
4502
|
+
async function loadBundle(file, context, logger) {
|
|
4231
4503
|
const absolutePath = resolve(file);
|
|
4232
|
-
const
|
|
4233
|
-
|
|
4234
|
-
const fileUrl = pathToFileURL(absolutePath).href;
|
|
4504
|
+
const fileUrl = pathToFileURL2(absolutePath).href;
|
|
4505
|
+
logger?.debug?.(`Importing bundle: ${absolutePath}`);
|
|
4235
4506
|
const module = await import(`${fileUrl}?t=${Date.now()}`);
|
|
4236
4507
|
if (!module.default || typeof module.default !== "function") {
|
|
4237
4508
|
throw new Error(
|
|
4238
|
-
`Invalid
|
|
4509
|
+
`Invalid bundle: ${file} must export a default factory function`
|
|
4239
4510
|
);
|
|
4240
4511
|
}
|
|
4512
|
+
logger?.debug?.("Calling factory function...");
|
|
4513
|
+
const result = await module.default(context ?? {});
|
|
4514
|
+
if (!result || !result.collector || typeof result.collector.push !== "function") {
|
|
4515
|
+
throw new Error(
|
|
4516
|
+
`Invalid bundle: factory must return { collector } with a push function`
|
|
4517
|
+
);
|
|
4518
|
+
}
|
|
4519
|
+
return {
|
|
4520
|
+
collector: result.collector,
|
|
4521
|
+
...typeof result.httpHandler === "function" ? { httpHandler: result.httpHandler } : {}
|
|
4522
|
+
};
|
|
4523
|
+
}
|
|
4524
|
+
|
|
4525
|
+
// src/runtime/runner.ts
|
|
4526
|
+
async function loadFlow(file, config, logger, loggerConfig, healthServer) {
|
|
4527
|
+
const absolutePath = resolve2(file);
|
|
4528
|
+
const flowDir = dirname2(absolutePath);
|
|
4529
|
+
process.chdir(flowDir);
|
|
4241
4530
|
const flowContext = {
|
|
4242
4531
|
...config,
|
|
4243
4532
|
...loggerConfig ? { logger: loggerConfig } : {},
|
|
4244
|
-
...healthServer ? {
|
|
4533
|
+
...healthServer ? { sourceSettings: { port: void 0 } } : {}
|
|
4245
4534
|
};
|
|
4246
|
-
const result = await
|
|
4247
|
-
if (!result || !result.collector) {
|
|
4248
|
-
throw new Error(`Invalid flow bundle: ${file} must return { collector }`);
|
|
4249
|
-
}
|
|
4535
|
+
const result = await loadBundle(absolutePath, flowContext, logger);
|
|
4250
4536
|
if (healthServer && typeof result.httpHandler === "function") {
|
|
4251
4537
|
healthServer.setFlowHandler(result.httpHandler);
|
|
4252
4538
|
}
|
|
@@ -4512,6 +4798,8 @@ async function runPipeline(options) {
|
|
|
4512
4798
|
logger.info(`Port: ${port}`);
|
|
4513
4799
|
let heartbeat = null;
|
|
4514
4800
|
let poller = null;
|
|
4801
|
+
let currentBundleCleanup;
|
|
4802
|
+
let currentConfigPath;
|
|
4515
4803
|
if (api) {
|
|
4516
4804
|
heartbeat = createHeartbeat(
|
|
4517
4805
|
{
|
|
@@ -4546,28 +4834,44 @@ async function runPipeline(options) {
|
|
|
4546
4834
|
);
|
|
4547
4835
|
return;
|
|
4548
4836
|
}
|
|
4549
|
-
const tmpConfigPath =
|
|
4837
|
+
const tmpConfigPath = getTmpPath(
|
|
4838
|
+
void 0,
|
|
4839
|
+
`walkeros-flow-${Date.now()}.json`
|
|
4840
|
+
);
|
|
4550
4841
|
writeFileSync4(
|
|
4551
4842
|
tmpConfigPath,
|
|
4552
4843
|
JSON.stringify(content, null, 2),
|
|
4553
4844
|
"utf-8"
|
|
4554
4845
|
);
|
|
4555
|
-
const
|
|
4846
|
+
const newBundleResult = await api.prepareBundleForRun(tmpConfigPath, {
|
|
4556
4847
|
verbose: false,
|
|
4557
4848
|
silent: true,
|
|
4558
4849
|
flowName: api.flowName
|
|
4559
4850
|
});
|
|
4560
4851
|
handle = await swapFlow(
|
|
4561
4852
|
handle,
|
|
4562
|
-
|
|
4853
|
+
newBundleResult.bundlePath,
|
|
4563
4854
|
runtimeConfig,
|
|
4564
4855
|
logger,
|
|
4565
4856
|
loggerConfig,
|
|
4566
4857
|
healthServer
|
|
4567
4858
|
);
|
|
4568
|
-
writeCache(
|
|
4859
|
+
writeCache(
|
|
4860
|
+
api.cacheDir,
|
|
4861
|
+
newBundleResult.bundlePath,
|
|
4862
|
+
JSON.stringify(content),
|
|
4863
|
+
version
|
|
4864
|
+
);
|
|
4569
4865
|
configVersion = version;
|
|
4570
4866
|
if (heartbeat) heartbeat.updateConfigVersion(version);
|
|
4867
|
+
if (currentBundleCleanup)
|
|
4868
|
+
await currentBundleCleanup().catch(() => {
|
|
4869
|
+
});
|
|
4870
|
+
if (currentConfigPath)
|
|
4871
|
+
await fs17.remove(currentConfigPath).catch(() => {
|
|
4872
|
+
});
|
|
4873
|
+
currentBundleCleanup = newBundleResult.cleanup;
|
|
4874
|
+
currentConfigPath = tmpConfigPath;
|
|
4571
4875
|
logger.info(`Hot-swapped to version ${version}`);
|
|
4572
4876
|
}
|
|
4573
4877
|
},
|
|
@@ -4589,6 +4893,10 @@ async function runPipeline(options) {
|
|
|
4589
4893
|
await handle.collector.command("shutdown");
|
|
4590
4894
|
}
|
|
4591
4895
|
await healthServer.close();
|
|
4896
|
+
if (currentBundleCleanup) await currentBundleCleanup().catch(() => {
|
|
4897
|
+
});
|
|
4898
|
+
if (currentConfigPath) await fs17.remove(currentConfigPath).catch(() => {
|
|
4899
|
+
});
|
|
4592
4900
|
logger.info("Shutdown complete");
|
|
4593
4901
|
clearTimeout(forceTimer);
|
|
4594
4902
|
process.exit(0);
|
|
@@ -4737,15 +5045,16 @@ async function resolveBundlePath(configInput, apiConfig, logger) {
|
|
|
4737
5045
|
logger.info(`Bundle: ${resolved.path}`);
|
|
4738
5046
|
}
|
|
4739
5047
|
if (isPreBuiltConfig(resolved.path)) {
|
|
4740
|
-
return
|
|
5048
|
+
return path18.resolve(resolved.path);
|
|
4741
5049
|
}
|
|
4742
5050
|
const flowFile = validateFlowFile(resolved.path);
|
|
4743
5051
|
logger.debug("Building flow bundle");
|
|
4744
|
-
|
|
5052
|
+
const result = await lazyPrepareBundleForRun(flowFile, {
|
|
4745
5053
|
verbose: false,
|
|
4746
5054
|
silent: true,
|
|
4747
5055
|
flowName: apiConfig?.flowName
|
|
4748
5056
|
});
|
|
5057
|
+
return result.bundlePath;
|
|
4749
5058
|
}
|
|
4750
5059
|
if (apiConfig) {
|
|
4751
5060
|
logger.info("Fetching config from API...");
|
|
@@ -4757,7 +5066,10 @@ async function resolveBundlePath(configInput, apiConfig, logger) {
|
|
|
4757
5066
|
flowId: apiConfig.flowId
|
|
4758
5067
|
});
|
|
4759
5068
|
if (result.changed) {
|
|
4760
|
-
const tmpConfigPath =
|
|
5069
|
+
const tmpConfigPath = getTmpPath(
|
|
5070
|
+
void 0,
|
|
5071
|
+
`walkeros-flow-${Date.now()}.json`
|
|
5072
|
+
);
|
|
4761
5073
|
writeFileSync5(
|
|
4762
5074
|
tmpConfigPath,
|
|
4763
5075
|
JSON.stringify(result.content, null, 2),
|
|
@@ -4765,7 +5077,7 @@ async function resolveBundlePath(configInput, apiConfig, logger) {
|
|
|
4765
5077
|
);
|
|
4766
5078
|
logger.info(`Config version: ${result.version}`);
|
|
4767
5079
|
logger.info("Building flow...");
|
|
4768
|
-
const
|
|
5080
|
+
const bundleResult = await lazyPrepareBundleForRun(tmpConfigPath, {
|
|
4769
5081
|
verbose: false,
|
|
4770
5082
|
silent: true,
|
|
4771
5083
|
flowName: apiConfig.flowName
|
|
@@ -4774,14 +5086,14 @@ async function resolveBundlePath(configInput, apiConfig, logger) {
|
|
|
4774
5086
|
const { writeCache: writeCache2 } = await Promise.resolve().then(() => (init_cache(), cache_exports));
|
|
4775
5087
|
writeCache2(
|
|
4776
5088
|
apiConfig.cacheDir,
|
|
4777
|
-
bundlePath,
|
|
5089
|
+
bundleResult.bundlePath,
|
|
4778
5090
|
JSON.stringify(result.content),
|
|
4779
5091
|
result.version
|
|
4780
5092
|
);
|
|
4781
5093
|
} catch {
|
|
4782
5094
|
logger.debug("Cache write failed (non-critical)");
|
|
4783
5095
|
}
|
|
4784
|
-
return bundlePath;
|
|
5096
|
+
return bundleResult.bundlePath;
|
|
4785
5097
|
}
|
|
4786
5098
|
} catch (error) {
|
|
4787
5099
|
logger.error(
|
|
@@ -4799,7 +5111,7 @@ async function resolveBundlePath(configInput, apiConfig, logger) {
|
|
|
4799
5111
|
}
|
|
4800
5112
|
const defaultFile = "server-collect.mjs";
|
|
4801
5113
|
logger.debug(`No config specified, using default: ${defaultFile}`);
|
|
4802
|
-
return
|
|
5114
|
+
return path18.resolve(defaultFile);
|
|
4803
5115
|
}
|
|
4804
5116
|
async function run(options) {
|
|
4805
5117
|
const startTime = Date.now();
|
|
@@ -4990,73 +5302,15 @@ function validateEntityActions(obj, prefix, errors) {
|
|
|
4990
5302
|
}
|
|
4991
5303
|
|
|
4992
5304
|
// src/commands/validate/validators/event.ts
|
|
4993
|
-
|
|
4994
|
-
|
|
4995
|
-
|
|
4996
|
-
const errors = [];
|
|
4997
|
-
const warnings = [];
|
|
4998
|
-
const details = {};
|
|
4999
|
-
const event = typeof input === "object" && input !== null ? input : {};
|
|
5000
|
-
if (!("name" in event) || event.name === void 0) {
|
|
5001
|
-
errors.push({
|
|
5002
|
-
path: "name",
|
|
5003
|
-
message: "Event must have a name field",
|
|
5004
|
-
code: "MISSING_EVENT_NAME"
|
|
5005
|
-
});
|
|
5006
|
-
} else if (typeof event.name !== "string" || event.name.trim() === "") {
|
|
5007
|
-
errors.push({
|
|
5008
|
-
path: "name",
|
|
5009
|
-
message: "Event name cannot be empty",
|
|
5010
|
-
value: event.name,
|
|
5011
|
-
code: "EMPTY_EVENT_NAME"
|
|
5012
|
-
});
|
|
5013
|
-
} else {
|
|
5014
|
-
const name = event.name;
|
|
5015
|
-
if (!name.includes(" ")) {
|
|
5016
|
-
errors.push({
|
|
5017
|
-
path: "name",
|
|
5018
|
-
message: 'Event name must be "entity action" format with space (e.g., "page view")',
|
|
5019
|
-
value: name,
|
|
5020
|
-
code: "INVALID_EVENT_NAME"
|
|
5021
|
-
});
|
|
5022
|
-
details.entity = null;
|
|
5023
|
-
details.action = null;
|
|
5024
|
-
} else {
|
|
5025
|
-
const parts = name.trim().split(/\s+/);
|
|
5026
|
-
const action = parts.pop();
|
|
5027
|
-
const entity = parts.join(" ");
|
|
5028
|
-
details.entity = entity;
|
|
5029
|
-
details.action = action;
|
|
5030
|
-
}
|
|
5031
|
-
}
|
|
5032
|
-
const zodResult = PartialEventSchema.safeParse(input);
|
|
5033
|
-
if (!zodResult.success) {
|
|
5034
|
-
for (const issue of zodResult.error.issues) {
|
|
5035
|
-
const path15 = issue.path.join(".");
|
|
5036
|
-
if (path15 === "name") continue;
|
|
5037
|
-
errors.push({
|
|
5038
|
-
path: path15 || "root",
|
|
5039
|
-
message: issue.message,
|
|
5040
|
-
code: "SCHEMA_VALIDATION"
|
|
5041
|
-
});
|
|
5042
|
-
}
|
|
5043
|
-
}
|
|
5044
|
-
if (!event.consent) {
|
|
5045
|
-
warnings.push({
|
|
5046
|
-
path: "consent",
|
|
5047
|
-
message: "No consent object provided",
|
|
5048
|
-
suggestion: "Consider adding a consent object for GDPR/privacy compliance"
|
|
5049
|
-
});
|
|
5050
|
-
}
|
|
5051
|
-
details.hasConsent = !!event.consent;
|
|
5052
|
-
details.hasData = !!event.data;
|
|
5053
|
-
details.hasContext = !!event.context;
|
|
5305
|
+
init_event_validation();
|
|
5306
|
+
function validateEvent2(input) {
|
|
5307
|
+
const result = validateEvent(input, "strict");
|
|
5054
5308
|
return {
|
|
5055
|
-
valid:
|
|
5309
|
+
valid: result.valid,
|
|
5056
5310
|
type: "event",
|
|
5057
|
-
errors,
|
|
5058
|
-
warnings,
|
|
5059
|
-
details
|
|
5311
|
+
errors: result.errors,
|
|
5312
|
+
warnings: result.warnings,
|
|
5313
|
+
details: result.details
|
|
5060
5314
|
};
|
|
5061
5315
|
}
|
|
5062
5316
|
|
|
@@ -5243,10 +5497,10 @@ function buildConnectionGraph(config) {
|
|
|
5243
5497
|
function checkCompatibility(conn, errors, warnings) {
|
|
5244
5498
|
const fromOuts = Object.entries(conn.from.examples).filter(([, ex]) => ex.out !== void 0 && ex.out !== false).map(([name, ex]) => ({ name, value: ex.out }));
|
|
5245
5499
|
const toIns = Object.entries(conn.to.examples).filter(([, ex]) => ex.in !== void 0).map(([name, ex]) => ({ name, value: ex.in }));
|
|
5246
|
-
const
|
|
5500
|
+
const path19 = `${conn.from.type}.${conn.from.name} \u2192 ${conn.to.type}.${conn.to.name}`;
|
|
5247
5501
|
if (fromOuts.length === 0 || toIns.length === 0) {
|
|
5248
5502
|
warnings.push({
|
|
5249
|
-
path:
|
|
5503
|
+
path: path19,
|
|
5250
5504
|
message: "Cannot check compatibility: missing out or in examples",
|
|
5251
5505
|
suggestion: "Add out examples to the source step or in examples to the target step"
|
|
5252
5506
|
});
|
|
@@ -5264,7 +5518,7 @@ function checkCompatibility(conn, errors, warnings) {
|
|
|
5264
5518
|
}
|
|
5265
5519
|
if (!hasMatch) {
|
|
5266
5520
|
errors.push({
|
|
5267
|
-
path:
|
|
5521
|
+
path: path19,
|
|
5268
5522
|
message: "No compatible out/in pair found between connected steps",
|
|
5269
5523
|
code: "INCOMPATIBLE_EXAMPLES"
|
|
5270
5524
|
});
|
|
@@ -5360,13 +5614,13 @@ function validateMapping(input) {
|
|
|
5360
5614
|
import Ajv from "ajv";
|
|
5361
5615
|
import { fetchPackageSchema } from "@walkeros/core";
|
|
5362
5616
|
var SECTIONS = ["destinations", "sources", "transformers"];
|
|
5363
|
-
function resolveEntry(
|
|
5617
|
+
function resolveEntry(path19, flowConfig) {
|
|
5364
5618
|
const flows = flowConfig.flows;
|
|
5365
5619
|
if (!flows || typeof flows !== "object") return "No flows found in config";
|
|
5366
5620
|
const flowName = Object.keys(flows)[0];
|
|
5367
5621
|
const flow = flows[flowName];
|
|
5368
5622
|
if (!flow) return `Flow "${flowName}" is empty`;
|
|
5369
|
-
const parts =
|
|
5623
|
+
const parts = path19.split(".");
|
|
5370
5624
|
if (parts.length === 2) {
|
|
5371
5625
|
const [section, key] = parts;
|
|
5372
5626
|
if (!SECTIONS.includes(section)) {
|
|
@@ -5403,15 +5657,15 @@ function resolveEntry(path15, flowConfig) {
|
|
|
5403
5657
|
}
|
|
5404
5658
|
return { section: matches[0].section, key, entry: matches[0].entry };
|
|
5405
5659
|
}
|
|
5406
|
-
return `Invalid path "${
|
|
5660
|
+
return `Invalid path "${path19}". Use "section.key" or just "key"`;
|
|
5407
5661
|
}
|
|
5408
|
-
async function validateEntry(
|
|
5409
|
-
const resolved = resolveEntry(
|
|
5662
|
+
async function validateEntry(path19, flowConfig) {
|
|
5663
|
+
const resolved = resolveEntry(path19, flowConfig);
|
|
5410
5664
|
if (typeof resolved === "string") {
|
|
5411
5665
|
return {
|
|
5412
5666
|
valid: false,
|
|
5413
5667
|
type: "entry",
|
|
5414
|
-
errors: [{ path:
|
|
5668
|
+
errors: [{ path: path19, message: resolved, code: "ENTRY_VALIDATION" }],
|
|
5415
5669
|
warnings: [],
|
|
5416
5670
|
details: {}
|
|
5417
5671
|
};
|
|
@@ -5442,7 +5696,7 @@ async function validateEntry(path15, flowConfig) {
|
|
|
5442
5696
|
type: "entry",
|
|
5443
5697
|
errors: [
|
|
5444
5698
|
{
|
|
5445
|
-
path:
|
|
5699
|
+
path: path19,
|
|
5446
5700
|
message: error instanceof Error ? error.message : "Unknown error",
|
|
5447
5701
|
code: "ENTRY_VALIDATION"
|
|
5448
5702
|
}
|
|
@@ -5467,10 +5721,10 @@ async function validateEntry(path15, flowConfig) {
|
|
|
5467
5721
|
const validate2 = ajv.compile(settingsSchema);
|
|
5468
5722
|
const isValid = validate2(settings || {});
|
|
5469
5723
|
if (!isValid) {
|
|
5470
|
-
const errors = (validate2.errors || []).map((
|
|
5471
|
-
path:
|
|
5472
|
-
message:
|
|
5473
|
-
code:
|
|
5724
|
+
const errors = (validate2.errors || []).map((e) => ({
|
|
5725
|
+
path: e.instancePath || "/",
|
|
5726
|
+
message: e.message || "Unknown error",
|
|
5727
|
+
code: e.keyword
|
|
5474
5728
|
}));
|
|
5475
5729
|
return {
|
|
5476
5730
|
valid: false,
|
|
@@ -5505,7 +5759,7 @@ async function validate(type, input, options = {}) {
|
|
|
5505
5759
|
case "contract":
|
|
5506
5760
|
return validateContract(resolved);
|
|
5507
5761
|
case "event":
|
|
5508
|
-
return
|
|
5762
|
+
return validateEvent2(resolved);
|
|
5509
5763
|
case "flow":
|
|
5510
5764
|
return validateFlow(resolved, { flow: options.flow });
|
|
5511
5765
|
case "mapping":
|
|
@@ -5790,10 +6044,10 @@ async function deleteProject(options = {}) {
|
|
|
5790
6044
|
throw new Error(error.error?.message || "Failed to delete project");
|
|
5791
6045
|
return data ?? { success: true };
|
|
5792
6046
|
}
|
|
5793
|
-
async function handleResult(
|
|
6047
|
+
async function handleResult(fn, options) {
|
|
5794
6048
|
const logger = createCLILogger(options);
|
|
5795
6049
|
try {
|
|
5796
|
-
const result = await
|
|
6050
|
+
const result = await fn();
|
|
5797
6051
|
await writeResult(JSON.stringify(result, null, 2), options);
|
|
5798
6052
|
} catch (error) {
|
|
5799
6053
|
logger.error(error instanceof Error ? error.message : String(error));
|
|
@@ -5949,10 +6203,10 @@ async function duplicateFlow(options) {
|
|
|
5949
6203
|
if (error) throwApiError(error, "Failed to duplicate flow");
|
|
5950
6204
|
return data;
|
|
5951
6205
|
}
|
|
5952
|
-
async function handleResult2(
|
|
6206
|
+
async function handleResult2(fn, options) {
|
|
5953
6207
|
const logger = createCLILogger(options);
|
|
5954
6208
|
try {
|
|
5955
|
-
const result = await
|
|
6209
|
+
const result = await fn();
|
|
5956
6210
|
await writeResult(JSON.stringify(result, null, 2), options);
|
|
5957
6211
|
} catch (error) {
|
|
5958
6212
|
logger.error(error instanceof Error ? error.message : String(error));
|
|
@@ -6111,8 +6365,8 @@ async function deploy(options) {
|
|
|
6111
6365
|
if (error) {
|
|
6112
6366
|
try {
|
|
6113
6367
|
throwApiError(error, "Failed to start deployment");
|
|
6114
|
-
} catch (
|
|
6115
|
-
if (
|
|
6368
|
+
} catch (e) {
|
|
6369
|
+
if (e instanceof ApiError && e.code === "AMBIGUOUS_CONFIG") {
|
|
6116
6370
|
const names = await getAvailableFlowNames({
|
|
6117
6371
|
flowId: options.flowId,
|
|
6118
6372
|
projectId
|
|
@@ -6123,7 +6377,7 @@ Available: ${names.join(", ")}`,
|
|
|
6123
6377
|
{ code: "AMBIGUOUS_CONFIG" }
|
|
6124
6378
|
);
|
|
6125
6379
|
}
|
|
6126
|
-
throw
|
|
6380
|
+
throw e;
|
|
6127
6381
|
}
|
|
6128
6382
|
}
|
|
6129
6383
|
if (!options.wait) return data;
|
|
@@ -6260,7 +6514,7 @@ async function getDeploymentCommand(flowId, options) {
|
|
|
6260
6514
|
// src/commands/deployments/index.ts
|
|
6261
6515
|
init_auth();
|
|
6262
6516
|
init_http();
|
|
6263
|
-
import { getPlatform as
|
|
6517
|
+
import { getPlatform as getPlatform5 } from "@walkeros/core";
|
|
6264
6518
|
init_cli_logger();
|
|
6265
6519
|
init_output();
|
|
6266
6520
|
init_loader();
|
|
@@ -6316,10 +6570,10 @@ async function deleteDeployment(options) {
|
|
|
6316
6570
|
const data = await response.json().catch(() => null);
|
|
6317
6571
|
return data ?? { success: true };
|
|
6318
6572
|
}
|
|
6319
|
-
async function handleResult3(
|
|
6573
|
+
async function handleResult3(fn, options) {
|
|
6320
6574
|
const logger = createCLILogger(options);
|
|
6321
6575
|
try {
|
|
6322
|
-
const result = await
|
|
6576
|
+
const result = await fn();
|
|
6323
6577
|
await writeResult(JSON.stringify(result, null, 2), options);
|
|
6324
6578
|
} catch (error) {
|
|
6325
6579
|
logger.error(error instanceof Error ? error.message : String(error));
|
|
@@ -6393,7 +6647,7 @@ async function createDeployCommand(config, options) {
|
|
|
6393
6647
|
const result2 = await loadFlowConfig(config, {
|
|
6394
6648
|
flowName: options.flow
|
|
6395
6649
|
});
|
|
6396
|
-
type =
|
|
6650
|
+
type = getPlatform5(result2.flowSettings);
|
|
6397
6651
|
}
|
|
6398
6652
|
const deployment = await createDeployment({
|
|
6399
6653
|
type,
|
|
@@ -6494,14 +6748,14 @@ async function feedbackCommand(text) {
|
|
|
6494
6748
|
}
|
|
6495
6749
|
}
|
|
6496
6750
|
function promptUser(question) {
|
|
6497
|
-
return new Promise((
|
|
6751
|
+
return new Promise((resolve3) => {
|
|
6498
6752
|
const rl = createInterface({
|
|
6499
6753
|
input: process.stdin,
|
|
6500
6754
|
output: process.stderr
|
|
6501
6755
|
});
|
|
6502
6756
|
rl.question(question, (answer) => {
|
|
6503
6757
|
rl.close();
|
|
6504
|
-
|
|
6758
|
+
resolve3(answer);
|
|
6505
6759
|
});
|
|
6506
6760
|
});
|
|
6507
6761
|
}
|
|
@@ -6514,6 +6768,108 @@ init_api_client();
|
|
|
6514
6768
|
init_config_file();
|
|
6515
6769
|
init_sse();
|
|
6516
6770
|
init_utils();
|
|
6771
|
+
|
|
6772
|
+
// src/commands/simulate/example-loader.ts
|
|
6773
|
+
function findExample(config, exampleName, stepTarget) {
|
|
6774
|
+
if (stepTarget) {
|
|
6775
|
+
return findExampleInStep(config, exampleName, stepTarget);
|
|
6776
|
+
}
|
|
6777
|
+
return findExampleAcrossSteps(config, exampleName);
|
|
6778
|
+
}
|
|
6779
|
+
function findExampleInStep(config, exampleName, stepTarget) {
|
|
6780
|
+
const dotIndex = stepTarget.indexOf(".");
|
|
6781
|
+
if (dotIndex === -1) {
|
|
6782
|
+
throw new Error(
|
|
6783
|
+
`Invalid --step format: "${stepTarget}". Expected "type.name" (e.g. "destination.gtag")`
|
|
6784
|
+
);
|
|
6785
|
+
}
|
|
6786
|
+
const type = stepTarget.substring(0, dotIndex);
|
|
6787
|
+
const name = stepTarget.substring(dotIndex + 1);
|
|
6788
|
+
const stepMap = getStepMap(config, type);
|
|
6789
|
+
if (!stepMap) {
|
|
6790
|
+
throw new Error(`No ${type}s found in flow config`);
|
|
6791
|
+
}
|
|
6792
|
+
const step = stepMap[name];
|
|
6793
|
+
if (!step) {
|
|
6794
|
+
const available = Object.keys(stepMap).join(", ");
|
|
6795
|
+
throw new Error(`${type} "${name}" not found. Available: ${available}`);
|
|
6796
|
+
}
|
|
6797
|
+
const examples = step.examples;
|
|
6798
|
+
if (!examples || !examples[exampleName]) {
|
|
6799
|
+
const available = examples ? Object.keys(examples).join(", ") : "none";
|
|
6800
|
+
throw new Error(
|
|
6801
|
+
`Example "${exampleName}" not found in ${type} "${name}". Available: ${available}`
|
|
6802
|
+
);
|
|
6803
|
+
}
|
|
6804
|
+
return {
|
|
6805
|
+
stepType: type,
|
|
6806
|
+
stepName: name,
|
|
6807
|
+
exampleName,
|
|
6808
|
+
example: examples[exampleName]
|
|
6809
|
+
};
|
|
6810
|
+
}
|
|
6811
|
+
function findExampleAcrossSteps(config, exampleName) {
|
|
6812
|
+
const matches = [];
|
|
6813
|
+
const stepTypes = ["source", "transformer", "destination"];
|
|
6814
|
+
for (const type of stepTypes) {
|
|
6815
|
+
const stepMap = getStepMap(config, type);
|
|
6816
|
+
if (!stepMap) continue;
|
|
6817
|
+
for (const [name, step] of Object.entries(stepMap)) {
|
|
6818
|
+
const examples = step.examples;
|
|
6819
|
+
if (examples && examples[exampleName]) {
|
|
6820
|
+
matches.push({
|
|
6821
|
+
stepType: type,
|
|
6822
|
+
stepName: name,
|
|
6823
|
+
exampleName,
|
|
6824
|
+
example: examples[exampleName]
|
|
6825
|
+
});
|
|
6826
|
+
}
|
|
6827
|
+
}
|
|
6828
|
+
}
|
|
6829
|
+
if (matches.length === 0) {
|
|
6830
|
+
throw new Error(`Example "${exampleName}" not found in any step`);
|
|
6831
|
+
}
|
|
6832
|
+
if (matches.length > 1) {
|
|
6833
|
+
const locations = matches.map((m2) => `${m2.stepType}.${m2.stepName}`).join(", ");
|
|
6834
|
+
throw new Error(
|
|
6835
|
+
`Example "${exampleName}" found in multiple steps: ${locations}. Use --step to disambiguate.`
|
|
6836
|
+
);
|
|
6837
|
+
}
|
|
6838
|
+
return matches[0];
|
|
6839
|
+
}
|
|
6840
|
+
function getStepMap(config, type) {
|
|
6841
|
+
switch (type) {
|
|
6842
|
+
case "source":
|
|
6843
|
+
return config.sources;
|
|
6844
|
+
case "transformer":
|
|
6845
|
+
return config.transformers;
|
|
6846
|
+
case "destination":
|
|
6847
|
+
return config.destinations;
|
|
6848
|
+
default:
|
|
6849
|
+
throw new Error(
|
|
6850
|
+
`Invalid step type: "${type}". Must be "source", "transformer", or "destination"`
|
|
6851
|
+
);
|
|
6852
|
+
}
|
|
6853
|
+
}
|
|
6854
|
+
|
|
6855
|
+
// src/commands/simulate/compare.ts
|
|
6856
|
+
function compareOutput(expected, actual) {
|
|
6857
|
+
const expectedStr = JSON.stringify(expected, null, 2);
|
|
6858
|
+
const actualStr = JSON.stringify(actual, null, 2);
|
|
6859
|
+
if (expectedStr === actualStr) {
|
|
6860
|
+
return { expected, actual, match: true };
|
|
6861
|
+
}
|
|
6862
|
+
return {
|
|
6863
|
+
expected,
|
|
6864
|
+
actual,
|
|
6865
|
+
match: false,
|
|
6866
|
+
diff: `Expected:
|
|
6867
|
+
${expectedStr}
|
|
6868
|
+
|
|
6869
|
+
Actual:
|
|
6870
|
+
${actualStr}`
|
|
6871
|
+
};
|
|
6872
|
+
}
|
|
6517
6873
|
export {
|
|
6518
6874
|
ApiError,
|
|
6519
6875
|
apiFetch,
|
|
@@ -6559,6 +6915,7 @@ export {
|
|
|
6559
6915
|
listFlowsCommand,
|
|
6560
6916
|
listProjects,
|
|
6561
6917
|
listProjectsCommand,
|
|
6918
|
+
loadConfig,
|
|
6562
6919
|
loadJsonConfig,
|
|
6563
6920
|
loginCommand,
|
|
6564
6921
|
logoutCommand,
|
|
@@ -6571,8 +6928,9 @@ export {
|
|
|
6571
6928
|
requireProjectId,
|
|
6572
6929
|
run,
|
|
6573
6930
|
runCommand,
|
|
6574
|
-
|
|
6575
|
-
|
|
6931
|
+
simulateDestination,
|
|
6932
|
+
simulateSource,
|
|
6933
|
+
simulateTransformer,
|
|
6576
6934
|
throwApiError,
|
|
6577
6935
|
updateFlow,
|
|
6578
6936
|
updateFlowCommand,
|