windmill-client 1.772.0 → 1.774.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/dist/client.d.ts +75 -7
- package/dist/client.mjs +97 -58
- package/dist/core/OpenAPI.mjs +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +246 -60
- package/dist/services.gen.d.ts +23 -1
- package/dist/services.gen.mjs +48 -2
- package/dist/types.gen.d.ts +234 -3
- package/dist/wacError.d.ts +24 -0
- package/dist/wacError.mjs +103 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -126,7 +126,7 @@ const OpenAPI = {
|
|
|
126
126
|
PASSWORD: void 0,
|
|
127
127
|
TOKEN: getEnv$1("WM_TOKEN"),
|
|
128
128
|
USERNAME: void 0,
|
|
129
|
-
VERSION: "1.
|
|
129
|
+
VERSION: "1.774.0",
|
|
130
130
|
WITH_CREDENTIALS: true,
|
|
131
131
|
interceptors: {
|
|
132
132
|
request: new Interceptors(),
|
|
@@ -2761,6 +2761,24 @@ var WorkspaceService = class {
|
|
|
2761
2761
|
});
|
|
2762
2762
|
}
|
|
2763
2763
|
/**
|
|
2764
|
+
* check what the data table's database lets its role do
|
|
2765
|
+
* @param data The data for the request.
|
|
2766
|
+
* @param data.workspace
|
|
2767
|
+
* @param data.datatableName
|
|
2768
|
+
* @returns unknown connection and privilege report
|
|
2769
|
+
* @throws ApiError
|
|
2770
|
+
*/
|
|
2771
|
+
static testDataTableConnection(data) {
|
|
2772
|
+
return request(OpenAPI, {
|
|
2773
|
+
method: "GET",
|
|
2774
|
+
url: "/w/{workspace}/workspaces/test_datatable_connection/{datatable_name}",
|
|
2775
|
+
path: {
|
|
2776
|
+
workspace: data.workspace,
|
|
2777
|
+
datatable_name: data.datatableName
|
|
2778
|
+
}
|
|
2779
|
+
});
|
|
2780
|
+
}
|
|
2781
|
+
/**
|
|
2764
2782
|
* list tables of all connected Datatables
|
|
2765
2783
|
* @param data The data for the request.
|
|
2766
2784
|
* @param data.workspace
|
|
@@ -7476,6 +7494,7 @@ var ScriptService = class {
|
|
|
7476
7494
|
* @param data.search case-insensitive substring match on summary or path
|
|
7477
7495
|
* @param data.perPage number of items to return for a given page (default 30, max 100)
|
|
7478
7496
|
* @param data.cursor opaque keyset cursor from a previous page's next_cursor
|
|
7497
|
+
* @param data.includeDraftOnly also list the caller's drafts at paths with no deployed row, sorted and paginated with the deployed ones. Ignored for operators, in the archived view, and under a label filter (a draft carries no labels).
|
|
7479
7498
|
* @returns unknown a page of merged, ordered runnables
|
|
7480
7499
|
* @throws ApiError
|
|
7481
7500
|
*/
|
|
@@ -7494,7 +7513,8 @@ var ScriptService = class {
|
|
|
7494
7513
|
label: data.label,
|
|
7495
7514
|
search: data.search,
|
|
7496
7515
|
per_page: data.perPage,
|
|
7497
|
-
cursor: data.cursor
|
|
7516
|
+
cursor: data.cursor,
|
|
7517
|
+
include_draft_only: data.includeDraftOnly
|
|
7498
7518
|
}
|
|
7499
7519
|
});
|
|
7500
7520
|
}
|
|
@@ -7504,6 +7524,7 @@ var ScriptService = class {
|
|
|
7504
7524
|
* @param data.workspace
|
|
7505
7525
|
* @param data.kinds comma-separated subset of script,flow,app (default all)
|
|
7506
7526
|
* @param data.includeWithoutMain include library scripts (no runnable main)
|
|
7527
|
+
* @param data.includeDraftOnly also count the caller's drafts at paths with no deployed row, matching the same flag on /runnables/list
|
|
7507
7528
|
* @returns unknown number of runnables per owner prefix, empty owners omitted. Excludes data-pipeline member scripts, which are listed as their folder's single pipeline entry rather than as runnables.
|
|
7508
7529
|
* @throws ApiError
|
|
7509
7530
|
*/
|
|
@@ -7514,7 +7535,8 @@ var ScriptService = class {
|
|
|
7514
7535
|
path: { workspace: data.workspace },
|
|
7515
7536
|
query: {
|
|
7516
7537
|
kinds: data.kinds,
|
|
7517
|
-
include_without_main: data.includeWithoutMain
|
|
7538
|
+
include_without_main: data.includeWithoutMain,
|
|
7539
|
+
include_draft_only: data.includeDraftOnly
|
|
7518
7540
|
}
|
|
7519
7541
|
});
|
|
7520
7542
|
}
|
|
@@ -9578,6 +9600,30 @@ var JobService = class {
|
|
|
9578
9600
|
});
|
|
9579
9601
|
}
|
|
9580
9602
|
/**
|
|
9603
|
+
* get statuses and truncated results for all jobs of a flow job's execution tree
|
|
9604
|
+
* @param data The data for the request.
|
|
9605
|
+
* @param data.workspace
|
|
9606
|
+
* @param data.id
|
|
9607
|
+
* @param data.maxResultLen per-entry cap (in characters of JSON text) on result_prefix (default 2000, max 30000)
|
|
9608
|
+
* @param data.step step address to resolve to a single job instead of enumerating the tree: "b", "b/c", "b[12]" (1-based iteration/branch), composable as "b[12]/c"
|
|
9609
|
+
* @returns unknown per-job statuses and truncated results of the flow's execution tree, or the single resolved entry when step is provided
|
|
9610
|
+
* @throws ApiError
|
|
9611
|
+
*/
|
|
9612
|
+
static getFlowAllResults(data) {
|
|
9613
|
+
return request(OpenAPI, {
|
|
9614
|
+
method: "GET",
|
|
9615
|
+
url: "/w/{workspace}/jobs_u/get_flow_all_results/{id}",
|
|
9616
|
+
path: {
|
|
9617
|
+
workspace: data.workspace,
|
|
9618
|
+
id: data.id
|
|
9619
|
+
},
|
|
9620
|
+
query: {
|
|
9621
|
+
max_result_len: data.maxResultLen,
|
|
9622
|
+
step: data.step
|
|
9623
|
+
}
|
|
9624
|
+
});
|
|
9625
|
+
}
|
|
9626
|
+
/**
|
|
9581
9627
|
* get completed job logs tail
|
|
9582
9628
|
* @param data The data for the request.
|
|
9583
9629
|
* @param data.workspace
|
|
@@ -16449,6 +16495,108 @@ var HubPublishService = class {
|
|
|
16449
16495
|
}
|
|
16450
16496
|
};
|
|
16451
16497
|
|
|
16498
|
+
//#endregion
|
|
16499
|
+
//#region src/wacError.ts
|
|
16500
|
+
/** Error properties the executors already report as named fields, so they must
|
|
16501
|
+
* not be repeated inside `extra`. Kept identical to the skip-list in the
|
|
16502
|
+
* generated bun/deno job wrappers. */
|
|
16503
|
+
const SERIALIZED_ERROR_FIELDS = [
|
|
16504
|
+
"line",
|
|
16505
|
+
"name",
|
|
16506
|
+
"stack",
|
|
16507
|
+
"column",
|
|
16508
|
+
"message",
|
|
16509
|
+
"sourceURL",
|
|
16510
|
+
"originalLine",
|
|
16511
|
+
"originalColumn"
|
|
16512
|
+
];
|
|
16513
|
+
/** Read a property off a value that may fight back: a proxy `get` trap or a
|
|
16514
|
+
* throwing accessor turns an ordinary field read into an exception. Callers
|
|
16515
|
+
* are on the failure-reporting path, where nothing has been checkpointed yet. */
|
|
16516
|
+
function safeRead(o, k) {
|
|
16517
|
+
try {
|
|
16518
|
+
return o?.[k];
|
|
16519
|
+
} catch {
|
|
16520
|
+
return void 0;
|
|
16521
|
+
}
|
|
16522
|
+
}
|
|
16523
|
+
/** @internal
|
|
16524
|
+
* Whether a caught value is the SDK's own suspend signal, which must be
|
|
16525
|
+
* rethrown rather than reported as a step failure.
|
|
16526
|
+
*
|
|
16527
|
+
* Both halves of the check can throw on a hostile value: `instanceof` consults
|
|
16528
|
+
* a proxy's `getPrototypeOf` trap, and reading `.name` its `get` trap. This
|
|
16529
|
+
* runs before anything has been checkpointed, so neither may escape — a value
|
|
16530
|
+
* that fights back is simply not a suspend. */
|
|
16531
|
+
function isSuspendSignal(e, suspendCtor) {
|
|
16532
|
+
try {
|
|
16533
|
+
if (e instanceof suspendCtor) return true;
|
|
16534
|
+
} catch {}
|
|
16535
|
+
return safeRead(e, "name") === "StepSuspend";
|
|
16536
|
+
}
|
|
16537
|
+
/** @internal
|
|
16538
|
+
* Serialize a failed `step()` body into the `__wmill_error` marker that task
|
|
16539
|
+
* failures also use, so it can be stored in `completed_steps`.
|
|
16540
|
+
*
|
|
16541
|
+
* The record's final shape is decided by the backend (`wac_failure_record`),
|
|
16542
|
+
* which normalizes task failures through the same function; what is built here
|
|
16543
|
+
* is the raw material plus the envelope the backend recognizes. */
|
|
16544
|
+
function stepErrorMarker(key, e) {
|
|
16545
|
+
const thrown = e;
|
|
16546
|
+
const rawName = safeRead(thrown, "name");
|
|
16547
|
+
const rawMessage = safeRead(thrown, "message");
|
|
16548
|
+
const rawStack = safeRead(thrown, "stack");
|
|
16549
|
+
const name = typeof rawName === "string" ? rawName : void 0;
|
|
16550
|
+
const message = typeof rawMessage === "string" ? rawMessage : void 0;
|
|
16551
|
+
const stack = typeof rawStack === "string" ? rawStack : void 0;
|
|
16552
|
+
const error = {};
|
|
16553
|
+
if (name) error.name = name;
|
|
16554
|
+
if (message !== void 0) error.message = message;
|
|
16555
|
+
if (stack) error.stack = stack;
|
|
16556
|
+
if (thrown !== null && typeof thrown === "object") {
|
|
16557
|
+
const extra = {};
|
|
16558
|
+
let keys = [];
|
|
16559
|
+
try {
|
|
16560
|
+
keys = Object.getOwnPropertyNames(thrown);
|
|
16561
|
+
} catch {
|
|
16562
|
+
keys = [];
|
|
16563
|
+
}
|
|
16564
|
+
for (const k of keys) {
|
|
16565
|
+
if (SERIALIZED_ERROR_FIELDS.includes(k)) continue;
|
|
16566
|
+
try {
|
|
16567
|
+
extra[k] = JSON.parse(JSON.stringify(thrown[k]));
|
|
16568
|
+
} catch {}
|
|
16569
|
+
}
|
|
16570
|
+
if (Object.keys(extra).length > 0) error.extra = extra;
|
|
16571
|
+
}
|
|
16572
|
+
let fallback;
|
|
16573
|
+
try {
|
|
16574
|
+
fallback = String(e);
|
|
16575
|
+
} catch {
|
|
16576
|
+
fallback = `unrepresentable ${typeof e} thrown`;
|
|
16577
|
+
}
|
|
16578
|
+
return {
|
|
16579
|
+
__wmill_error: true,
|
|
16580
|
+
message: message ?? fallback,
|
|
16581
|
+
step_key: key,
|
|
16582
|
+
result: { error }
|
|
16583
|
+
};
|
|
16584
|
+
}
|
|
16585
|
+
/** @internal
|
|
16586
|
+
* Rebuild the error a failed task or step throws. The run that produced the
|
|
16587
|
+
* failure and every later replay go through here: a catch is control flow,
|
|
16588
|
+
* `workflow()` re-runs its body from the top every round, so a handler that
|
|
16589
|
+
* branches on the failure it caught must be handed the same thing in every
|
|
16590
|
+
* round or it dispatches different tasks on the way back. */
|
|
16591
|
+
function taskErrorFromMarker(marker, fallbackMessage) {
|
|
16592
|
+
const err = new Error(marker?.message || fallbackMessage);
|
|
16593
|
+
err.name = "TaskError";
|
|
16594
|
+
err.result = marker?.result;
|
|
16595
|
+
err.step_key = marker?.step_key;
|
|
16596
|
+
err.child_job_id = marker?.child_job_id;
|
|
16597
|
+
return err;
|
|
16598
|
+
}
|
|
16599
|
+
|
|
16452
16600
|
//#endregion
|
|
16453
16601
|
//#region src/s3Types.ts
|
|
16454
16602
|
/**
|
|
@@ -17782,31 +17930,24 @@ var StepSuspend = class extends Error {
|
|
|
17782
17930
|
this.name = "StepSuspend";
|
|
17783
17931
|
}
|
|
17784
17932
|
};
|
|
17785
|
-
/**
|
|
17786
|
-
*
|
|
17787
|
-
|
|
17788
|
-
|
|
17789
|
-
|
|
17790
|
-
return
|
|
17791
|
-
__wmill_error: true,
|
|
17792
|
-
message,
|
|
17793
|
-
step_key: key,
|
|
17794
|
-
result: {
|
|
17795
|
-
error: message,
|
|
17796
|
-
type
|
|
17797
|
-
}
|
|
17798
|
-
};
|
|
17933
|
+
/** Encode a checkpoint payload the way the worker wrapper does on the suspend
|
|
17934
|
+
* path, so both arms record the same value for the same step. `undefined` maps
|
|
17935
|
+
* to null; a bigint to its digits, which the wrapper gets instead from the
|
|
17936
|
+
* `BigInt.prototype.toJSON` it installs and the SDK cannot count on. */
|
|
17937
|
+
function encodeCheckpointPayload(payload) {
|
|
17938
|
+
return JSON.stringify(payload, (_key, value) => typeof value === "undefined" ? null : typeof value === "bigint" ? value.toString() : value);
|
|
17799
17939
|
}
|
|
17800
|
-
/**
|
|
17801
|
-
*
|
|
17802
|
-
*
|
|
17803
|
-
function
|
|
17804
|
-
|
|
17805
|
-
|
|
17806
|
-
|
|
17807
|
-
|
|
17808
|
-
|
|
17809
|
-
|
|
17940
|
+
/** A whole result that `JSON.stringify` drops the key for leaves a checkpoint
|
|
17941
|
+
* with no `result`, which neither the endpoint nor `WacOutput` accepts. Only
|
|
17942
|
+
* the top level: nested, a dropped key is what every other bun path does. */
|
|
17943
|
+
function checkpointableResult(value) {
|
|
17944
|
+
return typeof value === "function" || typeof value === "symbol" ? null : value;
|
|
17945
|
+
}
|
|
17946
|
+
/** Put a value through the checkpoint's encoding without checkpointing it, so
|
|
17947
|
+
* the paths that never persist anything still hand back the shape the ones
|
|
17948
|
+
* that do would. */
|
|
17949
|
+
function jsonRoundTrip(value) {
|
|
17950
|
+
return JSON.parse(encodeCheckpointPayload({ value: checkpointableResult(value) })).value;
|
|
17810
17951
|
}
|
|
17811
17952
|
/** A step key travels as one path segment when its URLs are minted, so it must be
|
|
17812
17953
|
* non-empty and free of `/` and dot segments — otherwise `waitForApproval` would
|
|
@@ -17834,6 +17975,11 @@ var WorkflowCtx = class {
|
|
|
17834
17975
|
* `complete` whose step never reached `completed_steps`. Python is immune:
|
|
17835
17976
|
* `_StepSuspend` derives from `BaseException`. */
|
|
17836
17977
|
_pendingSuspend = null;
|
|
17978
|
+
/** The failure raised by the step this child round is executing. That exception
|
|
17979
|
+
* *is* the round's result, so a `catch` in the body must not be able to turn it
|
|
17980
|
+
* into a `complete` — the parent would then record the caught branch's value as
|
|
17981
|
+
* a successful step. Boxed: the thrown value may be any falsy value. */
|
|
17982
|
+
_pendingStepFailure = null;
|
|
17837
17983
|
/** When set, the task matching this key executes its inner function directly */
|
|
17838
17984
|
_executingKey;
|
|
17839
17985
|
/** Serializes fast-path POSTs across concurrent step() calls within one
|
|
@@ -17866,16 +18012,12 @@ var WorkflowCtx = class {
|
|
|
17866
18012
|
return key;
|
|
17867
18013
|
}
|
|
17868
18014
|
_nextStep(name, script, args = {}, dispatch_type = "inline", options) {
|
|
17869
|
-
this.
|
|
18015
|
+
this._rethrowSwallowed();
|
|
17870
18016
|
const key = this._allocKey(name || script || "step");
|
|
17871
18017
|
if (key in this.completed) {
|
|
17872
18018
|
const value = this.completed[key];
|
|
17873
18019
|
if (value && typeof value === "object" && value.__wmill_error) {
|
|
17874
|
-
const err =
|
|
17875
|
-
err.name = "TaskError";
|
|
17876
|
-
err.result = value.result;
|
|
17877
|
-
err.step_key = value.step_key;
|
|
17878
|
-
err.child_job_id = value.child_job_id;
|
|
18020
|
+
const err = taskErrorFromMarker(value, `Task '${name}' failed`);
|
|
17879
18021
|
return { then: (_resolve, reject) => {
|
|
17880
18022
|
if (reject) reject(err);
|
|
17881
18023
|
else throw err;
|
|
@@ -17925,7 +18067,7 @@ var WorkflowCtx = class {
|
|
|
17925
18067
|
return steps;
|
|
17926
18068
|
}
|
|
17927
18069
|
_waitForApproval(options) {
|
|
17928
|
-
this.
|
|
18070
|
+
this._rethrowSwallowed();
|
|
17929
18071
|
if (options?.key !== void 0) assertUsableStepKey(options.key, "waitForApproval key");
|
|
17930
18072
|
const key = this._allocKey(options?.key || "approval");
|
|
17931
18073
|
if (options?.key && key !== options.key) throw new Error(`WAC step key "${options.key}" is already used in this workflow. Give each waitForApproval() its own key so getApprovalUrls() can address it.`);
|
|
@@ -17945,7 +18087,7 @@ var WorkflowCtx = class {
|
|
|
17945
18087
|
});
|
|
17946
18088
|
}
|
|
17947
18089
|
_sleep(seconds) {
|
|
17948
|
-
this.
|
|
18090
|
+
this._rethrowSwallowed();
|
|
17949
18091
|
const key = this._allocKey("sleep");
|
|
17950
18092
|
if (key in this.completed) return { then: (resolve$1) => resolve$1(void 0) };
|
|
17951
18093
|
if (this._executingKey !== null) return { then: () => new Promise(() => {}) };
|
|
@@ -17958,11 +18100,11 @@ var WorkflowCtx = class {
|
|
|
17958
18100
|
});
|
|
17959
18101
|
}
|
|
17960
18102
|
async _runInlineStep(name, fn) {
|
|
17961
|
-
this.
|
|
18103
|
+
this._rethrowSwallowed();
|
|
17962
18104
|
const key = this._allocKey(name || "step");
|
|
17963
18105
|
if (key in this.completed) {
|
|
17964
18106
|
const value = this.completed[key];
|
|
17965
|
-
if (value && typeof value === "object" && value.__wmill_error) throw
|
|
18107
|
+
if (value && typeof value === "object" && value.__wmill_error) throw taskErrorFromMarker(value, `Step '${name}' failed`);
|
|
17966
18108
|
return value;
|
|
17967
18109
|
}
|
|
17968
18110
|
if (this._executingKey !== null) return new Promise(() => {});
|
|
@@ -17974,22 +18116,36 @@ var WorkflowCtx = class {
|
|
|
17974
18116
|
})}`);
|
|
17975
18117
|
const t0 = Date.now();
|
|
17976
18118
|
let result;
|
|
17977
|
-
let stepError;
|
|
17978
18119
|
let errored = false;
|
|
17979
18120
|
try {
|
|
17980
18121
|
result = await fn();
|
|
17981
18122
|
} catch (e) {
|
|
17982
|
-
if (e
|
|
18123
|
+
if (isSuspendSignal(e, StepSuspend)) throw e;
|
|
17983
18124
|
errored = true;
|
|
17984
|
-
stepError = e;
|
|
17985
18125
|
result = stepErrorMarker(key, e);
|
|
18126
|
+
console.log(`--- WAC: ${key} failed ---`);
|
|
18127
|
+
console.log(result?.result?.error?.stack ?? result?.message ?? "step failed");
|
|
17986
18128
|
}
|
|
17987
18129
|
const durationMs = Date.now() - t0;
|
|
17988
18130
|
const fastPathFlagRaw = (getEnv("WM_WAC_INLINE_FAST_PATH") ?? "1").trim().toLowerCase();
|
|
17989
18131
|
const fastPathEnabled = fastPathFlagRaw !== "0" && fastPathFlagRaw !== "false" && fastPathFlagRaw !== "off" && fastPathFlagRaw !== "no";
|
|
17990
18132
|
const jobId = getEnv("WM_JOB_ID");
|
|
17991
18133
|
const workspace = getEnv("WM_WORKSPACE");
|
|
17992
|
-
|
|
18134
|
+
let payload;
|
|
18135
|
+
let checkpointed;
|
|
18136
|
+
if (fastPathEnabled && jobId && workspace && OpenAPI.BASE && OpenAPI.TOKEN) try {
|
|
18137
|
+
payload = encodeCheckpointPayload({
|
|
18138
|
+
key,
|
|
18139
|
+
result: checkpointableResult(result),
|
|
18140
|
+
started_at: startedAt,
|
|
18141
|
+
duration_ms: durationMs
|
|
18142
|
+
});
|
|
18143
|
+
checkpointed = JSON.parse(payload).result;
|
|
18144
|
+
} catch (e) {
|
|
18145
|
+
console.log(`WAC v2 inline fast path could not serialize key ${key}, falling back to suspend: ${e}`);
|
|
18146
|
+
}
|
|
18147
|
+
if (payload !== void 0) {
|
|
18148
|
+
const body = payload;
|
|
17993
18149
|
const chainTail = this._inlineChain.then(async () => {
|
|
17994
18150
|
const ctrl = new AbortController();
|
|
17995
18151
|
const t = setTimeout(() => ctrl.abort(), 1e4);
|
|
@@ -18000,37 +18156,36 @@ var WorkflowCtx = class {
|
|
|
18000
18156
|
"Content-Type": "application/json",
|
|
18001
18157
|
Authorization: `Bearer ${OpenAPI.TOKEN}`
|
|
18002
18158
|
},
|
|
18003
|
-
body
|
|
18004
|
-
key,
|
|
18005
|
-
result,
|
|
18006
|
-
started_at: startedAt,
|
|
18007
|
-
duration_ms: durationMs
|
|
18008
|
-
}),
|
|
18159
|
+
body,
|
|
18009
18160
|
signal: ctrl.signal
|
|
18010
18161
|
});
|
|
18011
18162
|
if (!resp.ok) throw new Error(`inline_checkpoint API ${resp.status}`);
|
|
18163
|
+
if (!errored) return void 0;
|
|
18164
|
+
if (!(resp.headers.get("content-type") ?? "").includes("json")) return void 0;
|
|
18165
|
+
return (await resp.json())?.failure;
|
|
18012
18166
|
} finally {
|
|
18013
18167
|
clearTimeout(t);
|
|
18014
18168
|
}
|
|
18015
18169
|
});
|
|
18016
18170
|
this._inlineChain = chainTail.catch(() => {});
|
|
18017
18171
|
let fastPathOk = false;
|
|
18172
|
+
let storedFailure;
|
|
18018
18173
|
try {
|
|
18019
|
-
await chainTail;
|
|
18174
|
+
storedFailure = await chainTail;
|
|
18020
18175
|
fastPathOk = true;
|
|
18021
18176
|
} catch (e) {
|
|
18022
18177
|
console.log(`WAC v2 inline fast path failed for key ${key}, falling back to suspend: ${e}`);
|
|
18023
18178
|
}
|
|
18024
18179
|
if (fastPathOk) {
|
|
18025
|
-
if (errored) throw
|
|
18026
|
-
return
|
|
18180
|
+
if (errored) throw taskErrorFromMarker(storedFailure ?? checkpointed, `Step '${name}' failed`);
|
|
18181
|
+
return checkpointed;
|
|
18027
18182
|
}
|
|
18028
18183
|
}
|
|
18029
18184
|
this._raiseSuspend({
|
|
18030
18185
|
mode: "inline_checkpoint",
|
|
18031
18186
|
steps: [],
|
|
18032
18187
|
key,
|
|
18033
|
-
result,
|
|
18188
|
+
result: checkpointableResult(result),
|
|
18034
18189
|
started_at: startedAt,
|
|
18035
18190
|
duration_ms: durationMs
|
|
18036
18191
|
});
|
|
@@ -18042,11 +18197,18 @@ var WorkflowCtx = class {
|
|
|
18042
18197
|
this._pendingSuspend = suspend;
|
|
18043
18198
|
throw suspend;
|
|
18044
18199
|
}
|
|
18045
|
-
/**
|
|
18046
|
-
*
|
|
18047
|
-
|
|
18048
|
-
|
|
18049
|
-
|
|
18200
|
+
/** Park then raise the executing step's failure. Child mode only — in a parent
|
|
18201
|
+
* round a task failure is an ordinary `TaskError` the body may handle. */
|
|
18202
|
+
_raiseStepFailure(error) {
|
|
18203
|
+
this._pendingStepFailure = { error };
|
|
18204
|
+
throw error;
|
|
18205
|
+
}
|
|
18206
|
+
/** Re-throw a swallowed suspend or step failure at the next SDK call. It
|
|
18207
|
+
* happened before whatever the body is doing now, so it wins: the run is
|
|
18208
|
+
* unwinding either way and everything after it re-runs on the replay. Left
|
|
18209
|
+
* set, so a body that catches in a loop can't swallow it a second time. */
|
|
18210
|
+
_rethrowSwallowed() {
|
|
18211
|
+
if (this._pendingStepFailure) throw this._pendingStepFailure.error;
|
|
18050
18212
|
if (this._pendingSuspend) throw this._pendingSuspend;
|
|
18051
18213
|
}
|
|
18052
18214
|
/** Hand the runner a suspend the workflow body caught and swallowed, so it is
|
|
@@ -18057,16 +18219,30 @@ var WorkflowCtx = class {
|
|
|
18057
18219
|
this._pendingSuspend = null;
|
|
18058
18220
|
return s;
|
|
18059
18221
|
}
|
|
18222
|
+
/** Same for the executing step's failure, so the runner can fail the child job. */
|
|
18223
|
+
_takePendingStepFailure() {
|
|
18224
|
+
const f = this._pendingStepFailure;
|
|
18225
|
+
this._pendingStepFailure = null;
|
|
18226
|
+
return f;
|
|
18227
|
+
}
|
|
18060
18228
|
};
|
|
18061
18229
|
async function sleep(seconds) {
|
|
18062
18230
|
const ctx = _workflowCtx ?? Reflect.get(globalThis, "__wmill_wf_ctx");
|
|
18063
18231
|
if (ctx) return ctx._sleep(seconds);
|
|
18064
18232
|
await new Promise((r) => setTimeout(r, seconds * 1e3));
|
|
18065
18233
|
}
|
|
18234
|
+
/**
|
|
18235
|
+
* Execute `fn` inline and checkpoint the result. On replay the cached value is
|
|
18236
|
+
* returned without re-executing `fn`.
|
|
18237
|
+
*
|
|
18238
|
+
* `fn`'s result is encoded as JSON and decoded back before it is returned, so
|
|
18239
|
+
* the round that runs the body sees the same types every replay sees: a `Date`
|
|
18240
|
+
* comes back as a string, a `Map` as `{}`. {@link Jsonified} is that shape.
|
|
18241
|
+
*/
|
|
18066
18242
|
async function step(name, fn) {
|
|
18067
18243
|
const ctx = _workflowCtx ?? Reflect.get(globalThis, "__wmill_wf_ctx");
|
|
18068
18244
|
if (ctx) return ctx._runInlineStep(name, fn);
|
|
18069
|
-
return fn();
|
|
18245
|
+
return jsonRoundTrip(await fn());
|
|
18070
18246
|
}
|
|
18071
18247
|
/**
|
|
18072
18248
|
* Wrap an async function as a workflow task.
|
|
@@ -18077,6 +18253,10 @@ async function step(name, fn) {
|
|
|
18077
18253
|
*
|
|
18078
18254
|
* Inside a `workflow()`, calling a task dispatches it as a step.
|
|
18079
18255
|
* Outside a workflow, the function body executes directly.
|
|
18256
|
+
*
|
|
18257
|
+
* A task runs as its own job, so its result is always encoded as JSON and
|
|
18258
|
+
* decoded back before the caller sees it: a `Date` comes back as a string, a
|
|
18259
|
+
* `Map` as `{}`. {@link JsonifiedFn} is that shape.
|
|
18080
18260
|
*/
|
|
18081
18261
|
function task(fnOrPath, maybeFnOrOptions, maybeOptions) {
|
|
18082
18262
|
let fn;
|
|
@@ -18101,11 +18281,17 @@ function task(fnOrPath, maybeFnOrOptions, maybeOptions) {
|
|
|
18101
18281
|
else kwargs[`arg${i}`] = args[i];
|
|
18102
18282
|
const stepResult = ctx._nextStep(taskName, script, kwargs, "inline", taskOptions);
|
|
18103
18283
|
if (stepResult?._execute_directly) return (async () => {
|
|
18104
|
-
|
|
18284
|
+
let result;
|
|
18285
|
+
try {
|
|
18286
|
+
result = await fn(...args);
|
|
18287
|
+
} catch (e) {
|
|
18288
|
+
if (isSuspendSignal(e, StepSuspend)) throw e;
|
|
18289
|
+
ctx._raiseStepFailure(e);
|
|
18290
|
+
}
|
|
18105
18291
|
ctx._raiseSuspend({
|
|
18106
18292
|
mode: "step_complete",
|
|
18107
18293
|
steps: [],
|
|
18108
|
-
result
|
|
18294
|
+
result: checkpointableResult(result)
|
|
18109
18295
|
});
|
|
18110
18296
|
})();
|
|
18111
18297
|
return stepResult;
|
|
@@ -18127,7 +18313,7 @@ function task(fnOrPath, maybeFnOrOptions, maybeOptions) {
|
|
|
18127
18313
|
console.log(`Task ${taskName} (${jobId}) completed`);
|
|
18128
18314
|
return r;
|
|
18129
18315
|
})();
|
|
18130
|
-
else return fn(...args);
|
|
18316
|
+
else return Promise.resolve(fn(...args)).then(jsonRoundTrip);
|
|
18131
18317
|
};
|
|
18132
18318
|
Object.defineProperty(wrapper, "name", { value: taskName });
|
|
18133
18319
|
wrapper._is_task = true;
|