@elaraai/e3-api-client 1.0.87 → 1.0.89
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/README.md +10 -0
- package/dist/src/executions.d.ts +28 -2
- package/dist/src/executions.d.ts.map +1 -1
- package/dist/src/executions.js +65 -7
- package/dist/src/executions.js.map +1 -1
- package/dist/src/http.d.ts +124 -5
- package/dist/src/http.d.ts.map +1 -1
- package/dist/src/http.js +151 -8
- package/dist/src/http.js.map +1 -1
- package/dist/src/http.spec.js +56 -1
- package/dist/src/http.spec.js.map +1 -1
- package/dist/src/index.d.ts +6 -6
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +2 -2
- package/dist/src/index.js.map +1 -1
- package/dist/src/packages.js +1 -1
- package/dist/src/packages.js.map +1 -1
- package/dist/src/repository.d.ts +24 -5
- package/dist/src/repository.d.ts.map +1 -1
- package/dist/src/repository.js +47 -8
- package/dist/src/repository.js.map +1 -1
- package/dist/src/repository.spec.d.ts +6 -0
- package/dist/src/repository.spec.d.ts.map +1 -0
- package/dist/src/repository.spec.js +95 -0
- package/dist/src/repository.spec.js.map +1 -0
- package/dist/src/stopping-run.spec.d.ts +6 -0
- package/dist/src/stopping-run.spec.d.ts.map +1 -0
- package/dist/src/stopping-run.spec.js +145 -0
- package/dist/src/stopping-run.spec.js.map +1 -0
- package/dist/src/types.d.ts +11 -2
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/types.js +3 -2
- package/dist/src/types.js.map +1 -1
- package/dist/src/workspaces.d.ts +47 -2
- package/dist/src/workspaces.d.ts.map +1 -1
- package/dist/src/workspaces.js +56 -12
- package/dist/src/workspaces.js.map +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -78,6 +78,16 @@ A view that follows a few datasets asks for those alone:
|
|
|
78
78
|
named that the workspace has, and the tasks producing them, each as the whole
|
|
79
79
|
status gives it. It costs the server what the view binds, not the workspace.
|
|
80
80
|
|
|
81
|
+
A poll asks conditionally: `workspaceStatusSince(url, repo, ws, etag, options,
|
|
82
|
+
query)` answers the status with its `ETag`, and `null` while the status
|
|
83
|
+
answered under the tag it was given is current, which costs the server a read
|
|
84
|
+
of the workspace's revision and nothing else. The tag does not name the
|
|
85
|
+
runner's view of an execution recorded running, so a poll that must notice a
|
|
86
|
+
runner gone asks unconditionally (`etag` `null`) now and then. A poll gains
|
|
87
|
+
nothing from retrying a transient failure, since its next poll is its retry:
|
|
88
|
+
`pollRequestOptions(options)` gives it one attempt (`NO_RETRY`) unless the
|
|
89
|
+
caller set a policy of its own.
|
|
90
|
+
|
|
81
91
|
### Datasets
|
|
82
92
|
|
|
83
93
|
```typescript
|
package/dist/src/executions.d.ts
CHANGED
|
@@ -33,6 +33,12 @@ export interface DataflowPollOptions {
|
|
|
33
33
|
* Returns immediately after spawning execution in background.
|
|
34
34
|
* Use dataflowExecutePoll() to poll for progress.
|
|
35
35
|
*
|
|
36
|
+
* @remarks
|
|
37
|
+
* A workspace a run that is stopping still holds is refused with a
|
|
38
|
+
* `Retry-After`, which the client waits out ({@link retryingRefusal}). One held
|
|
39
|
+
* otherwise is asked of again a few times, backing off, before the refusal is
|
|
40
|
+
* raised.
|
|
41
|
+
*
|
|
36
42
|
* @param url - Base URL of the e3 API server
|
|
37
43
|
* @param repo - Repository name
|
|
38
44
|
* @param workspace - Workspace name
|
|
@@ -163,15 +169,35 @@ export declare function dataflowExecutePoll(url: string, repo: string, workspace
|
|
|
163
169
|
*/
|
|
164
170
|
export declare function dataflowBudget(url: string, repo: string, workspace: string, options: RequestOptions): Promise<DataflowBudget | null>;
|
|
165
171
|
/**
|
|
166
|
-
*
|
|
172
|
+
* How {@link dataflowCancel} follows the run it cancelled until it has
|
|
173
|
+
* stopped.
|
|
174
|
+
*/
|
|
175
|
+
export interface DataflowCancelOptions {
|
|
176
|
+
/** Called once when the run is still stopping after the cancel answered */
|
|
177
|
+
onStopping?: () => void;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Cancel a running dataflow execution, and answer once it has stopped.
|
|
181
|
+
*
|
|
182
|
+
* @remarks
|
|
183
|
+
* A server whose run stops where it runs answers the cancel once the run has
|
|
184
|
+
* ended, as the local one does. One whose run's tasks run in other processes
|
|
185
|
+
* or machines may answer once the cancel is recorded, its poll answering the
|
|
186
|
+
* run `stopping` until it has stopped. Either way the client follows the run
|
|
187
|
+
* it cancelled — the workspace's latest, as the cancel was asked — until its
|
|
188
|
+
* status is neither `running` nor `stopping`, or another run has followed it.
|
|
189
|
+
* A start, a deploy or a removal of the workspace straight after finds the
|
|
190
|
+
* run gone, but for the moment it takes to let the workspace go, which the
|
|
191
|
+
* server answers with a `Retry-After` that those calls wait out.
|
|
167
192
|
*
|
|
168
193
|
* @param url - Base URL of the API server
|
|
169
194
|
* @param repo - Repository name
|
|
170
195
|
* @param workspace - Workspace name
|
|
171
196
|
* @param options - Request options (token, etc.)
|
|
197
|
+
* @param cancelOptions - What hears that the run is still stopping
|
|
172
198
|
* @throws {ApiError} `dataflow_error`, "No active execution for this
|
|
173
199
|
* workspace", when no execution is running; or why else the cancel failed
|
|
174
200
|
* @throws {AuthError} On 401 Unauthorized
|
|
175
201
|
*/
|
|
176
|
-
export declare function dataflowCancel(url: string, repo: string, workspace: string, options: RequestOptions): Promise<void>;
|
|
202
|
+
export declare function dataflowCancel(url: string, repo: string, workspace: string, options: RequestOptions, cancelOptions?: DataflowCancelOptions): Promise<void>;
|
|
177
203
|
//# sourceMappingURL=executions.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"executions.d.ts","sourceRoot":"","sources":["../../src/executions.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,cAAc,EAAE,sBAAsB,EAAuB,MAAM,YAAY,CAAC;AAQ3I,OAAO,
|
|
1
|
+
{"version":3,"file":"executions.d.ts","sourceRoot":"","sources":["../../src/executions.ts"],"names":[],"mappings":"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"}
|
package/dist/src/executions.js
CHANGED
|
@@ -2,16 +2,22 @@
|
|
|
2
2
|
* Copyright (c) 2025 Elara AI Pty Ltd
|
|
3
3
|
* Licensed under BSL 1.1. See LICENSE for details.
|
|
4
4
|
*/
|
|
5
|
-
import { IntegerType, NullType, OptionType, lessFor, none, printFor, some, variant } from '@elaraai/east';
|
|
5
|
+
import { IntegerType, NullType, OptionType, StringType, equalFor, lessFor, none, printFor, some, variant } from '@elaraai/east';
|
|
6
6
|
import { dataflowForce } from '@elaraai/e3-types';
|
|
7
7
|
import { TaskLogChunkType, DataflowRequestType, DataflowGraphType, DataflowBudgetType, DataflowExecutionStateType, } from './types.js';
|
|
8
|
-
import { get, post, verboseQuery, ApiError } from './http.js';
|
|
8
|
+
import { get, post, retryingRefusal, verboseQuery, ApiError } from './http.js';
|
|
9
9
|
/**
|
|
10
10
|
* Start dataflow execution on a workspace (non-blocking).
|
|
11
11
|
*
|
|
12
12
|
* Returns immediately after spawning execution in background.
|
|
13
13
|
* Use dataflowExecutePoll() to poll for progress.
|
|
14
14
|
*
|
|
15
|
+
* @remarks
|
|
16
|
+
* A workspace a run that is stopping still holds is refused with a
|
|
17
|
+
* `Retry-After`, which the client waits out ({@link retryingRefusal}). One held
|
|
18
|
+
* otherwise is asked of again a few times, backing off, before the refusal is
|
|
19
|
+
* raised.
|
|
20
|
+
*
|
|
15
21
|
* @param url - Base URL of the e3 API server
|
|
16
22
|
* @param repo - Repository name
|
|
17
23
|
* @param workspace - Workspace name
|
|
@@ -25,14 +31,15 @@ export async function dataflowExecuteLaunch(url, repo, workspace, dataflowOption
|
|
|
25
31
|
const baseDelay = 200;
|
|
26
32
|
for (let attempt = 0;; attempt++) {
|
|
27
33
|
try {
|
|
28
|
-
await post(url, verboseQuery(`/repos/${encodeURIComponent(repo)}/workspaces/${encodeURIComponent(workspace)}/dataflow`, options), {
|
|
34
|
+
await retryingRefusal('workspace_locked', () => post(url, verboseQuery(`/repos/${encodeURIComponent(repo)}/workspaces/${encodeURIComponent(workspace)}/dataflow`, options), {
|
|
29
35
|
force: dataflowForce(dataflowOptions.force),
|
|
30
36
|
filter: dataflowOptions.filter != null ? some(dataflowOptions.filter) : none,
|
|
31
|
-
}, DataflowRequestType, NullType, options);
|
|
37
|
+
}, DataflowRequestType, NullType, options), options);
|
|
32
38
|
return;
|
|
33
39
|
}
|
|
34
40
|
catch (err) {
|
|
35
|
-
|
|
41
|
+
// A refusal that names a wait has been waited out already.
|
|
42
|
+
if (err instanceof ApiError && err.code === 'workspace_locked' && err.retryAfterMs === undefined && attempt < maxRetries) {
|
|
36
43
|
const delay = baseDelay * Math.pow(2, attempt) * (0.5 + Math.random() * 0.5);
|
|
37
44
|
await new Promise(r => setTimeout(r, delay));
|
|
38
45
|
continue;
|
|
@@ -262,18 +269,69 @@ export async function dataflowBudget(url, repo, workspace, options) {
|
|
|
262
269
|
const budget = await get(url, `/repos/${encodeURIComponent(repo)}/workspaces/${encodeURIComponent(workspace)}/dataflow/budget`, OptionType(DataflowBudgetType), options);
|
|
263
270
|
return budget.type === 'some' ? budget.value : null;
|
|
264
271
|
}
|
|
272
|
+
/** How long {@link dataflowCancel} waits between polls of a run that is
|
|
273
|
+
* stopping, at first and at most, in milliseconds. */
|
|
274
|
+
const STOPPING_POLL_MIN_MS = 100;
|
|
275
|
+
const STOPPING_POLL_MAX_MS = 2_000;
|
|
276
|
+
/** Whether two runs are one, by their ids. */
|
|
277
|
+
const sameRun = equalFor(StringType);
|
|
265
278
|
/**
|
|
266
|
-
*
|
|
279
|
+
* The id of a workspace's latest run, or `null` when it has none.
|
|
267
280
|
*
|
|
268
281
|
* @param url - Base URL of the API server
|
|
269
282
|
* @param repo - Repository name
|
|
270
283
|
* @param workspace - Workspace name
|
|
271
284
|
* @param options - Request options (token, etc.)
|
|
285
|
+
* @returns The run's id, or `null`
|
|
286
|
+
*/
|
|
287
|
+
async function latestRunId(url, repo, workspace, options) {
|
|
288
|
+
try {
|
|
289
|
+
return (await dataflowExecutePoll(url, repo, workspace, { limit: 0 }, options)).runId;
|
|
290
|
+
}
|
|
291
|
+
catch (err) {
|
|
292
|
+
if (err instanceof ApiError && err.code === 'execution_not_found')
|
|
293
|
+
return null;
|
|
294
|
+
throw err;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Cancel a running dataflow execution, and answer once it has stopped.
|
|
299
|
+
*
|
|
300
|
+
* @remarks
|
|
301
|
+
* A server whose run stops where it runs answers the cancel once the run has
|
|
302
|
+
* ended, as the local one does. One whose run's tasks run in other processes
|
|
303
|
+
* or machines may answer once the cancel is recorded, its poll answering the
|
|
304
|
+
* run `stopping` until it has stopped. Either way the client follows the run
|
|
305
|
+
* it cancelled — the workspace's latest, as the cancel was asked — until its
|
|
306
|
+
* status is neither `running` nor `stopping`, or another run has followed it.
|
|
307
|
+
* A start, a deploy or a removal of the workspace straight after finds the
|
|
308
|
+
* run gone, but for the moment it takes to let the workspace go, which the
|
|
309
|
+
* server answers with a `Retry-After` that those calls wait out.
|
|
310
|
+
*
|
|
311
|
+
* @param url - Base URL of the API server
|
|
312
|
+
* @param repo - Repository name
|
|
313
|
+
* @param workspace - Workspace name
|
|
314
|
+
* @param options - Request options (token, etc.)
|
|
315
|
+
* @param cancelOptions - What hears that the run is still stopping
|
|
272
316
|
* @throws {ApiError} `dataflow_error`, "No active execution for this
|
|
273
317
|
* workspace", when no execution is running; or why else the cancel failed
|
|
274
318
|
* @throws {AuthError} On 401 Unauthorized
|
|
275
319
|
*/
|
|
276
|
-
export async function dataflowCancel(url, repo, workspace, options) {
|
|
320
|
+
export async function dataflowCancel(url, repo, workspace, options, cancelOptions = {}) {
|
|
321
|
+
const run = await latestRunId(url, repo, workspace, options);
|
|
277
322
|
await post(url, `/repos/${encodeURIComponent(repo)}/workspaces/${encodeURIComponent(workspace)}/dataflow/cancel`, null, NullType, NullType, options);
|
|
323
|
+
if (run === null)
|
|
324
|
+
return;
|
|
325
|
+
let told = false;
|
|
326
|
+
for (let wait = STOPPING_POLL_MIN_MS;; wait = Math.min(wait * 2, STOPPING_POLL_MAX_MS)) {
|
|
327
|
+
const state = await dataflowExecutePoll(url, repo, workspace, { limit: 0 }, options);
|
|
328
|
+
if (!sameRun(state.runId, run) || (state.status.type !== 'running' && state.status.type !== 'stopping'))
|
|
329
|
+
return;
|
|
330
|
+
if (!told) {
|
|
331
|
+
told = true;
|
|
332
|
+
cancelOptions.onStopping?.();
|
|
333
|
+
}
|
|
334
|
+
await new Promise((resolve) => setTimeout(resolve, wait));
|
|
335
|
+
}
|
|
278
336
|
}
|
|
279
337
|
//# sourceMappingURL=executions.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"executions.js","sourceRoot":"","sources":["../../src/executions.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,UAAU,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"executions.js","sourceRoot":"","sources":["../../src/executions.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,UAAU,EAAE,UAAU,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAChI,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAElD,OAAO,EACL,gBAAgB,EAChB,mBAAmB,EACnB,iBAAiB,EACjB,kBAAkB,EAClB,0BAA0B,GAC3B,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,eAAe,EAAE,YAAY,EAAE,QAAQ,EAAuB,MAAM,WAAW,CAAC;AA2BpG;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,GAAW,EACX,IAAY,EACZ,SAAiB,EACjB,kBAAmC,EAAE,EACrC,OAAuB;IAEvB,MAAM,UAAU,GAAG,CAAC,CAAC;IACrB,MAAM,SAAS,GAAG,GAAG,CAAC;IAEtB,KAAK,IAAI,OAAO,GAAG,CAAC,GAAI,OAAO,EAAE,EAAE,CAAC;QAClC,IAAI,CAAC;YACH,MAAM,eAAe,CAAC,kBAAkB,EAAE,GAAG,EAAE,CAAC,IAAI,CAClD,GAAG,EACH,YAAY,CAAC,UAAU,kBAAkB,CAAC,IAAI,CAAC,eAAe,kBAAkB,CAAC,SAAS,CAAC,WAAW,EAAE,OAAO,CAAC,EAChH;gBACE,KAAK,EAAE,aAAa,CAAC,eAAe,CAAC,KAAK,CAAC;gBAC3C,MAAM,EAAE,eAAe,CAAC,MAAM,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI;aAC7E,EACD,mBAAmB,EACnB,QAAQ,EACR,OAAO,CACR,EAAE,OAAO,CAAC,CAAC;YACZ,OAAO;QACT,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,2DAA2D;YAC3D,IAAI,GAAG,YAAY,QAAQ,IAAI,GAAG,CAAC,IAAI,KAAK,kBAAkB,IAAI,GAAG,CAAC,YAAY,KAAK,SAAS,IAAI,OAAO,GAAG,UAAU,EAAE,CAAC;gBACzH,MAAM,KAAK,GAAG,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,GAAG,CAAC,CAAC;gBAC7E,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;gBAC7C,SAAS;YACX,CAAC;YACD,MAAM,GAAG,CAAC;QACZ,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,SAAS,mBAAmB,CAAC,KAA6B;IACxD,MAAM,KAAK,GAA0B,EAAE,CAAC;IAExC,uCAAuC;IACvC,yEAAyE;IACzE,4CAA4C;IAC5C,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;QACjC,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;YACnB,KAAK,UAAU;gBACb,KAAK,CAAC,IAAI,CAAC;oBACT,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,IAAI;oBACtB,MAAM,EAAE,KAAK;oBACb,KAAK,EAAE,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC;oBAC/B,QAAQ,EAAE,KAAK,CAAC,KAAK,CAAC,QAAQ;iBAC/B,CAAC,CAAC;gBACH,MAAM;YACR,KAAK,QAAQ;gBACX,KAAK,CAAC,IAAI,CAAC;oBACT,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,IAAI;oBACtB,MAAM,EAAE,IAAI;oBACZ,KAAK,EAAE,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC;oBAC/B,QAAQ,EAAE,CAAC;iBACZ,CAAC,CAAC;gBACH,MAAM;YACR,KAAK,QAAQ;gBACX,KAAK,CAAC,IAAI,CAAC;oBACT,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,IAAI;oBACtB,MAAM,EAAE,KAAK;oBACb,KAAK,EAAE,OAAO,CAAC,QAAQ,EAAE,EAAE,QAAQ,EAAE,KAAK,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;oBAC5D,QAAQ,EAAE,KAAK,CAAC,KAAK,CAAC,QAAQ;iBAC/B,CAAC,CAAC;gBACH,MAAM;YACR,KAAK,OAAO;gBACV,KAAK,CAAC,IAAI,CAAC;oBACT,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,IAAI;oBACtB,MAAM,EAAE,KAAK;oBACb,KAAK,EAAE,OAAO,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,KAAK,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;oBACzD,QAAQ,EAAE,CAAC;iBACZ,CAAC,CAAC;gBACH,MAAM;YACR,KAAK,mBAAmB;gBACtB,KAAK,CAAC,IAAI,CAAC;oBACT,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,IAAI;oBACtB,MAAM,EAAE,KAAK;oBACb,KAAK,EAAE,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC;oBAC/B,QAAQ,EAAE,CAAC;iBACZ,CAAC,CAAC;gBACH,MAAM;YACR,wEAAwE;QAC1E,CAAC;IACH,CAAC;IAED,iDAAiD;IACjD,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;QACpE,QAAQ,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,MAAM,CAAC;QACnF,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC;QAClD,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,CAAC,KAAK,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,MAAM,CAAC;QAC/F,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,MAAM,CAAC;QACrE,QAAQ,EAAE,CAAC;KACZ,CAAC;IAEF,OAAO;QACL,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,IAAI,KAAK,WAAW;QAC1C,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,KAAK;QACL,QAAQ,EAAE,OAAO,CAAC,QAAQ;KAC3B,CAAC;AACJ,CAAC;AAED,8DAA8D;AAC9D,MAAM,SAAS,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;AAEvC;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,oBAAoB,CAAC,KAA0D;IAC7F,OAAO,SAAS,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;AACjD,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,GAAW,EACX,IAAY,EACZ,SAAiB,EACjB,kBAAmC,EAAE,EACrC,OAAuB,EACvB,cAAmC,EAAE;IAErC,MAAM,EAAE,YAAY,GAAG,GAAG,EAAE,OAAO,GAAG,MAAM,EAAE,GAAG,WAAW,CAAC;IAE7D,kBAAkB;IAClB,MAAM,qBAAqB,CAAC,GAAG,EAAE,IAAI,EAAE,SAAS,EAAE,eAAe,EAAE,OAAO,CAAC,CAAC;IAE5E,2EAA2E;IAC3E,yEAAyE;IACzE,sEAAsE;IACtE,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAC7B,MAAM,MAAM,GAAqC,EAAE,CAAC;IACpD,IAAI,KAAK,GAAG,EAAE,CAAC;IACf,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,GAAG,OAAO,EAAE,CAAC;QACxC,MAAM,KAAK,GAAG,MAAM,mBAAmB,CAAC,GAAG,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,KAAK,EAAE,EAAE,OAAO,CAAC,CAAC;QAClF,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC;QAC7B,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;QAC9C,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC;QACtB,IAAI,KAAK,IAAI,oBAAoB,CAAC,KAAK,CAAC;YAAE,SAAS;QAEnD,IAAI,KAAK,CAAC,MAAM,CAAC,IAAI,KAAK,WAAW,IAAI,KAAK,CAAC,MAAM,CAAC,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YAC3G,OAAO,mBAAmB,CAAC,EAAE,GAAG,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;QACnD,CAAC;QAED,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC,CAAC;IACtD,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;AAClD,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,GAAW,EACX,IAAY,EACZ,SAAiB,EACjB,OAAuB;IAEvB,OAAO,GAAG,CACR,GAAG,EACH,UAAU,kBAAkB,CAAC,IAAI,CAAC,eAAe,kBAAkB,CAAC,SAAS,CAAC,iBAAiB,EAC/F,iBAAiB,EACjB,OAAO,CACR,CAAC;AACJ,CAAC;AAiBD;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,GAAW,EACX,IAAY,EACZ,SAAiB,EACjB,IAAY,EACZ,aAAyB,EAAE,EAC3B,OAAuB;IAEvB,MAAM,MAAM,GAAG,IAAI,eAAe,EAAE,CAAC;IACrC,IAAI,UAAU,CAAC,MAAM;QAAE,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC;IAC/D,IAAI,UAAU,CAAC,MAAM,IAAI,IAAI;QAAE,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;IAC/E,IAAI,UAAU,CAAC,KAAK,IAAI,IAAI;QAAE,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC;IAC5E,IAAI,UAAU,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;QACvC,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,UAAU,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;QACtD,MAAM,CAAC,GAAG,CAAC,WAAW,EAAE,UAAU,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;IAC5D,CAAC;IAED,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,EAAE,CAAC;IAChC,MAAM,IAAI,GAAG,UAAU,kBAAkB,CAAC,IAAI,CAAC,eAAe,kBAAkB,CAAC,SAAS,CAAC,kBAAkB,kBAAkB,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;IAEnK,OAAO,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE,gBAAgB,EAAE,OAAO,CAAC,CAAC;AACnD,CAAC;AAgBD,qCAAqC;AACrC,MAAM,QAAQ,GAAG,QAAQ,CAAC,WAAW,CAAC,CAAC;AAEvC;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,GAAW,EACX,IAAY,EACZ,SAAiB,EACjB,eAAsC,EAAE,EACxC,OAAuB;IAEvB,MAAM,MAAM,GAAG,IAAI,eAAe,EAAE,CAAC;IACrC,IAAI,YAAY,CAAC,KAAK,IAAI,IAAI;QAAE,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,QAAQ,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC;IAClF,IAAI,YAAY,CAAC,KAAK,IAAI,IAAI;QAAE,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC;IAEhF,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,EAAE,CAAC;IAChC,MAAM,IAAI,GAAG,UAAU,kBAAkB,CAAC,IAAI,CAAC,eAAe,kBAAkB,CAAC,SAAS,CAAC,sBAAsB,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;IAE5I,OAAO,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE,0BAA0B,EAAE,OAAO,CAAC,CAAC;AAC7D,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,GAAW,EACX,IAAY,EACZ,SAAiB,EACjB,OAAuB;IAEvB,MAAM,MAAM,GAAG,MAAM,GAAG,CACtB,GAAG,EACH,UAAU,kBAAkB,CAAC,IAAI,CAAC,eAAe,kBAAkB,CAAC,SAAS,CAAC,kBAAkB,EAChG,UAAU,CAAC,kBAAkB,CAAC,EAC9B,OAAO,CACR,CAAC;IACF,OAAO,MAAM,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AACtD,CAAC;AAED;uDACuD;AACvD,MAAM,oBAAoB,GAAG,GAAG,CAAC;AACjC,MAAM,oBAAoB,GAAG,KAAK,CAAC;AAEnC,8CAA8C;AAC9C,MAAM,OAAO,GAAG,QAAQ,CAAC,UAAU,CAAC,CAAC;AAWrC;;;;;;;;GAQG;AACH,KAAK,UAAU,WAAW,CAAC,GAAW,EAAE,IAAY,EAAE,SAAiB,EAAE,OAAuB;IAC9F,IAAI,CAAC;QACH,OAAO,CAAC,MAAM,mBAAmB,CAAC,GAAG,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC;IACxF,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,QAAQ,IAAI,GAAG,CAAC,IAAI,KAAK,qBAAqB;YAAE,OAAO,IAAI,CAAC;QAC/E,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,GAAW,EACX,IAAY,EACZ,SAAiB,EACjB,OAAuB,EACvB,gBAAuC,EAAE;IAEzC,MAAM,GAAG,GAAG,MAAM,WAAW,CAAC,GAAG,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;IAC7D,MAAM,IAAI,CACR,GAAG,EACH,UAAU,kBAAkB,CAAC,IAAI,CAAC,eAAe,kBAAkB,CAAC,SAAS,CAAC,kBAAkB,EAChG,IAAI,EACJ,QAAQ,EACR,QAAQ,EACR,OAAO,CACR,CAAC;IACF,IAAI,GAAG,KAAK,IAAI;QAAE,OAAO;IAEzB,IAAI,IAAI,GAAG,KAAK,CAAC;IACjB,KAAK,IAAI,IAAI,GAAG,oBAAoB,GAAI,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,EAAE,oBAAoB,CAAC,EAAE,CAAC;QACxF,MAAM,KAAK,GAAG,MAAM,mBAAmB,CAAC,GAAG,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;QACrF,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,KAAK,SAAS,IAAI,KAAK,CAAC,MAAM,CAAC,IAAI,KAAK,UAAU,CAAC;YAAE,OAAO;QAChH,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,IAAI,GAAG,IAAI,CAAC;YACZ,aAAa,CAAC,UAAU,EAAE,EAAE,CAAC;QAC/B,CAAC;QACD,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;IAC5D,CAAC;AACH,CAAC"}
|
package/dist/src/http.d.ts
CHANGED
|
@@ -101,7 +101,16 @@ export declare function verboseQuery(path: string, options: RequestOptions): str
|
|
|
101
101
|
export declare class ApiError extends Error {
|
|
102
102
|
readonly code: string;
|
|
103
103
|
readonly details?: unknown | undefined;
|
|
104
|
-
|
|
104
|
+
readonly retryAfterMs?: number | undefined;
|
|
105
|
+
/**
|
|
106
|
+
* @param code - The error's code
|
|
107
|
+
* @param details - What the server said of it
|
|
108
|
+
* @param retryAfterMs - How long the server asks the client to wait before
|
|
109
|
+
* it asks again, in milliseconds, as the refusal's `Retry-After` says:
|
|
110
|
+
* a workspace a run that is stopping still holds is refused with one
|
|
111
|
+
* ({@link retryingRefusal}); `undefined` when it names none
|
|
112
|
+
*/
|
|
113
|
+
constructor(code: string, details?: unknown | undefined, retryAfterMs?: number | undefined);
|
|
105
114
|
}
|
|
106
115
|
/**
|
|
107
116
|
* A read pinned to a content hash the dataset no longer holds (a 409
|
|
@@ -128,6 +137,24 @@ export declare class DatasetHashMismatchError extends ApiError {
|
|
|
128
137
|
export declare class AuthError extends Error {
|
|
129
138
|
constructor(message: string);
|
|
130
139
|
}
|
|
140
|
+
/**
|
|
141
|
+
* A retry policy of one attempt: a poll's, whose next poll is its retry.
|
|
142
|
+
*
|
|
143
|
+
* @remarks
|
|
144
|
+
* A call that is made again a second later gains nothing from retrying a
|
|
145
|
+
* transient failure in between, and a server under load is asked once per
|
|
146
|
+
* poll rather than four times. {@link pollRequestOptions} gives a poll this
|
|
147
|
+
* policy unless its caller set one.
|
|
148
|
+
*/
|
|
149
|
+
export declare const NO_RETRY: RetryOptions;
|
|
150
|
+
/**
|
|
151
|
+
* The request options of a poll: the caller's, with {@link NO_RETRY} unless
|
|
152
|
+
* the caller set a policy of its own.
|
|
153
|
+
*
|
|
154
|
+
* @param options - The caller's request options
|
|
155
|
+
* @returns The options a poll's request is made with
|
|
156
|
+
*/
|
|
157
|
+
export declare function pollRequestOptions(options: RequestOptions): RequestOptions;
|
|
131
158
|
/**
|
|
132
159
|
* Whether a thrown `fetch` error is a connection-level failure where the request
|
|
133
160
|
* did not complete, so a retry cannot double-apply. An `AbortError` is never
|
|
@@ -228,6 +255,39 @@ export declare function parseErrorBody(text: string, fallbackCode: string): ApiE
|
|
|
228
255
|
* @throws {AuthError} On 401 Unauthorized
|
|
229
256
|
*/
|
|
230
257
|
export declare function get<T extends EastType>(url: string, path: string, successType: T, options: RequestOptions): Promise<ValueTypeOf<T>>;
|
|
258
|
+
/**
|
|
259
|
+
* An answer a conditional GET was given, with the tag it carries: what a
|
|
260
|
+
* client sends back to ask whether the answer has changed.
|
|
261
|
+
*/
|
|
262
|
+
export interface Conditional<T> {
|
|
263
|
+
/** The answer's value */
|
|
264
|
+
readonly value: T;
|
|
265
|
+
/** The answer's `ETag`; `null` when the server named none, in which case
|
|
266
|
+
* the next ask is unconditional */
|
|
267
|
+
readonly etag: string | null;
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Make a conditional GET request: the answer, decoded, with the `ETag` it
|
|
271
|
+
* carries; or `null` when the server answers `304 Not Modified` to the tag
|
|
272
|
+
* sent as `If-None-Match`, which says the answer the client holds is current.
|
|
273
|
+
*
|
|
274
|
+
* @remarks
|
|
275
|
+
* A poll holds the tag of the last answer it was given and asks with it: an
|
|
276
|
+
* unchanged status costs the server a read of the workspace's revision, and
|
|
277
|
+
* the client no decoding. A server that names no tag answers in full every
|
|
278
|
+
* time, and the next ask is unconditional.
|
|
279
|
+
*
|
|
280
|
+
* @param url - Base URL of the e3 API server
|
|
281
|
+
* @param path - The request's path under `/api`
|
|
282
|
+
* @param successType - The type of the answer's value
|
|
283
|
+
* @param etag - The tag of the answer the client holds; `null` for none
|
|
284
|
+
* @param options - Request options including auth token
|
|
285
|
+
* @returns The answer and its tag, or `null` when the one the client holds is
|
|
286
|
+
* current
|
|
287
|
+
* @throws {ApiError} On application-level errors
|
|
288
|
+
* @throws {AuthError} On 401 Unauthorized
|
|
289
|
+
*/
|
|
290
|
+
export declare function getConditional<T extends EastType>(url: string, path: string, successType: T, etag: string | null, options: RequestOptions): Promise<Conditional<ValueTypeOf<T>> | null>;
|
|
231
291
|
/**
|
|
232
292
|
* Make a POST request with BEAST2 body and decode BEAST2 response.
|
|
233
293
|
* @param extraHeaders - Optional additional request headers (e.g. `Idempotency-Key`), merged after the defaults.
|
|
@@ -253,22 +313,81 @@ export declare function del<T extends EastType>(url: string, path: string, succe
|
|
|
253
313
|
* @throws {AuthError} On 401 Unauthorized
|
|
254
314
|
*/
|
|
255
315
|
export declare function putEmpty<T extends EastType>(url: string, path: string, successType: T, options: RequestOptions): Promise<ValueTypeOf<T>>;
|
|
316
|
+
/**
|
|
317
|
+
* An answer, with what its response says beside its value: whether the server
|
|
318
|
+
* took the request on to finish after answering (`202 Accepted`), where it
|
|
319
|
+
* says to follow it, and when to ask.
|
|
320
|
+
*/
|
|
321
|
+
export interface Answered<T> {
|
|
322
|
+
/** The answer's value */
|
|
323
|
+
readonly value: T;
|
|
324
|
+
/** Whether the server answered `202 Accepted` */
|
|
325
|
+
readonly accepted: boolean;
|
|
326
|
+
/** The URL the answer's `Location` names, resolved against the request's;
|
|
327
|
+
* `null` when it names none */
|
|
328
|
+
readonly location: string | null;
|
|
329
|
+
/** The answer's `Retry-After`, in milliseconds; `undefined` when it names
|
|
330
|
+
* none */
|
|
331
|
+
readonly retryAfterMs: number | undefined;
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* Make a request of a URL and decode its BEAST2 answer, keeping what the
|
|
335
|
+
* response says beside its value: whether the server accepted the request to
|
|
336
|
+
* finish after answering, the `Location` it names and its `Retry-After`.
|
|
337
|
+
*
|
|
338
|
+
* @param target - The request's URL, whole: a route's, or one a `Location`
|
|
339
|
+
* named
|
|
340
|
+
* @param method - `GET` or `DELETE`, either of which a retry sends again
|
|
341
|
+
* @param successType - The type of the answer's value
|
|
342
|
+
* @param options - Request options including auth token
|
|
343
|
+
* @returns The answer
|
|
344
|
+
* @throws {ApiError} On application-level errors
|
|
345
|
+
* @throws {AuthError} On 401 Unauthorized
|
|
346
|
+
*/
|
|
347
|
+
export declare function requestAnswered<T extends EastType>(target: string, method: 'GET' | 'DELETE', successType: T, options: RequestOptions): Promise<Answered<ValueTypeOf<T>>>;
|
|
348
|
+
/**
|
|
349
|
+
* How long, in all, {@link retryingRefusal} waits out a refusal its server
|
|
350
|
+
* says to ask again of, in milliseconds, before it raises it.
|
|
351
|
+
*/
|
|
352
|
+
export declare const RETRY_REFUSAL_MAX_MS: number;
|
|
353
|
+
/**
|
|
354
|
+
* Makes a call, and while its server refuses it with `code` and a
|
|
355
|
+
* `Retry-After`, waits as the server says and makes it again.
|
|
356
|
+
*
|
|
357
|
+
* @remarks
|
|
358
|
+
* A server refuses a start, a deploy or a workspace's removal so
|
|
359
|
+
* (`workspace_locked`) while a run that is stopping still holds the workspace:
|
|
360
|
+
* the run lets it go. A refusal with no `Retry-After`, or of another code, is
|
|
361
|
+
* raised at once, and so is one still refused after
|
|
362
|
+
* {@link RETRY_REFUSAL_MAX_MS}. Each wait is bounded as a `Retry-After` is
|
|
363
|
+
* ({@link RetryOptions.maxRetryAfterMs}).
|
|
364
|
+
*
|
|
365
|
+
* @param code - The refusal's code
|
|
366
|
+
* @param call - The call, made again for each retry
|
|
367
|
+
* @param options - Request options: the wait's bound
|
|
368
|
+
* @returns What the call answers
|
|
369
|
+
* @throws {ApiError} The refusal, once it is raised; or what else the call
|
|
370
|
+
* throws
|
|
371
|
+
*/
|
|
372
|
+
export declare function retryingRefusal<T>(code: string, call: () => Promise<T>, options: RequestOptions): Promise<T>;
|
|
256
373
|
/**
|
|
257
374
|
* Fetch a URL with streaming download progress reporting.
|
|
258
375
|
*
|
|
259
376
|
* Falls back to a single `arrayBuffer()` call if no `onProgress` callback
|
|
260
377
|
* is provided or if the response has no readable body stream.
|
|
261
378
|
*
|
|
262
|
-
* The initial request is retried per {@link fetchWithRetry} (GET is idempotent)
|
|
263
|
-
* once streaming begins a mid-stream
|
|
264
|
-
* cannot be safely resumed.
|
|
379
|
+
* The initial request is retried per {@link fetchWithRetry} (GET is idempotent),
|
|
380
|
+
* under the caller's policy when given; once streaming begins a mid-stream
|
|
381
|
+
* failure surfaces, since a partial download cannot be safely resumed.
|
|
265
382
|
*
|
|
266
383
|
* @param url - The URL to download
|
|
267
384
|
* @param onProgress - Told the bytes downloaded so far and the total
|
|
268
385
|
* @param signal - Aborts the download
|
|
269
386
|
* @param fetch - The `fetch` the download goes through
|
|
270
387
|
* ({@link RequestOptions.fetch}); the global one when absent
|
|
388
|
+
* @param retry - The retry policy of the request ({@link RequestOptions.retry});
|
|
389
|
+
* the default when absent
|
|
271
390
|
* @returns The downloaded bytes
|
|
272
391
|
*/
|
|
273
|
-
export declare function fetchWithProgress(url: string, onProgress?: (downloaded: number, total: number) => void, signal?: AbortSignal, fetch?: typeof globalThis.fetch): Promise<Uint8Array>;
|
|
392
|
+
export declare function fetchWithProgress(url: string, onProgress?: (downloaded: number, total: number) => void, signal?: AbortSignal, fetch?: typeof globalThis.fetch, retry?: RetryOptions): Promise<Uint8Array>;
|
|
274
393
|
//# sourceMappingURL=http.d.ts.map
|
package/dist/src/http.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/http.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE3D,OAAO,EAAgB,SAAS,EAAE,MAAM,YAAY,CAAC;AAErD;;;;;;;;;;GAUG;AACH,MAAM,MAAM,QAAQ,CAAC,CAAC,IAClB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,CAAC,CAAA;CAAE,GAC7B;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,WAAW,CAAC,OAAO,SAAS,CAAC,CAAA;CAAE,CAAC;AAE5D;;;;;;;GAOG;AACH,MAAM,WAAW,YAAY;IAC3B,sGAAsG;IACtG,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,yEAAyE;IACzE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;2CAEuC;IACvC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;;OAKG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC7B,qEAAqE;IACrE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB;;;OAGG;IACH,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB;;;;6DAIyD;IACzD,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;;;;;;;OAUG;IACH,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;CACjC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE;IAAE,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAA;CAAE,GAAG,OAAO,UAAU,CAAC,KAAK,CAElG;AAED,0EAA0E;AAC1E,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,GAAG,MAAM,CAE1E;AAED;;GAEG;AACH,qBAAa,QAAS,SAAQ,KAAK;
|
|
1
|
+
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/http.ts"],"names":[],"mappings":"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"}
|
package/dist/src/http.js
CHANGED
|
@@ -29,10 +29,20 @@ export function verboseQuery(path, options) {
|
|
|
29
29
|
export class ApiError extends Error {
|
|
30
30
|
code;
|
|
31
31
|
details;
|
|
32
|
-
|
|
32
|
+
retryAfterMs;
|
|
33
|
+
/**
|
|
34
|
+
* @param code - The error's code
|
|
35
|
+
* @param details - What the server said of it
|
|
36
|
+
* @param retryAfterMs - How long the server asks the client to wait before
|
|
37
|
+
* it asks again, in milliseconds, as the refusal's `Retry-After` says:
|
|
38
|
+
* a workspace a run that is stopping still holds is refused with one
|
|
39
|
+
* ({@link retryingRefusal}); `undefined` when it names none
|
|
40
|
+
*/
|
|
41
|
+
constructor(code, details, retryAfterMs) {
|
|
33
42
|
super(`API error: ${code}`);
|
|
34
43
|
this.code = code;
|
|
35
44
|
this.details = details;
|
|
45
|
+
this.retryAfterMs = retryAfterMs;
|
|
36
46
|
this.name = 'ApiError';
|
|
37
47
|
}
|
|
38
48
|
}
|
|
@@ -101,6 +111,26 @@ const DEFAULT_RETRY = {
|
|
|
101
111
|
maxDelayMs: 2000,
|
|
102
112
|
maxRetryAfterMs: 30_000,
|
|
103
113
|
};
|
|
114
|
+
/**
|
|
115
|
+
* A retry policy of one attempt: a poll's, whose next poll is its retry.
|
|
116
|
+
*
|
|
117
|
+
* @remarks
|
|
118
|
+
* A call that is made again a second later gains nothing from retrying a
|
|
119
|
+
* transient failure in between, and a server under load is asked once per
|
|
120
|
+
* poll rather than four times. {@link pollRequestOptions} gives a poll this
|
|
121
|
+
* policy unless its caller set one.
|
|
122
|
+
*/
|
|
123
|
+
export const NO_RETRY = { attempts: 1 };
|
|
124
|
+
/**
|
|
125
|
+
* The request options of a poll: the caller's, with {@link NO_RETRY} unless
|
|
126
|
+
* the caller set a policy of its own.
|
|
127
|
+
*
|
|
128
|
+
* @param options - The caller's request options
|
|
129
|
+
* @returns The options a poll's request is made with
|
|
130
|
+
*/
|
|
131
|
+
export function pollRequestOptions(options) {
|
|
132
|
+
return options.retry === undefined ? { ...options, retry: NO_RETRY } : options;
|
|
133
|
+
}
|
|
104
134
|
/** Merge caller overrides onto {@link DEFAULT_RETRY}, clamping to sane bounds. */
|
|
105
135
|
function resolveRetry(retry) {
|
|
106
136
|
return {
|
|
@@ -377,6 +407,43 @@ export async function get(url, path, successType, options) {
|
|
|
377
407
|
}, { idempotent: true, retry: options.retry, fetch: options.fetch });
|
|
378
408
|
return decodeResponse(response, successType);
|
|
379
409
|
}
|
|
410
|
+
/**
|
|
411
|
+
* Make a conditional GET request: the answer, decoded, with the `ETag` it
|
|
412
|
+
* carries; or `null` when the server answers `304 Not Modified` to the tag
|
|
413
|
+
* sent as `If-None-Match`, which says the answer the client holds is current.
|
|
414
|
+
*
|
|
415
|
+
* @remarks
|
|
416
|
+
* A poll holds the tag of the last answer it was given and asks with it: an
|
|
417
|
+
* unchanged status costs the server a read of the workspace's revision, and
|
|
418
|
+
* the client no decoding. A server that names no tag answers in full every
|
|
419
|
+
* time, and the next ask is unconditional.
|
|
420
|
+
*
|
|
421
|
+
* @param url - Base URL of the e3 API server
|
|
422
|
+
* @param path - The request's path under `/api`
|
|
423
|
+
* @param successType - The type of the answer's value
|
|
424
|
+
* @param etag - The tag of the answer the client holds; `null` for none
|
|
425
|
+
* @param options - Request options including auth token
|
|
426
|
+
* @returns The answer and its tag, or `null` when the one the client holds is
|
|
427
|
+
* current
|
|
428
|
+
* @throws {ApiError} On application-level errors
|
|
429
|
+
* @throws {AuthError} On 401 Unauthorized
|
|
430
|
+
*/
|
|
431
|
+
export async function getConditional(url, path, successType, etag, options) {
|
|
432
|
+
const response = await fetchWithRetry(`${url}/api${path}`, {
|
|
433
|
+
method: 'GET',
|
|
434
|
+
headers: {
|
|
435
|
+
'Accept': BEAST2_CONTENT_TYPE,
|
|
436
|
+
...(etag === null ? {} : { 'If-None-Match': etag }),
|
|
437
|
+
...(options.token ? { 'Authorization': `Bearer ${options.token}` } : {}),
|
|
438
|
+
},
|
|
439
|
+
}, { idempotent: true, retry: options.retry, fetch: options.fetch });
|
|
440
|
+
if (response.status === 304) {
|
|
441
|
+
await response.body?.cancel().catch(() => { });
|
|
442
|
+
return null;
|
|
443
|
+
}
|
|
444
|
+
const value = await decodeResponse(response, successType);
|
|
445
|
+
return { value, etag: response.headers.get('etag') };
|
|
446
|
+
}
|
|
380
447
|
/**
|
|
381
448
|
* Make a POST request with BEAST2 body and decode BEAST2 response.
|
|
382
449
|
* @param extraHeaders - Optional additional request headers (e.g. `Idempotency-Key`), merged after the defaults.
|
|
@@ -463,31 +530,107 @@ async function decodeResponse(response, successType) {
|
|
|
463
530
|
// Decode BEAST2 response
|
|
464
531
|
const bytes = new Uint8Array(await response.arrayBuffer());
|
|
465
532
|
const result = decodeBeast2For(ResponseType(successType))(bytes);
|
|
466
|
-
// Handle application-level errors in BEAST2 response
|
|
533
|
+
// Handle application-level errors in BEAST2 response, with the wait a
|
|
534
|
+
// refusal the server asks to be asked again of names
|
|
467
535
|
if (result.type === 'error') {
|
|
468
|
-
throw new ApiError(result.value.type, result.value.value);
|
|
536
|
+
throw new ApiError(result.value.type, result.value.value, parseRetryAfter(response.headers.get('retry-after'), Date.now()));
|
|
469
537
|
}
|
|
470
538
|
return result.value;
|
|
471
539
|
}
|
|
540
|
+
/**
|
|
541
|
+
* Make a request of a URL and decode its BEAST2 answer, keeping what the
|
|
542
|
+
* response says beside its value: whether the server accepted the request to
|
|
543
|
+
* finish after answering, the `Location` it names and its `Retry-After`.
|
|
544
|
+
*
|
|
545
|
+
* @param target - The request's URL, whole: a route's, or one a `Location`
|
|
546
|
+
* named
|
|
547
|
+
* @param method - `GET` or `DELETE`, either of which a retry sends again
|
|
548
|
+
* @param successType - The type of the answer's value
|
|
549
|
+
* @param options - Request options including auth token
|
|
550
|
+
* @returns The answer
|
|
551
|
+
* @throws {ApiError} On application-level errors
|
|
552
|
+
* @throws {AuthError} On 401 Unauthorized
|
|
553
|
+
*/
|
|
554
|
+
export async function requestAnswered(target, method, successType, options) {
|
|
555
|
+
const response = await fetchWithRetry(target, {
|
|
556
|
+
method,
|
|
557
|
+
headers: {
|
|
558
|
+
'Accept': BEAST2_CONTENT_TYPE,
|
|
559
|
+
...(options.token ? { 'Authorization': `Bearer ${options.token}` } : {}),
|
|
560
|
+
},
|
|
561
|
+
}, { idempotent: true, retry: options.retry, fetch: options.fetch });
|
|
562
|
+
const location = response.headers.get('location');
|
|
563
|
+
const retryAfterMs = parseRetryAfter(response.headers.get('retry-after'), Date.now());
|
|
564
|
+
const value = await decodeResponse(response, successType);
|
|
565
|
+
return {
|
|
566
|
+
value,
|
|
567
|
+
accepted: response.status === 202,
|
|
568
|
+
location: location === null ? null : new URL(location, target).toString(),
|
|
569
|
+
retryAfterMs,
|
|
570
|
+
};
|
|
571
|
+
}
|
|
572
|
+
/**
|
|
573
|
+
* How long, in all, {@link retryingRefusal} waits out a refusal its server
|
|
574
|
+
* says to ask again of, in milliseconds, before it raises it.
|
|
575
|
+
*/
|
|
576
|
+
export const RETRY_REFUSAL_MAX_MS = 5 * 60_000;
|
|
577
|
+
/**
|
|
578
|
+
* Makes a call, and while its server refuses it with `code` and a
|
|
579
|
+
* `Retry-After`, waits as the server says and makes it again.
|
|
580
|
+
*
|
|
581
|
+
* @remarks
|
|
582
|
+
* A server refuses a start, a deploy or a workspace's removal so
|
|
583
|
+
* (`workspace_locked`) while a run that is stopping still holds the workspace:
|
|
584
|
+
* the run lets it go. A refusal with no `Retry-After`, or of another code, is
|
|
585
|
+
* raised at once, and so is one still refused after
|
|
586
|
+
* {@link RETRY_REFUSAL_MAX_MS}. Each wait is bounded as a `Retry-After` is
|
|
587
|
+
* ({@link RetryOptions.maxRetryAfterMs}).
|
|
588
|
+
*
|
|
589
|
+
* @param code - The refusal's code
|
|
590
|
+
* @param call - The call, made again for each retry
|
|
591
|
+
* @param options - Request options: the wait's bound
|
|
592
|
+
* @returns What the call answers
|
|
593
|
+
* @throws {ApiError} The refusal, once it is raised; or what else the call
|
|
594
|
+
* throws
|
|
595
|
+
*/
|
|
596
|
+
export async function retryingRefusal(code, call, options) {
|
|
597
|
+
const cfg = resolveRetry(options.retry);
|
|
598
|
+
const deadline = Date.now() + RETRY_REFUSAL_MAX_MS;
|
|
599
|
+
for (;;) {
|
|
600
|
+
try {
|
|
601
|
+
return await call();
|
|
602
|
+
}
|
|
603
|
+
catch (err) {
|
|
604
|
+
if (!(err instanceof ApiError) || err.code !== code || err.retryAfterMs === undefined)
|
|
605
|
+
throw err;
|
|
606
|
+
const wait = Math.min(err.retryAfterMs, cfg.maxRetryAfterMs);
|
|
607
|
+
if (Date.now() + wait > deadline)
|
|
608
|
+
throw err;
|
|
609
|
+
await sleep(wait);
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
}
|
|
472
613
|
/**
|
|
473
614
|
* Fetch a URL with streaming download progress reporting.
|
|
474
615
|
*
|
|
475
616
|
* Falls back to a single `arrayBuffer()` call if no `onProgress` callback
|
|
476
617
|
* is provided or if the response has no readable body stream.
|
|
477
618
|
*
|
|
478
|
-
* The initial request is retried per {@link fetchWithRetry} (GET is idempotent)
|
|
479
|
-
* once streaming begins a mid-stream
|
|
480
|
-
* cannot be safely resumed.
|
|
619
|
+
* The initial request is retried per {@link fetchWithRetry} (GET is idempotent),
|
|
620
|
+
* under the caller's policy when given; once streaming begins a mid-stream
|
|
621
|
+
* failure surfaces, since a partial download cannot be safely resumed.
|
|
481
622
|
*
|
|
482
623
|
* @param url - The URL to download
|
|
483
624
|
* @param onProgress - Told the bytes downloaded so far and the total
|
|
484
625
|
* @param signal - Aborts the download
|
|
485
626
|
* @param fetch - The `fetch` the download goes through
|
|
486
627
|
* ({@link RequestOptions.fetch}); the global one when absent
|
|
628
|
+
* @param retry - The retry policy of the request ({@link RequestOptions.retry});
|
|
629
|
+
* the default when absent
|
|
487
630
|
* @returns The downloaded bytes
|
|
488
631
|
*/
|
|
489
|
-
export async function fetchWithProgress(url, onProgress, signal, fetch) {
|
|
490
|
-
const res = await fetchWithRetry(url, { method: 'GET', signal }, { idempotent: true, fetch });
|
|
632
|
+
export async function fetchWithProgress(url, onProgress, signal, fetch, retry) {
|
|
633
|
+
const res = await fetchWithRetry(url, { method: 'GET', signal }, { idempotent: true, retry, fetch });
|
|
491
634
|
if (!res.ok)
|
|
492
635
|
throw new Error(`Download failed: ${res.status} ${res.statusText}`);
|
|
493
636
|
if (!onProgress || !res.body) {
|