@walkeros/cli 3.1.1 → 3.2.0-next-1775064795590
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +66 -0
- package/README.md +50 -52
- package/dist/cli.js +2816 -2492
- package/dist/examples/README.md +4 -3
- package/dist/examples/flow-complete.json +18 -24
- package/dist/examples/flow-order-complete.json +1 -1
- package/dist/examples/flow-simple.json +1 -1
- package/dist/index.d.ts +156 -111
- package/dist/index.js +2111 -1745
- package/dist/index.js.map +1 -1
- package/examples/README.md +4 -3
- package/examples/flow-complete.json +18 -24
- package/examples/flow-order-complete.json +1 -1
- package/examples/flow-simple.json +1 -1
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
var __defProp = Object.defineProperty;
|
|
2
2
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
3
|
-
var __esm = (
|
|
4
|
-
return
|
|
3
|
+
var __esm = (fn, res) => function __init() {
|
|
4
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
5
5
|
};
|
|
6
6
|
var __export = (target, all) => {
|
|
7
7
|
for (var name in all)
|
|
@@ -205,26 +205,26 @@ function mergeAuthHeaders(token, headers) {
|
|
|
205
205
|
if (token) normalized.Authorization = `Bearer ${token}`;
|
|
206
206
|
return normalized;
|
|
207
207
|
}
|
|
208
|
-
async function apiFetch(
|
|
208
|
+
async function apiFetch(path19, init) {
|
|
209
209
|
const baseUrl = resolveAppUrl();
|
|
210
210
|
const token = resolveToken()?.token;
|
|
211
|
-
return fetch(`${baseUrl}${
|
|
211
|
+
return fetch(`${baseUrl}${path19}`, {
|
|
212
212
|
...init,
|
|
213
213
|
headers: mergeAuthHeaders(token, init?.headers)
|
|
214
214
|
});
|
|
215
215
|
}
|
|
216
|
-
async function publicFetch(
|
|
216
|
+
async function publicFetch(path19, init) {
|
|
217
217
|
const baseUrl = resolveAppUrl();
|
|
218
|
-
return fetch(`${baseUrl}${
|
|
218
|
+
return fetch(`${baseUrl}${path19}`, init);
|
|
219
219
|
}
|
|
220
|
-
async function deployFetch(
|
|
220
|
+
async function deployFetch(path19, init) {
|
|
221
221
|
const baseUrl = resolveAppUrl();
|
|
222
222
|
const token = resolveDeployToken() ?? resolveToken()?.token;
|
|
223
223
|
if (!token)
|
|
224
224
|
throw new Error(
|
|
225
225
|
"No authentication token available. Set WALKEROS_DEPLOY_TOKEN or run walkeros auth login."
|
|
226
226
|
);
|
|
227
|
-
return fetch(`${baseUrl}${
|
|
227
|
+
return fetch(`${baseUrl}${path19}`, {
|
|
228
228
|
...init,
|
|
229
229
|
headers: mergeAuthHeaders(token, init?.headers)
|
|
230
230
|
});
|
|
@@ -237,7 +237,6 @@ var init_http = __esm({
|
|
|
237
237
|
});
|
|
238
238
|
|
|
239
239
|
// src/config/utils.ts
|
|
240
|
-
import crypto from "crypto";
|
|
241
240
|
import fs2 from "fs-extra";
|
|
242
241
|
import path3 from "path";
|
|
243
242
|
function isUrl(str) {
|
|
@@ -248,132 +247,79 @@ function isUrl(str) {
|
|
|
248
247
|
return false;
|
|
249
248
|
}
|
|
250
249
|
}
|
|
251
|
-
async function
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
if (!response.ok) {
|
|
261
|
-
throw new Error(
|
|
262
|
-
`Failed to download ${url}: ${response.status} ${response.statusText}`
|
|
263
|
-
);
|
|
264
|
-
}
|
|
265
|
-
const content = await response.text();
|
|
266
|
-
const downloadsDir = getTmpPath(void 0, "downloads");
|
|
267
|
-
await fs2.ensureDir(downloadsDir);
|
|
268
|
-
const downloadId = crypto.randomUUID().slice(0, 8);
|
|
269
|
-
const tempPath = path3.join(downloadsDir, `flow-${downloadId}.json`);
|
|
270
|
-
await fs2.writeFile(tempPath, content, "utf-8");
|
|
271
|
-
return tempPath;
|
|
272
|
-
} catch (error) {
|
|
273
|
-
if (error instanceof Error) {
|
|
274
|
-
throw new Error(`Failed to download from URL: ${error.message}`);
|
|
275
|
-
}
|
|
276
|
-
throw error;
|
|
250
|
+
async function fetchContentString(url) {
|
|
251
|
+
const token = resolveToken()?.token;
|
|
252
|
+
const response = await fetch(url, {
|
|
253
|
+
headers: mergeAuthHeaders(token)
|
|
254
|
+
});
|
|
255
|
+
if (!response.ok) {
|
|
256
|
+
throw new Error(
|
|
257
|
+
`Failed to fetch ${url}: ${response.status} ${response.statusText}`
|
|
258
|
+
);
|
|
277
259
|
}
|
|
260
|
+
return response.text();
|
|
278
261
|
}
|
|
279
|
-
async function
|
|
280
|
-
const trimmed =
|
|
262
|
+
async function resolveContent(input) {
|
|
263
|
+
const trimmed = input.trim();
|
|
281
264
|
if (isUrl(trimmed)) {
|
|
282
|
-
|
|
283
|
-
try {
|
|
284
|
-
const rawConfig = await fs2.readJson(absolutePath2);
|
|
285
|
-
return rawConfig;
|
|
286
|
-
} catch (error) {
|
|
287
|
-
throw new Error(
|
|
288
|
-
`Invalid JSON in config file: ${configPath}. ${error instanceof Error ? error.message : error}`
|
|
289
|
-
);
|
|
290
|
-
} finally {
|
|
291
|
-
try {
|
|
292
|
-
await fs2.remove(absolutePath2);
|
|
293
|
-
} catch {
|
|
294
|
-
}
|
|
295
|
-
}
|
|
265
|
+
return fetchContentString(trimmed);
|
|
296
266
|
}
|
|
297
267
|
const absolutePath = path3.resolve(trimmed);
|
|
298
268
|
if (await fs2.pathExists(absolutePath)) {
|
|
299
|
-
|
|
300
|
-
const rawConfig = await fs2.readJson(absolutePath);
|
|
301
|
-
return rawConfig;
|
|
302
|
-
} catch (error) {
|
|
303
|
-
throw new Error(
|
|
304
|
-
`Invalid JSON in config file: ${configPath}. ${error instanceof Error ? error.message : error}`
|
|
305
|
-
);
|
|
306
|
-
}
|
|
269
|
+
return fs2.readFile(absolutePath, "utf-8");
|
|
307
270
|
}
|
|
308
271
|
if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
272
|
+
return trimmed;
|
|
273
|
+
}
|
|
274
|
+
throw new Error(`Configuration file not found: ${absolutePath}`);
|
|
275
|
+
}
|
|
276
|
+
async function loadConfig(input, options) {
|
|
277
|
+
const json = options?.json !== false;
|
|
278
|
+
if (!json) {
|
|
279
|
+
return resolveContent(input);
|
|
280
|
+
}
|
|
281
|
+
const trimmed = input.trim();
|
|
282
|
+
try {
|
|
283
|
+
const content = await resolveContent(trimmed);
|
|
284
|
+
return JSON.parse(content);
|
|
285
|
+
} catch (error) {
|
|
286
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
287
|
+
if (errorMessage.includes("not found") || errorMessage.includes("Failed to fetch")) {
|
|
288
|
+
throw error;
|
|
289
|
+
}
|
|
290
|
+
if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
|
|
312
291
|
throw new Error(
|
|
313
|
-
`Input appears to be JSON but contains errors: ${
|
|
292
|
+
`Input appears to be JSON but contains errors: ${errorMessage}`
|
|
314
293
|
);
|
|
315
294
|
}
|
|
295
|
+
throw new Error(`Invalid JSON in config file: ${input}. ${errorMessage}`);
|
|
316
296
|
}
|
|
317
|
-
|
|
297
|
+
}
|
|
298
|
+
async function loadJsonConfig(configPath) {
|
|
299
|
+
return loadConfig(configPath, { json: true });
|
|
318
300
|
}
|
|
319
301
|
async function loadJsonFromSource(source, options) {
|
|
320
302
|
const paramName = options?.name || "input";
|
|
321
303
|
if (!source || source.trim() === "") {
|
|
322
|
-
if (options?.required) {
|
|
323
|
-
|
|
324
|
-
}
|
|
325
|
-
if (options?.fallback !== void 0) {
|
|
326
|
-
return options.fallback;
|
|
327
|
-
}
|
|
304
|
+
if (options?.required) throw new Error(`${paramName} is required`);
|
|
305
|
+
if (options?.fallback !== void 0) return options.fallback;
|
|
328
306
|
return {};
|
|
329
307
|
}
|
|
330
|
-
const trimmedSource = source.trim();
|
|
331
|
-
if (isUrl(trimmedSource)) {
|
|
332
|
-
try {
|
|
333
|
-
const tempPath = await downloadFromUrl(trimmedSource);
|
|
334
|
-
try {
|
|
335
|
-
const data = await fs2.readJson(tempPath);
|
|
336
|
-
return data;
|
|
337
|
-
} finally {
|
|
338
|
-
try {
|
|
339
|
-
await fs2.remove(tempPath);
|
|
340
|
-
} catch {
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
} catch (error) {
|
|
344
|
-
throw new Error(
|
|
345
|
-
`Failed to load ${paramName} from URL ${trimmedSource}: ${getErrorMessage(error)}`
|
|
346
|
-
);
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
const resolvedPath = path3.resolve(trimmedSource);
|
|
350
|
-
if (await fs2.pathExists(resolvedPath)) {
|
|
351
|
-
try {
|
|
352
|
-
const data = await fs2.readJson(resolvedPath);
|
|
353
|
-
return data;
|
|
354
|
-
} catch (error) {
|
|
355
|
-
throw new Error(
|
|
356
|
-
`Failed to parse ${paramName} from file ${trimmedSource}: ${getErrorMessage(error)}`
|
|
357
|
-
);
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
308
|
try {
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
if (!
|
|
365
|
-
return { name:
|
|
309
|
+
return await loadJsonConfig(source);
|
|
310
|
+
} catch (error) {
|
|
311
|
+
const trimmed = source.trim();
|
|
312
|
+
if (!trimmed.startsWith("{") && !trimmed.startsWith("[")) {
|
|
313
|
+
return { name: trimmed };
|
|
366
314
|
}
|
|
367
315
|
throw new Error(
|
|
368
|
-
`Failed to parse ${paramName}.
|
|
316
|
+
`Failed to parse ${paramName}. ${error instanceof Error ? error.message : String(error)}`
|
|
369
317
|
);
|
|
370
318
|
}
|
|
371
319
|
}
|
|
372
320
|
var init_utils = __esm({
|
|
373
321
|
"src/config/utils.ts"() {
|
|
374
322
|
"use strict";
|
|
375
|
-
init_core();
|
|
376
|
-
init_tmp();
|
|
377
323
|
init_http();
|
|
378
324
|
init_config_file();
|
|
379
325
|
}
|
|
@@ -433,33 +379,82 @@ import path5 from "path";
|
|
|
433
379
|
import fs3 from "fs-extra";
|
|
434
380
|
async function resolveLocalPackage(packageName, localPath, configDir, logger) {
|
|
435
381
|
const absolutePath = path5.isAbsolute(localPath) ? localPath : path5.resolve(configDir, localPath);
|
|
436
|
-
|
|
382
|
+
const stat = await fs3.stat(absolutePath).catch(() => null);
|
|
383
|
+
if (stat?.isFile()) {
|
|
384
|
+
return { name: packageName, absolutePath, type: "file" };
|
|
385
|
+
}
|
|
386
|
+
if (!stat) {
|
|
387
|
+
for (const ext of [".ts", ".mjs", ".js", ".json"]) {
|
|
388
|
+
const withExt = absolutePath + ext;
|
|
389
|
+
if (await fs3.pathExists(withExt)) {
|
|
390
|
+
return { name: packageName, absolutePath: withExt, type: "file" };
|
|
391
|
+
}
|
|
392
|
+
}
|
|
437
393
|
throw new Error(
|
|
438
394
|
`Local package path not found: ${localPath} (resolved to ${absolutePath})`
|
|
439
395
|
);
|
|
440
396
|
}
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
`No package.json found at ${absolutePath}. Is this a valid package directory?`
|
|
445
|
-
);
|
|
446
|
-
}
|
|
447
|
-
const distPath = path5.join(absolutePath, "dist");
|
|
448
|
-
const hasDistFolder = await fs3.pathExists(distPath);
|
|
449
|
-
if (!hasDistFolder) {
|
|
450
|
-
logger.warn(
|
|
451
|
-
`\u26A0\uFE0F ${packageName}: No dist/ folder found. Using package root.`
|
|
397
|
+
if (stat.isDirectory()) {
|
|
398
|
+
const hasPkgJson = await fs3.pathExists(
|
|
399
|
+
path5.join(absolutePath, "package.json")
|
|
452
400
|
);
|
|
401
|
+
if (hasPkgJson) {
|
|
402
|
+
const distPath = path5.join(absolutePath, "dist");
|
|
403
|
+
const hasDistFolder = await fs3.pathExists(distPath);
|
|
404
|
+
if (!hasDistFolder) {
|
|
405
|
+
logger.warn(
|
|
406
|
+
`\u26A0\uFE0F ${packageName}: No dist/ folder found. Using package root.`
|
|
407
|
+
);
|
|
408
|
+
}
|
|
409
|
+
return {
|
|
410
|
+
name: packageName,
|
|
411
|
+
absolutePath,
|
|
412
|
+
type: "package",
|
|
413
|
+
distPath: hasDistFolder ? distPath : absolutePath,
|
|
414
|
+
hasDistFolder
|
|
415
|
+
};
|
|
416
|
+
}
|
|
417
|
+
return { name: packageName, absolutePath, type: "directory" };
|
|
453
418
|
}
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
distPath: hasDistFolder ? distPath : absolutePath,
|
|
458
|
-
hasDistFolder
|
|
459
|
-
};
|
|
419
|
+
throw new Error(
|
|
420
|
+
`Local package path not found: ${localPath} (resolved to ${absolutePath})`
|
|
421
|
+
);
|
|
460
422
|
}
|
|
461
423
|
async function copyLocalPackage(localPkg, targetDir, logger) {
|
|
462
424
|
const packageDir = path5.join(targetDir, "node_modules", localPkg.name);
|
|
425
|
+
if (localPkg.type === "file") {
|
|
426
|
+
await fs3.ensureDir(packageDir);
|
|
427
|
+
const ext = path5.extname(localPkg.absolutePath);
|
|
428
|
+
await fs3.copy(localPkg.absolutePath, path5.join(packageDir, `index${ext}`));
|
|
429
|
+
await fs3.writeJson(path5.join(packageDir, "package.json"), {
|
|
430
|
+
name: localPkg.name,
|
|
431
|
+
main: `./index${ext}`
|
|
432
|
+
});
|
|
433
|
+
logger.info(
|
|
434
|
+
`\u{1F4E6} Using local file: ${localPkg.name} from ${localPkg.absolutePath}`
|
|
435
|
+
);
|
|
436
|
+
return packageDir;
|
|
437
|
+
}
|
|
438
|
+
if (localPkg.type === "directory") {
|
|
439
|
+
await fs3.ensureDir(path5.dirname(packageDir));
|
|
440
|
+
const entries = await fs3.readdir(localPkg.absolutePath);
|
|
441
|
+
for (const entry of entries) {
|
|
442
|
+
if (!["node_modules", ".turbo", ".git"].includes(entry)) {
|
|
443
|
+
await fs3.copy(
|
|
444
|
+
path5.join(localPkg.absolutePath, entry),
|
|
445
|
+
path5.join(packageDir, entry)
|
|
446
|
+
);
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
await fs3.writeJson(path5.join(packageDir, "package.json"), {
|
|
450
|
+
name: localPkg.name,
|
|
451
|
+
main: "./index.ts"
|
|
452
|
+
});
|
|
453
|
+
logger.info(
|
|
454
|
+
`\u{1F4E6} Using local dir: ${localPkg.name} from ${localPkg.absolutePath}`
|
|
455
|
+
);
|
|
456
|
+
return packageDir;
|
|
457
|
+
}
|
|
463
458
|
await fs3.ensureDir(path5.dirname(packageDir));
|
|
464
459
|
await fs3.copy(
|
|
465
460
|
path5.join(localPkg.absolutePath, "package.json"),
|
|
@@ -505,14 +500,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
|
-
};
|
|
3400
|
-
}
|
|
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}`);
|
|
3236
|
+
return { type: prefix, name, chainType, transformerId };
|
|
3433
3237
|
}
|
|
3434
|
-
|
|
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();
|
|
3498
3361
|
}
|
|
3499
|
-
|
|
3500
|
-
|
|
3501
|
-
|
|
3502
|
-
|
|
3503
|
-
|
|
3504
|
-
|
|
3505
|
-
|
|
3506
|
-
|
|
3507
|
-
|
|
3508
|
-
|
|
3362
|
+
function countPending() {
|
|
3363
|
+
return Array.from(pending.values()).filter((t) => !t.cleared).length;
|
|
3364
|
+
}
|
|
3365
|
+
function restore() {
|
|
3366
|
+
for (const saved of targets) {
|
|
3367
|
+
saved.target.setTimeout = saved.setTimeout;
|
|
3368
|
+
saved.target.clearTimeout = saved.clearTimeout;
|
|
3369
|
+
saved.target.setInterval = saved.setInterval;
|
|
3370
|
+
saved.target.clearInterval = saved.clearInterval;
|
|
3371
|
+
}
|
|
3372
|
+
pending.clear();
|
|
3373
|
+
}
|
|
3374
|
+
return { flush, countPending, restore };
|
|
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,21 +3675,63 @@ 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) {
|
|
@@ -3774,158 +3787,438 @@ async function push(configOrPath, event, options = {}) {
|
|
|
3774
3787
|
"push() currently only supports config file paths. Config object support will be added in a future version. Please provide a path to a configuration file."
|
|
3775
3788
|
);
|
|
3776
3789
|
}
|
|
3777
|
-
|
|
3778
|
-
if (
|
|
3779
|
-
|
|
3790
|
+
const parsed = schemas3.PartialEventSchema.safeParse(event);
|
|
3791
|
+
if (!parsed.success) {
|
|
3792
|
+
return {
|
|
3793
|
+
success: false,
|
|
3794
|
+
duration: 0,
|
|
3795
|
+
error: `Invalid event: ${parsed.error.issues.map((i2) => `${i2.path.join(".")}: ${i2.message}`).join(", ")}`
|
|
3796
|
+
};
|
|
3780
3797
|
}
|
|
3781
|
-
return
|
|
3798
|
+
return pushCore(configOrPath, event, {
|
|
3782
3799
|
json: options.json ?? false,
|
|
3783
3800
|
verbose: options.verbose ?? false,
|
|
3784
3801
|
silent: options.silent ?? false,
|
|
3785
3802
|
flow: options.flow,
|
|
3786
|
-
platform: options.platform
|
|
3803
|
+
platform: options.platform,
|
|
3804
|
+
mock: options.mock,
|
|
3805
|
+
snapshot: options.snapshot
|
|
3787
3806
|
});
|
|
3788
3807
|
}
|
|
3789
|
-
async function executeConfigPush(options, validatedEvent, logger, setTempDir) {
|
|
3808
|
+
async function executeConfigPush(options, validatedEvent, logger, setTempDir, snapshotCode) {
|
|
3790
3809
|
logger.debug("Loading flow configuration");
|
|
3791
3810
|
const { flowSettings, buildOptions } = await loadFlowConfig(options.config, {
|
|
3792
3811
|
flowName: options.flow,
|
|
3793
3812
|
logger
|
|
3794
3813
|
});
|
|
3795
|
-
const platform =
|
|
3814
|
+
const platform = getPlatform4(flowSettings);
|
|
3815
|
+
const overrides = buildOverrides(
|
|
3816
|
+
{ mock: options.mock },
|
|
3817
|
+
flowSettings
|
|
3818
|
+
);
|
|
3819
|
+
if (overrides.destinations) {
|
|
3820
|
+
const { loadDestinationEnvs: loadDestinationEnvs2 } = await Promise.resolve().then(() => (init_env_loader(), env_loader_exports));
|
|
3821
|
+
const configDir = buildOptions.configDir || process.cwd();
|
|
3822
|
+
const envs = await loadDestinationEnvs2(
|
|
3823
|
+
flowSettings.destinations ?? {},
|
|
3824
|
+
flowSettings.packages,
|
|
3825
|
+
configDir
|
|
3826
|
+
);
|
|
3827
|
+
for (const [destId, env] of Object.entries(envs)) {
|
|
3828
|
+
if (overrides.destinations[destId] && env.push) {
|
|
3829
|
+
overrides.destinations[destId].env = env.push;
|
|
3830
|
+
if (env.simulation && env.simulation.length > 0) {
|
|
3831
|
+
overrides.destinations[destId].simulation = env.simulation;
|
|
3832
|
+
}
|
|
3833
|
+
}
|
|
3834
|
+
}
|
|
3835
|
+
}
|
|
3796
3836
|
logger.debug("Bundling flow configuration");
|
|
3797
|
-
const configDir = buildOptions.configDir || process.cwd();
|
|
3798
3837
|
const tempDir = getTmpPath(
|
|
3799
3838
|
void 0,
|
|
3800
3839
|
`push-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`
|
|
3801
3840
|
);
|
|
3802
3841
|
setTempDir(tempDir);
|
|
3803
|
-
await
|
|
3804
|
-
const tempPath =
|
|
3805
|
-
tempDir,
|
|
3806
|
-
`bundle.${platform === "web" ? "js" : "mjs"}`
|
|
3807
|
-
);
|
|
3842
|
+
await fs15.ensureDir(tempDir);
|
|
3843
|
+
const tempPath = path16.join(tempDir, "bundle.mjs");
|
|
3808
3844
|
const pushBuildOptions = {
|
|
3809
3845
|
...buildOptions,
|
|
3810
3846
|
output: tempPath,
|
|
3811
|
-
format:
|
|
3847
|
+
format: "esm",
|
|
3812
3848
|
platform: platform === "web" ? "browser" : "node",
|
|
3813
|
-
|
|
3814
|
-
|
|
3815
|
-
windowElb: "elb"
|
|
3816
|
-
}
|
|
3849
|
+
skipWrapper: true
|
|
3850
|
+
// CLI imports ESM directly — no platform wrapper
|
|
3817
3851
|
};
|
|
3818
3852
|
await bundleCore(flowSettings, pushBuildOptions, logger, false);
|
|
3819
3853
|
logger.debug(`Bundle created: ${tempPath}`);
|
|
3820
|
-
|
|
3821
|
-
|
|
3822
|
-
|
|
3823
|
-
|
|
3824
|
-
|
|
3825
|
-
|
|
3826
|
-
|
|
3827
|
-
|
|
3828
|
-
|
|
3829
|
-
|
|
3830
|
-
|
|
3854
|
+
logger.debug(
|
|
3855
|
+
`Executing in ${platform} environment (${platform === "web" ? "JSDOM" : "Node.js"})`
|
|
3856
|
+
);
|
|
3857
|
+
return executeDestinationPush(
|
|
3858
|
+
tempPath,
|
|
3859
|
+
validatedEvent,
|
|
3860
|
+
logger,
|
|
3861
|
+
platform,
|
|
3862
|
+
overrides,
|
|
3863
|
+
snapshotCode,
|
|
3864
|
+
platform === "server" ? 6e4 : void 0
|
|
3865
|
+
);
|
|
3831
3866
|
}
|
|
3832
|
-
async function executeBundlePush(bundleContent, platform, validatedEvent, logger, setTempDir,
|
|
3867
|
+
async function executeBundlePush(bundleContent, platform, validatedEvent, logger, setTempDir, overrides = {}, snapshotCode) {
|
|
3833
3868
|
const tempDir = getTmpPath(
|
|
3834
3869
|
void 0,
|
|
3835
3870
|
`push-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`
|
|
3836
3871
|
);
|
|
3837
3872
|
setTempDir(tempDir);
|
|
3838
|
-
await
|
|
3839
|
-
const tempPath =
|
|
3840
|
-
|
|
3841
|
-
`bundle.${platform === "server" ? "mjs" : "js"}`
|
|
3842
|
-
);
|
|
3843
|
-
await fs13.writeFile(tempPath, bundleContent, "utf8");
|
|
3873
|
+
await fs15.ensureDir(tempDir);
|
|
3874
|
+
const tempPath = path16.join(tempDir, "bundle.mjs");
|
|
3875
|
+
await fs15.writeFile(tempPath, bundleContent, "utf8");
|
|
3844
3876
|
logger.debug(`Bundle written to: ${tempPath}`);
|
|
3845
|
-
|
|
3846
|
-
|
|
3847
|
-
|
|
3848
|
-
|
|
3849
|
-
|
|
3850
|
-
|
|
3877
|
+
logger.debug(
|
|
3878
|
+
`Executing in ${platform} environment (${platform === "web" ? "JSDOM" : "Node.js"})`
|
|
3879
|
+
);
|
|
3880
|
+
return executeDestinationPush(
|
|
3881
|
+
tempPath,
|
|
3882
|
+
validatedEvent,
|
|
3883
|
+
logger,
|
|
3884
|
+
platform,
|
|
3885
|
+
overrides,
|
|
3886
|
+
snapshotCode,
|
|
3887
|
+
platform === "server" ? 6e4 : void 0
|
|
3888
|
+
);
|
|
3889
|
+
}
|
|
3890
|
+
async function executeDestinationPush(esmPath, event, logger, platform, overrides, snapshotCode, timeout) {
|
|
3891
|
+
const startTime = Date.now();
|
|
3892
|
+
const networkCalls = [];
|
|
3893
|
+
return withFlowContext(
|
|
3894
|
+
{ esmPath, platform, logger, snapshotCode, timeout, networkCalls, asyncDrain: { timeout: 5e3 } },
|
|
3895
|
+
async (module) => {
|
|
3896
|
+
const config = module.wireConfig(module.__configData ?? void 0);
|
|
3897
|
+
applyOverrides(config, overrides || {});
|
|
3898
|
+
const result = await module.startFlow(config);
|
|
3899
|
+
if (!result?.collector?.push)
|
|
3900
|
+
throw new Error("Invalid bundle: collector missing push");
|
|
3901
|
+
const collector = result.collector;
|
|
3902
|
+
logger.info(`Pushing event: ${event.name}`);
|
|
3903
|
+
const elbResult = await collector.push(event);
|
|
3904
|
+
await collector.command("shutdown");
|
|
3905
|
+
return {
|
|
3906
|
+
success: true,
|
|
3907
|
+
elbResult,
|
|
3908
|
+
...networkCalls.length > 0 ? { networkCalls } : {},
|
|
3909
|
+
duration: Date.now() - startTime
|
|
3910
|
+
};
|
|
3911
|
+
}
|
|
3912
|
+
);
|
|
3913
|
+
}
|
|
3914
|
+
async function simulateSource(configPath, input, options) {
|
|
3915
|
+
const startTime = Date.now();
|
|
3916
|
+
const prepared = await prepareFlow({
|
|
3917
|
+
configPath,
|
|
3918
|
+
flow: options.flow,
|
|
3919
|
+
simulate: ["source." + options.sourceId],
|
|
3920
|
+
silent: options.silent,
|
|
3921
|
+
verbose: options.verbose
|
|
3922
|
+
});
|
|
3923
|
+
try {
|
|
3924
|
+
const logger = createCLILogger({
|
|
3925
|
+
silent: options.silent,
|
|
3926
|
+
verbose: options.verbose
|
|
3927
|
+
});
|
|
3928
|
+
const sourceConfig = (prepared.flowSettings.sources ?? {})[options.sourceId];
|
|
3929
|
+
if (!sourceConfig?.package) {
|
|
3930
|
+
throw new Error(
|
|
3931
|
+
`Source "${options.sourceId}" has no package defined`
|
|
3932
|
+
);
|
|
3933
|
+
}
|
|
3934
|
+
const devPath = resolvePackageImportPath(
|
|
3935
|
+
sourceConfig.package,
|
|
3936
|
+
prepared.flowSettings.packages,
|
|
3937
|
+
prepared.configDir,
|
|
3938
|
+
"/dev"
|
|
3939
|
+
);
|
|
3940
|
+
const devModule = await import(devPath);
|
|
3941
|
+
const createTrigger = devModule.examples?.createTrigger || devModule.default?.examples?.createTrigger;
|
|
3942
|
+
if (!createTrigger) {
|
|
3943
|
+
throw new Error(
|
|
3944
|
+
`Source package "${sourceConfig.package}" has no createTrigger in /dev export`
|
|
3945
|
+
);
|
|
3946
|
+
}
|
|
3947
|
+
let snapshotCode;
|
|
3948
|
+
if (options.snapshot) {
|
|
3949
|
+
snapshotCode = await loadConfig(options.snapshot, {
|
|
3950
|
+
json: false
|
|
3951
|
+
});
|
|
3952
|
+
logger.debug(`Snapshot loaded (${snapshotCode.length} bytes)`);
|
|
3953
|
+
}
|
|
3954
|
+
const networkCalls = [];
|
|
3955
|
+
return await withFlowContext(
|
|
3956
|
+
{
|
|
3957
|
+
esmPath: prepared.bundlePath,
|
|
3958
|
+
platform: prepared.platform,
|
|
3959
|
+
logger,
|
|
3960
|
+
snapshotCode,
|
|
3961
|
+
networkCalls
|
|
3962
|
+
},
|
|
3963
|
+
async (module) => {
|
|
3964
|
+
const config = module.wireConfig(module.__configData ?? void 0);
|
|
3965
|
+
applyOverrides(config, prepared.overrides);
|
|
3966
|
+
const captured = [];
|
|
3967
|
+
config.hooks = {
|
|
3968
|
+
...config.hooks || {},
|
|
3969
|
+
prePush: ({ fn }, event) => {
|
|
3970
|
+
captured.push({ event, timestamp: Date.now() });
|
|
3971
|
+
return { ok: true };
|
|
3972
|
+
}
|
|
3973
|
+
};
|
|
3974
|
+
const instance = await createTrigger(config, { sourceId: options.sourceId });
|
|
3975
|
+
const { trigger } = instance;
|
|
3976
|
+
logger.info("Simulating source");
|
|
3977
|
+
const inputRecord = input ?? {};
|
|
3978
|
+
const content = inputRecord.content ?? input;
|
|
3979
|
+
const triggerOpts = inputRecord.trigger;
|
|
3980
|
+
await trigger(triggerOpts?.type, triggerOpts?.options)(content);
|
|
3981
|
+
if (instance.flow?.collector?.command) {
|
|
3982
|
+
await instance.flow.collector.command("shutdown");
|
|
3983
|
+
}
|
|
3984
|
+
return {
|
|
3985
|
+
success: true,
|
|
3986
|
+
...captured.length > 0 ? { captured } : {},
|
|
3987
|
+
...networkCalls.length > 0 ? { networkCalls } : {},
|
|
3988
|
+
duration: Date.now() - startTime
|
|
3989
|
+
};
|
|
3990
|
+
}
|
|
3991
|
+
);
|
|
3992
|
+
} catch (error) {
|
|
3993
|
+
return {
|
|
3994
|
+
success: false,
|
|
3995
|
+
duration: Date.now() - startTime,
|
|
3996
|
+
error: getErrorMessage(error)
|
|
3997
|
+
};
|
|
3998
|
+
} finally {
|
|
3999
|
+
await prepared.cleanup();
|
|
3851
4000
|
}
|
|
3852
4001
|
}
|
|
3853
|
-
async function
|
|
4002
|
+
async function simulateTransformer(configPath, event, options) {
|
|
3854
4003
|
const startTime = Date.now();
|
|
4004
|
+
const parsed = schemas3.PartialEventSchema.safeParse(event);
|
|
4005
|
+
if (!parsed.success) {
|
|
4006
|
+
return {
|
|
4007
|
+
success: false,
|
|
4008
|
+
duration: 0,
|
|
4009
|
+
error: parsed.error.message
|
|
4010
|
+
};
|
|
4011
|
+
}
|
|
4012
|
+
const prepared = await prepareFlow({
|
|
4013
|
+
configPath,
|
|
4014
|
+
flow: options.flow,
|
|
4015
|
+
simulate: ["transformer." + options.transformerId],
|
|
4016
|
+
mock: options.mock,
|
|
4017
|
+
silent: options.silent,
|
|
4018
|
+
verbose: options.verbose
|
|
4019
|
+
});
|
|
3855
4020
|
try {
|
|
3856
|
-
const
|
|
3857
|
-
|
|
3858
|
-
|
|
3859
|
-
runScripts: "dangerously",
|
|
3860
|
-
resources: "usable",
|
|
3861
|
-
virtualConsole
|
|
4021
|
+
const logger = createCLILogger({
|
|
4022
|
+
silent: options.silent,
|
|
4023
|
+
verbose: options.verbose
|
|
3862
4024
|
});
|
|
3863
|
-
|
|
3864
|
-
|
|
3865
|
-
|
|
3866
|
-
|
|
3867
|
-
|
|
3868
|
-
|
|
3869
|
-
|
|
3870
|
-
|
|
3871
|
-
|
|
4025
|
+
let snapshotCode;
|
|
4026
|
+
if (options.snapshot) {
|
|
4027
|
+
snapshotCode = await loadConfig(options.snapshot, {
|
|
4028
|
+
json: false
|
|
4029
|
+
});
|
|
4030
|
+
logger.debug(`Snapshot loaded (${snapshotCode.length} bytes)`);
|
|
4031
|
+
}
|
|
4032
|
+
const networkCalls = [];
|
|
4033
|
+
return await withFlowContext(
|
|
4034
|
+
{
|
|
4035
|
+
esmPath: prepared.bundlePath,
|
|
4036
|
+
platform: prepared.platform,
|
|
4037
|
+
logger,
|
|
4038
|
+
snapshotCode,
|
|
4039
|
+
networkCalls
|
|
4040
|
+
},
|
|
4041
|
+
async (module) => {
|
|
4042
|
+
const config = module.wireConfig(module.__configData ?? void 0);
|
|
4043
|
+
applyOverrides(config, prepared.overrides);
|
|
4044
|
+
if (config.sources) config.sources = {};
|
|
4045
|
+
if (config.destinations) config.destinations = {};
|
|
4046
|
+
const result = await module.startFlow(config);
|
|
4047
|
+
if (!result?.collector)
|
|
4048
|
+
throw new Error("Invalid bundle: collector not available");
|
|
4049
|
+
const collector = result.collector;
|
|
4050
|
+
const transformer = collector.transformers?.[options.transformerId];
|
|
4051
|
+
if (!transformer) {
|
|
4052
|
+
throw new Error(
|
|
4053
|
+
`Transformer "${options.transformerId}" not found in collector. Available: ${Object.keys(collector.transformers || {}).join(", ") || "none"}`
|
|
4054
|
+
);
|
|
4055
|
+
}
|
|
4056
|
+
const initialized = await ee(
|
|
4057
|
+
collector,
|
|
4058
|
+
transformer,
|
|
4059
|
+
options.transformerId
|
|
4060
|
+
);
|
|
4061
|
+
if (!initialized) {
|
|
4062
|
+
throw new Error(
|
|
4063
|
+
`Transformer "${options.transformerId}" failed to initialize`
|
|
4064
|
+
);
|
|
4065
|
+
}
|
|
4066
|
+
const inputEvent = event;
|
|
4067
|
+
const ingest = createIngest(options.transformerId);
|
|
4068
|
+
const captured = [];
|
|
4069
|
+
captured.push({ event: { ...inputEvent }, timestamp: Date.now() });
|
|
4070
|
+
logger.info(`Simulating transformer: ${options.transformerId}`);
|
|
4071
|
+
let processedEvent = inputEvent;
|
|
4072
|
+
const before = transformer.config.before;
|
|
4073
|
+
if (before && collector.transformers) {
|
|
4074
|
+
const beforeChainIds = resolveBeforeChain(
|
|
4075
|
+
before,
|
|
4076
|
+
collector.transformers,
|
|
4077
|
+
ingest,
|
|
4078
|
+
processedEvent
|
|
4079
|
+
);
|
|
4080
|
+
if (beforeChainIds.length > 0) {
|
|
4081
|
+
const beforeResult = await te(
|
|
4082
|
+
collector,
|
|
4083
|
+
collector.transformers,
|
|
4084
|
+
beforeChainIds,
|
|
4085
|
+
processedEvent,
|
|
4086
|
+
ingest,
|
|
4087
|
+
void 0,
|
|
4088
|
+
`transformer.${options.transformerId}.before`
|
|
4089
|
+
);
|
|
4090
|
+
if (beforeResult === null) {
|
|
4091
|
+
captured.push({ event: null, timestamp: Date.now() });
|
|
4092
|
+
await collector.command("shutdown");
|
|
4093
|
+
return {
|
|
4094
|
+
success: true,
|
|
4095
|
+
captured,
|
|
4096
|
+
duration: Date.now() - startTime
|
|
4097
|
+
};
|
|
4098
|
+
}
|
|
4099
|
+
processedEvent = Array.isArray(beforeResult) ? beforeResult[0] : beforeResult;
|
|
4100
|
+
}
|
|
4101
|
+
}
|
|
4102
|
+
const pushResult = await ne(
|
|
4103
|
+
collector,
|
|
4104
|
+
transformer,
|
|
4105
|
+
options.transformerId,
|
|
4106
|
+
processedEvent,
|
|
4107
|
+
ingest
|
|
4108
|
+
);
|
|
4109
|
+
if (pushResult === false) {
|
|
4110
|
+
captured.push({ event: null, timestamp: Date.now() });
|
|
4111
|
+
} else if (Array.isArray(pushResult)) {
|
|
4112
|
+
for (const r2 of pushResult) {
|
|
4113
|
+
captured.push({
|
|
4114
|
+
event: r2.event || processedEvent,
|
|
4115
|
+
timestamp: Date.now()
|
|
4116
|
+
});
|
|
4117
|
+
}
|
|
4118
|
+
} else if (pushResult && typeof pushResult === "object" && pushResult.event) {
|
|
4119
|
+
captured.push({ event: pushResult.event, timestamp: Date.now() });
|
|
4120
|
+
} else {
|
|
4121
|
+
captured.push({ event: processedEvent, timestamp: Date.now() });
|
|
4122
|
+
}
|
|
4123
|
+
await collector.command("shutdown");
|
|
4124
|
+
return {
|
|
4125
|
+
success: true,
|
|
4126
|
+
captured,
|
|
4127
|
+
...networkCalls.length > 0 ? { networkCalls } : {},
|
|
4128
|
+
duration: Date.now() - startTime
|
|
4129
|
+
};
|
|
4130
|
+
}
|
|
3872
4131
|
);
|
|
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
4132
|
} catch (error) {
|
|
3886
4133
|
return {
|
|
3887
4134
|
success: false,
|
|
3888
4135
|
duration: Date.now() - startTime,
|
|
3889
4136
|
error: getErrorMessage(error)
|
|
3890
4137
|
};
|
|
4138
|
+
} finally {
|
|
4139
|
+
await prepared.cleanup();
|
|
3891
4140
|
}
|
|
3892
4141
|
}
|
|
3893
|
-
async function
|
|
4142
|
+
async function simulateDestination(configPath, event, options) {
|
|
3894
4143
|
const startTime = Date.now();
|
|
3895
|
-
|
|
4144
|
+
const parsed = schemas3.PartialEventSchema.safeParse(event);
|
|
4145
|
+
if (!parsed.success) {
|
|
4146
|
+
return {
|
|
4147
|
+
success: false,
|
|
4148
|
+
duration: 0,
|
|
4149
|
+
error: parsed.error.message
|
|
4150
|
+
};
|
|
4151
|
+
}
|
|
4152
|
+
const prepared = await prepareFlow({
|
|
4153
|
+
configPath,
|
|
4154
|
+
flow: options.flow,
|
|
4155
|
+
simulate: ["destination." + options.destinationId],
|
|
4156
|
+
mock: options.mock,
|
|
4157
|
+
silent: options.silent,
|
|
4158
|
+
verbose: options.verbose
|
|
4159
|
+
});
|
|
3896
4160
|
try {
|
|
3897
|
-
const
|
|
3898
|
-
|
|
3899
|
-
|
|
3900
|
-
timeout
|
|
3901
|
-
);
|
|
4161
|
+
const logger = createCLILogger({
|
|
4162
|
+
silent: options.silent,
|
|
4163
|
+
verbose: options.verbose
|
|
3902
4164
|
});
|
|
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
|
|
4165
|
+
let snapshotCode;
|
|
4166
|
+
if (options.snapshot) {
|
|
4167
|
+
snapshotCode = await loadConfig(options.snapshot, {
|
|
4168
|
+
json: false
|
|
3921
4169
|
});
|
|
3922
|
-
|
|
3923
|
-
|
|
3924
|
-
|
|
3925
|
-
|
|
3926
|
-
|
|
3927
|
-
|
|
3928
|
-
|
|
4170
|
+
}
|
|
4171
|
+
const networkCalls = [];
|
|
4172
|
+
return await withFlowContext(
|
|
4173
|
+
{
|
|
4174
|
+
esmPath: prepared.bundlePath,
|
|
4175
|
+
platform: prepared.platform,
|
|
4176
|
+
logger,
|
|
4177
|
+
snapshotCode,
|
|
4178
|
+
networkCalls
|
|
4179
|
+
},
|
|
4180
|
+
async (module) => {
|
|
4181
|
+
const config = module.wireConfig(module.__configData ?? void 0);
|
|
4182
|
+
applyOverrides(config, prepared.overrides);
|
|
4183
|
+
const destOverride = prepared.overrides.destinations?.[options.destinationId];
|
|
4184
|
+
let trackedCalls = [];
|
|
4185
|
+
if (destOverride?.simulation?.length) {
|
|
4186
|
+
const destinations = config.destinations;
|
|
4187
|
+
const destConfig = destinations[options.destinationId]?.config;
|
|
4188
|
+
if (destConfig?.env) {
|
|
4189
|
+
const combined = {
|
|
4190
|
+
...destConfig.env,
|
|
4191
|
+
simulation: destOverride.simulation
|
|
4192
|
+
};
|
|
4193
|
+
const { wrappedEnv, calls } = Ge(combined);
|
|
4194
|
+
destConfig.env = wrappedEnv;
|
|
4195
|
+
trackedCalls = calls;
|
|
4196
|
+
}
|
|
4197
|
+
}
|
|
4198
|
+
if (config.sources) config.sources = {};
|
|
4199
|
+
const result = await module.startFlow(config);
|
|
4200
|
+
if (!result?.collector)
|
|
4201
|
+
throw new Error("Invalid bundle: collector not available");
|
|
4202
|
+
const collector = result.collector;
|
|
4203
|
+
if (!collector.destinations[options.destinationId] && !collector.pending.destinations[options.destinationId]) {
|
|
4204
|
+
throw new Error(
|
|
4205
|
+
`Destination "${options.destinationId}" not found in collector. Available: ${Object.keys(collector.destinations || {}).join(", ") || "none"}`
|
|
4206
|
+
);
|
|
4207
|
+
}
|
|
4208
|
+
logger.info(`Simulating destination: ${options.destinationId}`);
|
|
4209
|
+
const elbResult = await collector.push(event, {
|
|
4210
|
+
include: [options.destinationId]
|
|
4211
|
+
});
|
|
4212
|
+
await collector.command("shutdown");
|
|
4213
|
+
return {
|
|
4214
|
+
success: true,
|
|
4215
|
+
elbResult,
|
|
4216
|
+
...trackedCalls.length > 0 ? { usage: { [options.destinationId]: trackedCalls } } : {},
|
|
4217
|
+
...networkCalls.length > 0 ? { networkCalls } : {},
|
|
4218
|
+
duration: Date.now() - startTime
|
|
4219
|
+
};
|
|
4220
|
+
}
|
|
4221
|
+
);
|
|
3929
4222
|
} catch (error) {
|
|
3930
4223
|
return {
|
|
3931
4224
|
success: false,
|
|
@@ -3933,35 +4226,17 @@ async function executeServerPush(bundlePath, event, logger, timeout = 6e4, conte
|
|
|
3933
4226
|
error: getErrorMessage(error)
|
|
3934
4227
|
};
|
|
3935
4228
|
} finally {
|
|
3936
|
-
|
|
4229
|
+
await prepared.cleanup();
|
|
3937
4230
|
}
|
|
3938
4231
|
}
|
|
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
4232
|
|
|
3959
4233
|
// src/commands/run/index.ts
|
|
3960
4234
|
init_cli_logger();
|
|
3961
4235
|
init_core();
|
|
4236
|
+
init_tmp();
|
|
3962
4237
|
init_config_file();
|
|
3963
4238
|
init_auth();
|
|
3964
|
-
import
|
|
4239
|
+
import path18 from "path";
|
|
3965
4240
|
import { writeFileSync as writeFileSync5 } from "fs";
|
|
3966
4241
|
import { homedir as homedir2 } from "os";
|
|
3967
4242
|
import { join as join4 } from "path";
|
|
@@ -4009,12 +4284,12 @@ async function resolveBundle(bundleEnv) {
|
|
|
4009
4284
|
return { path: bundleEnv, source: "file" };
|
|
4010
4285
|
}
|
|
4011
4286
|
if (isUrl2(bundleEnv)) {
|
|
4012
|
-
const
|
|
4013
|
-
return { path:
|
|
4287
|
+
const path19 = await fetchBundle(bundleEnv, writePath);
|
|
4288
|
+
return { path: path19, source: "url" };
|
|
4014
4289
|
}
|
|
4015
4290
|
if (isStdinPiped()) {
|
|
4016
|
-
const
|
|
4017
|
-
return { path:
|
|
4291
|
+
const path19 = await readBundleFromStdin(writePath);
|
|
4292
|
+
return { path: path19, source: "stdin" };
|
|
4018
4293
|
}
|
|
4019
4294
|
return { path: bundleEnv, source: "file" };
|
|
4020
4295
|
}
|
|
@@ -4178,12 +4453,14 @@ function validatePort(port) {
|
|
|
4178
4453
|
init_utils3();
|
|
4179
4454
|
|
|
4180
4455
|
// src/commands/run/pipeline.ts
|
|
4456
|
+
init_tmp();
|
|
4181
4457
|
import { writeFileSync as writeFileSync4 } from "fs";
|
|
4458
|
+
import fs17 from "fs-extra";
|
|
4182
4459
|
|
|
4183
4460
|
// src/runtime/health-server.ts
|
|
4184
4461
|
import http from "http";
|
|
4185
4462
|
function createHealthServer(port, logger) {
|
|
4186
|
-
return new Promise((
|
|
4463
|
+
return new Promise((resolve3, reject) => {
|
|
4187
4464
|
let flowHandler = null;
|
|
4188
4465
|
const server = http.createServer((req, res) => {
|
|
4189
4466
|
if (req.url === "/health" && req.method === "GET") {
|
|
@@ -4210,7 +4487,7 @@ function createHealthServer(port, logger) {
|
|
|
4210
4487
|
server.headersTimeout = 1e4;
|
|
4211
4488
|
server.listen(port, "0.0.0.0", () => {
|
|
4212
4489
|
logger.info(`Health server listening on port ${port}`);
|
|
4213
|
-
|
|
4490
|
+
resolve3({
|
|
4214
4491
|
server,
|
|
4215
4492
|
setFlowHandler(handler) {
|
|
4216
4493
|
flowHandler = handler;
|
|
@@ -4225,28 +4502,45 @@ function createHealthServer(port, logger) {
|
|
|
4225
4502
|
}
|
|
4226
4503
|
|
|
4227
4504
|
// src/runtime/runner.ts
|
|
4228
|
-
import {
|
|
4229
|
-
|
|
4230
|
-
|
|
4505
|
+
import { resolve as resolve2, dirname as dirname2 } from "path";
|
|
4506
|
+
|
|
4507
|
+
// src/runtime/load-bundle.ts
|
|
4508
|
+
import { resolve } from "path";
|
|
4509
|
+
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
4510
|
+
async function loadBundle(file, context, logger) {
|
|
4231
4511
|
const absolutePath = resolve(file);
|
|
4232
|
-
const
|
|
4233
|
-
|
|
4234
|
-
const fileUrl = pathToFileURL(absolutePath).href;
|
|
4512
|
+
const fileUrl = pathToFileURL2(absolutePath).href;
|
|
4513
|
+
logger?.debug?.(`Importing bundle: ${absolutePath}`);
|
|
4235
4514
|
const module = await import(`${fileUrl}?t=${Date.now()}`);
|
|
4236
4515
|
if (!module.default || typeof module.default !== "function") {
|
|
4237
4516
|
throw new Error(
|
|
4238
|
-
`Invalid
|
|
4517
|
+
`Invalid bundle: ${file} must export a default factory function`
|
|
4239
4518
|
);
|
|
4240
4519
|
}
|
|
4520
|
+
logger?.debug?.("Calling factory function...");
|
|
4521
|
+
const result = await module.default(context ?? {});
|
|
4522
|
+
if (!result || !result.collector || typeof result.collector.push !== "function") {
|
|
4523
|
+
throw new Error(
|
|
4524
|
+
`Invalid bundle: factory must return { collector } with a push function`
|
|
4525
|
+
);
|
|
4526
|
+
}
|
|
4527
|
+
return {
|
|
4528
|
+
collector: result.collector,
|
|
4529
|
+
...typeof result.httpHandler === "function" ? { httpHandler: result.httpHandler } : {}
|
|
4530
|
+
};
|
|
4531
|
+
}
|
|
4532
|
+
|
|
4533
|
+
// src/runtime/runner.ts
|
|
4534
|
+
async function loadFlow(file, config, logger, loggerConfig, healthServer) {
|
|
4535
|
+
const absolutePath = resolve2(file);
|
|
4536
|
+
const flowDir = dirname2(absolutePath);
|
|
4537
|
+
process.chdir(flowDir);
|
|
4241
4538
|
const flowContext = {
|
|
4242
4539
|
...config,
|
|
4243
4540
|
...loggerConfig ? { logger: loggerConfig } : {},
|
|
4244
|
-
...healthServer ? {
|
|
4541
|
+
...healthServer ? { sourceSettings: { port: void 0 } } : {}
|
|
4245
4542
|
};
|
|
4246
|
-
const result = await
|
|
4247
|
-
if (!result || !result.collector) {
|
|
4248
|
-
throw new Error(`Invalid flow bundle: ${file} must return { collector }`);
|
|
4249
|
-
}
|
|
4543
|
+
const result = await loadBundle(absolutePath, flowContext, logger);
|
|
4250
4544
|
if (healthServer && typeof result.httpHandler === "function") {
|
|
4251
4545
|
healthServer.setFlowHandler(result.httpHandler);
|
|
4252
4546
|
}
|
|
@@ -4512,6 +4806,8 @@ async function runPipeline(options) {
|
|
|
4512
4806
|
logger.info(`Port: ${port}`);
|
|
4513
4807
|
let heartbeat = null;
|
|
4514
4808
|
let poller = null;
|
|
4809
|
+
let currentBundleCleanup;
|
|
4810
|
+
let currentConfigPath;
|
|
4515
4811
|
if (api) {
|
|
4516
4812
|
heartbeat = createHeartbeat(
|
|
4517
4813
|
{
|
|
@@ -4546,28 +4842,44 @@ async function runPipeline(options) {
|
|
|
4546
4842
|
);
|
|
4547
4843
|
return;
|
|
4548
4844
|
}
|
|
4549
|
-
const tmpConfigPath =
|
|
4845
|
+
const tmpConfigPath = getTmpPath(
|
|
4846
|
+
void 0,
|
|
4847
|
+
`walkeros-flow-${Date.now()}.json`
|
|
4848
|
+
);
|
|
4550
4849
|
writeFileSync4(
|
|
4551
4850
|
tmpConfigPath,
|
|
4552
4851
|
JSON.stringify(content, null, 2),
|
|
4553
4852
|
"utf-8"
|
|
4554
4853
|
);
|
|
4555
|
-
const
|
|
4854
|
+
const newBundleResult = await api.prepareBundleForRun(tmpConfigPath, {
|
|
4556
4855
|
verbose: false,
|
|
4557
4856
|
silent: true,
|
|
4558
4857
|
flowName: api.flowName
|
|
4559
4858
|
});
|
|
4560
4859
|
handle = await swapFlow(
|
|
4561
4860
|
handle,
|
|
4562
|
-
|
|
4861
|
+
newBundleResult.bundlePath,
|
|
4563
4862
|
runtimeConfig,
|
|
4564
4863
|
logger,
|
|
4565
4864
|
loggerConfig,
|
|
4566
4865
|
healthServer
|
|
4567
4866
|
);
|
|
4568
|
-
writeCache(
|
|
4867
|
+
writeCache(
|
|
4868
|
+
api.cacheDir,
|
|
4869
|
+
newBundleResult.bundlePath,
|
|
4870
|
+
JSON.stringify(content),
|
|
4871
|
+
version
|
|
4872
|
+
);
|
|
4569
4873
|
configVersion = version;
|
|
4570
4874
|
if (heartbeat) heartbeat.updateConfigVersion(version);
|
|
4875
|
+
if (currentBundleCleanup)
|
|
4876
|
+
await currentBundleCleanup().catch(() => {
|
|
4877
|
+
});
|
|
4878
|
+
if (currentConfigPath)
|
|
4879
|
+
await fs17.remove(currentConfigPath).catch(() => {
|
|
4880
|
+
});
|
|
4881
|
+
currentBundleCleanup = newBundleResult.cleanup;
|
|
4882
|
+
currentConfigPath = tmpConfigPath;
|
|
4571
4883
|
logger.info(`Hot-swapped to version ${version}`);
|
|
4572
4884
|
}
|
|
4573
4885
|
},
|
|
@@ -4589,6 +4901,10 @@ async function runPipeline(options) {
|
|
|
4589
4901
|
await handle.collector.command("shutdown");
|
|
4590
4902
|
}
|
|
4591
4903
|
await healthServer.close();
|
|
4904
|
+
if (currentBundleCleanup) await currentBundleCleanup().catch(() => {
|
|
4905
|
+
});
|
|
4906
|
+
if (currentConfigPath) await fs17.remove(currentConfigPath).catch(() => {
|
|
4907
|
+
});
|
|
4592
4908
|
logger.info("Shutdown complete");
|
|
4593
4909
|
clearTimeout(forceTimer);
|
|
4594
4910
|
process.exit(0);
|
|
@@ -4737,15 +5053,16 @@ async function resolveBundlePath(configInput, apiConfig, logger) {
|
|
|
4737
5053
|
logger.info(`Bundle: ${resolved.path}`);
|
|
4738
5054
|
}
|
|
4739
5055
|
if (isPreBuiltConfig(resolved.path)) {
|
|
4740
|
-
return
|
|
5056
|
+
return path18.resolve(resolved.path);
|
|
4741
5057
|
}
|
|
4742
5058
|
const flowFile = validateFlowFile(resolved.path);
|
|
4743
5059
|
logger.debug("Building flow bundle");
|
|
4744
|
-
|
|
5060
|
+
const result = await lazyPrepareBundleForRun(flowFile, {
|
|
4745
5061
|
verbose: false,
|
|
4746
5062
|
silent: true,
|
|
4747
5063
|
flowName: apiConfig?.flowName
|
|
4748
5064
|
});
|
|
5065
|
+
return result.bundlePath;
|
|
4749
5066
|
}
|
|
4750
5067
|
if (apiConfig) {
|
|
4751
5068
|
logger.info("Fetching config from API...");
|
|
@@ -4757,7 +5074,10 @@ async function resolveBundlePath(configInput, apiConfig, logger) {
|
|
|
4757
5074
|
flowId: apiConfig.flowId
|
|
4758
5075
|
});
|
|
4759
5076
|
if (result.changed) {
|
|
4760
|
-
const tmpConfigPath =
|
|
5077
|
+
const tmpConfigPath = getTmpPath(
|
|
5078
|
+
void 0,
|
|
5079
|
+
`walkeros-flow-${Date.now()}.json`
|
|
5080
|
+
);
|
|
4761
5081
|
writeFileSync5(
|
|
4762
5082
|
tmpConfigPath,
|
|
4763
5083
|
JSON.stringify(result.content, null, 2),
|
|
@@ -4765,7 +5085,7 @@ async function resolveBundlePath(configInput, apiConfig, logger) {
|
|
|
4765
5085
|
);
|
|
4766
5086
|
logger.info(`Config version: ${result.version}`);
|
|
4767
5087
|
logger.info("Building flow...");
|
|
4768
|
-
const
|
|
5088
|
+
const bundleResult = await lazyPrepareBundleForRun(tmpConfigPath, {
|
|
4769
5089
|
verbose: false,
|
|
4770
5090
|
silent: true,
|
|
4771
5091
|
flowName: apiConfig.flowName
|
|
@@ -4774,14 +5094,14 @@ async function resolveBundlePath(configInput, apiConfig, logger) {
|
|
|
4774
5094
|
const { writeCache: writeCache2 } = await Promise.resolve().then(() => (init_cache(), cache_exports));
|
|
4775
5095
|
writeCache2(
|
|
4776
5096
|
apiConfig.cacheDir,
|
|
4777
|
-
bundlePath,
|
|
5097
|
+
bundleResult.bundlePath,
|
|
4778
5098
|
JSON.stringify(result.content),
|
|
4779
5099
|
result.version
|
|
4780
5100
|
);
|
|
4781
5101
|
} catch {
|
|
4782
5102
|
logger.debug("Cache write failed (non-critical)");
|
|
4783
5103
|
}
|
|
4784
|
-
return bundlePath;
|
|
5104
|
+
return bundleResult.bundlePath;
|
|
4785
5105
|
}
|
|
4786
5106
|
} catch (error) {
|
|
4787
5107
|
logger.error(
|
|
@@ -4799,7 +5119,7 @@ async function resolveBundlePath(configInput, apiConfig, logger) {
|
|
|
4799
5119
|
}
|
|
4800
5120
|
const defaultFile = "server-collect.mjs";
|
|
4801
5121
|
logger.debug(`No config specified, using default: ${defaultFile}`);
|
|
4802
|
-
return
|
|
5122
|
+
return path18.resolve(defaultFile);
|
|
4803
5123
|
}
|
|
4804
5124
|
async function run(options) {
|
|
4805
5125
|
const startTime = Date.now();
|
|
@@ -4990,73 +5310,15 @@ function validateEntityActions(obj, prefix, errors) {
|
|
|
4990
5310
|
}
|
|
4991
5311
|
|
|
4992
5312
|
// 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;
|
|
5313
|
+
init_event_validation();
|
|
5314
|
+
function validateEvent2(input) {
|
|
5315
|
+
const result = validateEvent(input, "strict");
|
|
5054
5316
|
return {
|
|
5055
|
-
valid:
|
|
5317
|
+
valid: result.valid,
|
|
5056
5318
|
type: "event",
|
|
5057
|
-
errors,
|
|
5058
|
-
warnings,
|
|
5059
|
-
details
|
|
5319
|
+
errors: result.errors,
|
|
5320
|
+
warnings: result.warnings,
|
|
5321
|
+
details: result.details
|
|
5060
5322
|
};
|
|
5061
5323
|
}
|
|
5062
5324
|
|
|
@@ -5243,10 +5505,10 @@ function buildConnectionGraph(config) {
|
|
|
5243
5505
|
function checkCompatibility(conn, errors, warnings) {
|
|
5244
5506
|
const fromOuts = Object.entries(conn.from.examples).filter(([, ex]) => ex.out !== void 0 && ex.out !== false).map(([name, ex]) => ({ name, value: ex.out }));
|
|
5245
5507
|
const toIns = Object.entries(conn.to.examples).filter(([, ex]) => ex.in !== void 0).map(([name, ex]) => ({ name, value: ex.in }));
|
|
5246
|
-
const
|
|
5508
|
+
const path19 = `${conn.from.type}.${conn.from.name} \u2192 ${conn.to.type}.${conn.to.name}`;
|
|
5247
5509
|
if (fromOuts.length === 0 || toIns.length === 0) {
|
|
5248
5510
|
warnings.push({
|
|
5249
|
-
path:
|
|
5511
|
+
path: path19,
|
|
5250
5512
|
message: "Cannot check compatibility: missing out or in examples",
|
|
5251
5513
|
suggestion: "Add out examples to the source step or in examples to the target step"
|
|
5252
5514
|
});
|
|
@@ -5264,7 +5526,7 @@ function checkCompatibility(conn, errors, warnings) {
|
|
|
5264
5526
|
}
|
|
5265
5527
|
if (!hasMatch) {
|
|
5266
5528
|
errors.push({
|
|
5267
|
-
path:
|
|
5529
|
+
path: path19,
|
|
5268
5530
|
message: "No compatible out/in pair found between connected steps",
|
|
5269
5531
|
code: "INCOMPATIBLE_EXAMPLES"
|
|
5270
5532
|
});
|
|
@@ -5360,13 +5622,13 @@ function validateMapping(input) {
|
|
|
5360
5622
|
import Ajv from "ajv";
|
|
5361
5623
|
import { fetchPackageSchema } from "@walkeros/core";
|
|
5362
5624
|
var SECTIONS = ["destinations", "sources", "transformers"];
|
|
5363
|
-
function resolveEntry(
|
|
5625
|
+
function resolveEntry(path19, flowConfig) {
|
|
5364
5626
|
const flows = flowConfig.flows;
|
|
5365
5627
|
if (!flows || typeof flows !== "object") return "No flows found in config";
|
|
5366
5628
|
const flowName = Object.keys(flows)[0];
|
|
5367
5629
|
const flow = flows[flowName];
|
|
5368
5630
|
if (!flow) return `Flow "${flowName}" is empty`;
|
|
5369
|
-
const parts =
|
|
5631
|
+
const parts = path19.split(".");
|
|
5370
5632
|
if (parts.length === 2) {
|
|
5371
5633
|
const [section, key] = parts;
|
|
5372
5634
|
if (!SECTIONS.includes(section)) {
|
|
@@ -5403,15 +5665,15 @@ function resolveEntry(path15, flowConfig) {
|
|
|
5403
5665
|
}
|
|
5404
5666
|
return { section: matches[0].section, key, entry: matches[0].entry };
|
|
5405
5667
|
}
|
|
5406
|
-
return `Invalid path "${
|
|
5668
|
+
return `Invalid path "${path19}". Use "section.key" or just "key"`;
|
|
5407
5669
|
}
|
|
5408
|
-
async function validateEntry(
|
|
5409
|
-
const resolved = resolveEntry(
|
|
5670
|
+
async function validateEntry(path19, flowConfig) {
|
|
5671
|
+
const resolved = resolveEntry(path19, flowConfig);
|
|
5410
5672
|
if (typeof resolved === "string") {
|
|
5411
5673
|
return {
|
|
5412
5674
|
valid: false,
|
|
5413
5675
|
type: "entry",
|
|
5414
|
-
errors: [{ path:
|
|
5676
|
+
errors: [{ path: path19, message: resolved, code: "ENTRY_VALIDATION" }],
|
|
5415
5677
|
warnings: [],
|
|
5416
5678
|
details: {}
|
|
5417
5679
|
};
|
|
@@ -5442,7 +5704,7 @@ async function validateEntry(path15, flowConfig) {
|
|
|
5442
5704
|
type: "entry",
|
|
5443
5705
|
errors: [
|
|
5444
5706
|
{
|
|
5445
|
-
path:
|
|
5707
|
+
path: path19,
|
|
5446
5708
|
message: error instanceof Error ? error.message : "Unknown error",
|
|
5447
5709
|
code: "ENTRY_VALIDATION"
|
|
5448
5710
|
}
|
|
@@ -5467,10 +5729,10 @@ async function validateEntry(path15, flowConfig) {
|
|
|
5467
5729
|
const validate2 = ajv.compile(settingsSchema);
|
|
5468
5730
|
const isValid = validate2(settings || {});
|
|
5469
5731
|
if (!isValid) {
|
|
5470
|
-
const errors = (validate2.errors || []).map((
|
|
5471
|
-
path:
|
|
5472
|
-
message:
|
|
5473
|
-
code:
|
|
5732
|
+
const errors = (validate2.errors || []).map((e) => ({
|
|
5733
|
+
path: e.instancePath || "/",
|
|
5734
|
+
message: e.message || "Unknown error",
|
|
5735
|
+
code: e.keyword
|
|
5474
5736
|
}));
|
|
5475
5737
|
return {
|
|
5476
5738
|
valid: false,
|
|
@@ -5505,7 +5767,7 @@ async function validate(type, input, options = {}) {
|
|
|
5505
5767
|
case "contract":
|
|
5506
5768
|
return validateContract(resolved);
|
|
5507
5769
|
case "event":
|
|
5508
|
-
return
|
|
5770
|
+
return validateEvent2(resolved);
|
|
5509
5771
|
case "flow":
|
|
5510
5772
|
return validateFlow(resolved, { flow: options.flow });
|
|
5511
5773
|
case "mapping":
|
|
@@ -5790,10 +6052,10 @@ async function deleteProject(options = {}) {
|
|
|
5790
6052
|
throw new Error(error.error?.message || "Failed to delete project");
|
|
5791
6053
|
return data ?? { success: true };
|
|
5792
6054
|
}
|
|
5793
|
-
async function handleResult(
|
|
6055
|
+
async function handleResult(fn, options) {
|
|
5794
6056
|
const logger = createCLILogger(options);
|
|
5795
6057
|
try {
|
|
5796
|
-
const result = await
|
|
6058
|
+
const result = await fn();
|
|
5797
6059
|
await writeResult(JSON.stringify(result, null, 2), options);
|
|
5798
6060
|
} catch (error) {
|
|
5799
6061
|
logger.error(error instanceof Error ? error.message : String(error));
|
|
@@ -5949,10 +6211,10 @@ async function duplicateFlow(options) {
|
|
|
5949
6211
|
if (error) throwApiError(error, "Failed to duplicate flow");
|
|
5950
6212
|
return data;
|
|
5951
6213
|
}
|
|
5952
|
-
async function handleResult2(
|
|
6214
|
+
async function handleResult2(fn, options) {
|
|
5953
6215
|
const logger = createCLILogger(options);
|
|
5954
6216
|
try {
|
|
5955
|
-
const result = await
|
|
6217
|
+
const result = await fn();
|
|
5956
6218
|
await writeResult(JSON.stringify(result, null, 2), options);
|
|
5957
6219
|
} catch (error) {
|
|
5958
6220
|
logger.error(error instanceof Error ? error.message : String(error));
|
|
@@ -6111,8 +6373,8 @@ async function deploy(options) {
|
|
|
6111
6373
|
if (error) {
|
|
6112
6374
|
try {
|
|
6113
6375
|
throwApiError(error, "Failed to start deployment");
|
|
6114
|
-
} catch (
|
|
6115
|
-
if (
|
|
6376
|
+
} catch (e) {
|
|
6377
|
+
if (e instanceof ApiError && e.code === "AMBIGUOUS_CONFIG") {
|
|
6116
6378
|
const names = await getAvailableFlowNames({
|
|
6117
6379
|
flowId: options.flowId,
|
|
6118
6380
|
projectId
|
|
@@ -6123,7 +6385,7 @@ Available: ${names.join(", ")}`,
|
|
|
6123
6385
|
{ code: "AMBIGUOUS_CONFIG" }
|
|
6124
6386
|
);
|
|
6125
6387
|
}
|
|
6126
|
-
throw
|
|
6388
|
+
throw e;
|
|
6127
6389
|
}
|
|
6128
6390
|
}
|
|
6129
6391
|
if (!options.wait) return data;
|
|
@@ -6260,7 +6522,7 @@ async function getDeploymentCommand(flowId, options) {
|
|
|
6260
6522
|
// src/commands/deployments/index.ts
|
|
6261
6523
|
init_auth();
|
|
6262
6524
|
init_http();
|
|
6263
|
-
import { getPlatform as
|
|
6525
|
+
import { getPlatform as getPlatform5 } from "@walkeros/core";
|
|
6264
6526
|
init_cli_logger();
|
|
6265
6527
|
init_output();
|
|
6266
6528
|
init_loader();
|
|
@@ -6316,10 +6578,10 @@ async function deleteDeployment(options) {
|
|
|
6316
6578
|
const data = await response.json().catch(() => null);
|
|
6317
6579
|
return data ?? { success: true };
|
|
6318
6580
|
}
|
|
6319
|
-
async function handleResult3(
|
|
6581
|
+
async function handleResult3(fn, options) {
|
|
6320
6582
|
const logger = createCLILogger(options);
|
|
6321
6583
|
try {
|
|
6322
|
-
const result = await
|
|
6584
|
+
const result = await fn();
|
|
6323
6585
|
await writeResult(JSON.stringify(result, null, 2), options);
|
|
6324
6586
|
} catch (error) {
|
|
6325
6587
|
logger.error(error instanceof Error ? error.message : String(error));
|
|
@@ -6393,7 +6655,7 @@ async function createDeployCommand(config, options) {
|
|
|
6393
6655
|
const result2 = await loadFlowConfig(config, {
|
|
6394
6656
|
flowName: options.flow
|
|
6395
6657
|
});
|
|
6396
|
-
type =
|
|
6658
|
+
type = getPlatform5(result2.flowSettings);
|
|
6397
6659
|
}
|
|
6398
6660
|
const deployment = await createDeployment({
|
|
6399
6661
|
type,
|
|
@@ -6494,14 +6756,14 @@ async function feedbackCommand(text) {
|
|
|
6494
6756
|
}
|
|
6495
6757
|
}
|
|
6496
6758
|
function promptUser(question) {
|
|
6497
|
-
return new Promise((
|
|
6759
|
+
return new Promise((resolve3) => {
|
|
6498
6760
|
const rl = createInterface({
|
|
6499
6761
|
input: process.stdin,
|
|
6500
6762
|
output: process.stderr
|
|
6501
6763
|
});
|
|
6502
6764
|
rl.question(question, (answer) => {
|
|
6503
6765
|
rl.close();
|
|
6504
|
-
|
|
6766
|
+
resolve3(answer);
|
|
6505
6767
|
});
|
|
6506
6768
|
});
|
|
6507
6769
|
}
|
|
@@ -6514,6 +6776,108 @@ init_api_client();
|
|
|
6514
6776
|
init_config_file();
|
|
6515
6777
|
init_sse();
|
|
6516
6778
|
init_utils();
|
|
6779
|
+
|
|
6780
|
+
// src/commands/simulate/example-loader.ts
|
|
6781
|
+
function findExample(config, exampleName, stepTarget) {
|
|
6782
|
+
if (stepTarget) {
|
|
6783
|
+
return findExampleInStep(config, exampleName, stepTarget);
|
|
6784
|
+
}
|
|
6785
|
+
return findExampleAcrossSteps(config, exampleName);
|
|
6786
|
+
}
|
|
6787
|
+
function findExampleInStep(config, exampleName, stepTarget) {
|
|
6788
|
+
const dotIndex = stepTarget.indexOf(".");
|
|
6789
|
+
if (dotIndex === -1) {
|
|
6790
|
+
throw new Error(
|
|
6791
|
+
`Invalid --step format: "${stepTarget}". Expected "type.name" (e.g. "destination.gtag")`
|
|
6792
|
+
);
|
|
6793
|
+
}
|
|
6794
|
+
const type = stepTarget.substring(0, dotIndex);
|
|
6795
|
+
const name = stepTarget.substring(dotIndex + 1);
|
|
6796
|
+
const stepMap = getStepMap(config, type);
|
|
6797
|
+
if (!stepMap) {
|
|
6798
|
+
throw new Error(`No ${type}s found in flow config`);
|
|
6799
|
+
}
|
|
6800
|
+
const step = stepMap[name];
|
|
6801
|
+
if (!step) {
|
|
6802
|
+
const available = Object.keys(stepMap).join(", ");
|
|
6803
|
+
throw new Error(`${type} "${name}" not found. Available: ${available}`);
|
|
6804
|
+
}
|
|
6805
|
+
const examples = step.examples;
|
|
6806
|
+
if (!examples || !examples[exampleName]) {
|
|
6807
|
+
const available = examples ? Object.keys(examples).join(", ") : "none";
|
|
6808
|
+
throw new Error(
|
|
6809
|
+
`Example "${exampleName}" not found in ${type} "${name}". Available: ${available}`
|
|
6810
|
+
);
|
|
6811
|
+
}
|
|
6812
|
+
return {
|
|
6813
|
+
stepType: type,
|
|
6814
|
+
stepName: name,
|
|
6815
|
+
exampleName,
|
|
6816
|
+
example: examples[exampleName]
|
|
6817
|
+
};
|
|
6818
|
+
}
|
|
6819
|
+
function findExampleAcrossSteps(config, exampleName) {
|
|
6820
|
+
const matches = [];
|
|
6821
|
+
const stepTypes = ["source", "transformer", "destination"];
|
|
6822
|
+
for (const type of stepTypes) {
|
|
6823
|
+
const stepMap = getStepMap(config, type);
|
|
6824
|
+
if (!stepMap) continue;
|
|
6825
|
+
for (const [name, step] of Object.entries(stepMap)) {
|
|
6826
|
+
const examples = step.examples;
|
|
6827
|
+
if (examples && examples[exampleName]) {
|
|
6828
|
+
matches.push({
|
|
6829
|
+
stepType: type,
|
|
6830
|
+
stepName: name,
|
|
6831
|
+
exampleName,
|
|
6832
|
+
example: examples[exampleName]
|
|
6833
|
+
});
|
|
6834
|
+
}
|
|
6835
|
+
}
|
|
6836
|
+
}
|
|
6837
|
+
if (matches.length === 0) {
|
|
6838
|
+
throw new Error(`Example "${exampleName}" not found in any step`);
|
|
6839
|
+
}
|
|
6840
|
+
if (matches.length > 1) {
|
|
6841
|
+
const locations = matches.map((m2) => `${m2.stepType}.${m2.stepName}`).join(", ");
|
|
6842
|
+
throw new Error(
|
|
6843
|
+
`Example "${exampleName}" found in multiple steps: ${locations}. Use --step to disambiguate.`
|
|
6844
|
+
);
|
|
6845
|
+
}
|
|
6846
|
+
return matches[0];
|
|
6847
|
+
}
|
|
6848
|
+
function getStepMap(config, type) {
|
|
6849
|
+
switch (type) {
|
|
6850
|
+
case "source":
|
|
6851
|
+
return config.sources;
|
|
6852
|
+
case "transformer":
|
|
6853
|
+
return config.transformers;
|
|
6854
|
+
case "destination":
|
|
6855
|
+
return config.destinations;
|
|
6856
|
+
default:
|
|
6857
|
+
throw new Error(
|
|
6858
|
+
`Invalid step type: "${type}". Must be "source", "transformer", or "destination"`
|
|
6859
|
+
);
|
|
6860
|
+
}
|
|
6861
|
+
}
|
|
6862
|
+
|
|
6863
|
+
// src/commands/simulate/compare.ts
|
|
6864
|
+
function compareOutput(expected, actual) {
|
|
6865
|
+
const expectedStr = JSON.stringify(expected, null, 2);
|
|
6866
|
+
const actualStr = JSON.stringify(actual, null, 2);
|
|
6867
|
+
if (expectedStr === actualStr) {
|
|
6868
|
+
return { expected, actual, match: true };
|
|
6869
|
+
}
|
|
6870
|
+
return {
|
|
6871
|
+
expected,
|
|
6872
|
+
actual,
|
|
6873
|
+
match: false,
|
|
6874
|
+
diff: `Expected:
|
|
6875
|
+
${expectedStr}
|
|
6876
|
+
|
|
6877
|
+
Actual:
|
|
6878
|
+
${actualStr}`
|
|
6879
|
+
};
|
|
6880
|
+
}
|
|
6517
6881
|
export {
|
|
6518
6882
|
ApiError,
|
|
6519
6883
|
apiFetch,
|
|
@@ -6559,6 +6923,7 @@ export {
|
|
|
6559
6923
|
listFlowsCommand,
|
|
6560
6924
|
listProjects,
|
|
6561
6925
|
listProjectsCommand,
|
|
6926
|
+
loadConfig,
|
|
6562
6927
|
loadJsonConfig,
|
|
6563
6928
|
loginCommand,
|
|
6564
6929
|
logoutCommand,
|
|
@@ -6571,8 +6936,9 @@ export {
|
|
|
6571
6936
|
requireProjectId,
|
|
6572
6937
|
run,
|
|
6573
6938
|
runCommand,
|
|
6574
|
-
|
|
6575
|
-
|
|
6939
|
+
simulateDestination,
|
|
6940
|
+
simulateSource,
|
|
6941
|
+
simulateTransformer,
|
|
6576
6942
|
throwApiError,
|
|
6577
6943
|
updateFlow,
|
|
6578
6944
|
updateFlowCommand,
|