@walkeros/cli 4.2.0-next-1781000333052 → 4.3.0-next-1781171238534
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 +44 -11
- package/dist/cli.js +203 -74
- package/dist/index.d.ts +86 -7
- package/dist/index.js +215 -78
- package/dist/index.js.map +1 -1
- package/package.json +8 -8
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,38 @@
|
|
|
1
1
|
# @walkeros/cli
|
|
2
2
|
|
|
3
|
-
## 4.
|
|
3
|
+
## 4.3.0-next-1781171238534
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 5cbcd23: `walkeros run` reads two new environment variables.
|
|
8
|
+
`WALKEROS_OBSERVE_LEVEL` sets the runtime's baseline telemetry level (`off`,
|
|
9
|
+
`standard`, or `trace`). `WALKEROS_CONFIG_FROZEN` (`1` or `true`) serves the
|
|
10
|
+
bundle as an immutable snapshot: secrets are still injected at boot, but
|
|
11
|
+
config hot-swap and heartbeat are disabled.
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- b03bfce: `walkeros deploy` now waits long enough to cover a full server deploy
|
|
16
|
+
by default, so a slow but healthy deploy is no longer aborted early and
|
|
17
|
+
reported as a failure. Each run sends a fresh idempotency key, so retrying
|
|
18
|
+
after a failure starts a new deploy instead of replaying the previous result.
|
|
19
|
+
Failures print a stable, machine-readable error code (with a `Retry-After`
|
|
20
|
+
hint on rate limits), and `deploy create` no longer prints an empty token
|
|
21
|
+
placeholder.
|
|
22
|
+
- 5cbcd23: All four simulate functions (`simulateSource`, `simulateTransformer`,
|
|
23
|
+
`simulateCollector`, `simulateDestination`) accept a new `data` option to run
|
|
24
|
+
an existing bundle with updated configuration values, without rebundling. The
|
|
25
|
+
new `buildDataPayload`, `classifyStepProperties`, and `containsCodeMarkers`
|
|
26
|
+
exports build and inspect that payload. Destination simulation results now
|
|
27
|
+
include `mappingKey`, the entity-action key of the matched mapping rule.
|
|
28
|
+
- Updated dependencies [5cbcd23]
|
|
29
|
+
- @walkeros/core@4.3.0-next-1781171238534
|
|
30
|
+
- @walkeros/collector@4.3.0-next-1781171238534
|
|
31
|
+
- @walkeros/server-core@4.3.0-next-1781171238534
|
|
32
|
+
- @walkeros/server-destination-api@4.3.0-next-1781171238534
|
|
33
|
+
- @walkeros/transformer-validate@4.3.0-next-1781171238534
|
|
34
|
+
|
|
35
|
+
## 4.2.0
|
|
4
36
|
|
|
5
37
|
### Minor Changes
|
|
6
38
|
|
|
@@ -47,7 +79,7 @@
|
|
|
47
79
|
custom domains, entitlements, LLM settings, chat sessions, MCP tokens,
|
|
48
80
|
runners, and the package catalog. No runtime behavior change; clients gain
|
|
49
81
|
accurate types for these endpoints.
|
|
50
|
-
-
|
|
82
|
+
- 5b1a134: Browser flow bundles are now emitted as an IIFE so all internal code
|
|
51
83
|
stays inside a private scope. Previously the bundled helper functions could
|
|
52
84
|
leak onto the global `window` object and collide with other scripts on the
|
|
53
85
|
page, such as Google Analytics or a consent manager. Server bundles are
|
|
@@ -86,7 +118,7 @@
|
|
|
86
118
|
without a trace poll. When the telemetry options omit `traceUrl`, the bundle
|
|
87
119
|
emits at a fixed level with no polling, suited to short-lived, URL-opted-in
|
|
88
120
|
sessions. Bundles that pass `traceUrl` keep the existing poll behavior.
|
|
89
|
-
-
|
|
121
|
+
- 23d4b86: New `@walkeros/transformer-validate` transformer validates events
|
|
90
122
|
against JSON Schema contracts. It runs in both web and server flows, supports
|
|
91
123
|
strict and pass modes, and writes the verdict and error list to configurable
|
|
92
124
|
paths so you can gate or observe event quality.
|
|
@@ -99,7 +131,7 @@
|
|
|
99
131
|
examples against the resolved contract.
|
|
100
132
|
|
|
101
133
|
- Updated dependencies [76d32c1]
|
|
102
|
-
- Updated dependencies [
|
|
134
|
+
- Updated dependencies [5b1a134]
|
|
103
135
|
- Updated dependencies [908d6f0]
|
|
104
136
|
- Updated dependencies [654ba38]
|
|
105
137
|
- Updated dependencies [c27d3c1]
|
|
@@ -114,14 +146,15 @@
|
|
|
114
146
|
- Updated dependencies [654ba38]
|
|
115
147
|
- Updated dependencies [6a72a32]
|
|
116
148
|
- Updated dependencies [3eb2467]
|
|
117
|
-
- Updated dependencies [
|
|
118
|
-
- Updated dependencies [
|
|
149
|
+
- Updated dependencies [5b1a134]
|
|
150
|
+
- Updated dependencies [23d4b86]
|
|
119
151
|
- Updated dependencies [18c9469]
|
|
120
|
-
|
|
121
|
-
- @walkeros/
|
|
122
|
-
- @walkeros/
|
|
123
|
-
- @walkeros/server-
|
|
124
|
-
- @walkeros/
|
|
152
|
+
- Updated dependencies [0cad016]
|
|
153
|
+
- @walkeros/core@4.2.0
|
|
154
|
+
- @walkeros/collector@4.2.0
|
|
155
|
+
- @walkeros/server-core@4.2.0
|
|
156
|
+
- @walkeros/server-destination-api@4.2.0
|
|
157
|
+
- @walkeros/transformer-validate@4.2.0
|
|
125
158
|
|
|
126
159
|
## 4.1.2
|
|
127
160
|
|
package/dist/cli.js
CHANGED
|
@@ -31,25 +31,62 @@ var init_client_context = __esm({
|
|
|
31
31
|
});
|
|
32
32
|
|
|
33
33
|
// src/core/api-error.ts
|
|
34
|
-
function
|
|
35
|
-
if (error
|
|
36
|
-
|
|
37
|
-
const message = inner.message || fallbackMessage;
|
|
38
|
-
const code = inner.code;
|
|
39
|
-
const details = inner.details?.errors;
|
|
40
|
-
const options = { code, details };
|
|
41
|
-
if (code === "CLIENT_OUTDATED") {
|
|
42
|
-
options.minVersion = inner.minVersion;
|
|
43
|
-
options.clientVersion = inner.clientVersion;
|
|
44
|
-
options.client = inner.client;
|
|
45
|
-
options.upgrade = inner.upgrade;
|
|
46
|
-
options.docs = inner.docs;
|
|
47
|
-
}
|
|
48
|
-
throw new ApiError(message, options);
|
|
34
|
+
function extractApiErrorOptions(error, fallbackMessage) {
|
|
35
|
+
if (!error || typeof error !== "object" || !("error" in error) || typeof error.error !== "object") {
|
|
36
|
+
return null;
|
|
49
37
|
}
|
|
38
|
+
const inner = error.error;
|
|
39
|
+
const message = inner.message || fallbackMessage;
|
|
40
|
+
const code = inner.code;
|
|
41
|
+
const details = inner.details?.errors;
|
|
42
|
+
const options = { code, details };
|
|
43
|
+
if (code === "CLIENT_OUTDATED") {
|
|
44
|
+
options.minVersion = inner.minVersion;
|
|
45
|
+
options.clientVersion = inner.clientVersion;
|
|
46
|
+
options.client = inner.client;
|
|
47
|
+
options.upgrade = inner.upgrade;
|
|
48
|
+
options.docs = inner.docs;
|
|
49
|
+
}
|
|
50
|
+
return { message, options };
|
|
51
|
+
}
|
|
52
|
+
function throwApiError(error, fallbackMessage) {
|
|
53
|
+
const extracted = extractApiErrorOptions(error, fallbackMessage);
|
|
54
|
+
if (extracted) throw new ApiError(extracted.message, extracted.options);
|
|
50
55
|
throw new ApiError(fallbackMessage);
|
|
51
56
|
}
|
|
57
|
+
function parseRetryAfter(value) {
|
|
58
|
+
if (!value) return void 0;
|
|
59
|
+
const trimmed = value.trim();
|
|
60
|
+
if (/^\d+$/.test(trimmed)) return parseInt(trimmed, 10);
|
|
61
|
+
const when = Date.parse(trimmed);
|
|
62
|
+
if (Number.isNaN(when)) return void 0;
|
|
63
|
+
return Math.max(0, Math.round((when - Date.now()) / 1e3));
|
|
64
|
+
}
|
|
65
|
+
function throwApiResponseError(response, body, fallbackMessage) {
|
|
66
|
+
const status = response.status;
|
|
67
|
+
const retryAfterSeconds = parseRetryAfter(
|
|
68
|
+
response.headers.get("retry-after")
|
|
69
|
+
);
|
|
70
|
+
const retryable = status === 429 || status === 503 && retryAfterSeconds !== void 0;
|
|
71
|
+
const extracted = extractApiErrorOptions(body, fallbackMessage);
|
|
72
|
+
const message = extracted?.message ?? fallbackMessage;
|
|
73
|
+
const options = {
|
|
74
|
+
...extracted?.options ?? {},
|
|
75
|
+
status,
|
|
76
|
+
retryable,
|
|
77
|
+
retryAfterSeconds
|
|
78
|
+
};
|
|
79
|
+
throw new ApiError(message, options);
|
|
80
|
+
}
|
|
81
|
+
function machineReadableErrorLine(err) {
|
|
82
|
+
const code = err instanceof ApiError ? err.code ?? "UNKNOWN" : "UNKNOWN";
|
|
83
|
+
const retryable = err instanceof ApiError ? err.retryable === true : false;
|
|
84
|
+
const retryAfter = err instanceof ApiError && err.retryAfterSeconds !== void 0 ? ` retryAfter=${err.retryAfterSeconds}` : "";
|
|
85
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
86
|
+
return `error: code=${code} retryable=${retryable}${retryAfter} message=${message}`;
|
|
87
|
+
}
|
|
52
88
|
function handleCliError(err) {
|
|
89
|
+
console.error(machineReadableErrorLine(err));
|
|
53
90
|
if (err instanceof ApiError && err.code === "CLIENT_OUTDATED") {
|
|
54
91
|
console.error(`
|
|
55
92
|
${err.message}
|
|
@@ -59,17 +96,25 @@ ${err.message}
|
|
|
59
96
|
`);
|
|
60
97
|
process.exit(2);
|
|
61
98
|
}
|
|
62
|
-
|
|
63
|
-
|
|
99
|
+
if (err instanceof ApiError && err.retryable) {
|
|
100
|
+
const hint = err.retryAfterSeconds !== void 0 ? ` Retry after ${err.retryAfterSeconds}s.` : " This is temporary, retry shortly.";
|
|
101
|
+
console.error(`${err.message}${hint}`);
|
|
102
|
+
process.exit(EXIT_RETRYABLE);
|
|
103
|
+
}
|
|
104
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
64
105
|
process.exit(1);
|
|
65
106
|
}
|
|
66
|
-
var ApiError;
|
|
107
|
+
var EXIT_RETRYABLE, ApiError;
|
|
67
108
|
var init_api_error = __esm({
|
|
68
109
|
"src/core/api-error.ts"() {
|
|
69
110
|
"use strict";
|
|
111
|
+
EXIT_RETRYABLE = 75;
|
|
70
112
|
ApiError = class extends Error {
|
|
71
113
|
code;
|
|
72
114
|
details;
|
|
115
|
+
status;
|
|
116
|
+
retryable;
|
|
117
|
+
retryAfterSeconds;
|
|
73
118
|
// Populated only for CLIENT_OUTDATED responses (HTTP 426).
|
|
74
119
|
minVersion;
|
|
75
120
|
clientVersion;
|
|
@@ -81,6 +126,9 @@ var init_api_error = __esm({
|
|
|
81
126
|
this.name = "ApiError";
|
|
82
127
|
this.code = options?.code;
|
|
83
128
|
this.details = options?.details;
|
|
129
|
+
this.status = options?.status;
|
|
130
|
+
this.retryable = options?.retryable;
|
|
131
|
+
this.retryAfterSeconds = options?.retryAfterSeconds;
|
|
84
132
|
this.minVersion = options?.minVersion;
|
|
85
133
|
this.clientVersion = options?.clientVersion;
|
|
86
134
|
this.client = options?.client;
|
|
@@ -2770,9 +2818,8 @@ function validateReference(type, name, ref) {
|
|
|
2770
2818
|
return;
|
|
2771
2819
|
}
|
|
2772
2820
|
const hasPackage = !!ref.package;
|
|
2773
|
-
const hasInlineCode = isInlineCode(ref.code);
|
|
2774
2821
|
const hasCode = hasCodeReference(ref.code);
|
|
2775
|
-
if (hasPackage &&
|
|
2822
|
+
if (hasPackage && hasCode) {
|
|
2776
2823
|
throw new Error(
|
|
2777
2824
|
`${type} "${name}": Cannot specify both package and code. Use one or the other.`
|
|
2778
2825
|
);
|
|
@@ -2812,13 +2859,13 @@ function validateStoreReferences(flowSettings, storeIds) {
|
|
|
2812
2859
|
collectRefs(component, `${section}.${id}`);
|
|
2813
2860
|
}
|
|
2814
2861
|
}
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
}
|
|
2862
|
+
const missing = refs.filter(({ ref }) => !storeIds.has(ref));
|
|
2863
|
+
if (missing.length > 0) {
|
|
2864
|
+
const available = storeIds.size > 0 ? `Available stores: ${Array.from(storeIds).join(", ")}` : "No stores defined";
|
|
2865
|
+
const details = missing.map(
|
|
2866
|
+
({ ref, location: location2 }) => `"$store.${ref}" in ${location2} (store "${ref}" not found)`
|
|
2867
|
+
).join("; ");
|
|
2868
|
+
throw new Error(`Invalid store references: ${details}. ${available}`);
|
|
2822
2869
|
}
|
|
2823
2870
|
}
|
|
2824
2871
|
var VALID_JS_IDENTIFIER;
|
|
@@ -4571,7 +4618,7 @@ ${destinationsEntries.join(",\n")}
|
|
|
4571
4618
|
stores${collectorStr}
|
|
4572
4619
|
}`;
|
|
4573
4620
|
const dataPayload = JSON.stringify(dataPayloadObj, null, 2);
|
|
4574
|
-
return { storesDeclaration, codeConfigObject, dataPayload };
|
|
4621
|
+
return { storesDeclaration, codeConfigObject, dataPayloadObj, dataPayload };
|
|
4575
4622
|
}
|
|
4576
4623
|
function generateSplitWireConfigModule(storesDeclaration, codeConfigObject, userCode) {
|
|
4577
4624
|
const codeSection = userCode ? `
|
|
@@ -6699,7 +6746,7 @@ async function wt(e4, t4, o4) {
|
|
|
6699
6746
|
}
|
|
6700
6747
|
}
|
|
6701
6748
|
function vt(e4, t4) {
|
|
6702
|
-
return { timing: Math.round((Date.now() - e4.timing) / 10) / 100, source: { type: "collector", schema: "4", version: "4.
|
|
6749
|
+
return { timing: Math.round((Date.now() - e4.timing) / 10) / 100, source: { type: "collector", schema: "4", version: "4.3.0-next-1781171238534" }, ...t4 };
|
|
6703
6750
|
}
|
|
6704
6751
|
function bt(e4, t4) {
|
|
6705
6752
|
if (!t4.name) throw new Error("Event name is required");
|
|
@@ -7754,7 +7801,7 @@ function toError(error) {
|
|
|
7754
7801
|
return error instanceof Error ? error : new Error(getErrorMessage(error));
|
|
7755
7802
|
}
|
|
7756
7803
|
function buildSimulationResult(args) {
|
|
7757
|
-
const { step, name, startTime, captured, usage, error } = args;
|
|
7804
|
+
const { step, name, startTime, captured, usage, mappingKey, error } = args;
|
|
7758
7805
|
const events = (captured ?? []).filter(hasEvent).map((entry) => entry.event);
|
|
7759
7806
|
const calls = usage ? Object.values(usage).flat().map((call) => ({ fn: call.fn, args: call.args, ts: call.ts })) : [];
|
|
7760
7807
|
return {
|
|
@@ -7763,6 +7810,7 @@ function buildSimulationResult(args) {
|
|
|
7763
7810
|
events,
|
|
7764
7811
|
calls,
|
|
7765
7812
|
duration: Date.now() - startTime,
|
|
7813
|
+
...mappingKey !== void 0 ? { mappingKey } : {},
|
|
7766
7814
|
...error !== void 0 ? { error: toError(error) } : {}
|
|
7767
7815
|
};
|
|
7768
7816
|
}
|
|
@@ -8356,7 +8404,9 @@ async function simulateSource(configOrPath, input, options) {
|
|
|
8356
8404
|
`Source package "${sourceConfig.package}" has no createTrigger in /dev export`
|
|
8357
8405
|
);
|
|
8358
8406
|
}
|
|
8359
|
-
const flowConfig = module.wireConfig(
|
|
8407
|
+
const flowConfig = module.wireConfig(
|
|
8408
|
+
options.data ?? module.__configData ?? void 0
|
|
8409
|
+
);
|
|
8360
8410
|
applyOverrides(flowConfig, prepared.overrides);
|
|
8361
8411
|
const captured = [];
|
|
8362
8412
|
flowConfig.hooks = {
|
|
@@ -8461,7 +8511,9 @@ async function simulateTransformer(configOrPath, event, options) {
|
|
|
8461
8511
|
networkCalls
|
|
8462
8512
|
},
|
|
8463
8513
|
async (module) => {
|
|
8464
|
-
const flowConfig = module.wireConfig(
|
|
8514
|
+
const flowConfig = module.wireConfig(
|
|
8515
|
+
options.data ?? module.__configData ?? void 0
|
|
8516
|
+
);
|
|
8465
8517
|
applyOverrides(flowConfig, prepared.overrides);
|
|
8466
8518
|
if (flowConfig.sources) flowConfig.sources = {};
|
|
8467
8519
|
if (flowConfig.destinations) flowConfig.destinations = {};
|
|
@@ -8627,7 +8679,9 @@ async function simulateCollector(configOrPath, event, options) {
|
|
|
8627
8679
|
networkCalls
|
|
8628
8680
|
},
|
|
8629
8681
|
async (module) => {
|
|
8630
|
-
const flowConfig = module.wireConfig(
|
|
8682
|
+
const flowConfig = module.wireConfig(
|
|
8683
|
+
options.data ?? module.__configData ?? void 0
|
|
8684
|
+
);
|
|
8631
8685
|
applyOverrides(flowConfig, prepared.overrides);
|
|
8632
8686
|
if (flowConfig.sources) flowConfig.sources = {};
|
|
8633
8687
|
if (flowConfig.destinations) flowConfig.destinations = {};
|
|
@@ -8730,7 +8784,9 @@ async function simulateDestination(configOrPath, event, options) {
|
|
|
8730
8784
|
networkCalls
|
|
8731
8785
|
},
|
|
8732
8786
|
async (module) => {
|
|
8733
|
-
const flowConfig = module.wireConfig(
|
|
8787
|
+
const flowConfig = module.wireConfig(
|
|
8788
|
+
options.data ?? module.__configData ?? void 0
|
|
8789
|
+
);
|
|
8734
8790
|
applyOverrides(flowConfig, prepared.overrides);
|
|
8735
8791
|
const destPkg = (prepared.flowSettings.destinations ?? {})[options.destinationId];
|
|
8736
8792
|
let trackedCalls = [];
|
|
@@ -8766,6 +8822,16 @@ async function simulateDestination(configOrPath, event, options) {
|
|
|
8766
8822
|
);
|
|
8767
8823
|
}
|
|
8768
8824
|
logger.info(`Simulating destination: ${options.destinationId}`);
|
|
8825
|
+
let mappingKey;
|
|
8826
|
+
const targetStepId = o("destination", options.destinationId);
|
|
8827
|
+
const captureMappingKey = (state) => {
|
|
8828
|
+
if (state.stepId === targetStepId && state.mappingKey) {
|
|
8829
|
+
mappingKey = state.mappingKey;
|
|
8830
|
+
}
|
|
8831
|
+
};
|
|
8832
|
+
if (collector.observers instanceof Set) {
|
|
8833
|
+
collector.observers.add(captureMappingKey);
|
|
8834
|
+
}
|
|
8769
8835
|
await collector.push(event, {
|
|
8770
8836
|
include: [options.destinationId]
|
|
8771
8837
|
});
|
|
@@ -8774,7 +8840,8 @@ async function simulateDestination(configOrPath, event, options) {
|
|
|
8774
8840
|
step: "destination",
|
|
8775
8841
|
name: options.destinationId,
|
|
8776
8842
|
startTime,
|
|
8777
|
-
usage: trackedCalls.length ? { [options.destinationId]: trackedCalls } : void 0
|
|
8843
|
+
usage: trackedCalls.length ? { [options.destinationId]: trackedCalls } : void 0,
|
|
8844
|
+
mappingKey
|
|
8778
8845
|
});
|
|
8779
8846
|
},
|
|
8780
8847
|
(error) => buildSimulationResult({
|
|
@@ -9499,13 +9566,21 @@ init_cache();
|
|
|
9499
9566
|
async function runPipeline(options) {
|
|
9500
9567
|
const { bundlePath, port, logger, loggerConfig, api } = options;
|
|
9501
9568
|
let configVersion;
|
|
9569
|
+
const configFrozen = readConfigFrozen();
|
|
9502
9570
|
if (api) {
|
|
9503
9571
|
await injectSecrets(api, logger);
|
|
9504
9572
|
}
|
|
9505
9573
|
logger.info(`walkeros/flow v${VERSION}`);
|
|
9506
9574
|
logger.info(`Instance: ${getInstanceId()}`);
|
|
9575
|
+
if (configFrozen) {
|
|
9576
|
+
logger.info("Config frozen: hot-swap and heartbeat disabled");
|
|
9577
|
+
}
|
|
9507
9578
|
const healthServer = await createHealthServer(port, logger);
|
|
9508
|
-
const
|
|
9579
|
+
const observeLevel = readObserveLevel(logger);
|
|
9580
|
+
const telemetryObservers = buildTelemetryObservers(
|
|
9581
|
+
api?.flowId ?? "flow",
|
|
9582
|
+
observeLevel
|
|
9583
|
+
);
|
|
9509
9584
|
const runtimeConfig = { port };
|
|
9510
9585
|
let handle;
|
|
9511
9586
|
try {
|
|
@@ -9534,20 +9609,24 @@ async function runPipeline(options) {
|
|
|
9534
9609
|
const ingestToken = process.env.WALKEROS_INGEST_TOKEN;
|
|
9535
9610
|
const deploymentId = process.env.WALKEROS_DEPLOYMENT_ID;
|
|
9536
9611
|
if (observerBase && ingestToken && deploymentId) {
|
|
9537
|
-
|
|
9538
|
-
|
|
9539
|
-
|
|
9540
|
-
|
|
9541
|
-
|
|
9542
|
-
|
|
9543
|
-
|
|
9544
|
-
|
|
9545
|
-
|
|
9546
|
-
|
|
9612
|
+
if (observeLevel === "trace") {
|
|
9613
|
+
logger.info("Trace poller: skipped (observe level is trace)");
|
|
9614
|
+
} else {
|
|
9615
|
+
tracePoller = createTracePoller(
|
|
9616
|
+
{
|
|
9617
|
+
url: `${observerBase}/trace/${deploymentId}`,
|
|
9618
|
+
token: ingestToken,
|
|
9619
|
+
intervalMs: 15e3
|
|
9620
|
+
},
|
|
9621
|
+
logger
|
|
9622
|
+
);
|
|
9623
|
+
tracePoller.start();
|
|
9624
|
+
logger.info("Trace poller: active (every 15s)");
|
|
9625
|
+
}
|
|
9547
9626
|
}
|
|
9548
9627
|
let currentBundleCleanup;
|
|
9549
9628
|
let currentConfigPath;
|
|
9550
|
-
if (api) {
|
|
9629
|
+
if (api && !configFrozen) {
|
|
9551
9630
|
heartbeat = createHeartbeat(
|
|
9552
9631
|
{
|
|
9553
9632
|
appUrl: api.appUrl,
|
|
@@ -9664,17 +9743,39 @@ async function runPipeline(options) {
|
|
|
9664
9743
|
await new Promise(() => {
|
|
9665
9744
|
});
|
|
9666
9745
|
}
|
|
9667
|
-
|
|
9746
|
+
var OBSERVE_LEVELS = [
|
|
9747
|
+
"off",
|
|
9748
|
+
"standard",
|
|
9749
|
+
"trace"
|
|
9750
|
+
];
|
|
9751
|
+
function readConfigFrozen() {
|
|
9752
|
+
const raw = process.env.WALKEROS_CONFIG_FROZEN;
|
|
9753
|
+
return raw === "1" || raw === "true";
|
|
9754
|
+
}
|
|
9755
|
+
function readObserveLevel(logger) {
|
|
9756
|
+
const raw = process.env.WALKEROS_OBSERVE_LEVEL;
|
|
9757
|
+
if (raw === void 0 || raw === "") return void 0;
|
|
9758
|
+
const level = OBSERVE_LEVELS.find((candidate) => candidate === raw);
|
|
9759
|
+
if (!level) {
|
|
9760
|
+
logger.warn(
|
|
9761
|
+
`Ignoring invalid WALKEROS_OBSERVE_LEVEL "${raw}" (expected off, standard, or trace)`
|
|
9762
|
+
);
|
|
9763
|
+
return void 0;
|
|
9764
|
+
}
|
|
9765
|
+
return level;
|
|
9766
|
+
}
|
|
9767
|
+
function buildTelemetryObservers(flowId, observeLevel) {
|
|
9668
9768
|
const base = process.env.WALKEROS_OBSERVER_URL;
|
|
9669
9769
|
const token = process.env.WALKEROS_INGEST_TOKEN;
|
|
9670
9770
|
const deploymentId = process.env.WALKEROS_DEPLOYMENT_ID;
|
|
9671
9771
|
if (!base || !token || !deploymentId) return void 0;
|
|
9672
9772
|
const url = `${base}/ingest/${deploymentId}`;
|
|
9673
9773
|
const emit = ht({ url, token });
|
|
9774
|
+
const observe = observeLevel !== void 0 ? { level: observeLevel } : void 0;
|
|
9674
9775
|
return [
|
|
9675
9776
|
ft(
|
|
9676
9777
|
emit,
|
|
9677
|
-
() => pt({ flowId, traceUntil: mt() })
|
|
9778
|
+
() => pt({ flowId, observe, traceUntil: mt() })
|
|
9678
9779
|
)
|
|
9679
9780
|
];
|
|
9680
9781
|
}
|
|
@@ -11402,7 +11503,8 @@ function n4(e4) {
|
|
|
11402
11503
|
return i3.set(r5, o4), o4;
|
|
11403
11504
|
}
|
|
11404
11505
|
function s5(e4) {
|
|
11405
|
-
|
|
11506
|
+
if ("object" != typeof e4 || null === e4) return false;
|
|
11507
|
+
return "events" in e4 && "object" == typeof e4.events && null !== e4.events || "schema" in e4;
|
|
11406
11508
|
}
|
|
11407
11509
|
function o3(e4, t4, r5) {
|
|
11408
11510
|
return e4[t4]?.[r5] ?? e4[t4]?.["*"] ?? e4["*"]?.[r5] ?? e4["*"]?.["*"];
|
|
@@ -11940,7 +12042,7 @@ function validateMapping(input) {
|
|
|
11940
12042
|
// src/commands/validate/validators/entry.ts
|
|
11941
12043
|
init_dist();
|
|
11942
12044
|
import Ajv from "ajv";
|
|
11943
|
-
var CLIENT_HEADER = "walkeros-cli/4.
|
|
12045
|
+
var CLIENT_HEADER = "walkeros-cli/4.3.0-next-1781171238534";
|
|
11944
12046
|
var SECTIONS = ["destinations", "sources", "transformers"];
|
|
11945
12047
|
function resolveEntry(path19, flowConfig) {
|
|
11946
12048
|
const flows = flowConfig.flows;
|
|
@@ -12575,6 +12677,7 @@ init_sse();
|
|
|
12575
12677
|
init_cli_logger();
|
|
12576
12678
|
init_output();
|
|
12577
12679
|
init_flows();
|
|
12680
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
12578
12681
|
async function resolveSettingsId(options) {
|
|
12579
12682
|
const flow = await getFlow({
|
|
12580
12683
|
flowId: options.flowId,
|
|
@@ -12600,8 +12703,9 @@ async function getAvailableFlowNames(options) {
|
|
|
12600
12703
|
const settings = flow.settings;
|
|
12601
12704
|
return settings?.map((c2) => c2.name) ?? [];
|
|
12602
12705
|
}
|
|
12706
|
+
var DEFAULT_DEPLOY_WAIT_MS = 12 * 60 * 1e3;
|
|
12603
12707
|
async function streamDeploymentStatus(projectId, deploymentId, options) {
|
|
12604
|
-
const timeoutMs = options.timeout ??
|
|
12708
|
+
const timeoutMs = options.timeout ?? DEFAULT_DEPLOY_WAIT_MS;
|
|
12605
12709
|
const response = await apiFetch(
|
|
12606
12710
|
`/api/projects/${projectId}/deployments/${deploymentId}/stream`,
|
|
12607
12711
|
{
|
|
@@ -12660,7 +12764,10 @@ async function deploy(options) {
|
|
|
12660
12764
|
}
|
|
12661
12765
|
const { data, error } = await client.POST(
|
|
12662
12766
|
"/api/projects/{projectId}/flows/{flowId}/deploy",
|
|
12663
|
-
{
|
|
12767
|
+
{
|
|
12768
|
+
params: { path: { projectId, flowId: options.flowId } },
|
|
12769
|
+
headers: { "Idempotency-Key": randomUUID2() }
|
|
12770
|
+
}
|
|
12664
12771
|
);
|
|
12665
12772
|
if (error) {
|
|
12666
12773
|
try {
|
|
@@ -12690,13 +12797,38 @@ Available: ${names.join(", ")}`,
|
|
|
12690
12797
|
}
|
|
12691
12798
|
async function deploySettings(options) {
|
|
12692
12799
|
const { flowId, projectId, settingsId } = options;
|
|
12693
|
-
const
|
|
12800
|
+
const triggerDeploy = () => apiFetch(
|
|
12694
12801
|
`/api/projects/${projectId}/flows/${flowId}/settings/${settingsId}/deploy`,
|
|
12695
|
-
{ method: "POST" }
|
|
12802
|
+
{ method: "POST", headers: { "Idempotency-Key": randomUUID2() } }
|
|
12696
12803
|
);
|
|
12804
|
+
let response = await triggerDeploy();
|
|
12805
|
+
if (!response.ok && options.wait) {
|
|
12806
|
+
let retryBody = {};
|
|
12807
|
+
try {
|
|
12808
|
+
retryBody = await response.clone().json();
|
|
12809
|
+
} catch {
|
|
12810
|
+
retryBody = {};
|
|
12811
|
+
}
|
|
12812
|
+
try {
|
|
12813
|
+
throwApiResponseError(
|
|
12814
|
+
response,
|
|
12815
|
+
retryBody,
|
|
12816
|
+
`Deploy failed (${response.status})`
|
|
12817
|
+
);
|
|
12818
|
+
} catch (e4) {
|
|
12819
|
+
if (e4 instanceof ApiError && e4.retryable) {
|
|
12820
|
+
const waitSeconds = Math.min(e4.retryAfterSeconds ?? 5, 60);
|
|
12821
|
+
options.onStatus?.("rate_limited", `retrying in ${waitSeconds}s`);
|
|
12822
|
+
await new Promise((resolve4) => setTimeout(resolve4, waitSeconds * 1e3));
|
|
12823
|
+
response = await triggerDeploy();
|
|
12824
|
+
} else {
|
|
12825
|
+
throw e4;
|
|
12826
|
+
}
|
|
12827
|
+
}
|
|
12828
|
+
}
|
|
12697
12829
|
if (!response.ok) {
|
|
12698
12830
|
const body = await response.json().catch(() => ({}));
|
|
12699
|
-
|
|
12831
|
+
throwApiResponseError(response, body, `Deploy failed (${response.status})`);
|
|
12700
12832
|
}
|
|
12701
12833
|
const data = await response.json();
|
|
12702
12834
|
if (!options.wait) return data;
|
|
@@ -12708,16 +12840,20 @@ async function deploySettings(options) {
|
|
|
12708
12840
|
return { ...data, ...result };
|
|
12709
12841
|
}
|
|
12710
12842
|
var statusLabels = {
|
|
12711
|
-
|
|
12712
|
-
"
|
|
12713
|
-
"bundling:publishing": "Publishing to web...",
|
|
12714
|
-
deploying: "Deploying container...",
|
|
12843
|
+
"deploying:building": "Building bundle...",
|
|
12844
|
+
"deploying:publishing": "Publishing to web...",
|
|
12715
12845
|
"deploying:provisioning": "Provisioning container...",
|
|
12716
12846
|
"deploying:starting": "Starting container...",
|
|
12847
|
+
deploying: "Deploying...",
|
|
12717
12848
|
active: "Container is live",
|
|
12718
12849
|
published: "Published",
|
|
12850
|
+
stopped: "Stopped",
|
|
12719
12851
|
failed: "Deployment failed"
|
|
12720
12852
|
};
|
|
12853
|
+
function renderStatusLabel(status, substatus) {
|
|
12854
|
+
const key = substatus ? `${status}:${substatus}` : status;
|
|
12855
|
+
return statusLabels[key] || statusLabels[status] || `Status: ${status}`;
|
|
12856
|
+
}
|
|
12721
12857
|
async function deployCommand(flowId, options) {
|
|
12722
12858
|
const log = createCLILogger(options);
|
|
12723
12859
|
const timeoutMs = options.timeout ? parseInt(options.timeout, 10) * 1e3 : void 0;
|
|
@@ -12729,10 +12865,7 @@ async function deployCommand(flowId, options) {
|
|
|
12729
12865
|
wait: options.wait !== false,
|
|
12730
12866
|
timeout: timeoutMs,
|
|
12731
12867
|
onStatus: options.json ? void 0 : (status, substatus) => {
|
|
12732
|
-
|
|
12733
|
-
log.info(
|
|
12734
|
-
statusLabels[key] || statusLabels[status] || `Status: ${status}`
|
|
12735
|
-
);
|
|
12868
|
+
log.info(renderStatusLabel(status, substatus));
|
|
12736
12869
|
}
|
|
12737
12870
|
});
|
|
12738
12871
|
if (options.json) {
|
|
@@ -12747,7 +12880,7 @@ async function deployCommand(flowId, options) {
|
|
|
12747
12880
|
} else if (r5.status === "failed") {
|
|
12748
12881
|
log.error(`Failed: ${r5.errorMessage || "Unknown error"}`);
|
|
12749
12882
|
process.exit(1);
|
|
12750
|
-
} else if (r5.status === "
|
|
12883
|
+
} else if (r5.status === "deploying") {
|
|
12751
12884
|
log.info(`Deployment started: ${r5.deploymentId} (${r5.type})`);
|
|
12752
12885
|
} else {
|
|
12753
12886
|
log.info(`Status: ${r5.status}`);
|
|
@@ -12902,20 +13035,16 @@ async function createDeployCommand(config, options) {
|
|
|
12902
13035
|
log.info(`Deployment created: ${result.id}`);
|
|
12903
13036
|
log.info(` Slug: ${result.slug}`);
|
|
12904
13037
|
log.info(` Type: ${result.type}`);
|
|
12905
|
-
if (result.deployToken) {
|
|
12906
|
-
log.info(` Token: ${result.deployToken}`);
|
|
12907
|
-
log.warn(" Save this token \u2014 it will not be shown again.");
|
|
12908
|
-
}
|
|
12909
13038
|
log.info("");
|
|
12910
13039
|
log.info("Run locally:");
|
|
12911
13040
|
log.info(
|
|
12912
13041
|
` walkeros run ${isRemoteFlow ? "flow.json" : config} --deploy ${result.id}`
|
|
12913
13042
|
);
|
|
12914
13043
|
log.info("");
|
|
12915
|
-
log.info("
|
|
12916
|
-
log.info(
|
|
12917
|
-
|
|
12918
|
-
);
|
|
13044
|
+
log.info("Create a deploy token for this flow in the app");
|
|
13045
|
+
log.info("(Settings, Self-hosted deploy token) and set it as");
|
|
13046
|
+
log.info("WALKEROS_DEPLOY_TOKEN, then run with Docker:");
|
|
13047
|
+
log.info(" docker run -e WALKEROS_DEPLOY_TOKEN \\");
|
|
12919
13048
|
log.info(" -e WALKEROS_APP_URL=https://app.walkeros.io \\");
|
|
12920
13049
|
log.info(" walkeros/flow:latest");
|
|
12921
13050
|
} catch (err) {
|
|
@@ -13231,7 +13360,7 @@ deployCmd.command("create [config]").description(
|
|
|
13231
13360
|
});
|
|
13232
13361
|
deployCmd.command("start <flowId>").description("Deploy a flow to walkerOS cloud (auto-detects web or server)").option("--project <id>", "project ID (defaults to WALKEROS_PROJECT_ID)").option("-f, --flow <name>", "flow name for multi-config flows").option("--no-wait", "do not wait for deployment to complete").option(
|
|
13233
13362
|
"--timeout <seconds>",
|
|
13234
|
-
"timeout for deployment polling (default:
|
|
13363
|
+
"timeout in seconds for deployment polling (default: 720, the 12-minute server deploy budget)"
|
|
13235
13364
|
).option("-o, --output <path>", "output file path").option("--json", "output as JSON").option("-v, --verbose", "verbose output").option("-s, --silent", "suppress output").action(async (flowId, options) => {
|
|
13236
13365
|
await deployCommand(flowId, options);
|
|
13237
13366
|
});
|