@walkeros/cli 4.0.0-next-1777882869103 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +30 -5
- package/dist/cli.js +248 -138
- package/dist/index.d.ts +10 -1
- package/dist/index.js +228 -116
- package/dist/index.js.map +1 -1
- package/package.json +7 -7
- package/src/telemetry/flow.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3401,7 +3401,51 @@ function installTimerInterception(options = {}) {
|
|
|
3401
3401
|
}
|
|
3402
3402
|
pending.clear();
|
|
3403
3403
|
}
|
|
3404
|
-
return { flush, countPending, restore };
|
|
3404
|
+
return { flush, countPending, restore, pending };
|
|
3405
|
+
}
|
|
3406
|
+
|
|
3407
|
+
// src/commands/push/async-drain-pump.ts
|
|
3408
|
+
var realSetImmediate = setImmediate;
|
|
3409
|
+
var DEFAULT_MAX_ITERATIONS = 1e3;
|
|
3410
|
+
var DEFAULT_MAX_WALL_MS = 3e4;
|
|
3411
|
+
var intervalRequeueCounter = -1;
|
|
3412
|
+
function startDrainPump(pending, options = {}) {
|
|
3413
|
+
const maxIterations = options.maxIterations ?? DEFAULT_MAX_ITERATIONS;
|
|
3414
|
+
const maxWallMs = options.maxWallMs ?? DEFAULT_MAX_WALL_MS;
|
|
3415
|
+
const start = Date.now();
|
|
3416
|
+
let running = true;
|
|
3417
|
+
let iterations = 0;
|
|
3418
|
+
const tick = () => {
|
|
3419
|
+
if (!running) return;
|
|
3420
|
+
if (iterations >= maxIterations) return;
|
|
3421
|
+
if (Date.now() - start > maxWallMs) return;
|
|
3422
|
+
if (pending.size === 0) {
|
|
3423
|
+
realSetImmediate(tick);
|
|
3424
|
+
return;
|
|
3425
|
+
}
|
|
3426
|
+
iterations += 1;
|
|
3427
|
+
const snapshot = [...pending.values()].filter((t) => !t.cleared).sort((a, b) => a.delay - b.delay);
|
|
3428
|
+
for (const timer of snapshot) {
|
|
3429
|
+
pending.delete(timer.id);
|
|
3430
|
+
try {
|
|
3431
|
+
timer.callback(...timer.args);
|
|
3432
|
+
} catch (err) {
|
|
3433
|
+
console.warn(`[async-drain] timer ${timer.id} threw during pump:`, err);
|
|
3434
|
+
}
|
|
3435
|
+
if (timer.type === "interval" && !timer.cleared) {
|
|
3436
|
+
const requeued = {
|
|
3437
|
+
...timer,
|
|
3438
|
+
id: intervalRequeueCounter--
|
|
3439
|
+
};
|
|
3440
|
+
pending.set(requeued.id, requeued);
|
|
3441
|
+
}
|
|
3442
|
+
}
|
|
3443
|
+
realSetImmediate(tick);
|
|
3444
|
+
};
|
|
3445
|
+
realSetImmediate(tick);
|
|
3446
|
+
return () => {
|
|
3447
|
+
running = false;
|
|
3448
|
+
};
|
|
3405
3449
|
}
|
|
3406
3450
|
|
|
3407
3451
|
// src/commands/push/flow-context.ts
|
|
@@ -3413,7 +3457,8 @@ async function withFlowContext(options, fn) {
|
|
|
3413
3457
|
snapshotCode,
|
|
3414
3458
|
timeout,
|
|
3415
3459
|
networkCalls,
|
|
3416
|
-
asyncDrain
|
|
3460
|
+
asyncDrain,
|
|
3461
|
+
drainPump
|
|
3417
3462
|
} = options;
|
|
3418
3463
|
const startTime = Date.now();
|
|
3419
3464
|
const g = global;
|
|
@@ -3476,7 +3521,13 @@ async function withFlowContext(options, fn) {
|
|
|
3476
3521
|
__devExports: module.__devExports
|
|
3477
3522
|
};
|
|
3478
3523
|
if (timerControl) {
|
|
3479
|
-
const
|
|
3524
|
+
const stopPump = drainPump ? startDrainPump(timerControl.pending) : null;
|
|
3525
|
+
let result;
|
|
3526
|
+
try {
|
|
3527
|
+
result = await fn(flowModule);
|
|
3528
|
+
} finally {
|
|
3529
|
+
if (stopPump) stopPump();
|
|
3530
|
+
}
|
|
3480
3531
|
await timerControl.flush(asyncDrain?.timeout ?? 5e3);
|
|
3481
3532
|
return result;
|
|
3482
3533
|
} else if (timeout) {
|
|
@@ -3620,6 +3671,145 @@ async function prepareFlow(input) {
|
|
|
3620
3671
|
|
|
3621
3672
|
// src/commands/push/index.ts
|
|
3622
3673
|
import { schemas as schemas3 } from "@walkeros/core/dev";
|
|
3674
|
+
|
|
3675
|
+
// src/commands/push/plan-simulate.ts
|
|
3676
|
+
function planSimulate(flags) {
|
|
3677
|
+
if (flags.length === 0) return { kind: "none", ids: [] };
|
|
3678
|
+
const parsed = flags.map((flag) => {
|
|
3679
|
+
const step = parseStep(flag);
|
|
3680
|
+
if (step.chainType) {
|
|
3681
|
+
throw new Error(
|
|
3682
|
+
`--simulate "${flag}": chain syntax (${step.type}.${step.name}.${step.chainType}.\u2026) is not supported for --simulate. Use --mock for path-specific overrides.`
|
|
3683
|
+
);
|
|
3684
|
+
}
|
|
3685
|
+
return step;
|
|
3686
|
+
});
|
|
3687
|
+
const types = new Set(parsed.map((p) => p.type));
|
|
3688
|
+
if (types.size > 1) {
|
|
3689
|
+
const sorted = [...types].sort();
|
|
3690
|
+
throw new Error(
|
|
3691
|
+
`Cannot --simulate ${sorted.join(" and ")} in the same invocation. Run separate commands for each step type.`
|
|
3692
|
+
);
|
|
3693
|
+
}
|
|
3694
|
+
const [type] = types;
|
|
3695
|
+
const ids = [...new Set(parsed.map((p) => p.name))];
|
|
3696
|
+
if ((type === "source" || type === "transformer") && ids.length > 1) {
|
|
3697
|
+
throw new Error(
|
|
3698
|
+
`--simulate ${type}.* expects a single target; got ${ids.length}. Run one --simulate ${type}.NAME per invocation.`
|
|
3699
|
+
);
|
|
3700
|
+
}
|
|
3701
|
+
return { kind: type, ids };
|
|
3702
|
+
}
|
|
3703
|
+
|
|
3704
|
+
// src/commands/push/dispatch-simulate.ts
|
|
3705
|
+
function dispatchSimulate(flags) {
|
|
3706
|
+
const plan = planSimulate(flags);
|
|
3707
|
+
return { route: plan.kind, ids: plan.ids };
|
|
3708
|
+
}
|
|
3709
|
+
|
|
3710
|
+
// src/commands/push/run.ts
|
|
3711
|
+
init_core();
|
|
3712
|
+
init_config();
|
|
3713
|
+
async function runPushCommand(options) {
|
|
3714
|
+
const startTime = Date.now();
|
|
3715
|
+
try {
|
|
3716
|
+
const plan = dispatchSimulate(options.simulate ?? []);
|
|
3717
|
+
let config;
|
|
3718
|
+
if (isStdinPiped() && !options.config) {
|
|
3719
|
+
config = await readStdinToTempFile("push");
|
|
3720
|
+
} else {
|
|
3721
|
+
config = options.config || "bundle.config.json";
|
|
3722
|
+
}
|
|
3723
|
+
let resolvedEvent = options.event;
|
|
3724
|
+
if (typeof options.event === "string") {
|
|
3725
|
+
resolvedEvent = await loadJsonFromSource(options.event, {
|
|
3726
|
+
name: "event"
|
|
3727
|
+
});
|
|
3728
|
+
}
|
|
3729
|
+
let result;
|
|
3730
|
+
switch (plan.route) {
|
|
3731
|
+
case "none":
|
|
3732
|
+
result = await push(config, resolvedEvent, {
|
|
3733
|
+
flow: options.flow,
|
|
3734
|
+
json: options.json,
|
|
3735
|
+
verbose: options.verbose,
|
|
3736
|
+
silent: options.silent,
|
|
3737
|
+
platform: options.platform,
|
|
3738
|
+
mock: options.mock,
|
|
3739
|
+
snapshot: options.snapshot
|
|
3740
|
+
});
|
|
3741
|
+
break;
|
|
3742
|
+
case "source":
|
|
3743
|
+
result = await simulateSource(config, resolvedEvent, {
|
|
3744
|
+
sourceId: plan.ids[0],
|
|
3745
|
+
flow: options.flow,
|
|
3746
|
+
silent: options.silent,
|
|
3747
|
+
verbose: options.verbose,
|
|
3748
|
+
snapshot: options.snapshot
|
|
3749
|
+
});
|
|
3750
|
+
break;
|
|
3751
|
+
case "transformer":
|
|
3752
|
+
result = await simulateTransformer(
|
|
3753
|
+
config,
|
|
3754
|
+
resolvedEvent,
|
|
3755
|
+
{
|
|
3756
|
+
transformerId: plan.ids[0],
|
|
3757
|
+
flow: options.flow,
|
|
3758
|
+
mock: options.mock,
|
|
3759
|
+
silent: options.silent,
|
|
3760
|
+
verbose: options.verbose,
|
|
3761
|
+
snapshot: options.snapshot
|
|
3762
|
+
}
|
|
3763
|
+
);
|
|
3764
|
+
break;
|
|
3765
|
+
case "destination":
|
|
3766
|
+
result = await runDestinationSimulationLoop(
|
|
3767
|
+
config,
|
|
3768
|
+
resolvedEvent,
|
|
3769
|
+
plan.ids,
|
|
3770
|
+
options
|
|
3771
|
+
);
|
|
3772
|
+
break;
|
|
3773
|
+
}
|
|
3774
|
+
return result;
|
|
3775
|
+
} catch (error) {
|
|
3776
|
+
return {
|
|
3777
|
+
success: false,
|
|
3778
|
+
duration: Date.now() - startTime,
|
|
3779
|
+
error: getErrorMessage(error)
|
|
3780
|
+
};
|
|
3781
|
+
}
|
|
3782
|
+
}
|
|
3783
|
+
async function runDestinationSimulationLoop(config, event, destinationIds, options) {
|
|
3784
|
+
const startTime = Date.now();
|
|
3785
|
+
const perDestination = {};
|
|
3786
|
+
for (const destinationId of destinationIds) {
|
|
3787
|
+
const r = await simulateDestination(config, event, {
|
|
3788
|
+
destinationId,
|
|
3789
|
+
flow: options.flow,
|
|
3790
|
+
mock: options.mock,
|
|
3791
|
+
silent: options.silent,
|
|
3792
|
+
verbose: options.verbose,
|
|
3793
|
+
snapshot: options.snapshot
|
|
3794
|
+
});
|
|
3795
|
+
perDestination[destinationId] = r;
|
|
3796
|
+
if (!r.success) {
|
|
3797
|
+
return {
|
|
3798
|
+
success: false,
|
|
3799
|
+
duration: Date.now() - startTime,
|
|
3800
|
+
error: `simulate destination.${destinationId}: ${r.error ?? "unknown error"}`,
|
|
3801
|
+
perDestination
|
|
3802
|
+
};
|
|
3803
|
+
}
|
|
3804
|
+
}
|
|
3805
|
+
return {
|
|
3806
|
+
success: true,
|
|
3807
|
+
duration: Date.now() - startTime,
|
|
3808
|
+
perDestination
|
|
3809
|
+
};
|
|
3810
|
+
}
|
|
3811
|
+
|
|
3812
|
+
// src/commands/push/index.ts
|
|
3623
3813
|
function resolveBeforeChain(before, transformers, ingest, event) {
|
|
3624
3814
|
if (!before) return [];
|
|
3625
3815
|
const next = before;
|
|
@@ -3698,108 +3888,32 @@ async function pushCore(inputPath, event, options = {}) {
|
|
|
3698
3888
|
}
|
|
3699
3889
|
}
|
|
3700
3890
|
async function pushCommand(options) {
|
|
3701
|
-
const
|
|
3702
|
-
const
|
|
3703
|
-
|
|
3704
|
-
|
|
3705
|
-
|
|
3706
|
-
|
|
3707
|
-
|
|
3708
|
-
|
|
3709
|
-
|
|
3710
|
-
|
|
3711
|
-
|
|
3712
|
-
|
|
3713
|
-
|
|
3714
|
-
|
|
3715
|
-
|
|
3716
|
-
|
|
3717
|
-
|
|
3718
|
-
if (simulateFlag?.startsWith("source.")) {
|
|
3719
|
-
result = await simulateSource(config, resolvedEvent, {
|
|
3720
|
-
sourceId: simulateFlag.replace("source.", ""),
|
|
3721
|
-
flow: options.flow,
|
|
3722
|
-
silent: options.silent,
|
|
3723
|
-
verbose: options.verbose,
|
|
3724
|
-
snapshot: options.snapshot
|
|
3725
|
-
});
|
|
3726
|
-
} else if (simulateFlag?.startsWith("transformer.")) {
|
|
3727
|
-
result = await simulateTransformer(
|
|
3728
|
-
config,
|
|
3729
|
-
resolvedEvent,
|
|
3730
|
-
{
|
|
3731
|
-
transformerId: simulateFlag.replace("transformer.", ""),
|
|
3732
|
-
flow: options.flow,
|
|
3733
|
-
mock: options.mock,
|
|
3734
|
-
silent: options.silent,
|
|
3735
|
-
verbose: options.verbose,
|
|
3736
|
-
snapshot: options.snapshot
|
|
3737
|
-
}
|
|
3738
|
-
);
|
|
3739
|
-
} else if (simulateFlag?.startsWith("destination.")) {
|
|
3740
|
-
result = await simulateDestination(
|
|
3741
|
-
config,
|
|
3742
|
-
resolvedEvent,
|
|
3743
|
-
{
|
|
3744
|
-
destinationId: simulateFlag.replace("destination.", ""),
|
|
3745
|
-
flow: options.flow,
|
|
3746
|
-
mock: options.mock,
|
|
3747
|
-
silent: options.silent,
|
|
3748
|
-
verbose: options.verbose,
|
|
3749
|
-
snapshot: options.snapshot
|
|
3750
|
-
}
|
|
3751
|
-
);
|
|
3752
|
-
} else {
|
|
3753
|
-
result = await push(config, resolvedEvent, {
|
|
3754
|
-
flow: options.flow,
|
|
3755
|
-
json: options.json,
|
|
3756
|
-
verbose: options.verbose,
|
|
3757
|
-
silent: options.silent,
|
|
3758
|
-
platform: options.platform,
|
|
3759
|
-
mock: options.mock,
|
|
3760
|
-
snapshot: options.snapshot
|
|
3761
|
-
});
|
|
3762
|
-
}
|
|
3763
|
-
const duration = Date.now() - startTime;
|
|
3764
|
-
let output;
|
|
3765
|
-
if (options.json) {
|
|
3766
|
-
output = JSON.stringify({ ...result, duration }, null, 2);
|
|
3767
|
-
} else {
|
|
3768
|
-
const lines = [];
|
|
3769
|
-
if (result.success) {
|
|
3770
|
-
lines.push("Event pushed successfully");
|
|
3771
|
-
if (result.elbResult && typeof result.elbResult === "object") {
|
|
3772
|
-
const pushResult = result.elbResult;
|
|
3773
|
-
if ("id" in pushResult && pushResult.id)
|
|
3774
|
-
lines.push(` Event ID: ${pushResult.id}`);
|
|
3775
|
-
if ("entity" in pushResult && pushResult.entity)
|
|
3776
|
-
lines.push(` Entity: ${pushResult.entity}`);
|
|
3777
|
-
if ("action" in pushResult && pushResult.action)
|
|
3778
|
-
lines.push(` Action: ${pushResult.action}`);
|
|
3779
|
-
}
|
|
3780
|
-
lines.push(` Duration: ${duration}ms`);
|
|
3781
|
-
} else {
|
|
3782
|
-
lines.push(`Error: ${result.error}`);
|
|
3891
|
+
const result = await runPushCommand(options);
|
|
3892
|
+
const duration = result.duration;
|
|
3893
|
+
let output;
|
|
3894
|
+
if (options.json) {
|
|
3895
|
+
output = JSON.stringify({ ...result, duration }, null, 2);
|
|
3896
|
+
} else {
|
|
3897
|
+
const lines = [];
|
|
3898
|
+
if (result.success) {
|
|
3899
|
+
lines.push("Event pushed successfully");
|
|
3900
|
+
if (result.elbResult && typeof result.elbResult === "object") {
|
|
3901
|
+
const pushResult = result.elbResult;
|
|
3902
|
+
if ("id" in pushResult && pushResult.id)
|
|
3903
|
+
lines.push(` Event ID: ${pushResult.id}`);
|
|
3904
|
+
if ("entity" in pushResult && pushResult.entity)
|
|
3905
|
+
lines.push(` Entity: ${pushResult.entity}`);
|
|
3906
|
+
if ("action" in pushResult && pushResult.action)
|
|
3907
|
+
lines.push(` Action: ${pushResult.action}`);
|
|
3783
3908
|
}
|
|
3784
|
-
|
|
3785
|
-
}
|
|
3786
|
-
await writeResult(output + "\n", { output: options.output });
|
|
3787
|
-
process.exit(result.success ? 0 : 1);
|
|
3788
|
-
} catch (error) {
|
|
3789
|
-
const duration = Date.now() - startTime;
|
|
3790
|
-
const errorMessage = getErrorMessage(error);
|
|
3791
|
-
if (options.json) {
|
|
3792
|
-
const errorOutput = JSON.stringify(
|
|
3793
|
-
{ success: false, error: errorMessage, duration },
|
|
3794
|
-
null,
|
|
3795
|
-
2
|
|
3796
|
-
);
|
|
3797
|
-
await writeResult(errorOutput + "\n", { output: options.output });
|
|
3909
|
+
lines.push(` Duration: ${duration}ms`);
|
|
3798
3910
|
} else {
|
|
3799
|
-
|
|
3911
|
+
lines.push(`Error: ${result.error}`);
|
|
3800
3912
|
}
|
|
3801
|
-
|
|
3913
|
+
output = lines.join("\n");
|
|
3802
3914
|
}
|
|
3915
|
+
await writeResult(output + "\n", { output: options.output });
|
|
3916
|
+
process.exit(result.success ? 0 : 1);
|
|
3803
3917
|
}
|
|
3804
3918
|
async function push(configOrPath, event, options = {}) {
|
|
3805
3919
|
if (typeof configOrPath !== "string") {
|
|
@@ -3898,7 +4012,12 @@ async function executeDestinationPush(esmPath, event, logger, platform, override
|
|
|
3898
4012
|
snapshotCode,
|
|
3899
4013
|
timeout,
|
|
3900
4014
|
networkCalls,
|
|
3901
|
-
asyncDrain: { timeout: 5e3 }
|
|
4015
|
+
asyncDrain: { timeout: 5e3 },
|
|
4016
|
+
// Real push (non-simulate) needs the pump so destinations whose init
|
|
4017
|
+
// awaits a captured setTimeout (e.g., amplitude engagement plugin)
|
|
4018
|
+
// don't deadlock. Simulate routes use their own withFlowContext call
|
|
4019
|
+
// sites without `drainPump`, preserving snapshot ordering.
|
|
4020
|
+
drainPump: true
|
|
3902
4021
|
},
|
|
3903
4022
|
async (module) => {
|
|
3904
4023
|
const config = module.wireConfig(module.__configData ?? void 0);
|
|
@@ -5752,7 +5871,7 @@ function validateMapping(input) {
|
|
|
5752
5871
|
// src/commands/validate/validators/entry.ts
|
|
5753
5872
|
import Ajv from "ajv";
|
|
5754
5873
|
import { fetchPackageSchema } from "@walkeros/core";
|
|
5755
|
-
var CLIENT_HEADER = "walkeros-cli/4.0.0
|
|
5874
|
+
var CLIENT_HEADER = "walkeros-cli/4.0.0";
|
|
5756
5875
|
var SECTIONS = ["destinations", "sources", "transformers"];
|
|
5757
5876
|
function resolveEntry(path19, flowConfig) {
|
|
5758
5877
|
const flows = flowConfig.flows;
|
|
@@ -7525,9 +7644,6 @@ __export(telemetry_exports, {
|
|
|
7525
7644
|
});
|
|
7526
7645
|
|
|
7527
7646
|
// src/telemetry/emitter.ts
|
|
7528
|
-
import { readFileSync as readFileSync4 } from "fs";
|
|
7529
|
-
import { join as join6, dirname as dirname5 } from "path";
|
|
7530
|
-
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
7531
7647
|
import { startFlow } from "@walkeros/collector";
|
|
7532
7648
|
import { destinationAPI } from "@walkeros/server-destination-api";
|
|
7533
7649
|
|
|
@@ -7591,6 +7707,7 @@ function maybePrintFirstRunNotice() {
|
|
|
7591
7707
|
}
|
|
7592
7708
|
|
|
7593
7709
|
// src/telemetry/emitter.ts
|
|
7710
|
+
init_config_file();
|
|
7594
7711
|
var SEND_TIMEOUT_MS = 1e3;
|
|
7595
7712
|
async function createEmitter(opts) {
|
|
7596
7713
|
if (!isTelemetryEnabled()) {
|
|
@@ -7608,7 +7725,7 @@ async function createEmitter(opts) {
|
|
|
7608
7725
|
}
|
|
7609
7726
|
const device = maybeDevice;
|
|
7610
7727
|
const debug = isDebugMode();
|
|
7611
|
-
const endpoint =
|
|
7728
|
+
const endpoint = resolveTelemetryEndpoint();
|
|
7612
7729
|
if (!endpoint && !debug) {
|
|
7613
7730
|
return {
|
|
7614
7731
|
async send() {
|
|
@@ -7683,15 +7800,10 @@ async function createEmitter(opts) {
|
|
|
7683
7800
|
}
|
|
7684
7801
|
};
|
|
7685
7802
|
}
|
|
7686
|
-
function
|
|
7687
|
-
|
|
7688
|
-
|
|
7689
|
-
|
|
7690
|
-
const url = raw.flows?.default?.destinations?.api?.config?.url;
|
|
7691
|
-
if (url && !url.startsWith("$")) return url;
|
|
7692
|
-
} catch {
|
|
7693
|
-
}
|
|
7694
|
-
return void 0;
|
|
7803
|
+
function resolveTelemetryEndpoint() {
|
|
7804
|
+
const appUrl = resolveAppUrl();
|
|
7805
|
+
if (!appUrl) return void 0;
|
|
7806
|
+
return `${appUrl.replace(/\/$/, "")}/api/telemetry`;
|
|
7695
7807
|
}
|
|
7696
7808
|
async function withTimeout2(p, ms) {
|
|
7697
7809
|
return Promise.race([
|