windmill-client 1.805.0 → 1.807.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 +47 -1
- package/dist/client.mjs +128 -44
- package/dist/core/OpenAPI.mjs +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +286 -51
- package/dist/services.gen.d.ts +96 -7
- package/dist/services.gen.mjs +157 -6
- package/dist/types.gen.d.ts +322 -3
- 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.807.0",
|
|
130
130
|
WITH_CREDENTIALS: !getEnv$1("WM_RAW_APP"),
|
|
131
131
|
interceptors: {
|
|
132
132
|
request: new Interceptors(),
|
|
@@ -1655,6 +1655,59 @@ var GitSyncService = class {
|
|
|
1655
1655
|
});
|
|
1656
1656
|
}
|
|
1657
1657
|
/**
|
|
1658
|
+
* List the GitLab projects a token can sync
|
|
1659
|
+
* Lists the projects the supplied GitLab token can push to, so a git repository resource can be filled in without hand-writing a project path. The token is used for this call only and is never stored. Requires workspace admin.
|
|
1660
|
+
* @param data The data for the request.
|
|
1661
|
+
* @param data.workspace
|
|
1662
|
+
* @param data.requestBody
|
|
1663
|
+
* @returns GitlabProject the projects the token can sync
|
|
1664
|
+
* @throws ApiError
|
|
1665
|
+
*/
|
|
1666
|
+
static listGitlabProjects(data) {
|
|
1667
|
+
return request(OpenAPI, {
|
|
1668
|
+
method: "POST",
|
|
1669
|
+
url: "/w/{workspace}/git_sync/gitlab/projects",
|
|
1670
|
+
path: { workspace: data.workspace },
|
|
1671
|
+
body: data.requestBody,
|
|
1672
|
+
mediaType: "application/json"
|
|
1673
|
+
});
|
|
1674
|
+
}
|
|
1675
|
+
/**
|
|
1676
|
+
* Where a repository's credential comes from
|
|
1677
|
+
* Whether Windmill holds this repository's access token, and which host it talks to. `held` means this workspace stores it, `borrowed` means an ancestor does and it is not this workspace's to replace. Both absent means the repository authenticates with whatever its URL carries. Returns no secret. Requires workspace admin.
|
|
1678
|
+
* @param data The data for the request.
|
|
1679
|
+
* @param data.workspace
|
|
1680
|
+
* @param data.path Path of the git repository resource, with or without the `$res:` prefix. A path rather than a URL, because a resource URL may carry a token and a URL in a query string lands in logs.
|
|
1681
|
+
* @returns unknown where the credential comes from
|
|
1682
|
+
* @throws ApiError
|
|
1683
|
+
*/
|
|
1684
|
+
static getCredentialOrigin(data) {
|
|
1685
|
+
return request(OpenAPI, {
|
|
1686
|
+
method: "GET",
|
|
1687
|
+
url: "/w/{workspace}/git_sync/credential/origin",
|
|
1688
|
+
path: { workspace: data.workspace },
|
|
1689
|
+
query: { path: data.path }
|
|
1690
|
+
});
|
|
1691
|
+
}
|
|
1692
|
+
/**
|
|
1693
|
+
* Store the credential for a git repository
|
|
1694
|
+
* Stores the access token a git repository authenticates with, so it does not have to be written into the repository URL or a workspace variable. The token is write-only: it is served only to a git-sync job that presents its own job token, and a fork of this workspace reads this copy instead of holding one of its own. Requires workspace admin.
|
|
1695
|
+
* @param data The data for the request.
|
|
1696
|
+
* @param data.workspace
|
|
1697
|
+
* @param data.requestBody
|
|
1698
|
+
* @returns string the credential was stored
|
|
1699
|
+
* @throws ApiError
|
|
1700
|
+
*/
|
|
1701
|
+
static setGitCredential(data) {
|
|
1702
|
+
return request(OpenAPI, {
|
|
1703
|
+
method: "POST",
|
|
1704
|
+
url: "/w/{workspace}/git_sync/credential",
|
|
1705
|
+
path: { workspace: data.workspace },
|
|
1706
|
+
body: data.requestBody,
|
|
1707
|
+
mediaType: "application/json"
|
|
1708
|
+
});
|
|
1709
|
+
}
|
|
1710
|
+
/**
|
|
1658
1711
|
* GHES installation callback
|
|
1659
1712
|
* Register a self-managed GitHub App installation from GitHub Enterprise Server
|
|
1660
1713
|
* @param data The data for the request.
|
|
@@ -1950,11 +2003,11 @@ var WorkspaceService = class {
|
|
|
1950
2003
|
});
|
|
1951
2004
|
}
|
|
1952
2005
|
/**
|
|
1953
|
-
* get
|
|
2006
|
+
* get the git credential for a git-sync job (GitHub App token, or the credential stored for the repository)
|
|
1954
2007
|
* @param data The data for the request.
|
|
1955
2008
|
* @param data.workspace
|
|
1956
2009
|
* @param data.requestBody jwt job token
|
|
1957
|
-
* @returns unknown
|
|
2010
|
+
* @returns unknown git credential
|
|
1958
2011
|
* @throws ApiError
|
|
1959
2012
|
*/
|
|
1960
2013
|
static getGithubAppToken(data) {
|
|
@@ -3351,7 +3404,7 @@ var WorkspaceService = class {
|
|
|
3351
3404
|
}
|
|
3352
3405
|
/**
|
|
3353
3406
|
* enable or disable guest sessions for this workspace
|
|
3354
|
-
* Guests are people the identity provider authenticates who have no Windmill account; the `guest` app execution mode admits them. Off by default. Re-read where a guest session is minted and at the auth door on every guest request, so turning it off takes effect immediately, for sessions already issued and for apps whose policy already says `guest`.
|
|
3407
|
+
* Guests are people the identity provider authenticates who have no Windmill account; the `guest` app execution mode admits them. Off by default. Re-read where a guest session is minted and at the auth door on every guest request, so turning it off takes effect immediately, for sessions already issued and for apps whose policy already says `guest`. Turning it *on* is refused with a 400 where guests are unavailable (the shared cloud); turning it off always works.
|
|
3355
3408
|
* @param data The data for the request.
|
|
3356
3409
|
* @param data.workspace
|
|
3357
3410
|
* @param data.requestBody Whether guest sessions are admitted
|
|
@@ -3369,7 +3422,7 @@ var WorkspaceService = class {
|
|
|
3369
3422
|
}
|
|
3370
3423
|
/**
|
|
3371
3424
|
* set the key guest JWTs are verified against for this workspace
|
|
3372
|
-
* A guest JWT (`jwt_guest_`) is minted by the embedding customer's own backend and verified against this key: a PEM public key (RS/ES family, HS* refused) or a JWKS URL, at most one. Both empty clears the workspace key; off cloud, verification then falls back to the instance issuer (`JWT_EXT_JWKS_URL`) if one is set, else no guest JWT is accepted (`guest_access_enabled` is the on/off switch). Workspace-admin gated. The key is validated before it is stored.
|
|
3425
|
+
* A guest JWT (`jwt_guest_`) is minted by the embedding customer's own backend and verified against this key: a PEM public key (RS/ES family, HS* refused) or a JWKS URL, at most one. Both empty clears the workspace key; off cloud, verification then falls back to the instance issuer (`JWT_EXT_JWKS_URL`) if one is set, else no guest JWT is accepted (`guest_access_enabled` is the on/off switch). Workspace-admin gated. The key is validated before it is stored. Setting a key is refused with a 400 where guests are unavailable (the shared cloud); clearing one always works.
|
|
3373
3426
|
* @param data The data for the request.
|
|
3374
3427
|
* @param data.workspace
|
|
3375
3428
|
* @param data.requestBody The guest JWT verification key
|
|
@@ -6322,7 +6375,7 @@ var AppService = class {
|
|
|
6322
6375
|
}
|
|
6323
6376
|
/**
|
|
6324
6377
|
* whether the app behind a custom path admits guests
|
|
6325
|
-
* The custom-path counterpart of `getGuestEntry`. Unauthenticated; 404 unless the app's execution mode is `guest` AND its workspace has `guest_access_enabled` AND the instance has not set `guest_access_disabled
|
|
6378
|
+
* The custom-path counterpart of `getGuestEntry`. Unauthenticated; 404 unless the app's execution mode is `guest` AND its workspace has `guest_access_enabled` AND the instance has not set `guest_access_disabled`, and never on a deployment where guests are unavailable (the shared cloud). Returns the workspace too, since a custom URL may not carry it.
|
|
6326
6379
|
* @param data The data for the request.
|
|
6327
6380
|
* @param data.customPath
|
|
6328
6381
|
* @returns GuestEntry the app is open to guests
|
|
@@ -6658,7 +6711,7 @@ var AppService = class {
|
|
|
6658
6711
|
}
|
|
6659
6712
|
/**
|
|
6660
6713
|
* whether the app behind a share secret admits guests
|
|
6661
|
-
* Unauthenticated: what a signed-out visitor reads to learn that signing in would let them in. 404 unless the app's execution mode is `guest` AND the workspace has `guest_access_enabled` AND the instance has not set the `guest_access_disabled` global setting, so it says nothing about apps that are not open to guests. Discloses only the app path, to a caller already holding the share secret.
|
|
6714
|
+
* Unauthenticated: what a signed-out visitor reads to learn that signing in would let them in. 404 unless the app's execution mode is `guest` AND the workspace has `guest_access_enabled` AND the instance has not set the `guest_access_disabled` global setting, and never on a deployment where guests are unavailable (the shared cloud), so it says nothing about apps that are not open to guests. Discloses only the app path, to a caller already holding the share secret.
|
|
6662
6715
|
* @param data The data for the request.
|
|
6663
6716
|
* @param data.workspace
|
|
6664
6717
|
* @param data.path
|
|
@@ -11059,6 +11112,29 @@ var JobService = class {
|
|
|
11059
11112
|
});
|
|
11060
11113
|
}
|
|
11061
11114
|
/**
|
|
11115
|
+
* Get relations' project column lineage as one run saw it
|
|
11116
|
+
* The same answer as `assets/column_lineage`, for the project version a single job ran — including the dbt editor's parse of its own buffer, whose graph belongs to that job and is reachable no other way. One project answers here, the one the run is of, since the graph this annotates is that project's too. Authorized through the job, the same gate as `dbt_graph`. Reaching the run is not on its own enough to read the project: a caller with no access to the script gets its relations and `ref()` edges from `dbt_graph` and an empty answer here, exactly as that endpoint redacts the model's SQL.
|
|
11117
|
+
*
|
|
11118
|
+
* @param data The data for the request.
|
|
11119
|
+
* @param data.workspace
|
|
11120
|
+
* @param data.id The job whose graph the lineage is read from
|
|
11121
|
+
* @param data.assetPath The `dbt://` relations whose lineage to return. Repeated, once per relation, and answered as one union. At least one, and at most 1000 — a request naming none, or more than that, is refused rather than answered with an empty component.
|
|
11122
|
+
*
|
|
11123
|
+
* @returns DbtColumnLineage the relations' column-level lineage
|
|
11124
|
+
* @throws ApiError
|
|
11125
|
+
*/
|
|
11126
|
+
static getDbtRunColumnLineage(data) {
|
|
11127
|
+
return request(OpenAPI, {
|
|
11128
|
+
method: "GET",
|
|
11129
|
+
url: "/w/{workspace}/jobs/dbt_column_lineage/{id}",
|
|
11130
|
+
path: {
|
|
11131
|
+
workspace: data.workspace,
|
|
11132
|
+
id: data.id
|
|
11133
|
+
},
|
|
11134
|
+
query: { asset_path: data.assetPath }
|
|
11135
|
+
});
|
|
11136
|
+
}
|
|
11137
|
+
/**
|
|
11062
11138
|
* List the per-relation progress one job has recorded so far
|
|
11063
11139
|
* Live materialization state for the relations a single job writes, keyed by relation. Polled while a run is in flight so a graph can move a node as its model completes. Authorized through the job, so a caller who may not read it is refused rather than told the run has no progress. An empty list means the job exists and has recorded nothing yet, or is unknown to this workspace.
|
|
11064
11140
|
*
|
|
@@ -13012,6 +13088,33 @@ var NativeTriggerService = class {
|
|
|
13012
13088
|
});
|
|
13013
13089
|
}
|
|
13014
13090
|
/**
|
|
13091
|
+
* set enabled state of native trigger
|
|
13092
|
+
* Enables or disables a native trigger. A disabled trigger stays registered on the
|
|
13093
|
+
* external service but starts no job when it fires.
|
|
13094
|
+
* Requires write access to the script or flow that the trigger is associated with.
|
|
13095
|
+
*
|
|
13096
|
+
* @param data The data for the request.
|
|
13097
|
+
* @param data.workspace
|
|
13098
|
+
* @param data.serviceName
|
|
13099
|
+
* @param data.externalId The external ID of the trigger from the external service
|
|
13100
|
+
* @param data.requestBody updated enabled state
|
|
13101
|
+
* @returns string native trigger enabled state updated
|
|
13102
|
+
* @throws ApiError
|
|
13103
|
+
*/
|
|
13104
|
+
static setNativeTriggerEnabled(data) {
|
|
13105
|
+
return request(OpenAPI, {
|
|
13106
|
+
method: "POST",
|
|
13107
|
+
url: "/w/{workspace}/native_triggers/{service_name}/setenabled/{external_id}",
|
|
13108
|
+
path: {
|
|
13109
|
+
workspace: data.workspace,
|
|
13110
|
+
service_name: data.serviceName,
|
|
13111
|
+
external_id: data.externalId
|
|
13112
|
+
},
|
|
13113
|
+
body: data.requestBody,
|
|
13114
|
+
mediaType: "application/json"
|
|
13115
|
+
});
|
|
13116
|
+
}
|
|
13117
|
+
/**
|
|
13015
13118
|
* list native triggers
|
|
13016
13119
|
* Lists all native triggers for the specified service in the workspace.
|
|
13017
13120
|
* @param data The data for the request.
|
|
@@ -16797,6 +16900,33 @@ var AssetService = class {
|
|
|
16797
16900
|
});
|
|
16798
16901
|
}
|
|
16799
16902
|
/**
|
|
16903
|
+
* Column-level lineage of a set of dbt relations
|
|
16904
|
+
* The direct (`copy` / `mod`) column-to-column lineage the given relations' columns sit in — the connected component around them, from the engine's static analysis. Not their own edges, which would stop one hop out since a column trace walks transitively, and not a whole project's, which carries model families the selection cannot reach.
|
|
16905
|
+
* Several relations, answered as one union, because one selection reaches several: a script's output column can derive from columns of several dbt models. Unpinned, the component crosses projects — a relation one project produces is another's source — and the caller's access is decided again for every project it reaches, so a trace ends where their grants do. A pinned answer, by version here or by job on the run route, is one project's.
|
|
16906
|
+
* Its own endpoint rather than a field on the asset graph: the graph is folder-wide and polled by a run page, while this is rendered for one selection at a time. Empty for projects that did not opt into the analysis pass (`column_lineage: true`), which is the ordinary case. The indirect `scan` kind is stored but never served: it reaches every output column of its model.
|
|
16907
|
+
*
|
|
16908
|
+
* @param data The data for the request.
|
|
16909
|
+
* @param data.workspace
|
|
16910
|
+
* @param data.assetPath The `dbt://` relations whose lineage to return. Repeated, once per relation, and answered as one union. At least one, and at most 1000 — a request naming none, or more than that, is refused rather than answered with an empty component.
|
|
16911
|
+
*
|
|
16912
|
+
* @param data.dbtScriptHash The deployed version a view is drawing, when it is drawing one — the dbt editor, which shows a single project as of a single deploy. A version-pinned answer is that version's project alone, the same as a job-pinned one, and only the unpinned answer crosses projects: a pin says which stored graph is on screen, and another project's live graph is not part of it.
|
|
16913
|
+
* A run's or an editor buffer's own graph is not reachable here: that pins to a job, and costs the job-read gate — see `jobs/dbt_column_lineage/{id}`.
|
|
16914
|
+
*
|
|
16915
|
+
* @returns DbtColumnLineage the relations' column-level lineage
|
|
16916
|
+
* @throws ApiError
|
|
16917
|
+
*/
|
|
16918
|
+
static getDbtColumnLineage(data) {
|
|
16919
|
+
return request(OpenAPI, {
|
|
16920
|
+
method: "GET",
|
|
16921
|
+
url: "/w/{workspace}/assets/column_lineage",
|
|
16922
|
+
path: { workspace: data.workspace },
|
|
16923
|
+
query: {
|
|
16924
|
+
asset_path: data.assetPath,
|
|
16925
|
+
dbt_script_hash: data.dbtScriptHash
|
|
16926
|
+
}
|
|
16927
|
+
});
|
|
16928
|
+
}
|
|
16929
|
+
/**
|
|
16800
16930
|
* List every workspace DuckDB macro (deployed `// macros` libraries)
|
|
16801
16931
|
* @param data The data for the request.
|
|
16802
16932
|
* @param data.workspace
|
|
@@ -17513,6 +17643,27 @@ var HubPublishService = class {
|
|
|
17513
17643
|
});
|
|
17514
17644
|
}
|
|
17515
17645
|
/**
|
|
17646
|
+
* list the hub's published projects
|
|
17647
|
+
* Forwards to the configured Hub's public project catalogue and returns its
|
|
17648
|
+
* status code and raw response body. Readable by any workspace member: the
|
|
17649
|
+
* listing is not workspace-scoped, and it is proxied only because the Hub's
|
|
17650
|
+
* listing endpoint sends no CORS header. Refused with 400 when the instance
|
|
17651
|
+
* has the Hub disabled, in which case no outbound request is made.
|
|
17652
|
+
*
|
|
17653
|
+
* @param data The data for the request.
|
|
17654
|
+
* @param data.workspace
|
|
17655
|
+
* @returns string raw Hub response body (status code is passed through from the Hub)
|
|
17656
|
+
* @throws ApiError
|
|
17657
|
+
*/
|
|
17658
|
+
static listHubProjects(data) {
|
|
17659
|
+
return request(OpenAPI, {
|
|
17660
|
+
method: "GET",
|
|
17661
|
+
url: "/w/{workspace}/hub/projects",
|
|
17662
|
+
path: { workspace: data.workspace },
|
|
17663
|
+
errors: { 400: "the Hub is disabled on this instance" }
|
|
17664
|
+
});
|
|
17665
|
+
}
|
|
17666
|
+
/**
|
|
17516
17667
|
* get the hub project linked to a workspace folder
|
|
17517
17668
|
* Requires the caller to be a workspace admin. Forwards the request to the
|
|
17518
17669
|
* configured Hub scoped to the `{workspace}:{folder}` source and returns
|
|
@@ -19021,6 +19172,35 @@ function checkpointableResult(value) {
|
|
|
19021
19172
|
function jsonRoundTrip(value) {
|
|
19022
19173
|
return JSON.parse(encodeCheckpointPayload({ value: checkpointableResult(value) })).value;
|
|
19023
19174
|
}
|
|
19175
|
+
/** The worker deserializes a sleep into a `u32` of seconds and fails the whole
|
|
19176
|
+
* job on anything wider, so a delay a multiplier has run away with has to be
|
|
19177
|
+
* capped here rather than sent. */
|
|
19178
|
+
const MAX_SLEEP_SECONDS = 4294967295;
|
|
19179
|
+
/** Every attempt claims its keys before the first one is dispatched, so an
|
|
19180
|
+
* unbounded `attempts` is a workflow that hangs allocating rather than a very
|
|
19181
|
+
* patient one. */
|
|
19182
|
+
const MAX_RETRY_ATTEMPTS = 100;
|
|
19183
|
+
/** Rejected where the policy is written, so a workflow fails at its first line
|
|
19184
|
+
* rather than mid-run on a replay. */
|
|
19185
|
+
function assertUsableRetry(retry) {
|
|
19186
|
+
if (retry === void 0) return;
|
|
19187
|
+
const { attempts } = retry;
|
|
19188
|
+
if (!Number.isInteger(attempts) || attempts < 0 || attempts > MAX_RETRY_ATTEMPTS) throw new Error(`retry.attempts must be a whole number between 0 and ${MAX_RETRY_ATTEMPTS}, got ${attempts}`);
|
|
19189
|
+
}
|
|
19190
|
+
/** How many retries the policy asks for, defended against a value that reached
|
|
19191
|
+
* `_nextStep` without going through `assertUsableRetry`. */
|
|
19192
|
+
function retryAttempts(retry) {
|
|
19193
|
+
const attempts = Math.trunc(retry?.attempts ?? 0) || 0;
|
|
19194
|
+
return Math.min(Math.max(attempts, 0), MAX_RETRY_ATTEMPTS);
|
|
19195
|
+
}
|
|
19196
|
+
/** Seconds to wait before retry number `attempt` (0 is the first retry). */
|
|
19197
|
+
function retryDelaySeconds(retry, attempt) {
|
|
19198
|
+
const base = retry.delay ?? 0;
|
|
19199
|
+
if (!(base > 0)) return 0;
|
|
19200
|
+
const grown = base * Math.pow(retry.multiplier ?? 1, attempt);
|
|
19201
|
+
const seconds = Math.floor(Math.min(retry.max_delay ?? grown, grown, MAX_SLEEP_SECONDS));
|
|
19202
|
+
return seconds > 0 ? seconds : 0;
|
|
19203
|
+
}
|
|
19024
19204
|
/** A step key travels as one path segment when its URLs are minted, so it must be
|
|
19025
19205
|
* non-empty and free of `/` and dot segments — otherwise `waitForApproval` would
|
|
19026
19206
|
* accept a key `getApprovalUrls` can never address. */
|
|
@@ -19052,6 +19232,11 @@ var WorkflowCtx = class {
|
|
|
19052
19232
|
* into a `complete` — the parent would then record the caught branch's value as
|
|
19053
19233
|
* a successful step. Boxed: the thrown value may be any falsy value. */
|
|
19054
19234
|
_pendingStepFailure = null;
|
|
19235
|
+
/** Failed tasks whose rejection nothing has consumed, by step key. An unawaited
|
|
19236
|
+
* task is still dispatched and still fails, but nothing drives the rejecting
|
|
19237
|
+
* thenable it returned. The first `.then()` on that thenable drops the entry,
|
|
19238
|
+
* so what remains is only what the body never looked at. */
|
|
19239
|
+
_unobservedTaskFailures = new Map();
|
|
19055
19240
|
/** When set, the task matching this key executes its inner function directly */
|
|
19056
19241
|
_executingKey;
|
|
19057
19242
|
/** Serializes fast-path POSTs across concurrent step() calls within one
|
|
@@ -19085,52 +19270,90 @@ var WorkflowCtx = class {
|
|
|
19085
19270
|
}
|
|
19086
19271
|
_nextStep(name, script, args = {}, dispatch_type = "inline", options) {
|
|
19087
19272
|
this._rethrowSwallowed();
|
|
19088
|
-
const
|
|
19089
|
-
|
|
19090
|
-
|
|
19091
|
-
|
|
19092
|
-
|
|
19093
|
-
|
|
19094
|
-
|
|
19095
|
-
|
|
19096
|
-
|
|
19273
|
+
const stepName = name || script || "step";
|
|
19274
|
+
const maxRetries = retryAttempts(options?.retry);
|
|
19275
|
+
const baseKey = this._allocKey(stepName);
|
|
19276
|
+
const attemptKeys = [baseKey];
|
|
19277
|
+
const backoffKeys = [];
|
|
19278
|
+
for (let i = 0; i < maxRetries; i++) {
|
|
19279
|
+
backoffKeys.push(this._allocKey(`${baseKey}#retry${i + 2}`));
|
|
19280
|
+
attemptKeys.push(this._allocKey(`${baseKey}#${i + 2}`));
|
|
19281
|
+
}
|
|
19282
|
+
for (let attempt = 0;; attempt++) {
|
|
19283
|
+
const key = attemptKeys[attempt];
|
|
19284
|
+
if (key in this.completed) {
|
|
19285
|
+
const value = this.completed[key];
|
|
19286
|
+
if (value && typeof value === "object" && value.__wmill_error) {
|
|
19287
|
+
if (attempt < maxRetries) {
|
|
19288
|
+
this._retryBackoff(backoffKeys[attempt], baseKey, options.retry, attempt);
|
|
19289
|
+
continue;
|
|
19290
|
+
}
|
|
19291
|
+
const err = taskErrorFromMarker(value, `Task '${name}' failed`);
|
|
19292
|
+
this._unobservedTaskFailures.set(baseKey, err);
|
|
19293
|
+
return { then: (_resolve, reject) => {
|
|
19294
|
+
this._unobservedTaskFailures.delete(baseKey);
|
|
19295
|
+
if (reject) reject(err);
|
|
19296
|
+
else throw err;
|
|
19297
|
+
} };
|
|
19298
|
+
}
|
|
19299
|
+
return { then: (resolve$1) => resolve$1(value) };
|
|
19097
19300
|
}
|
|
19098
|
-
|
|
19301
|
+
if (this._executingKey === key) return {
|
|
19302
|
+
then: (resolve$1) => resolve$1(null),
|
|
19303
|
+
_execute_directly: true
|
|
19304
|
+
};
|
|
19305
|
+
if (this._executingKey !== null) return { then: () => new Promise(() => {}) };
|
|
19306
|
+
const stepInfo = {
|
|
19307
|
+
name: name || key,
|
|
19308
|
+
script: script || key,
|
|
19309
|
+
args,
|
|
19310
|
+
key,
|
|
19311
|
+
dispatch_type
|
|
19312
|
+
};
|
|
19313
|
+
if (options) {
|
|
19314
|
+
if (options.timeout !== void 0) stepInfo.timeout = options.timeout;
|
|
19315
|
+
if (options.tag !== void 0) stepInfo.tag = options.tag;
|
|
19316
|
+
if (options.cache_ttl !== void 0) stepInfo.cache_ttl = options.cache_ttl;
|
|
19317
|
+
if (options.priority !== void 0) stepInfo.priority = options.priority;
|
|
19318
|
+
if (options.concurrency_limit !== void 0) stepInfo.concurrent_limit = options.concurrency_limit;
|
|
19319
|
+
if (options.concurrency_key !== void 0) stepInfo.concurrency_key = options.concurrency_key;
|
|
19320
|
+
if (options.concurrency_time_window_s !== void 0) stepInfo.concurrency_time_window_s = options.concurrency_time_window_s;
|
|
19321
|
+
}
|
|
19322
|
+
this.pending.push(stepInfo);
|
|
19323
|
+
return { then: () => {
|
|
19324
|
+
if (this._suspended) return new Promise(() => {});
|
|
19325
|
+
this._suspended = true;
|
|
19326
|
+
const steps = [...this.pending];
|
|
19327
|
+
this.pending = [];
|
|
19328
|
+
const names = steps.map((s) => s.name).join(", ");
|
|
19329
|
+
console.log(`\n--- WAC: ${names} ---`);
|
|
19330
|
+
this._raiseSuspend({
|
|
19331
|
+
mode: steps.length > 1 ? "parallel" : "sequential",
|
|
19332
|
+
steps
|
|
19333
|
+
});
|
|
19334
|
+
} };
|
|
19099
19335
|
}
|
|
19100
|
-
|
|
19101
|
-
|
|
19102
|
-
|
|
19103
|
-
|
|
19104
|
-
|
|
19105
|
-
|
|
19106
|
-
|
|
19107
|
-
|
|
19108
|
-
|
|
19336
|
+
}
|
|
19337
|
+
/** Wait out the backoff between two attempts of a retried task, as a durable
|
|
19338
|
+
* sleep, and return once there is nothing to wait for — no delay configured,
|
|
19339
|
+
* or the sleep already in the checkpoint.
|
|
19340
|
+
*
|
|
19341
|
+
* Raises where it stands, the way `_sleep` does, rather than handing back a
|
|
19342
|
+
* thenable: a task call the body never awaits is still dispatched (the runner
|
|
19343
|
+
* flushes `pending`), so a backoff that only fired when awaited would drop
|
|
19344
|
+
* the retry and let the round report the workflow complete. */
|
|
19345
|
+
_retryBackoff(key, baseKey, retry, attempt) {
|
|
19346
|
+
const seconds = retryDelaySeconds(retry, attempt);
|
|
19347
|
+
if (seconds < 1) return;
|
|
19348
|
+
if (key in this.completed) return;
|
|
19349
|
+
if (this._executingKey !== null) return;
|
|
19350
|
+
console.log(`\n--- WAC: sleep(${key}, ${seconds}s) before retrying ${baseKey} ---`);
|
|
19351
|
+
this._raiseSuspend({
|
|
19352
|
+
mode: "sleep",
|
|
19109
19353
|
key,
|
|
19110
|
-
|
|
19111
|
-
|
|
19112
|
-
|
|
19113
|
-
if (options.timeout !== void 0) stepInfo.timeout = options.timeout;
|
|
19114
|
-
if (options.tag !== void 0) stepInfo.tag = options.tag;
|
|
19115
|
-
if (options.cache_ttl !== void 0) stepInfo.cache_ttl = options.cache_ttl;
|
|
19116
|
-
if (options.priority !== void 0) stepInfo.priority = options.priority;
|
|
19117
|
-
if (options.concurrency_limit !== void 0) stepInfo.concurrent_limit = options.concurrency_limit;
|
|
19118
|
-
if (options.concurrency_key !== void 0) stepInfo.concurrency_key = options.concurrency_key;
|
|
19119
|
-
if (options.concurrency_time_window_s !== void 0) stepInfo.concurrency_time_window_s = options.concurrency_time_window_s;
|
|
19120
|
-
}
|
|
19121
|
-
this.pending.push(stepInfo);
|
|
19122
|
-
return { then: () => {
|
|
19123
|
-
if (this._suspended) return new Promise(() => {});
|
|
19124
|
-
this._suspended = true;
|
|
19125
|
-
const steps = [...this.pending];
|
|
19126
|
-
this.pending = [];
|
|
19127
|
-
const names = steps.map((s) => s.name).join(", ");
|
|
19128
|
-
console.log(`\n--- WAC: ${names} ---`);
|
|
19129
|
-
this._raiseSuspend({
|
|
19130
|
-
mode: steps.length > 1 ? "parallel" : "sequential",
|
|
19131
|
-
steps
|
|
19132
|
-
});
|
|
19133
|
-
} };
|
|
19354
|
+
seconds,
|
|
19355
|
+
steps: []
|
|
19356
|
+
});
|
|
19134
19357
|
}
|
|
19135
19358
|
/** Return and clear any pending (unawaited) steps. */
|
|
19136
19359
|
_flushPending() {
|
|
@@ -19297,6 +19520,13 @@ var WorkflowCtx = class {
|
|
|
19297
19520
|
this._pendingStepFailure = null;
|
|
19298
19521
|
return f;
|
|
19299
19522
|
}
|
|
19523
|
+
/** Report the task failures the body never looked at, and forget them. Which
|
|
19524
|
+
* rounds may call this is the runner's constraint, stated where it is enforced. */
|
|
19525
|
+
_warnUnobservedTaskFailures() {
|
|
19526
|
+
if (this._executingKey !== null) return;
|
|
19527
|
+
for (const [key, err] of this._unobservedTaskFailures) console.log(`\n--- WAC: task '${key}' failed but was never awaited, so the workflow result does not reflect it: ${err.message} ---`);
|
|
19528
|
+
this._unobservedTaskFailures.clear();
|
|
19529
|
+
}
|
|
19300
19530
|
};
|
|
19301
19531
|
async function sleep(seconds) {
|
|
19302
19532
|
const ctx = _workflowCtx ?? Reflect.get(globalThis, "__wmill_wf_ctx");
|
|
@@ -19322,9 +19552,11 @@ async function step(name, fn) {
|
|
|
19322
19552
|
* @example
|
|
19323
19553
|
* const extract_data = task(async (url: string) => { ... });
|
|
19324
19554
|
* const run_external = task("f/external_script", async (x: number) => { ... });
|
|
19555
|
+
* const call_api = task(fetchOrders, { retry: { attempts: 3, delay: 30, multiplier: 2 } });
|
|
19325
19556
|
*
|
|
19326
19557
|
* Inside a `workflow()`, calling a task dispatches it as a step.
|
|
19327
|
-
* Outside a workflow, the function body executes directly
|
|
19558
|
+
* Outside a workflow, the function body executes directly and
|
|
19559
|
+
* {@link TaskOptions} — retry included — does not apply.
|
|
19328
19560
|
*
|
|
19329
19561
|
* A task runs as its own job, so its result is always encoded as JSON and
|
|
19330
19562
|
* decoded back before the caller sees it: a `Date` comes back as a string, a
|
|
@@ -19342,6 +19574,7 @@ function task(fnOrPath, maybeFnOrOptions, maybeOptions) {
|
|
|
19342
19574
|
fn = fnOrPath;
|
|
19343
19575
|
taskOptions = maybeFnOrOptions;
|
|
19344
19576
|
}
|
|
19577
|
+
assertUsableRetry(taskOptions?.retry);
|
|
19345
19578
|
const taskName = fn.name || taskPath || "";
|
|
19346
19579
|
const wrapper = function(...args) {
|
|
19347
19580
|
const ctx = _workflowCtx ?? Reflect.get(globalThis, "__wmill_wf_ctx");
|
|
@@ -19400,6 +19633,7 @@ function task(fnOrPath, maybeFnOrOptions, maybeOptions) {
|
|
|
19400
19633
|
* // inside workflow: await extract({ url: "https://..." })
|
|
19401
19634
|
*/
|
|
19402
19635
|
function taskScript(path, options) {
|
|
19636
|
+
assertUsableRetry(options?.retry);
|
|
19403
19637
|
const name = path.split("/").pop() || path;
|
|
19404
19638
|
const wrapper = function(...args) {
|
|
19405
19639
|
const ctx = _workflowCtx ?? Reflect.get(globalThis, "__wmill_wf_ctx");
|
|
@@ -19425,6 +19659,7 @@ function taskScript(path, options) {
|
|
|
19425
19659
|
* // inside workflow: await pipeline({ input: data })
|
|
19426
19660
|
*/
|
|
19427
19661
|
function taskFlow(path, options) {
|
|
19662
|
+
assertUsableRetry(options?.retry);
|
|
19428
19663
|
const name = path.split("/").pop() || path;
|
|
19429
19664
|
const wrapper = function(...args) {
|
|
19430
19665
|
const ctx = _workflowCtx ?? Reflect.get(globalThis, "__wmill_wf_ctx");
|