@walkeros/cli 4.2.0 → 4.2.1-next-1781526381392
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 +34 -0
- package/dist/cli.js +315 -79
- package/dist/index.d.ts +855 -119
- package/dist/index.js +330 -85
- package/dist/index.js.map +1 -1
- package/openapi/spec.json +2599 -1580
- package/package.json +8 -8
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
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
34
|
+
function extractApiErrorOptions(error, fallbackMessage) {
|
|
35
|
+
if (!error || typeof error !== "object" || !("error" in error) || typeof error.error !== "object") {
|
|
36
|
+
return null;
|
|
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
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;
|
|
@@ -4570,7 +4618,7 @@ ${destinationsEntries.join(",\n")}
|
|
|
4570
4618
|
stores${collectorStr}
|
|
4571
4619
|
}`;
|
|
4572
4620
|
const dataPayload = JSON.stringify(dataPayloadObj, null, 2);
|
|
4573
|
-
return { storesDeclaration, codeConfigObject, dataPayload };
|
|
4621
|
+
return { storesDeclaration, codeConfigObject, dataPayloadObj, dataPayload };
|
|
4574
4622
|
}
|
|
4575
4623
|
function generateSplitWireConfigModule(storesDeclaration, codeConfigObject, userCode) {
|
|
4576
4624
|
const codeSection = userCode ? `
|
|
@@ -5314,7 +5362,7 @@ var init_contract = __esm({
|
|
|
5314
5362
|
"src/core/contract.ts"() {
|
|
5315
5363
|
"use strict";
|
|
5316
5364
|
init_config_file();
|
|
5317
|
-
bakedContractVersion = true ? "
|
|
5365
|
+
bakedContractVersion = true ? "2.0.0" : PLACEHOLDER;
|
|
5318
5366
|
}
|
|
5319
5367
|
});
|
|
5320
5368
|
|
|
@@ -6698,7 +6746,7 @@ async function wt(e4, t4, o4) {
|
|
|
6698
6746
|
}
|
|
6699
6747
|
}
|
|
6700
6748
|
function vt(e4, t4) {
|
|
6701
|
-
return { timing: Math.round((Date.now() - e4.timing) / 10) / 100, source: { type: "collector", schema: "4", version: "4.2.
|
|
6749
|
+
return { timing: Math.round((Date.now() - e4.timing) / 10) / 100, source: { type: "collector", schema: "4", version: "4.2.1-next-1781526381392" }, ...t4 };
|
|
6702
6750
|
}
|
|
6703
6751
|
function bt(e4, t4) {
|
|
6704
6752
|
if (!t4.name) throw new Error("Event name is required");
|
|
@@ -7451,13 +7499,13 @@ function installTimerInterception(options = {}) {
|
|
|
7451
7499
|
setInterval: Reflect.get(target, "setInterval"),
|
|
7452
7500
|
clearInterval: Reflect.get(target, "clearInterval")
|
|
7453
7501
|
});
|
|
7454
|
-
const trackedSetTimeout = (callback,
|
|
7502
|
+
const trackedSetTimeout = (callback, delay2, ...args) => {
|
|
7455
7503
|
if (typeof callback !== "function") return 0;
|
|
7456
7504
|
const id = nextId++;
|
|
7457
7505
|
pending.set(id, {
|
|
7458
7506
|
id,
|
|
7459
7507
|
callback,
|
|
7460
|
-
delay:
|
|
7508
|
+
delay: delay2 ?? 0,
|
|
7461
7509
|
type: "timeout",
|
|
7462
7510
|
args,
|
|
7463
7511
|
cleared: false
|
|
@@ -7470,13 +7518,13 @@ function installTimerInterception(options = {}) {
|
|
|
7470
7518
|
const entry = pending.get(numId);
|
|
7471
7519
|
if (entry) entry.cleared = true;
|
|
7472
7520
|
};
|
|
7473
|
-
const trackedSetInterval = (callback,
|
|
7521
|
+
const trackedSetInterval = (callback, delay2, ...args) => {
|
|
7474
7522
|
if (typeof callback !== "function") return 0;
|
|
7475
7523
|
const id = nextId++;
|
|
7476
7524
|
pending.set(id, {
|
|
7477
7525
|
id,
|
|
7478
7526
|
callback,
|
|
7479
|
-
delay:
|
|
7527
|
+
delay: delay2 ?? 0,
|
|
7480
7528
|
type: "interval",
|
|
7481
7529
|
args,
|
|
7482
7530
|
cleared: false
|
|
@@ -7753,7 +7801,7 @@ function toError(error) {
|
|
|
7753
7801
|
return error instanceof Error ? error : new Error(getErrorMessage(error));
|
|
7754
7802
|
}
|
|
7755
7803
|
function buildSimulationResult(args) {
|
|
7756
|
-
const { step, name, startTime, captured, usage, error } = args;
|
|
7804
|
+
const { step, name, startTime, captured, usage, mappingKey, error } = args;
|
|
7757
7805
|
const events = (captured ?? []).filter(hasEvent).map((entry) => entry.event);
|
|
7758
7806
|
const calls = usage ? Object.values(usage).flat().map((call) => ({ fn: call.fn, args: call.args, ts: call.ts })) : [];
|
|
7759
7807
|
return {
|
|
@@ -7762,6 +7810,7 @@ function buildSimulationResult(args) {
|
|
|
7762
7810
|
events,
|
|
7763
7811
|
calls,
|
|
7764
7812
|
duration: Date.now() - startTime,
|
|
7813
|
+
...mappingKey !== void 0 ? { mappingKey } : {},
|
|
7765
7814
|
...error !== void 0 ? { error: toError(error) } : {}
|
|
7766
7815
|
};
|
|
7767
7816
|
}
|
|
@@ -8355,7 +8404,9 @@ async function simulateSource(configOrPath, input, options) {
|
|
|
8355
8404
|
`Source package "${sourceConfig.package}" has no createTrigger in /dev export`
|
|
8356
8405
|
);
|
|
8357
8406
|
}
|
|
8358
|
-
const flowConfig = module.wireConfig(
|
|
8407
|
+
const flowConfig = module.wireConfig(
|
|
8408
|
+
options.data ?? module.__configData ?? void 0
|
|
8409
|
+
);
|
|
8359
8410
|
applyOverrides(flowConfig, prepared.overrides);
|
|
8360
8411
|
const captured = [];
|
|
8361
8412
|
flowConfig.hooks = {
|
|
@@ -8460,7 +8511,9 @@ async function simulateTransformer(configOrPath, event, options) {
|
|
|
8460
8511
|
networkCalls
|
|
8461
8512
|
},
|
|
8462
8513
|
async (module) => {
|
|
8463
|
-
const flowConfig = module.wireConfig(
|
|
8514
|
+
const flowConfig = module.wireConfig(
|
|
8515
|
+
options.data ?? module.__configData ?? void 0
|
|
8516
|
+
);
|
|
8464
8517
|
applyOverrides(flowConfig, prepared.overrides);
|
|
8465
8518
|
if (flowConfig.sources) flowConfig.sources = {};
|
|
8466
8519
|
if (flowConfig.destinations) flowConfig.destinations = {};
|
|
@@ -8626,7 +8679,9 @@ async function simulateCollector(configOrPath, event, options) {
|
|
|
8626
8679
|
networkCalls
|
|
8627
8680
|
},
|
|
8628
8681
|
async (module) => {
|
|
8629
|
-
const flowConfig = module.wireConfig(
|
|
8682
|
+
const flowConfig = module.wireConfig(
|
|
8683
|
+
options.data ?? module.__configData ?? void 0
|
|
8684
|
+
);
|
|
8630
8685
|
applyOverrides(flowConfig, prepared.overrides);
|
|
8631
8686
|
if (flowConfig.sources) flowConfig.sources = {};
|
|
8632
8687
|
if (flowConfig.destinations) flowConfig.destinations = {};
|
|
@@ -8729,7 +8784,9 @@ async function simulateDestination(configOrPath, event, options) {
|
|
|
8729
8784
|
networkCalls
|
|
8730
8785
|
},
|
|
8731
8786
|
async (module) => {
|
|
8732
|
-
const flowConfig = module.wireConfig(
|
|
8787
|
+
const flowConfig = module.wireConfig(
|
|
8788
|
+
options.data ?? module.__configData ?? void 0
|
|
8789
|
+
);
|
|
8733
8790
|
applyOverrides(flowConfig, prepared.overrides);
|
|
8734
8791
|
const destPkg = (prepared.flowSettings.destinations ?? {})[options.destinationId];
|
|
8735
8792
|
let trackedCalls = [];
|
|
@@ -8765,6 +8822,16 @@ async function simulateDestination(configOrPath, event, options) {
|
|
|
8765
8822
|
);
|
|
8766
8823
|
}
|
|
8767
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
|
+
}
|
|
8768
8835
|
await collector.push(event, {
|
|
8769
8836
|
include: [options.destinationId]
|
|
8770
8837
|
});
|
|
@@ -8773,7 +8840,8 @@ async function simulateDestination(configOrPath, event, options) {
|
|
|
8773
8840
|
step: "destination",
|
|
8774
8841
|
name: options.destinationId,
|
|
8775
8842
|
startTime,
|
|
8776
|
-
usage: trackedCalls.length ? { [options.destinationId]: trackedCalls } : void 0
|
|
8843
|
+
usage: trackedCalls.length ? { [options.destinationId]: trackedCalls } : void 0,
|
|
8844
|
+
mappingKey
|
|
8777
8845
|
});
|
|
8778
8846
|
},
|
|
8779
8847
|
(error) => buildSimulationResult({
|
|
@@ -8818,8 +8886,117 @@ import {
|
|
|
8818
8886
|
import { dirname as dirname4, join as join5 } from "path";
|
|
8819
8887
|
import { Readable } from "stream";
|
|
8820
8888
|
import { x as tarExtract } from "tar";
|
|
8889
|
+
|
|
8890
|
+
// src/runtime/fetch-retry.ts
|
|
8891
|
+
var DEFAULT_PER_ATTEMPT_TIMEOUT_MS = 3e4;
|
|
8892
|
+
var DEFAULT_MAX_TOTAL_MS = 6e4;
|
|
8893
|
+
var DEFAULT_ATTEMPTS = 3;
|
|
8894
|
+
var MIN_ATTEMPT_BUDGET_MS = 1e3;
|
|
8895
|
+
var BASE_BACKOFF_MS = [2e3, 5e3];
|
|
8896
|
+
var JITTER = 0.2;
|
|
8897
|
+
var RETRYABLE_NETWORK_CODES = /* @__PURE__ */ new Set([
|
|
8898
|
+
"ECONNRESET",
|
|
8899
|
+
"ECONNREFUSED",
|
|
8900
|
+
"ETIMEDOUT",
|
|
8901
|
+
"EAI_AGAIN",
|
|
8902
|
+
"ENOTFOUND"
|
|
8903
|
+
]);
|
|
8904
|
+
function readErrorCode(value) {
|
|
8905
|
+
if (typeof value !== "object" || value === null) return void 0;
|
|
8906
|
+
const code = Reflect.get(value, "code");
|
|
8907
|
+
return typeof code === "string" ? code : void 0;
|
|
8908
|
+
}
|
|
8909
|
+
function readErrorName(value) {
|
|
8910
|
+
if (typeof value !== "object" || value === null) return void 0;
|
|
8911
|
+
const name = Reflect.get(value, "name");
|
|
8912
|
+
return typeof name === "string" ? name : void 0;
|
|
8913
|
+
}
|
|
8914
|
+
function isTransientThrow(error) {
|
|
8915
|
+
const name = readErrorName(error);
|
|
8916
|
+
if (name === "TimeoutError" || name === "AbortError") return true;
|
|
8917
|
+
const directCode = readErrorCode(error);
|
|
8918
|
+
if (directCode && RETRYABLE_NETWORK_CODES.has(directCode)) return true;
|
|
8919
|
+
if (typeof error === "object" && error !== null) {
|
|
8920
|
+
const causeCode = readErrorCode(Reflect.get(error, "cause"));
|
|
8921
|
+
if (causeCode && RETRYABLE_NETWORK_CODES.has(causeCode)) return true;
|
|
8922
|
+
}
|
|
8923
|
+
return error instanceof TypeError;
|
|
8924
|
+
}
|
|
8925
|
+
function isTransientStatus(status) {
|
|
8926
|
+
return status >= 500 || status === 429;
|
|
8927
|
+
}
|
|
8928
|
+
function readErrorMessage(value) {
|
|
8929
|
+
if (typeof value !== "object" || value === null) return void 0;
|
|
8930
|
+
const message = Reflect.get(value, "message");
|
|
8931
|
+
return typeof message === "string" ? message : void 0;
|
|
8932
|
+
}
|
|
8933
|
+
function describeReason(reason) {
|
|
8934
|
+
if (reason.kind === "status") return `HTTP ${reason.status}`;
|
|
8935
|
+
const name = readErrorName(reason.error);
|
|
8936
|
+
const message = reason.error instanceof Error ? reason.error.message : String(reason.error);
|
|
8937
|
+
let detail = name ? `${name}: ${message}` : message;
|
|
8938
|
+
if (typeof reason.error === "object" && reason.error !== null) {
|
|
8939
|
+
const cause = Reflect.get(reason.error, "cause");
|
|
8940
|
+
const causeCode = readErrorCode(cause);
|
|
8941
|
+
const causeMessage = readErrorMessage(cause);
|
|
8942
|
+
const causeDetail = causeCode ?? causeMessage;
|
|
8943
|
+
if (causeDetail) detail = `${detail} (${causeDetail})`;
|
|
8944
|
+
}
|
|
8945
|
+
return detail;
|
|
8946
|
+
}
|
|
8947
|
+
function backoffForAttempt(index) {
|
|
8948
|
+
const base = BASE_BACKOFF_MS[Math.min(index, BASE_BACKOFF_MS.length - 1)] ?? 0;
|
|
8949
|
+
const spread = base * JITTER;
|
|
8950
|
+
return base + (Math.random() * 2 - 1) * spread;
|
|
8951
|
+
}
|
|
8952
|
+
function delay(ms) {
|
|
8953
|
+
return new Promise((resolve4) => {
|
|
8954
|
+
setTimeout(resolve4, ms);
|
|
8955
|
+
});
|
|
8956
|
+
}
|
|
8957
|
+
async function fetchWithRetry(url, options = {}) {
|
|
8958
|
+
const attempts = options.attempts ?? DEFAULT_ATTEMPTS;
|
|
8959
|
+
const perAttemptTimeoutMs = options.perAttemptTimeoutMs ?? DEFAULT_PER_ATTEMPT_TIMEOUT_MS;
|
|
8960
|
+
const maxTotalMs = options.maxTotalMs ?? DEFAULT_MAX_TOTAL_MS;
|
|
8961
|
+
const init = options.init;
|
|
8962
|
+
const start = Date.now();
|
|
8963
|
+
let lastReason;
|
|
8964
|
+
let made = 0;
|
|
8965
|
+
for (let attempt = 0; attempt < attempts; attempt++) {
|
|
8966
|
+
const remaining = maxTotalMs - (Date.now() - start);
|
|
8967
|
+
if (remaining <= MIN_ATTEMPT_BUDGET_MS) break;
|
|
8968
|
+
const attemptTimeoutMs = Math.min(perAttemptTimeoutMs, remaining);
|
|
8969
|
+
made = attempt + 1;
|
|
8970
|
+
let reason;
|
|
8971
|
+
try {
|
|
8972
|
+
const response = await fetch(url, {
|
|
8973
|
+
...init,
|
|
8974
|
+
signal: AbortSignal.timeout(attemptTimeoutMs)
|
|
8975
|
+
});
|
|
8976
|
+
if (!isTransientStatus(response.status)) return response;
|
|
8977
|
+
await response.body?.cancel();
|
|
8978
|
+
reason = { kind: "status", status: response.status };
|
|
8979
|
+
} catch (error) {
|
|
8980
|
+
if (!isTransientThrow(error)) throw error;
|
|
8981
|
+
reason = { kind: "throw", error };
|
|
8982
|
+
}
|
|
8983
|
+
lastReason = reason;
|
|
8984
|
+
const isLastAttempt = attempt === attempts - 1;
|
|
8985
|
+
const budgetSpent = Date.now() - start >= maxTotalMs;
|
|
8986
|
+
if (isLastAttempt || budgetSpent) break;
|
|
8987
|
+
const sleepMs = Math.min(
|
|
8988
|
+
backoffForAttempt(attempt),
|
|
8989
|
+
maxTotalMs - (Date.now() - start)
|
|
8990
|
+
);
|
|
8991
|
+
if (sleepMs <= 0) break;
|
|
8992
|
+
await delay(sleepMs);
|
|
8993
|
+
}
|
|
8994
|
+
const cause = lastReason ? describeReason(lastReason) : "no attempts made";
|
|
8995
|
+
throw new Error(`Fetch failed after ${made} attempts: ${cause}`);
|
|
8996
|
+
}
|
|
8997
|
+
|
|
8998
|
+
// src/runtime/resolve-bundle.ts
|
|
8821
8999
|
var ARCHIVE_ENTRY = "flow.mjs";
|
|
8822
|
-
var FETCH_TIMEOUT_MS = 3e4;
|
|
8823
9000
|
function getDefaultWritePath() {
|
|
8824
9001
|
if (existsSync2("/app/flow")) return "/app/flow/flow.mjs";
|
|
8825
9002
|
return "/tmp/walkeros-flow.mjs";
|
|
@@ -8844,9 +9021,7 @@ function writeBundleToDisk(writePath, content) {
|
|
|
8844
9021
|
writeFileSync2(writePath, content, "utf-8");
|
|
8845
9022
|
}
|
|
8846
9023
|
async function fetchOk(url) {
|
|
8847
|
-
const response = await
|
|
8848
|
-
signal: AbortSignal.timeout(FETCH_TIMEOUT_MS)
|
|
8849
|
-
});
|
|
9024
|
+
const response = await fetchWithRetry(url);
|
|
8850
9025
|
if (!response.ok) {
|
|
8851
9026
|
throw new Error(
|
|
8852
9027
|
`Failed to fetch bundle from ${url}: ${response.status} ${response.statusText}`
|
|
@@ -8967,10 +9142,7 @@ async function fetchConfig(options) {
|
|
|
8967
9142
|
options.token,
|
|
8968
9143
|
options.lastEtag ? { "If-None-Match": options.lastEtag } : void 0
|
|
8969
9144
|
);
|
|
8970
|
-
const response = await
|
|
8971
|
-
headers,
|
|
8972
|
-
signal: AbortSignal.timeout(3e4)
|
|
8973
|
-
});
|
|
9145
|
+
const response = await fetchWithRetry(url, { init: { headers } });
|
|
8974
9146
|
if (response.status === 304) {
|
|
8975
9147
|
return { changed: false };
|
|
8976
9148
|
}
|
|
@@ -9482,8 +9654,11 @@ var SecretsHttpError = class extends Error {
|
|
|
9482
9654
|
async function fetchSecrets(options) {
|
|
9483
9655
|
const { appUrl, token, projectId, flowId } = options;
|
|
9484
9656
|
const url = `${appUrl}/api/projects/${encodeURIComponent(projectId)}/flows/${encodeURIComponent(flowId)}/secrets/values`;
|
|
9485
|
-
const res = await
|
|
9486
|
-
|
|
9657
|
+
const res = await fetchWithRetry(url, {
|
|
9658
|
+
maxTotalMs: 2e4,
|
|
9659
|
+
init: {
|
|
9660
|
+
headers: mergeAuthHeaders(token, { "Content-Type": "application/json" })
|
|
9661
|
+
}
|
|
9487
9662
|
});
|
|
9488
9663
|
await throwIfRunnerAuthFailure(res);
|
|
9489
9664
|
if (!res.ok) {
|
|
@@ -9498,13 +9673,21 @@ init_cache();
|
|
|
9498
9673
|
async function runPipeline(options) {
|
|
9499
9674
|
const { bundlePath, port, logger, loggerConfig, api } = options;
|
|
9500
9675
|
let configVersion;
|
|
9676
|
+
const configFrozen = readConfigFrozen();
|
|
9501
9677
|
if (api) {
|
|
9502
9678
|
await injectSecrets(api, logger);
|
|
9503
9679
|
}
|
|
9504
9680
|
logger.info(`walkeros/flow v${VERSION}`);
|
|
9505
9681
|
logger.info(`Instance: ${getInstanceId()}`);
|
|
9682
|
+
if (configFrozen) {
|
|
9683
|
+
logger.info("Config frozen: hot-swap and heartbeat disabled");
|
|
9684
|
+
}
|
|
9506
9685
|
const healthServer = await createHealthServer(port, logger);
|
|
9507
|
-
const
|
|
9686
|
+
const observeLevel = readObserveLevel(logger);
|
|
9687
|
+
const telemetryObservers = buildTelemetryObservers(
|
|
9688
|
+
api?.flowId ?? "flow",
|
|
9689
|
+
observeLevel
|
|
9690
|
+
);
|
|
9508
9691
|
const runtimeConfig = { port };
|
|
9509
9692
|
let handle;
|
|
9510
9693
|
try {
|
|
@@ -9533,20 +9716,24 @@ async function runPipeline(options) {
|
|
|
9533
9716
|
const ingestToken = process.env.WALKEROS_INGEST_TOKEN;
|
|
9534
9717
|
const deploymentId = process.env.WALKEROS_DEPLOYMENT_ID;
|
|
9535
9718
|
if (observerBase && ingestToken && deploymentId) {
|
|
9536
|
-
|
|
9537
|
-
|
|
9538
|
-
|
|
9539
|
-
|
|
9540
|
-
|
|
9541
|
-
|
|
9542
|
-
|
|
9543
|
-
|
|
9544
|
-
|
|
9545
|
-
|
|
9719
|
+
if (observeLevel === "trace") {
|
|
9720
|
+
logger.info("Trace poller: skipped (observe level is trace)");
|
|
9721
|
+
} else {
|
|
9722
|
+
tracePoller = createTracePoller(
|
|
9723
|
+
{
|
|
9724
|
+
url: `${observerBase}/trace/${deploymentId}`,
|
|
9725
|
+
token: ingestToken,
|
|
9726
|
+
intervalMs: 15e3
|
|
9727
|
+
},
|
|
9728
|
+
logger
|
|
9729
|
+
);
|
|
9730
|
+
tracePoller.start();
|
|
9731
|
+
logger.info("Trace poller: active (every 15s)");
|
|
9732
|
+
}
|
|
9546
9733
|
}
|
|
9547
9734
|
let currentBundleCleanup;
|
|
9548
9735
|
let currentConfigPath;
|
|
9549
|
-
if (api) {
|
|
9736
|
+
if (api && !configFrozen) {
|
|
9550
9737
|
heartbeat = createHeartbeat(
|
|
9551
9738
|
{
|
|
9552
9739
|
appUrl: api.appUrl,
|
|
@@ -9663,17 +9850,39 @@ async function runPipeline(options) {
|
|
|
9663
9850
|
await new Promise(() => {
|
|
9664
9851
|
});
|
|
9665
9852
|
}
|
|
9666
|
-
|
|
9853
|
+
var OBSERVE_LEVELS = [
|
|
9854
|
+
"off",
|
|
9855
|
+
"standard",
|
|
9856
|
+
"trace"
|
|
9857
|
+
];
|
|
9858
|
+
function readConfigFrozen() {
|
|
9859
|
+
const raw = process.env.WALKEROS_CONFIG_FROZEN;
|
|
9860
|
+
return raw === "1" || raw === "true";
|
|
9861
|
+
}
|
|
9862
|
+
function readObserveLevel(logger) {
|
|
9863
|
+
const raw = process.env.WALKEROS_OBSERVE_LEVEL;
|
|
9864
|
+
if (raw === void 0 || raw === "") return void 0;
|
|
9865
|
+
const level = OBSERVE_LEVELS.find((candidate) => candidate === raw);
|
|
9866
|
+
if (!level) {
|
|
9867
|
+
logger.warn(
|
|
9868
|
+
`Ignoring invalid WALKEROS_OBSERVE_LEVEL "${raw}" (expected off, standard, or trace)`
|
|
9869
|
+
);
|
|
9870
|
+
return void 0;
|
|
9871
|
+
}
|
|
9872
|
+
return level;
|
|
9873
|
+
}
|
|
9874
|
+
function buildTelemetryObservers(flowId, observeLevel) {
|
|
9667
9875
|
const base = process.env.WALKEROS_OBSERVER_URL;
|
|
9668
9876
|
const token = process.env.WALKEROS_INGEST_TOKEN;
|
|
9669
9877
|
const deploymentId = process.env.WALKEROS_DEPLOYMENT_ID;
|
|
9670
9878
|
if (!base || !token || !deploymentId) return void 0;
|
|
9671
9879
|
const url = `${base}/ingest/${deploymentId}`;
|
|
9672
9880
|
const emit = ht({ url, token });
|
|
9881
|
+
const observe = observeLevel !== void 0 ? { level: observeLevel } : void 0;
|
|
9673
9882
|
return [
|
|
9674
9883
|
ft(
|
|
9675
9884
|
emit,
|
|
9676
|
-
() => pt({ flowId, traceUntil: mt() })
|
|
9885
|
+
() => pt({ flowId, observe, traceUntil: mt() })
|
|
9677
9886
|
)
|
|
9678
9887
|
];
|
|
9679
9888
|
}
|
|
@@ -11940,7 +12149,7 @@ function validateMapping(input) {
|
|
|
11940
12149
|
// src/commands/validate/validators/entry.ts
|
|
11941
12150
|
init_dist();
|
|
11942
12151
|
import Ajv from "ajv";
|
|
11943
|
-
var CLIENT_HEADER = "walkeros-cli/4.2.
|
|
12152
|
+
var CLIENT_HEADER = "walkeros-cli/4.2.1-next-1781526381392";
|
|
11944
12153
|
var SECTIONS = ["destinations", "sources", "transformers"];
|
|
11945
12154
|
function resolveEntry(path19, flowConfig) {
|
|
11946
12155
|
const flows = flowConfig.flows;
|
|
@@ -12575,6 +12784,7 @@ init_sse();
|
|
|
12575
12784
|
init_cli_logger();
|
|
12576
12785
|
init_output();
|
|
12577
12786
|
init_flows();
|
|
12787
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
12578
12788
|
async function resolveSettingsId(options) {
|
|
12579
12789
|
const flow = await getFlow({
|
|
12580
12790
|
flowId: options.flowId,
|
|
@@ -12600,8 +12810,9 @@ async function getAvailableFlowNames(options) {
|
|
|
12600
12810
|
const settings = flow.settings;
|
|
12601
12811
|
return settings?.map((c2) => c2.name) ?? [];
|
|
12602
12812
|
}
|
|
12813
|
+
var DEFAULT_DEPLOY_WAIT_MS = 12 * 60 * 1e3;
|
|
12603
12814
|
async function streamDeploymentStatus(projectId, deploymentId, options) {
|
|
12604
|
-
const timeoutMs = options.timeout ??
|
|
12815
|
+
const timeoutMs = options.timeout ?? DEFAULT_DEPLOY_WAIT_MS;
|
|
12605
12816
|
const response = await apiFetch(
|
|
12606
12817
|
`/api/projects/${projectId}/deployments/${deploymentId}/stream`,
|
|
12607
12818
|
{
|
|
@@ -12660,7 +12871,10 @@ async function deploy(options) {
|
|
|
12660
12871
|
}
|
|
12661
12872
|
const { data, error } = await client.POST(
|
|
12662
12873
|
"/api/projects/{projectId}/flows/{flowId}/deploy",
|
|
12663
|
-
{
|
|
12874
|
+
{
|
|
12875
|
+
params: { path: { projectId, flowId: options.flowId } },
|
|
12876
|
+
headers: { "Idempotency-Key": randomUUID2() }
|
|
12877
|
+
}
|
|
12664
12878
|
);
|
|
12665
12879
|
if (error) {
|
|
12666
12880
|
try {
|
|
@@ -12690,13 +12904,38 @@ Available: ${names.join(", ")}`,
|
|
|
12690
12904
|
}
|
|
12691
12905
|
async function deploySettings(options) {
|
|
12692
12906
|
const { flowId, projectId, settingsId } = options;
|
|
12693
|
-
const
|
|
12907
|
+
const triggerDeploy = () => apiFetch(
|
|
12694
12908
|
`/api/projects/${projectId}/flows/${flowId}/settings/${settingsId}/deploy`,
|
|
12695
|
-
{ method: "POST" }
|
|
12909
|
+
{ method: "POST", headers: { "Idempotency-Key": randomUUID2() } }
|
|
12696
12910
|
);
|
|
12911
|
+
let response = await triggerDeploy();
|
|
12912
|
+
if (!response.ok && options.wait) {
|
|
12913
|
+
let retryBody = {};
|
|
12914
|
+
try {
|
|
12915
|
+
retryBody = await response.clone().json();
|
|
12916
|
+
} catch {
|
|
12917
|
+
retryBody = {};
|
|
12918
|
+
}
|
|
12919
|
+
try {
|
|
12920
|
+
throwApiResponseError(
|
|
12921
|
+
response,
|
|
12922
|
+
retryBody,
|
|
12923
|
+
`Deploy failed (${response.status})`
|
|
12924
|
+
);
|
|
12925
|
+
} catch (e4) {
|
|
12926
|
+
if (e4 instanceof ApiError && e4.retryable) {
|
|
12927
|
+
const waitSeconds = Math.min(e4.retryAfterSeconds ?? 5, 60);
|
|
12928
|
+
options.onStatus?.("rate_limited", `retrying in ${waitSeconds}s`);
|
|
12929
|
+
await new Promise((resolve4) => setTimeout(resolve4, waitSeconds * 1e3));
|
|
12930
|
+
response = await triggerDeploy();
|
|
12931
|
+
} else {
|
|
12932
|
+
throw e4;
|
|
12933
|
+
}
|
|
12934
|
+
}
|
|
12935
|
+
}
|
|
12697
12936
|
if (!response.ok) {
|
|
12698
12937
|
const body = await response.json().catch(() => ({}));
|
|
12699
|
-
|
|
12938
|
+
throwApiResponseError(response, body, `Deploy failed (${response.status})`);
|
|
12700
12939
|
}
|
|
12701
12940
|
const data = await response.json();
|
|
12702
12941
|
if (!options.wait) return data;
|
|
@@ -12708,16 +12947,20 @@ async function deploySettings(options) {
|
|
|
12708
12947
|
return { ...data, ...result };
|
|
12709
12948
|
}
|
|
12710
12949
|
var statusLabels = {
|
|
12711
|
-
|
|
12712
|
-
"
|
|
12713
|
-
"bundling:publishing": "Publishing to web...",
|
|
12714
|
-
deploying: "Deploying container...",
|
|
12950
|
+
"deploying:building": "Building bundle...",
|
|
12951
|
+
"deploying:publishing": "Publishing to web...",
|
|
12715
12952
|
"deploying:provisioning": "Provisioning container...",
|
|
12716
12953
|
"deploying:starting": "Starting container...",
|
|
12954
|
+
deploying: "Deploying...",
|
|
12717
12955
|
active: "Container is live",
|
|
12718
12956
|
published: "Published",
|
|
12957
|
+
stopped: "Stopped",
|
|
12719
12958
|
failed: "Deployment failed"
|
|
12720
12959
|
};
|
|
12960
|
+
function renderStatusLabel(status, substatus) {
|
|
12961
|
+
const key = substatus ? `${status}:${substatus}` : status;
|
|
12962
|
+
return statusLabels[key] || statusLabels[status] || `Status: ${status}`;
|
|
12963
|
+
}
|
|
12721
12964
|
async function deployCommand(flowId, options) {
|
|
12722
12965
|
const log = createCLILogger(options);
|
|
12723
12966
|
const timeoutMs = options.timeout ? parseInt(options.timeout, 10) * 1e3 : void 0;
|
|
@@ -12729,10 +12972,7 @@ async function deployCommand(flowId, options) {
|
|
|
12729
12972
|
wait: options.wait !== false,
|
|
12730
12973
|
timeout: timeoutMs,
|
|
12731
12974
|
onStatus: options.json ? void 0 : (status, substatus) => {
|
|
12732
|
-
|
|
12733
|
-
log.info(
|
|
12734
|
-
statusLabels[key] || statusLabels[status] || `Status: ${status}`
|
|
12735
|
-
);
|
|
12975
|
+
log.info(renderStatusLabel(status, substatus));
|
|
12736
12976
|
}
|
|
12737
12977
|
});
|
|
12738
12978
|
if (options.json) {
|
|
@@ -12747,7 +12987,7 @@ async function deployCommand(flowId, options) {
|
|
|
12747
12987
|
} else if (r5.status === "failed") {
|
|
12748
12988
|
log.error(`Failed: ${r5.errorMessage || "Unknown error"}`);
|
|
12749
12989
|
process.exit(1);
|
|
12750
|
-
} else if (r5.status === "
|
|
12990
|
+
} else if (r5.status === "deploying") {
|
|
12751
12991
|
log.info(`Deployment started: ${r5.deploymentId} (${r5.type})`);
|
|
12752
12992
|
} else {
|
|
12753
12993
|
log.info(`Status: ${r5.status}`);
|
|
@@ -12902,20 +13142,16 @@ async function createDeployCommand(config, options) {
|
|
|
12902
13142
|
log.info(`Deployment created: ${result.id}`);
|
|
12903
13143
|
log.info(` Slug: ${result.slug}`);
|
|
12904
13144
|
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
13145
|
log.info("");
|
|
12910
13146
|
log.info("Run locally:");
|
|
12911
13147
|
log.info(
|
|
12912
13148
|
` walkeros run ${isRemoteFlow ? "flow.json" : config} --deploy ${result.id}`
|
|
12913
13149
|
);
|
|
12914
13150
|
log.info("");
|
|
12915
|
-
log.info("
|
|
12916
|
-
log.info(
|
|
12917
|
-
|
|
12918
|
-
);
|
|
13151
|
+
log.info("Create a deploy token for this flow in the app");
|
|
13152
|
+
log.info("(Settings, Self-hosted deploy token) and set it as");
|
|
13153
|
+
log.info("WALKEROS_DEPLOY_TOKEN, then run with Docker:");
|
|
13154
|
+
log.info(" docker run -e WALKEROS_DEPLOY_TOKEN \\");
|
|
12919
13155
|
log.info(" -e WALKEROS_APP_URL=https://app.walkeros.io \\");
|
|
12920
13156
|
log.info(" walkeros/flow:latest");
|
|
12921
13157
|
} catch (err) {
|
|
@@ -13231,7 +13467,7 @@ deployCmd.command("create [config]").description(
|
|
|
13231
13467
|
});
|
|
13232
13468
|
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
13469
|
"--timeout <seconds>",
|
|
13234
|
-
"timeout for deployment polling (default:
|
|
13470
|
+
"timeout in seconds for deployment polling (default: 720, the 12-minute server deploy budget)"
|
|
13235
13471
|
).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
13472
|
await deployCommand(flowId, options);
|
|
13237
13473
|
});
|