@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/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @walkeros/cli
|
|
2
2
|
|
|
3
|
-
## 4.0.0
|
|
3
|
+
## 4.0.0
|
|
4
4
|
|
|
5
5
|
### Major Changes
|
|
6
6
|
|
|
@@ -232,6 +232,31 @@
|
|
|
232
232
|
|
|
233
233
|
### Patch Changes
|
|
234
234
|
|
|
235
|
+
- ca237ef: Fix `walkeros push` deadlock for web flows whose destinations await
|
|
236
|
+
real timers during init.
|
|
237
|
+
|
|
238
|
+
Previously, async-drain timer interception captured every `setTimeout` into a
|
|
239
|
+
pending map and only fired them via a post-`fn` flush. If a destination's init
|
|
240
|
+
awaited one of those captured timers (e.g.,
|
|
241
|
+
`@walkeros/web-destination-amplitude`'s engagement plugin awaits a 10s
|
|
242
|
+
setTimeout to give up on a CDN script load), `init` never resolved,
|
|
243
|
+
`await collector.push` deadlocked, and Node exited with
|
|
244
|
+
`Detected unsettled top-level await` (exit 13).
|
|
245
|
+
|
|
246
|
+
A drain pump now runs alongside `fn(flowModule)` for non-`--simulate` runs:
|
|
247
|
+
each tick fires every captured non-cleared timer using a real `setImmediate`
|
|
248
|
+
reference. Timers fire in delay-ascending order, intervals re-register,
|
|
249
|
+
callback errors are reported via `console.warn`. Bounded by max-iterations
|
|
250
|
+
(1000) and wall-clock (30s) caps.
|
|
251
|
+
|
|
252
|
+
`--simulate <step>` continues to use the post-`fn` flush path so snapshot
|
|
253
|
+
ordering remains stable.
|
|
254
|
+
|
|
255
|
+
Behavior change (edge case): a destination using `setTimeout` for retry
|
|
256
|
+
backoff under `walkeros push` (real, non-simulate) now sees its timer fire
|
|
257
|
+
instantly. This was already the documented contract for `--simulate <step>`
|
|
258
|
+
snapshots; it now extends to real `push` for consistency.
|
|
259
|
+
|
|
235
260
|
- 6422b9b: Validate device-code and token responses from the auth server with
|
|
236
261
|
Zod schemas at the trust boundary in `login/index.ts`. Malformed responses now
|
|
237
262
|
surface as structured errors instead of being trusted into config writes or
|
|
@@ -271,10 +296,10 @@
|
|
|
271
296
|
- Updated dependencies [8e06b1f]
|
|
272
297
|
- Updated dependencies [3d50dd6]
|
|
273
298
|
- Updated dependencies [1ef33d9]
|
|
274
|
-
- @walkeros/core@4.0.0
|
|
275
|
-
- @walkeros/collector@4.0.0
|
|
276
|
-
- @walkeros/server-destination-api@4.0.0
|
|
277
|
-
- @walkeros/server-core@4.0.0
|
|
299
|
+
- @walkeros/core@4.0.0
|
|
300
|
+
- @walkeros/collector@4.0.0
|
|
301
|
+
- @walkeros/server-destination-api@4.0.0
|
|
302
|
+
- @walkeros/server-core@4.0.0
|
|
278
303
|
|
|
279
304
|
## 3.4.2
|
|
280
305
|
|
package/dist/cli.js
CHANGED
|
@@ -4050,22 +4050,22 @@ import {
|
|
|
4050
4050
|
mkdirSync as mkdirSync3,
|
|
4051
4051
|
copyFileSync,
|
|
4052
4052
|
writeFileSync as writeFileSync3,
|
|
4053
|
-
readFileSync as
|
|
4053
|
+
readFileSync as readFileSync3
|
|
4054
4054
|
} from "fs";
|
|
4055
|
-
import { join as
|
|
4055
|
+
import { join as join3 } from "path";
|
|
4056
4056
|
function writeCache(cacheDir, bundlePath, configContent, version) {
|
|
4057
4057
|
mkdirSync3(cacheDir, { recursive: true });
|
|
4058
|
-
copyFileSync(bundlePath,
|
|
4059
|
-
writeFileSync3(
|
|
4058
|
+
copyFileSync(bundlePath, join3(cacheDir, "bundle.mjs"));
|
|
4059
|
+
writeFileSync3(join3(cacheDir, "config.json"), configContent, "utf-8");
|
|
4060
4060
|
const meta = { version, timestamp: Date.now() };
|
|
4061
|
-
writeFileSync3(
|
|
4061
|
+
writeFileSync3(join3(cacheDir, "meta.json"), JSON.stringify(meta), "utf-8");
|
|
4062
4062
|
}
|
|
4063
4063
|
function readCache(cacheDir) {
|
|
4064
4064
|
try {
|
|
4065
|
-
const metaPath =
|
|
4066
|
-
const bundlePath =
|
|
4065
|
+
const metaPath = join3(cacheDir, "meta.json");
|
|
4066
|
+
const bundlePath = join3(cacheDir, "bundle.mjs");
|
|
4067
4067
|
if (!existsSync3(metaPath) || !existsSync3(bundlePath)) return null;
|
|
4068
|
-
const meta = JSON.parse(
|
|
4068
|
+
const meta = JSON.parse(readFileSync3(metaPath, "utf-8"));
|
|
4069
4069
|
return { bundlePath, version: meta.version };
|
|
4070
4070
|
} catch {
|
|
4071
4071
|
return null;
|
|
@@ -4073,9 +4073,9 @@ function readCache(cacheDir) {
|
|
|
4073
4073
|
}
|
|
4074
4074
|
function readCacheConfig(cacheDir) {
|
|
4075
4075
|
try {
|
|
4076
|
-
const configPath =
|
|
4076
|
+
const configPath = join3(cacheDir, "config.json");
|
|
4077
4077
|
if (!existsSync3(configPath)) return null;
|
|
4078
|
-
return
|
|
4078
|
+
return readFileSync3(configPath, "utf-8");
|
|
4079
4079
|
} catch {
|
|
4080
4080
|
return null;
|
|
4081
4081
|
}
|
|
@@ -4577,11 +4577,6 @@ function printBanner(version) {
|
|
|
4577
4577
|
console.error("");
|
|
4578
4578
|
}
|
|
4579
4579
|
|
|
4580
|
-
// src/telemetry/emitter.ts
|
|
4581
|
-
import { readFileSync as readFileSync3 } from "fs";
|
|
4582
|
-
import { join as join3, dirname as dirname2 } from "path";
|
|
4583
|
-
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
4584
|
-
|
|
4585
4580
|
// ../collector/dist/index.mjs
|
|
4586
4581
|
init_dist();
|
|
4587
4582
|
init_dist();
|
|
@@ -5214,7 +5209,7 @@ function Re2(e3, n4) {
|
|
|
5214
5209
|
}
|
|
5215
5210
|
async function Ge(e3) {
|
|
5216
5211
|
const n4 = G({ globalsStatic: {}, sessionStatic: {}, run: true }, e3, { merge: false, extend: false }), t3 = { level: e3.logger?.level, handler: e3.logger?.handler }, o2 = _e(t3), s4 = { ...n4.globalsStatic, ...e3.globals }, i2 = { allowed: false, config: n4, consent: e3.consent || {}, custom: e3.custom || {}, destinations: {}, transformers: {}, stores: {}, globals: s4, hooks: e3.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: e3.user || {}, sources: {}, pending: { sources: {}, destinations: {} }, push: void 0, command: void 0 };
|
|
5217
|
-
i2.push = Re2(i2, (e4) => ({ timing: Math.round((Date.now() - i2.timing) / 10) / 100, source: { type: "collector", schema: "4", version: "4.0.0
|
|
5212
|
+
i2.push = Re2(i2, (e4) => ({ timing: Math.round((Date.now() - i2.timing) / 10) / 100, source: { type: "collector", schema: "4", version: "4.0.0" }, ...e4 })), i2.command = (function(e4, n5) {
|
|
5218
5213
|
return Je(async (t4, o3, s5) => await Te(async () => await n5(e4, t4, o3, s5), () => ye({ ok: false }))(), "Command", e4.hooks, e4.logger);
|
|
5219
5214
|
})(i2, qe);
|
|
5220
5215
|
const c3 = e3.stores || {};
|
|
@@ -5414,6 +5409,7 @@ function maybePrintFirstRunNotice() {
|
|
|
5414
5409
|
}
|
|
5415
5410
|
|
|
5416
5411
|
// src/telemetry/emitter.ts
|
|
5412
|
+
init_config_file();
|
|
5417
5413
|
var SEND_TIMEOUT_MS = 1e3;
|
|
5418
5414
|
async function createEmitter(opts) {
|
|
5419
5415
|
if (!isTelemetryEnabled()) {
|
|
@@ -5431,7 +5427,7 @@ async function createEmitter(opts) {
|
|
|
5431
5427
|
}
|
|
5432
5428
|
const device = maybeDevice;
|
|
5433
5429
|
const debug = isDebugMode();
|
|
5434
|
-
const endpoint =
|
|
5430
|
+
const endpoint = resolveTelemetryEndpoint();
|
|
5435
5431
|
if (!endpoint && !debug) {
|
|
5436
5432
|
return {
|
|
5437
5433
|
async send() {
|
|
@@ -5506,15 +5502,10 @@ async function createEmitter(opts) {
|
|
|
5506
5502
|
}
|
|
5507
5503
|
};
|
|
5508
5504
|
}
|
|
5509
|
-
function
|
|
5510
|
-
|
|
5511
|
-
|
|
5512
|
-
|
|
5513
|
-
const url = raw.flows?.default?.destinations?.api?.config?.url;
|
|
5514
|
-
if (url && !url.startsWith("$")) return url;
|
|
5515
|
-
} catch {
|
|
5516
|
-
}
|
|
5517
|
-
return void 0;
|
|
5505
|
+
function resolveTelemetryEndpoint() {
|
|
5506
|
+
const appUrl = resolveAppUrl();
|
|
5507
|
+
if (!appUrl) return void 0;
|
|
5508
|
+
return `${appUrl.replace(/\/$/, "")}/api/telemetry`;
|
|
5518
5509
|
}
|
|
5519
5510
|
async function withTimeout(p2, ms) {
|
|
5520
5511
|
return Promise.race([
|
|
@@ -5822,7 +5813,51 @@ function installTimerInterception(options = {}) {
|
|
|
5822
5813
|
}
|
|
5823
5814
|
pending.clear();
|
|
5824
5815
|
}
|
|
5825
|
-
return { flush, countPending, restore };
|
|
5816
|
+
return { flush, countPending, restore, pending };
|
|
5817
|
+
}
|
|
5818
|
+
|
|
5819
|
+
// src/commands/push/async-drain-pump.ts
|
|
5820
|
+
var realSetImmediate = setImmediate;
|
|
5821
|
+
var DEFAULT_MAX_ITERATIONS = 1e3;
|
|
5822
|
+
var DEFAULT_MAX_WALL_MS = 3e4;
|
|
5823
|
+
var intervalRequeueCounter = -1;
|
|
5824
|
+
function startDrainPump(pending, options = {}) {
|
|
5825
|
+
const maxIterations = options.maxIterations ?? DEFAULT_MAX_ITERATIONS;
|
|
5826
|
+
const maxWallMs = options.maxWallMs ?? DEFAULT_MAX_WALL_MS;
|
|
5827
|
+
const start = Date.now();
|
|
5828
|
+
let running = true;
|
|
5829
|
+
let iterations = 0;
|
|
5830
|
+
const tick = () => {
|
|
5831
|
+
if (!running) return;
|
|
5832
|
+
if (iterations >= maxIterations) return;
|
|
5833
|
+
if (Date.now() - start > maxWallMs) return;
|
|
5834
|
+
if (pending.size === 0) {
|
|
5835
|
+
realSetImmediate(tick);
|
|
5836
|
+
return;
|
|
5837
|
+
}
|
|
5838
|
+
iterations += 1;
|
|
5839
|
+
const snapshot = [...pending.values()].filter((t3) => !t3.cleared).sort((a4, b2) => a4.delay - b2.delay);
|
|
5840
|
+
for (const timer of snapshot) {
|
|
5841
|
+
pending.delete(timer.id);
|
|
5842
|
+
try {
|
|
5843
|
+
timer.callback(...timer.args);
|
|
5844
|
+
} catch (err) {
|
|
5845
|
+
console.warn(`[async-drain] timer ${timer.id} threw during pump:`, err);
|
|
5846
|
+
}
|
|
5847
|
+
if (timer.type === "interval" && !timer.cleared) {
|
|
5848
|
+
const requeued = {
|
|
5849
|
+
...timer,
|
|
5850
|
+
id: intervalRequeueCounter--
|
|
5851
|
+
};
|
|
5852
|
+
pending.set(requeued.id, requeued);
|
|
5853
|
+
}
|
|
5854
|
+
}
|
|
5855
|
+
realSetImmediate(tick);
|
|
5856
|
+
};
|
|
5857
|
+
realSetImmediate(tick);
|
|
5858
|
+
return () => {
|
|
5859
|
+
running = false;
|
|
5860
|
+
};
|
|
5826
5861
|
}
|
|
5827
5862
|
|
|
5828
5863
|
// src/commands/push/flow-context.ts
|
|
@@ -5834,7 +5869,8 @@ async function withFlowContext(options, fn) {
|
|
|
5834
5869
|
snapshotCode,
|
|
5835
5870
|
timeout,
|
|
5836
5871
|
networkCalls,
|
|
5837
|
-
asyncDrain
|
|
5872
|
+
asyncDrain,
|
|
5873
|
+
drainPump
|
|
5838
5874
|
} = options;
|
|
5839
5875
|
const startTime = Date.now();
|
|
5840
5876
|
const g2 = global;
|
|
@@ -5897,7 +5933,13 @@ async function withFlowContext(options, fn) {
|
|
|
5897
5933
|
__devExports: module.__devExports
|
|
5898
5934
|
};
|
|
5899
5935
|
if (timerControl) {
|
|
5900
|
-
const
|
|
5936
|
+
const stopPump = drainPump ? startDrainPump(timerControl.pending) : null;
|
|
5937
|
+
let result;
|
|
5938
|
+
try {
|
|
5939
|
+
result = await fn(flowModule);
|
|
5940
|
+
} finally {
|
|
5941
|
+
if (stopPump) stopPump();
|
|
5942
|
+
}
|
|
5901
5943
|
await timerControl.flush(asyncDrain?.timeout ?? 5e3);
|
|
5902
5944
|
return result;
|
|
5903
5945
|
} else if (timeout) {
|
|
@@ -6041,6 +6083,145 @@ async function prepareFlow(input) {
|
|
|
6041
6083
|
|
|
6042
6084
|
// src/commands/push/index.ts
|
|
6043
6085
|
init_dev();
|
|
6086
|
+
|
|
6087
|
+
// src/commands/push/plan-simulate.ts
|
|
6088
|
+
function planSimulate(flags) {
|
|
6089
|
+
if (flags.length === 0) return { kind: "none", ids: [] };
|
|
6090
|
+
const parsed = flags.map((flag) => {
|
|
6091
|
+
const step = parseStep(flag);
|
|
6092
|
+
if (step.chainType) {
|
|
6093
|
+
throw new Error(
|
|
6094
|
+
`--simulate "${flag}": chain syntax (${step.type}.${step.name}.${step.chainType}.\u2026) is not supported for --simulate. Use --mock for path-specific overrides.`
|
|
6095
|
+
);
|
|
6096
|
+
}
|
|
6097
|
+
return step;
|
|
6098
|
+
});
|
|
6099
|
+
const types = new Set(parsed.map((p2) => p2.type));
|
|
6100
|
+
if (types.size > 1) {
|
|
6101
|
+
const sorted = [...types].sort();
|
|
6102
|
+
throw new Error(
|
|
6103
|
+
`Cannot --simulate ${sorted.join(" and ")} in the same invocation. Run separate commands for each step type.`
|
|
6104
|
+
);
|
|
6105
|
+
}
|
|
6106
|
+
const [type] = types;
|
|
6107
|
+
const ids = [...new Set(parsed.map((p2) => p2.name))];
|
|
6108
|
+
if ((type === "source" || type === "transformer") && ids.length > 1) {
|
|
6109
|
+
throw new Error(
|
|
6110
|
+
`--simulate ${type}.* expects a single target; got ${ids.length}. Run one --simulate ${type}.NAME per invocation.`
|
|
6111
|
+
);
|
|
6112
|
+
}
|
|
6113
|
+
return { kind: type, ids };
|
|
6114
|
+
}
|
|
6115
|
+
|
|
6116
|
+
// src/commands/push/dispatch-simulate.ts
|
|
6117
|
+
function dispatchSimulate(flags) {
|
|
6118
|
+
const plan = planSimulate(flags);
|
|
6119
|
+
return { route: plan.kind, ids: plan.ids };
|
|
6120
|
+
}
|
|
6121
|
+
|
|
6122
|
+
// src/commands/push/run.ts
|
|
6123
|
+
init_core();
|
|
6124
|
+
init_config();
|
|
6125
|
+
async function runPushCommand(options) {
|
|
6126
|
+
const startTime = Date.now();
|
|
6127
|
+
try {
|
|
6128
|
+
const plan = dispatchSimulate(options.simulate ?? []);
|
|
6129
|
+
let config;
|
|
6130
|
+
if (isStdinPiped() && !options.config) {
|
|
6131
|
+
config = await readStdinToTempFile("push");
|
|
6132
|
+
} else {
|
|
6133
|
+
config = options.config || "bundle.config.json";
|
|
6134
|
+
}
|
|
6135
|
+
let resolvedEvent = options.event;
|
|
6136
|
+
if (typeof options.event === "string") {
|
|
6137
|
+
resolvedEvent = await loadJsonFromSource(options.event, {
|
|
6138
|
+
name: "event"
|
|
6139
|
+
});
|
|
6140
|
+
}
|
|
6141
|
+
let result;
|
|
6142
|
+
switch (plan.route) {
|
|
6143
|
+
case "none":
|
|
6144
|
+
result = await push(config, resolvedEvent, {
|
|
6145
|
+
flow: options.flow,
|
|
6146
|
+
json: options.json,
|
|
6147
|
+
verbose: options.verbose,
|
|
6148
|
+
silent: options.silent,
|
|
6149
|
+
platform: options.platform,
|
|
6150
|
+
mock: options.mock,
|
|
6151
|
+
snapshot: options.snapshot
|
|
6152
|
+
});
|
|
6153
|
+
break;
|
|
6154
|
+
case "source":
|
|
6155
|
+
result = await simulateSource(config, resolvedEvent, {
|
|
6156
|
+
sourceId: plan.ids[0],
|
|
6157
|
+
flow: options.flow,
|
|
6158
|
+
silent: options.silent,
|
|
6159
|
+
verbose: options.verbose,
|
|
6160
|
+
snapshot: options.snapshot
|
|
6161
|
+
});
|
|
6162
|
+
break;
|
|
6163
|
+
case "transformer":
|
|
6164
|
+
result = await simulateTransformer(
|
|
6165
|
+
config,
|
|
6166
|
+
resolvedEvent,
|
|
6167
|
+
{
|
|
6168
|
+
transformerId: plan.ids[0],
|
|
6169
|
+
flow: options.flow,
|
|
6170
|
+
mock: options.mock,
|
|
6171
|
+
silent: options.silent,
|
|
6172
|
+
verbose: options.verbose,
|
|
6173
|
+
snapshot: options.snapshot
|
|
6174
|
+
}
|
|
6175
|
+
);
|
|
6176
|
+
break;
|
|
6177
|
+
case "destination":
|
|
6178
|
+
result = await runDestinationSimulationLoop(
|
|
6179
|
+
config,
|
|
6180
|
+
resolvedEvent,
|
|
6181
|
+
plan.ids,
|
|
6182
|
+
options
|
|
6183
|
+
);
|
|
6184
|
+
break;
|
|
6185
|
+
}
|
|
6186
|
+
return result;
|
|
6187
|
+
} catch (error) {
|
|
6188
|
+
return {
|
|
6189
|
+
success: false,
|
|
6190
|
+
duration: Date.now() - startTime,
|
|
6191
|
+
error: getErrorMessage(error)
|
|
6192
|
+
};
|
|
6193
|
+
}
|
|
6194
|
+
}
|
|
6195
|
+
async function runDestinationSimulationLoop(config, event, destinationIds, options) {
|
|
6196
|
+
const startTime = Date.now();
|
|
6197
|
+
const perDestination = {};
|
|
6198
|
+
for (const destinationId of destinationIds) {
|
|
6199
|
+
const r3 = await simulateDestination(config, event, {
|
|
6200
|
+
destinationId,
|
|
6201
|
+
flow: options.flow,
|
|
6202
|
+
mock: options.mock,
|
|
6203
|
+
silent: options.silent,
|
|
6204
|
+
verbose: options.verbose,
|
|
6205
|
+
snapshot: options.snapshot
|
|
6206
|
+
});
|
|
6207
|
+
perDestination[destinationId] = r3;
|
|
6208
|
+
if (!r3.success) {
|
|
6209
|
+
return {
|
|
6210
|
+
success: false,
|
|
6211
|
+
duration: Date.now() - startTime,
|
|
6212
|
+
error: `simulate destination.${destinationId}: ${r3.error ?? "unknown error"}`,
|
|
6213
|
+
perDestination
|
|
6214
|
+
};
|
|
6215
|
+
}
|
|
6216
|
+
}
|
|
6217
|
+
return {
|
|
6218
|
+
success: true,
|
|
6219
|
+
duration: Date.now() - startTime,
|
|
6220
|
+
perDestination
|
|
6221
|
+
};
|
|
6222
|
+
}
|
|
6223
|
+
|
|
6224
|
+
// src/commands/push/index.ts
|
|
6044
6225
|
function resolveBeforeChain(before, transformers, ingest, event) {
|
|
6045
6226
|
if (!before) return [];
|
|
6046
6227
|
const next = before;
|
|
@@ -6119,108 +6300,32 @@ async function pushCore(inputPath, event, options = {}) {
|
|
|
6119
6300
|
}
|
|
6120
6301
|
}
|
|
6121
6302
|
async function pushCommand(options) {
|
|
6122
|
-
const
|
|
6123
|
-
const
|
|
6124
|
-
|
|
6125
|
-
|
|
6126
|
-
|
|
6127
|
-
|
|
6128
|
-
|
|
6129
|
-
|
|
6130
|
-
|
|
6131
|
-
|
|
6132
|
-
|
|
6133
|
-
|
|
6134
|
-
|
|
6135
|
-
|
|
6136
|
-
|
|
6137
|
-
|
|
6138
|
-
|
|
6139
|
-
|
|
6140
|
-
|
|
6141
|
-
sourceId: simulateFlag.replace("source.", ""),
|
|
6142
|
-
flow: options.flow,
|
|
6143
|
-
silent: options.silent,
|
|
6144
|
-
verbose: options.verbose,
|
|
6145
|
-
snapshot: options.snapshot
|
|
6146
|
-
});
|
|
6147
|
-
} else if (simulateFlag?.startsWith("transformer.")) {
|
|
6148
|
-
result = await simulateTransformer(
|
|
6149
|
-
config,
|
|
6150
|
-
resolvedEvent,
|
|
6151
|
-
{
|
|
6152
|
-
transformerId: simulateFlag.replace("transformer.", ""),
|
|
6153
|
-
flow: options.flow,
|
|
6154
|
-
mock: options.mock,
|
|
6155
|
-
silent: options.silent,
|
|
6156
|
-
verbose: options.verbose,
|
|
6157
|
-
snapshot: options.snapshot
|
|
6158
|
-
}
|
|
6159
|
-
);
|
|
6160
|
-
} else if (simulateFlag?.startsWith("destination.")) {
|
|
6161
|
-
result = await simulateDestination(
|
|
6162
|
-
config,
|
|
6163
|
-
resolvedEvent,
|
|
6164
|
-
{
|
|
6165
|
-
destinationId: simulateFlag.replace("destination.", ""),
|
|
6166
|
-
flow: options.flow,
|
|
6167
|
-
mock: options.mock,
|
|
6168
|
-
silent: options.silent,
|
|
6169
|
-
verbose: options.verbose,
|
|
6170
|
-
snapshot: options.snapshot
|
|
6171
|
-
}
|
|
6172
|
-
);
|
|
6173
|
-
} else {
|
|
6174
|
-
result = await push(config, resolvedEvent, {
|
|
6175
|
-
flow: options.flow,
|
|
6176
|
-
json: options.json,
|
|
6177
|
-
verbose: options.verbose,
|
|
6178
|
-
silent: options.silent,
|
|
6179
|
-
platform: options.platform,
|
|
6180
|
-
mock: options.mock,
|
|
6181
|
-
snapshot: options.snapshot
|
|
6182
|
-
});
|
|
6183
|
-
}
|
|
6184
|
-
const duration = Date.now() - startTime;
|
|
6185
|
-
let output;
|
|
6186
|
-
if (options.json) {
|
|
6187
|
-
output = JSON.stringify({ ...result, duration }, null, 2);
|
|
6188
|
-
} else {
|
|
6189
|
-
const lines = [];
|
|
6190
|
-
if (result.success) {
|
|
6191
|
-
lines.push("Event pushed successfully");
|
|
6192
|
-
if (result.elbResult && typeof result.elbResult === "object") {
|
|
6193
|
-
const pushResult = result.elbResult;
|
|
6194
|
-
if ("id" in pushResult && pushResult.id)
|
|
6195
|
-
lines.push(` Event ID: ${pushResult.id}`);
|
|
6196
|
-
if ("entity" in pushResult && pushResult.entity)
|
|
6197
|
-
lines.push(` Entity: ${pushResult.entity}`);
|
|
6198
|
-
if ("action" in pushResult && pushResult.action)
|
|
6199
|
-
lines.push(` Action: ${pushResult.action}`);
|
|
6200
|
-
}
|
|
6201
|
-
lines.push(` Duration: ${duration}ms`);
|
|
6202
|
-
} else {
|
|
6203
|
-
lines.push(`Error: ${result.error}`);
|
|
6204
|
-
}
|
|
6205
|
-
output = lines.join("\n");
|
|
6206
|
-
}
|
|
6207
|
-
await writeResult(output + "\n", { output: options.output });
|
|
6208
|
-
process.exit(result.success ? 0 : 1);
|
|
6209
|
-
} catch (error) {
|
|
6210
|
-
const duration = Date.now() - startTime;
|
|
6211
|
-
const errorMessage = getErrorMessage(error);
|
|
6212
|
-
if (options.json) {
|
|
6213
|
-
const errorOutput = JSON.stringify(
|
|
6214
|
-
{ success: false, error: errorMessage, duration },
|
|
6215
|
-
null,
|
|
6216
|
-
2
|
|
6217
|
-
);
|
|
6218
|
-
await writeResult(errorOutput + "\n", { output: options.output });
|
|
6303
|
+
const result = await runPushCommand(options);
|
|
6304
|
+
const duration = result.duration;
|
|
6305
|
+
let output;
|
|
6306
|
+
if (options.json) {
|
|
6307
|
+
output = JSON.stringify({ ...result, duration }, null, 2);
|
|
6308
|
+
} else {
|
|
6309
|
+
const lines = [];
|
|
6310
|
+
if (result.success) {
|
|
6311
|
+
lines.push("Event pushed successfully");
|
|
6312
|
+
if (result.elbResult && typeof result.elbResult === "object") {
|
|
6313
|
+
const pushResult = result.elbResult;
|
|
6314
|
+
if ("id" in pushResult && pushResult.id)
|
|
6315
|
+
lines.push(` Event ID: ${pushResult.id}`);
|
|
6316
|
+
if ("entity" in pushResult && pushResult.entity)
|
|
6317
|
+
lines.push(` Entity: ${pushResult.entity}`);
|
|
6318
|
+
if ("action" in pushResult && pushResult.action)
|
|
6319
|
+
lines.push(` Action: ${pushResult.action}`);
|
|
6320
|
+
}
|
|
6321
|
+
lines.push(` Duration: ${duration}ms`);
|
|
6219
6322
|
} else {
|
|
6220
|
-
|
|
6323
|
+
lines.push(`Error: ${result.error}`);
|
|
6221
6324
|
}
|
|
6222
|
-
|
|
6325
|
+
output = lines.join("\n");
|
|
6223
6326
|
}
|
|
6327
|
+
await writeResult(output + "\n", { output: options.output });
|
|
6328
|
+
process.exit(result.success ? 0 : 1);
|
|
6224
6329
|
}
|
|
6225
6330
|
async function push(configOrPath, event, options = {}) {
|
|
6226
6331
|
if (typeof configOrPath !== "string") {
|
|
@@ -6319,7 +6424,12 @@ async function executeDestinationPush(esmPath, event, logger, platform, override
|
|
|
6319
6424
|
snapshotCode,
|
|
6320
6425
|
timeout,
|
|
6321
6426
|
networkCalls,
|
|
6322
|
-
asyncDrain: { timeout: 5e3 }
|
|
6427
|
+
asyncDrain: { timeout: 5e3 },
|
|
6428
|
+
// Real push (non-simulate) needs the pump so destinations whose init
|
|
6429
|
+
// awaits a captured setTimeout (e.g., amplitude engagement plugin)
|
|
6430
|
+
// don't deadlock. Simulate routes use their own withFlowContext call
|
|
6431
|
+
// sites without `drainPump`, preserving snapshot ordering.
|
|
6432
|
+
drainPump: true
|
|
6323
6433
|
},
|
|
6324
6434
|
async (module) => {
|
|
6325
6435
|
const config = module.wireConfig(module.__configData ?? void 0);
|
|
@@ -6719,12 +6829,12 @@ init_auth();
|
|
|
6719
6829
|
import path17 from "path";
|
|
6720
6830
|
import { writeFileSync as writeFileSync5 } from "fs";
|
|
6721
6831
|
import { homedir as homedir2 } from "os";
|
|
6722
|
-
import { join as
|
|
6832
|
+
import { join as join4 } from "path";
|
|
6723
6833
|
|
|
6724
6834
|
// src/runtime/resolve-bundle.ts
|
|
6725
6835
|
init_stdin();
|
|
6726
6836
|
import { existsSync as existsSync2, mkdirSync as mkdirSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
6727
|
-
import { dirname as
|
|
6837
|
+
import { dirname as dirname2 } from "path";
|
|
6728
6838
|
function getDefaultWritePath() {
|
|
6729
6839
|
if (existsSync2("/app/flow")) return "/app/flow/bundle.mjs";
|
|
6730
6840
|
return "/tmp/walkeros-bundle.mjs";
|
|
@@ -6733,7 +6843,7 @@ function isUrl2(value) {
|
|
|
6733
6843
|
return value.startsWith("http://") || value.startsWith("https://");
|
|
6734
6844
|
}
|
|
6735
6845
|
function writeBundleToDisk(writePath, content) {
|
|
6736
|
-
const dir =
|
|
6846
|
+
const dir = dirname2(writePath);
|
|
6737
6847
|
if (!existsSync2(dir)) {
|
|
6738
6848
|
mkdirSync2(dir, { recursive: true });
|
|
6739
6849
|
}
|
|
@@ -7009,7 +7119,7 @@ function createHealthServer(port, logger) {
|
|
|
7009
7119
|
}
|
|
7010
7120
|
|
|
7011
7121
|
// src/runtime/runner.ts
|
|
7012
|
-
import { resolve as resolve2, dirname as
|
|
7122
|
+
import { resolve as resolve2, dirname as dirname3 } from "path";
|
|
7013
7123
|
|
|
7014
7124
|
// src/runtime/load-bundle.ts
|
|
7015
7125
|
import { resolve } from "path";
|
|
@@ -7040,7 +7150,7 @@ async function loadBundle(file, context2, logger) {
|
|
|
7040
7150
|
// src/runtime/runner.ts
|
|
7041
7151
|
async function loadFlow(file, config, logger, loggerConfig, healthServer) {
|
|
7042
7152
|
const absolutePath = resolve2(file);
|
|
7043
|
-
const flowDir =
|
|
7153
|
+
const flowDir = dirname3(absolutePath);
|
|
7044
7154
|
process.chdir(flowDir);
|
|
7045
7155
|
const flowContext = {
|
|
7046
7156
|
...config,
|
|
@@ -7433,8 +7543,8 @@ async function injectSecrets(api, logger) {
|
|
|
7433
7543
|
// src/commands/run/index.ts
|
|
7434
7544
|
function defaultCacheDir() {
|
|
7435
7545
|
const xdgCache = process.env.XDG_CACHE_HOME;
|
|
7436
|
-
const base = xdgCache ||
|
|
7437
|
-
return
|
|
7546
|
+
const base = xdgCache || join4(homedir2(), ".cache");
|
|
7547
|
+
return join4(base, "walkeros");
|
|
7438
7548
|
}
|
|
7439
7549
|
async function lazyPrepareBundleForRun(configPath, options) {
|
|
7440
7550
|
const { prepareBundleForRun: prepareBundleForRun2 } = await Promise.resolve().then(() => (init_utils3(), utils_exports));
|
|
@@ -8122,7 +8232,7 @@ function validateMapping(input) {
|
|
|
8122
8232
|
// src/commands/validate/validators/entry.ts
|
|
8123
8233
|
init_dist();
|
|
8124
8234
|
import Ajv from "ajv";
|
|
8125
|
-
var CLIENT_HEADER = "walkeros-cli/4.0.0
|
|
8235
|
+
var CLIENT_HEADER = "walkeros-cli/4.0.0";
|
|
8126
8236
|
var SECTIONS = ["destinations", "sources", "transformers"];
|
|
8127
8237
|
function resolveEntry(path18, flowConfig) {
|
|
8128
8238
|
const flows = flowConfig.flows;
|
|
@@ -9274,7 +9384,7 @@ program.command("push [file]").description("Push an event through the flow with
|
|
|
9274
9384
|
"event to push (JSON string, file path, or URL)"
|
|
9275
9385
|
).option("-o, --output <path>", "write result to file").option("-f, --flow <name>", "flow name for multi-flow configs").option("-p, --platform <platform>", "platform override (web or server)").option("--json", "output as JSON").option("-v, --verbose", "verbose output").option("-s, --silent", "suppress output").option(
|
|
9276
9386
|
"--simulate <step>",
|
|
9277
|
-
"simulate a
|
|
9387
|
+
"simulate a step (repeatable for destination.*; format: source.NAME | destination.NAME | transformer.NAME)",
|
|
9278
9388
|
(val, arr) => {
|
|
9279
9389
|
arr.push(val);
|
|
9280
9390
|
return arr;
|
package/dist/index.d.ts
CHANGED
|
@@ -336,6 +336,11 @@ interface PushResult {
|
|
|
336
336
|
}>>;
|
|
337
337
|
/** Network calls captured during web simulation (fetch + sendBeacon) */
|
|
338
338
|
networkCalls?: NetworkCall[];
|
|
339
|
+
/**
|
|
340
|
+
* Per-destination simulation results when --simulate destination.* is
|
|
341
|
+
* called with multiple ids. Undefined for single-target or non-simulate runs.
|
|
342
|
+
*/
|
|
343
|
+
perDestination?: Record<string, PushResult>;
|
|
339
344
|
duration: number;
|
|
340
345
|
error?: string;
|
|
341
346
|
}
|
|
@@ -360,7 +365,11 @@ declare const PushOptionsSchema: z.ZodObject<{
|
|
|
360
365
|
type PushOptions = z.infer<typeof PushOptionsSchema>;
|
|
361
366
|
|
|
362
367
|
/**
|
|
363
|
-
* CLI command handler for push command
|
|
368
|
+
* CLI command handler for push command.
|
|
369
|
+
*
|
|
370
|
+
* Thin wrapper around `runPushCommand`: delegates result production to the
|
|
371
|
+
* pure helper, then formats output and decides the exit code. Tests target
|
|
372
|
+
* `runPushCommand` directly to avoid `process.exit` killing Jest workers.
|
|
364
373
|
*/
|
|
365
374
|
declare function pushCommand(options: PushCommandOptions): Promise<void>;
|
|
366
375
|
/**
|