@usestatemachines/sdk 0.5.0 → 0.6.1
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 +177 -521
- package/agents/SKILL.md +38 -47
- package/agents/index.js +7 -7
- package/agents/llms.txt +50 -46
- package/agents/prompt.md +11 -11
- package/esm/extensions/client.d.ts +104 -127
- package/esm/extensions/client.js +162 -322
- package/esm/extensions/credentials.d.ts +13 -0
- package/esm/extensions/credentials.js +73 -0
- package/esm/extensions/environment.d.ts +25 -0
- package/esm/extensions/environment.js +1 -0
- package/esm/extensions/errors.d.ts +42 -75
- package/esm/extensions/errors.js +125 -110
- package/esm/extensions/index.d.ts +6 -11
- package/esm/extensions/index.js +2 -7
- package/esm/extensions/wait.d.ts +17 -18
- package/esm/extensions/wait.js +60 -56
- package/esm/extensions/yaml.d.ts +6 -0
- package/esm/extensions/yaml.js +137 -0
- package/esm/funcs/{catalog-release.d.ts → apps-list.d.ts} +1 -1
- package/esm/funcs/{environments-get-connection.js → apps-list.js} +11 -16
- package/esm/funcs/{credential-get.d.ts → apps-versions.d.ts} +1 -1
- package/esm/funcs/{workspaces-events.js → apps-versions.js} +6 -7
- package/esm/funcs/{environments-get-connection.d.ts → audit-events-list.d.ts} +1 -1
- package/esm/funcs/audit-events-list.js +93 -0
- package/esm/funcs/{workspaces-events.d.ts → environments-connect.d.ts} +1 -1
- package/esm/funcs/{environments-reveal.js → environments-connect.js} +7 -6
- package/esm/funcs/environments-create.d.ts +2 -1
- package/esm/funcs/environments-create.js +5 -10
- package/esm/funcs/{environments-events.d.ts → environments-delete.d.ts} +1 -1
- package/esm/funcs/{environments-stop.js → environments-delete.js} +7 -6
- package/esm/funcs/environments-get.d.ts +2 -1
- package/esm/funcs/environments-get.js +2 -1
- package/esm/funcs/environments-list.d.ts +1 -1
- package/esm/funcs/environments-list.js +11 -16
- package/esm/funcs/environments-pause.d.ts +12 -0
- package/esm/funcs/{environments-suspend.js → environments-pause.js} +6 -5
- package/esm/funcs/environments-resume.d.ts +2 -1
- package/esm/funcs/environments-resume.js +2 -1
- package/esm/funcs/environments-update.d.ts +12 -0
- package/esm/funcs/{environments-events.js → environments-update.js} +9 -13
- package/esm/funcs/me.d.ts +11 -0
- package/esm/funcs/{catalog-get.js → me.js} +5 -5
- package/esm/funcs/{catalog-get.d.ts → requests-body.d.ts} +1 -1
- package/esm/funcs/{environments-get-request-payload.js → requests-body.js} +5 -9
- package/esm/funcs/{environments-get-request-stats.d.ts → requests-get.d.ts} +2 -1
- package/esm/funcs/{catalog-release.js → requests-get.js} +7 -6
- package/esm/funcs/{environments-stop.d.ts → requests-list.d.ts} +1 -1
- package/esm/funcs/{environments-list-requests.js → requests-list.js} +9 -14
- package/esm/funcs/requests-stats.d.ts +12 -0
- package/esm/funcs/{environments-get-request-stats.js → requests-stats.js} +10 -14
- package/esm/funcs/snapshots-create.d.ts +12 -0
- package/esm/funcs/{snapshots-capture.js → snapshots-create.js} +6 -11
- package/esm/funcs/snapshots-delete.d.ts +2 -1
- package/esm/funcs/snapshots-delete.js +2 -1
- package/esm/funcs/snapshots-get.d.ts +2 -1
- package/esm/funcs/snapshots-get.js +2 -1
- package/esm/funcs/snapshots-list.d.ts +1 -1
- package/esm/funcs/snapshots-list.js +9 -13
- package/esm/funcs/snapshots-update.d.ts +2 -1
- package/esm/funcs/snapshots-update.js +2 -1
- package/esm/funcs/workspaces-get.d.ts +2 -1
- package/esm/funcs/workspaces-get.js +2 -1
- package/esm/funcs/workspaces-list.d.ts +1 -1
- package/esm/funcs/workspaces-list.js +3 -1
- package/esm/lib/config.d.ts +3 -3
- package/esm/lib/config.js +3 -3
- package/esm/models/actor.d.ts +2 -3
- package/esm/models/actor.js +2 -3
- package/esm/models/{api-profile.d.ts → api.d.ts} +4 -4
- package/esm/models/{api-profile.js → api.js} +4 -5
- package/esm/models/app.d.ts +9 -1
- package/esm/models/app.js +7 -1
- package/esm/models/{event.d.ts → audit-event.d.ts} +6 -6
- package/esm/models/{event.js → audit-event.js} +7 -6
- package/esm/models/{request-payload-preview.d.ts → body-preview.d.ts} +4 -4
- package/esm/models/{request-payload-preview.js → body-preview.js} +5 -4
- package/esm/models/create-environment.d.ts +51 -0
- package/esm/models/create-environment.js +35 -0
- package/esm/models/credentials.d.ts +31 -0
- package/esm/models/credentials.js +31 -0
- package/esm/models/environment-failure.d.ts +22 -0
- package/esm/models/environment-failure.js +25 -0
- package/esm/models/environment-status.d.ts +14 -0
- package/esm/models/environment-status.js +15 -0
- package/esm/models/environment.d.ts +27 -27
- package/esm/models/environment.js +28 -27
- package/esm/models/error.d.ts +38 -0
- package/esm/models/error.js +39 -0
- package/esm/models/errors/{error-response.d.ts → error.d.ts} +5 -5
- package/esm/models/errors/{error-response.js → error.js} +4 -4
- package/esm/models/errors/index.d.ts +1 -1
- package/esm/models/errors/index.js +1 -1
- package/esm/models/index.d.ts +17 -20
- package/esm/models/index.js +17 -20
- package/esm/models/me.d.ts +66 -0
- package/esm/models/me.js +75 -0
- package/esm/models/operations/create-credentials.d.ts +25 -0
- package/esm/models/operations/create-credentials.js +20 -0
- package/esm/models/operations/create-environment.d.ts +14 -0
- package/esm/models/operations/create-environment.js +18 -0
- package/esm/models/operations/create-snapshot.d.ts +25 -0
- package/esm/models/operations/create-snapshot.js +25 -0
- package/esm/models/operations/delete-environment.d.ts +13 -0
- package/esm/models/operations/delete-environment.js +17 -0
- package/esm/models/operations/delete-snapshot.d.ts +0 -12
- package/esm/models/operations/delete-snapshot.js +0 -9
- package/esm/models/operations/get-environment.d.ts +0 -12
- package/esm/models/operations/get-environment.js +0 -9
- package/esm/models/operations/get-request-body.d.ts +21 -0
- package/esm/models/operations/{get-environment-request-payload.js → get-request-body.js} +3 -4
- package/esm/models/operations/get-request-stats.d.ts +51 -0
- package/esm/models/operations/get-request-stats.js +40 -0
- package/esm/models/operations/get-request.d.ts +11 -0
- package/esm/models/operations/get-request.js +11 -0
- package/esm/models/operations/get-snapshot.d.ts +0 -12
- package/esm/models/operations/get-snapshot.js +0 -9
- package/esm/models/operations/get-workspace.d.ts +0 -12
- package/esm/models/operations/get-workspace.js +0 -9
- package/esm/models/operations/index.d.ts +13 -16
- package/esm/models/operations/index.js +13 -16
- package/esm/models/operations/list-apps.d.ts +26 -0
- package/esm/models/operations/list-apps.js +23 -0
- package/esm/models/operations/list-audit-events.d.ts +30 -0
- package/esm/models/operations/list-audit-events.js +25 -0
- package/esm/models/operations/list-environments.d.ts +6 -21
- package/esm/models/operations/list-environments.js +3 -16
- package/esm/models/operations/list-requests.d.ts +68 -0
- package/esm/models/operations/list-requests.js +53 -0
- package/esm/models/operations/list-snapshots.d.ts +8 -6
- package/esm/models/operations/list-snapshots.js +4 -3
- package/esm/models/operations/list-versions.d.ts +28 -0
- package/esm/models/operations/list-versions.js +24 -0
- package/esm/models/operations/list-workspaces.d.ts +8 -4
- package/esm/models/operations/list-workspaces.js +7 -4
- package/esm/models/operations/pause-environment.d.ts +13 -0
- package/esm/models/operations/pause-environment.js +17 -0
- package/esm/models/operations/resume-environment.d.ts +0 -12
- package/esm/models/operations/resume-environment.js +0 -9
- package/esm/models/operations/update-environment.d.ts +29 -0
- package/esm/models/operations/update-environment.js +20 -0
- package/esm/models/operations/update-snapshot.d.ts +0 -14
- package/esm/models/operations/update-snapshot.js +0 -10
- package/esm/models/permission.d.ts +17 -0
- package/esm/models/permission.js +18 -0
- package/esm/models/principal.d.ts +20 -0
- package/esm/models/principal.js +24 -0
- package/esm/models/request-detail.d.ts +39 -0
- package/esm/models/request-detail.js +38 -0
- package/esm/models/{environment-request-stats.d.ts → request-stats.d.ts} +3 -3
- package/esm/models/{environment-request-stats.js → request-stats.js} +3 -3
- package/esm/models/request.d.ts +30 -0
- package/esm/models/{environment-request.js → request.js} +11 -11
- package/esm/models/snapshot-status.d.ts +13 -0
- package/esm/models/snapshot-status.js +14 -0
- package/esm/models/snapshot.d.ts +47 -0
- package/esm/models/snapshot.js +54 -0
- package/esm/models/version.d.ts +27 -0
- package/esm/models/version.js +31 -0
- package/esm/models/workspace.d.ts +2 -4
- package/esm/models/workspace.js +2 -4
- package/esm/sdk/apps.d.ts +6 -0
- package/esm/sdk/apps.js +15 -0
- package/esm/sdk/audit-events.d.ts +5 -0
- package/esm/sdk/audit-events.js +11 -0
- package/esm/sdk/environments.d.ts +8 -13
- package/esm/sdk/environments.js +18 -38
- package/esm/sdk/requests.d.ts +9 -0
- package/esm/sdk/requests.js +23 -0
- package/esm/sdk/sdk.d.ts +11 -8
- package/esm/sdk/sdk.js +16 -11
- package/esm/sdk/snapshots.d.ts +6 -5
- package/esm/sdk/snapshots.js +7 -7
- package/esm/sdk/workspaces.d.ts +1 -2
- package/esm/sdk/workspaces.js +0 -4
- package/openapi.json +1697 -2507
- package/package.json +15 -13
- package/esm/extensions/apps.d.ts +0 -18
- package/esm/extensions/apps.js +0 -39
- package/esm/extensions/connection.d.ts +0 -42
- package/esm/extensions/connection.js +0 -133
- package/esm/extensions/running-environment.d.ts +0 -46
- package/esm/extensions/running-environment.js +0 -66
- package/esm/funcs/create-environment-definition.d.ts +0 -11
- package/esm/funcs/create-environment-definition.js +0 -94
- package/esm/funcs/credential-get.js +0 -76
- package/esm/funcs/environments-get-request-payload.d.ts +0 -11
- package/esm/funcs/environments-get-request.d.ts +0 -11
- package/esm/funcs/environments-get-request.js +0 -96
- package/esm/funcs/environments-list-requests.d.ts +0 -11
- package/esm/funcs/environments-reveal.d.ts +0 -11
- package/esm/funcs/environments-suspend.d.ts +0 -11
- package/esm/funcs/snapshots-capture.d.ts +0 -11
- package/esm/models/app-instance-snapshot.d.ts +0 -15
- package/esm/models/app-instance-snapshot.js +0 -19
- package/esm/models/catalog.d.ts +0 -12
- package/esm/models/catalog.js +0 -15
- package/esm/models/connection-secret.d.ts +0 -30
- package/esm/models/connection-secret.js +0 -31
- package/esm/models/connection.d.ts +0 -40
- package/esm/models/connection.js +0 -44
- package/esm/models/create-environment-input.d.ts +0 -39
- package/esm/models/create-environment-input.js +0 -25
- package/esm/models/credential-kind.d.ts +0 -9
- package/esm/models/credential-kind.js +0 -10
- package/esm/models/credential.d.ts +0 -48
- package/esm/models/credential.js +0 -44
- package/esm/models/environment-app.d.ts +0 -45
- package/esm/models/environment-app.js +0 -47
- package/esm/models/environment-lifetime.d.ts +0 -10
- package/esm/models/environment-lifetime.js +0 -14
- package/esm/models/environment-request-detail.d.ts +0 -40
- package/esm/models/environment-request-detail.js +0 -39
- package/esm/models/environment-request.d.ts +0 -31
- package/esm/models/environment-snapshot.d.ts +0 -40
- package/esm/models/environment-snapshot.js +0 -42
- package/esm/models/error-response.d.ts +0 -57
- package/esm/models/error-response.js +0 -59
- package/esm/models/event-page.d.ts +0 -11
- package/esm/models/event-page.js +0 -16
- package/esm/models/operations/capture-snapshot.d.ts +0 -41
- package/esm/models/operations/capture-snapshot.js +0 -36
- package/esm/models/operations/create-environment-definition.d.ts +0 -153
- package/esm/models/operations/create-environment-definition.js +0 -93
- package/esm/models/operations/create-environments.d.ts +0 -27
- package/esm/models/operations/create-environments.js +0 -27
- package/esm/models/operations/get-catalog.d.ts +0 -13
- package/esm/models/operations/get-catalog.js +0 -13
- package/esm/models/operations/get-connection.d.ts +0 -25
- package/esm/models/operations/get-connection.js +0 -21
- package/esm/models/operations/get-credential.d.ts +0 -13
- package/esm/models/operations/get-credential.js +0 -13
- package/esm/models/operations/get-environment-request-payload.d.ts +0 -23
- package/esm/models/operations/get-environment-request-stats.d.ts +0 -70
- package/esm/models/operations/get-environment-request-stats.js +0 -55
- package/esm/models/operations/get-environment-request.d.ts +0 -25
- package/esm/models/operations/get-environment-request.js +0 -21
- package/esm/models/operations/get-release.d.ts +0 -23
- package/esm/models/operations/get-release.js +0 -20
- package/esm/models/operations/list-environment-events.d.ts +0 -15
- package/esm/models/operations/list-environment-events.js +0 -13
- package/esm/models/operations/list-environment-requests.d.ts +0 -75
- package/esm/models/operations/list-environment-requests.js +0 -59
- package/esm/models/operations/list-workspace-events.d.ts +0 -15
- package/esm/models/operations/list-workspace-events.js +0 -13
- package/esm/models/operations/reveal-connection.d.ts +0 -59
- package/esm/models/operations/reveal-connection.js +0 -55
- package/esm/models/operations/stop-environment.d.ts +0 -25
- package/esm/models/operations/stop-environment.js +0 -26
- package/esm/models/operations/suspend-environment.d.ts +0 -25
- package/esm/models/operations/suspend-environment.js +0 -26
- package/esm/models/release-actor.d.ts +0 -11
- package/esm/models/release-actor.js +0 -15
- package/esm/models/release.d.ts +0 -37
- package/esm/models/release.js +0 -39
- package/esm/sdk/catalog.d.ts +0 -6
- package/esm/sdk/catalog.js +0 -15
- package/esm/sdk/credential.d.ts +0 -5
- package/esm/sdk/credential.js +0 -11
package/esm/extensions/client.js
CHANGED
|
@@ -1,330 +1,214 @@
|
|
|
1
1
|
import { SDK_METADATA } from '../lib/config.js';
|
|
2
2
|
import { HTTPClient } from '../lib/http.js';
|
|
3
3
|
import { StateMachines as Generated } from '../sdk/sdk.js';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { CallerAbortedError, EnvironmentFailedError, SnapshotFailedError, SnapshotTimeoutError, StateMachinesError, TimeoutError, toStateMachinesError, } from './errors.js';
|
|
7
|
-
import { RunningEnvironment } from './running-environment.js';
|
|
4
|
+
import { bindCredentials } from './credentials.js';
|
|
5
|
+
import { CallerAbortedError, StateMachinesError, toStateMachinesError, } from './errors.js';
|
|
8
6
|
import { linkSignal } from './signal.js';
|
|
9
|
-
import {
|
|
10
|
-
const stopAfterFailureMs = 30000;
|
|
11
|
-
const busyBudgetMs = 60000;
|
|
7
|
+
import { environmentAt, poll, snapshotAt, } from './wait.js';
|
|
12
8
|
export class StateMachines {
|
|
13
9
|
#sdk;
|
|
14
10
|
#fetch;
|
|
15
11
|
#workspaceId;
|
|
16
12
|
#callSignals = new Map();
|
|
13
|
+
#apis = new Map();
|
|
17
14
|
#lastCall = 0;
|
|
18
|
-
#credentialWorkspace;
|
|
19
15
|
constructor(options = {}) {
|
|
20
16
|
const apiKey = options.apiKey ?? environmentApiKey();
|
|
21
17
|
if (!apiKey) {
|
|
22
|
-
throw new TypeError('Pass apiKey or set
|
|
18
|
+
throw new TypeError('Pass apiKey or set STATEMACHINES_API_KEY.');
|
|
23
19
|
}
|
|
24
20
|
// Checked here so a malformed key is never echoed by a header validation error.
|
|
25
21
|
if (!/^[\x21-\x7e]+$/.test(apiKey)) {
|
|
26
22
|
throw new TypeError('apiKey must be printable ASCII with no spaces.');
|
|
27
23
|
}
|
|
28
|
-
|
|
29
|
-
|
|
24
|
+
const attemptTimeoutMs = options.attemptTimeoutMs ?? 60000;
|
|
25
|
+
if (!(attemptTimeoutMs > 0 && Number.isFinite(attemptTimeoutMs))) {
|
|
26
|
+
throw new RangeError('attemptTimeoutMs must be a positive, finite number.');
|
|
30
27
|
}
|
|
31
28
|
const fetcher = options.fetch;
|
|
32
29
|
// The arrow keeps `this` unbound; runtimes such as workerd reject fetch called on another object.
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
throw new RangeError('timeoutMs must be a positive, finite number.');
|
|
36
|
-
}
|
|
37
|
-
const httpClient = options.httpClient?.clone() ??
|
|
38
|
-
new HTTPClient(fetcher ? { fetcher: (input) => fetcher(input) } : {});
|
|
39
|
-
addAttemptTimeout(httpClient, timeoutMs, this.#callSignals);
|
|
30
|
+
const httpClient = new HTTPClient(fetcher ? { fetcher: (input) => fetcher(input) } : {});
|
|
31
|
+
addAttemptTimeout(httpClient, attemptTimeoutMs, this.#callSignals);
|
|
40
32
|
this.#fetch = fetcher;
|
|
41
33
|
this.#workspaceId = options.workspaceId;
|
|
42
34
|
this.#sdk = new Generated({
|
|
43
35
|
apiKey,
|
|
44
36
|
userAgent: `statemachines-sdk-ts/${SDK_METADATA.sdkVersion}`,
|
|
45
37
|
httpClient,
|
|
46
|
-
...(options.
|
|
38
|
+
...(options.baseUrl ? { serverURL: options.baseUrl } : {}),
|
|
47
39
|
});
|
|
48
40
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
41
|
+
/** The caller: its principal, organization, workspace, permissions and limits. */
|
|
42
|
+
me() {
|
|
43
|
+
return this.#call(undefined, (call) => this.#sdk.me(call));
|
|
44
|
+
}
|
|
45
|
+
apps = {
|
|
46
|
+
list: (query = {}) => this.#call(undefined, (call) => this.#sdk.apps.list(query, call)),
|
|
47
|
+
/** Published versions, including retired ones. */
|
|
48
|
+
versions: (appId, query = {}) => this.#call(undefined, (call) => this.#sdk.apps.versions({ ...query, appId }, call)),
|
|
55
49
|
};
|
|
56
50
|
workspaces = {
|
|
57
|
-
list: (query = {}
|
|
58
|
-
get: (workspaceId
|
|
59
|
-
events: (workspaceId, query = {}, options) => this.#call(options, (call) => this.#sdk.workspaces.events({ ...query, workspaceId }, call)),
|
|
51
|
+
list: (query = {}) => this.#call(undefined, (call) => this.#sdk.workspaces.list(query, call)),
|
|
52
|
+
get: (workspaceId) => this.#call(undefined, (call) => this.#sdk.workspaces.get({ workspaceId }, call)),
|
|
60
53
|
};
|
|
61
54
|
environments = {
|
|
62
|
-
|
|
63
|
-
const { workspaceId, ...filters } = query;
|
|
64
|
-
const resolved = await this.#workspace(workspaceId, call.signal);
|
|
65
|
-
return this.#sdk.environments.list({ ...filters, workspaceId: resolved }, call);
|
|
66
|
-
}),
|
|
67
|
-
get: (environmentId, options) => this.#unwrap(options, (call) => this.#sdk.environments.get({ environmentId }, call)),
|
|
68
|
-
/**
|
|
69
|
-
* Creates an environment and waits until it's running. If the wait fails, stops the
|
|
70
|
-
* environment (unless the caller passed its own `idempotencyKey`), then rethrows the
|
|
71
|
-
* error with `environmentId`, `stopped` and `stopError`.
|
|
72
|
-
*/
|
|
73
|
-
start: async (input, options = {}) => {
|
|
74
|
-
const { readyTimeoutMs, ...createOptions } = options;
|
|
75
|
-
const { idempotencyKey, signal } = options;
|
|
76
|
-
const timeoutMs = readyTimeoutMs ?? defaultTimeoutMs;
|
|
77
|
-
if (!(timeoutMs > 0)) {
|
|
78
|
-
throw new RangeError('readyTimeoutMs must be more than 0.');
|
|
79
|
-
}
|
|
80
|
-
const created = await this.environments.create(input, createOptions);
|
|
81
|
-
try {
|
|
82
|
-
const environment = await this.environments.waitUntilReady(created.id, {
|
|
83
|
-
timeoutMs,
|
|
84
|
-
...(signal ? { signal } : {}),
|
|
85
|
-
});
|
|
86
|
-
return new RunningEnvironment(this, environment);
|
|
87
|
-
}
|
|
88
|
-
catch (error) {
|
|
89
|
-
// The API replays a create by key, returning the same environment to another
|
|
90
|
-
// start() that may still be using it, so only the SDK's own key allows a stop.
|
|
91
|
-
const outcome = idempotencyKey === undefined
|
|
92
|
-
? await this.#stopAfterFailure(created.id)
|
|
93
|
-
: { environmentId: created.id, stopped: false };
|
|
94
|
-
const isCallerReason = signal?.aborted && Object.is(error, signal.reason);
|
|
95
|
-
if (isCallerReason) {
|
|
96
|
-
if (outcome.stopped) {
|
|
97
|
-
throw error;
|
|
98
|
-
}
|
|
99
|
-
throw Object.assign(new StateMachinesError(new CallerAbortedError(error)), outcome);
|
|
100
|
-
}
|
|
101
|
-
if (isStartError(error) && Object.isExtensible(error)) {
|
|
102
|
-
Object.assign(error, outcome);
|
|
103
|
-
}
|
|
104
|
-
throw error;
|
|
105
|
-
}
|
|
106
|
-
},
|
|
107
|
-
/**
|
|
108
|
-
* A string app is shorthand for `{ key: <the string>, appId: <the string> }`. Every
|
|
109
|
-
* failure carries the `idempotencyKey`; replaying the create with it is safe.
|
|
110
|
-
*/
|
|
55
|
+
/** Creates an environment and, unless `wait` is false, waits until it is `running`. */
|
|
111
56
|
create: async (input, options = {}) => {
|
|
57
|
+
const { signal } = options;
|
|
112
58
|
const idempotencyKey = options.idempotencyKey ?? crypto.randomUUID();
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
if (!environment) {
|
|
120
|
-
throw new Error('Invalid response from the State API: the create returned no environment.');
|
|
121
|
-
}
|
|
122
|
-
return environment;
|
|
59
|
+
const created = await this.#call(signal, (call) => this.#sdk.environments.create({ idempotencyKey, body: this.#inWorkspace(input) }, call));
|
|
60
|
+
return options.wait === false
|
|
61
|
+
? this.#bind(created)
|
|
62
|
+
: this.environments.wait(created.id, {
|
|
63
|
+
status: 'running',
|
|
64
|
+
...waitOptions(options),
|
|
123
65
|
});
|
|
124
|
-
}
|
|
125
|
-
catch (error) {
|
|
126
|
-
// Always a new instance: concurrent creates can share one failed workspace lookup.
|
|
127
|
-
throw new StateMachinesError(error, { idempotencyKey });
|
|
128
|
-
}
|
|
129
66
|
},
|
|
130
|
-
/**
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
waitUntilSuspended: (environmentId, options) => poll((signal) => this.#poll(environmentId, signal), suspended, options),
|
|
153
|
-
/** Resolves when the environment ended and every sandbox is confirmed disposed. */
|
|
154
|
-
waitUntilStopped: (environmentId, options) => poll((signal) => this.#poll(environmentId, signal), disposed, options),
|
|
67
|
+
/** Newest first. Leaves deleted environments out unless `status` asks for them. */
|
|
68
|
+
list: async (query = {}) => {
|
|
69
|
+
const page = await this.#call(undefined, (call) => this.#sdk.environments.list(this.#inWorkspace(query), call));
|
|
70
|
+
return { ...page, data: page.data.map((each) => this.#bind(each)) };
|
|
71
|
+
},
|
|
72
|
+
get: async (environmentId) => this.#bind(await this.#call(undefined, (call) => this.#sdk.environments.get({ environmentId }, call))),
|
|
73
|
+
/** `labels` replaces the whole map. */
|
|
74
|
+
update: async (environmentId, body) => this.#bind(await this.#call(undefined, (call) => this.#sdk.environments.update({ environmentId, body }, call))),
|
|
75
|
+
/** Takes effect when the API answers: the gateway refuses calls from then on. */
|
|
76
|
+
pause: async (environmentId, options = {}) => this.#bind(await this.#call(options.signal, (call) => this.#sdk.environments.pause({ environmentId }, call))),
|
|
77
|
+
/** Resumes a paused or failed environment and, unless `wait` is false, waits until it is `running`. */
|
|
78
|
+
resume: async (environmentId, options = {}) => {
|
|
79
|
+
const resumed = await this.#call(options.signal, (call) => this.#sdk.environments.resume({ environmentId }, call));
|
|
80
|
+
return options.wait === false
|
|
81
|
+
? this.#bind(resumed)
|
|
82
|
+
: this.environments.wait(environmentId, {
|
|
83
|
+
status: 'running',
|
|
84
|
+
...waitOptions(options),
|
|
85
|
+
});
|
|
86
|
+
},
|
|
87
|
+
/** Deletes the environment and its data. Safe to repeat. */
|
|
88
|
+
delete: async (environmentId, options = {}) => this.#bind(await this.#call(options.signal, (call) => this.#sdk.environments.delete({ environmentId }, call))),
|
|
155
89
|
/**
|
|
156
|
-
*
|
|
157
|
-
*
|
|
158
|
-
* actors() to act with that user's permissions.
|
|
90
|
+
* Resolves when the environment has `status`. Throws once it cannot get there without
|
|
91
|
+
* another call: `EnvironmentFailedError` if it failed, else `UnexpectedStatusError`.
|
|
159
92
|
*/
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
throw new TypeError(`App ${appKey} is not ready to connect (${details.status}).`);
|
|
164
|
-
}
|
|
165
|
-
// The API resolves { actorId } to that actor's first connection, not the declared one.
|
|
166
|
-
const body = options.actorId === undefined && details.defaultConnection
|
|
167
|
-
? { connectionKey: details.defaultConnection }
|
|
168
|
-
: { actorId: pickActor(appKey, details.actors, options.actorId).id };
|
|
169
|
-
const api = pickApi(appKey, details.apis, options.apiId);
|
|
170
|
-
const secret = await this.#reveal(environmentId, appKey, body, options);
|
|
171
|
-
return new Connection(details.baseUrl, api, secret, this.#fetch);
|
|
172
|
-
},
|
|
93
|
+
wait: async (environmentId, options) => this.#bind(await poll(environmentId, (signal) => this.#read(signal, (call) => this.#sdk.environments.get({ environmentId }, call)), environmentAt(options.status), options)),
|
|
94
|
+
/** Credentials for one app of the environment. */
|
|
95
|
+
connect: (environmentId, app, options = {}) => this.#connect(environmentId, null, app, options),
|
|
173
96
|
};
|
|
174
97
|
snapshots = {
|
|
175
|
-
/**
|
|
176
|
-
create: (
|
|
177
|
-
/**
|
|
178
|
-
* Creates a snapshot and waits until it's `ready`. Needs `snapshots:create` and
|
|
179
|
-
* `snapshots:read`. A failed or timed-out snapshot is never deleted: the error
|
|
180
|
-
* carries `snapshotId` and `idempotencyKey`.
|
|
181
|
-
*/
|
|
182
|
-
capture: async (environmentId, input = {}, options = {}) => {
|
|
183
|
-
const { readyTimeoutMs, ...createOptions } = options;
|
|
184
|
-
const { signal } = options;
|
|
98
|
+
/** Creates a snapshot of a running environment and, unless `wait` is false, waits until it is `ready`. */
|
|
99
|
+
create: async (input, options = {}) => {
|
|
185
100
|
const idempotencyKey = options.idempotencyKey ?? crypto.randomUUID();
|
|
186
|
-
const
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
signal?.throwIfAborted();
|
|
193
|
-
if (snapshotReady(created)) {
|
|
194
|
-
return created;
|
|
195
|
-
}
|
|
196
|
-
return await this.snapshots.waitUntilReady(created.id, {
|
|
197
|
-
timeoutMs,
|
|
198
|
-
...(signal ? { signal } : {}),
|
|
101
|
+
const created = await this.#call(options.signal, (call) => this.#sdk.snapshots.create({ idempotencyKey, body: input }, call));
|
|
102
|
+
return options.wait === false
|
|
103
|
+
? created
|
|
104
|
+
: this.snapshots.wait(created.id, {
|
|
105
|
+
status: 'ready',
|
|
106
|
+
...waitOptions(options),
|
|
199
107
|
});
|
|
200
|
-
}
|
|
201
|
-
catch (error) {
|
|
202
|
-
const snapshotId = created.id;
|
|
203
|
-
if (signal?.aborted && Object.is(error, signal.reason)) {
|
|
204
|
-
throw Object.assign(new StateMachinesError(new CallerAbortedError(error), {
|
|
205
|
-
idempotencyKey,
|
|
206
|
-
}), { snapshotId });
|
|
207
|
-
}
|
|
208
|
-
if (error instanceof StateMachinesError ||
|
|
209
|
-
error instanceof SnapshotFailedError ||
|
|
210
|
-
error instanceof SnapshotTimeoutError) {
|
|
211
|
-
Object.assign(error, { snapshotId, idempotencyKey });
|
|
212
|
-
}
|
|
213
|
-
throw error;
|
|
214
|
-
}
|
|
215
108
|
},
|
|
216
|
-
/**
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
const resolved = await this.#workspace(workspaceId, call.signal);
|
|
224
|
-
return this.#sdk.snapshots.list({ ...filters, workspaceId: resolved }, call);
|
|
225
|
-
}),
|
|
109
|
+
/** Newest first. Leaves deleted snapshots out unless `status` asks for them. */
|
|
110
|
+
list: (query = {}) => this.#call(undefined, (call) => this.#sdk.snapshots.list(this.#inWorkspace(query), call)),
|
|
111
|
+
get: (snapshotId) => this.#call(undefined, (call) => this.#sdk.snapshots.get({ snapshotId }, call)),
|
|
112
|
+
/** `null` clears the name. */
|
|
113
|
+
update: (snapshotId, body) => this.#call(undefined, (call) => this.#sdk.snapshots.update({ snapshotId, body }, call)),
|
|
114
|
+
/** A `saving` snapshot cannot be deleted. Safe to repeat. */
|
|
115
|
+
delete: (snapshotId) => this.#call(undefined, (call) => this.#sdk.snapshots.delete({ snapshotId }, call)),
|
|
226
116
|
/**
|
|
227
|
-
*
|
|
228
|
-
*
|
|
117
|
+
* Resolves when the snapshot has `status`. Throws once it cannot get there without
|
|
118
|
+
* another call: `SnapshotFailedError` if it failed, else `UnexpectedStatusError`.
|
|
229
119
|
*/
|
|
230
|
-
|
|
231
|
-
/** Marks the snapshot deleted and returns it; safe to repeat. A capturing snapshot is a 409 `not-ready`. */
|
|
232
|
-
delete: (snapshotId, options) => this.#unwrap(options, (call) => this.#sdk.snapshots.delete({ snapshotId }, call)),
|
|
120
|
+
wait: (snapshotId, options) => poll(snapshotId, (signal) => this.#read(signal, (call) => this.#sdk.snapshots.get({ snapshotId }, call)), snapshotAt(options.status), options),
|
|
233
121
|
};
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
try {
|
|
256
|
-
return (await this.#sdk.snapshots.capture(request, call)).data;
|
|
257
|
-
}
|
|
258
|
-
catch (error) {
|
|
259
|
-
const busy = toStateMachinesError(error);
|
|
260
|
-
const waitMs = Math.max(busy.retryAfter ?? 0, backoff(attempt));
|
|
261
|
-
if (busy.code !== 'snapshot-limit' ||
|
|
262
|
-
Date.now() + waitMs >= deadline) {
|
|
263
|
-
throw error;
|
|
264
|
-
}
|
|
265
|
-
await sleep(waitMs, call.signal);
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
});
|
|
269
|
-
}
|
|
270
|
-
catch (error) {
|
|
271
|
-
throw new StateMachinesError(error, { idempotencyKey });
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
#reveal(environmentId, appKey, body, options) {
|
|
275
|
-
return this.#unwrap(options, (call) => this.#sdk.environments.reveal({ environmentId, appKey, body }, call));
|
|
276
|
-
}
|
|
277
|
-
async #stopAfterFailure(environmentId) {
|
|
278
|
-
const budget = linkSignal(undefined, stopAfterFailureMs);
|
|
279
|
-
try {
|
|
280
|
-
// abortable() ends the wait at the budget even during a retry delay.
|
|
281
|
-
await abortable(this.environments.stop(environmentId, { signal: budget.signal }), budget.signal);
|
|
282
|
-
return { environmentId, stopped: true };
|
|
283
|
-
}
|
|
284
|
-
catch (stopError) {
|
|
285
|
-
return { environmentId, stopped: false, stopError };
|
|
286
|
-
}
|
|
287
|
-
finally {
|
|
288
|
-
budget.dispose();
|
|
289
|
-
}
|
|
122
|
+
requests = {
|
|
123
|
+
/** Calls the gateway recorded for one environment, newest first. Recording is best effort. */
|
|
124
|
+
list: (query) => this.#call(undefined, (call) => this.#sdk.requests.list(query, call)),
|
|
125
|
+
get: (requestId) => this.#call(undefined, (call) => this.#sdk.requests.get({ requestId }, call)),
|
|
126
|
+
stats: (query) => this.#call(undefined, (call) => this.#sdk.requests.stats(query, call)),
|
|
127
|
+
/** The recorded body, in full. */
|
|
128
|
+
body: (requestId, direction) =>
|
|
129
|
+
// Read inside the call: settling it aborts the signal the body streams under.
|
|
130
|
+
this.#call(undefined, async (call) => {
|
|
131
|
+
const stream = await this.#sdk.requests.body({ requestId, direction }, call);
|
|
132
|
+
return new Uint8Array(await new Response(stream).arrayBuffer());
|
|
133
|
+
}),
|
|
134
|
+
};
|
|
135
|
+
auditEvents = {
|
|
136
|
+
/** Newest first. An API key that names no filter gets its own workspace. */
|
|
137
|
+
list: (query = {}) => this.#call(undefined, (call) => this.#sdk.auditEvents.list(query.environmentId ? query : this.#inWorkspace(query), call)),
|
|
138
|
+
};
|
|
139
|
+
#inWorkspace(input) {
|
|
140
|
+
return input.workspaceId === undefined && this.#workspaceId !== undefined
|
|
141
|
+
? { ...input, workspaceId: this.#workspaceId }
|
|
142
|
+
: input;
|
|
290
143
|
}
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
144
|
+
async #connect(environmentId, known, app, options) {
|
|
145
|
+
const body = options.actorId === undefined ? {} : { actorId: options.actorId };
|
|
146
|
+
const [credentials, apis] = await Promise.all([
|
|
147
|
+
this.#call(undefined, (call) => this.#sdk.environments.connect({ environmentId, appName: app, body }, call)),
|
|
148
|
+
(async () => {
|
|
149
|
+
const environment = known ?? (await this.environments.get(environmentId));
|
|
150
|
+
const entry = environment.apps.find(({ name }) => name === app);
|
|
151
|
+
return entry ? this.#versionApis(entry.appId, entry.versionId) : [];
|
|
152
|
+
})(),
|
|
153
|
+
]);
|
|
154
|
+
return bindCredentials(credentials, apis, this.#fetch);
|
|
294
155
|
}
|
|
295
|
-
/**
|
|
296
|
-
#
|
|
297
|
-
|
|
298
|
-
if (
|
|
299
|
-
|
|
156
|
+
/** A version's APIs never change, so each is read once per client. */
|
|
157
|
+
#versionApis(appId, versionId) {
|
|
158
|
+
let apis = this.#apis.get(versionId);
|
|
159
|
+
if (!apis) {
|
|
160
|
+
apis = this.#findVersion(appId, versionId);
|
|
161
|
+
apis.catch(() => this.#apis.delete(versionId));
|
|
162
|
+
this.#apis.set(versionId, apis);
|
|
300
163
|
}
|
|
301
|
-
|
|
302
|
-
// The lookup is shared, so one caller's abort only stops that caller waiting.
|
|
303
|
-
return abortable(this.#credentialWorkspace, signal);
|
|
164
|
+
return apis;
|
|
304
165
|
}
|
|
305
|
-
#
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
lookup.catch(() => {
|
|
313
|
-
if (this.#credentialWorkspace === lookup) {
|
|
314
|
-
this.#credentialWorkspace = undefined;
|
|
166
|
+
async #findVersion(appId, versionId) {
|
|
167
|
+
let cursor;
|
|
168
|
+
do {
|
|
169
|
+
const page = await this.apps.versions(appId, cursor ? { cursor } : {});
|
|
170
|
+
const version = page.data.find(({ id }) => id === versionId);
|
|
171
|
+
if (version) {
|
|
172
|
+
return version.apis;
|
|
315
173
|
}
|
|
174
|
+
cursor = page.nextCursor ?? undefined;
|
|
175
|
+
} while (cursor);
|
|
176
|
+
throw new StateMachinesError({
|
|
177
|
+
message: `Version ${versionId} of ${appId} was not found.`,
|
|
178
|
+
status: null,
|
|
179
|
+
code: 'not_found',
|
|
180
|
+
requestId: null,
|
|
181
|
+
fields: null,
|
|
182
|
+
retryAfterMs: null,
|
|
316
183
|
});
|
|
317
|
-
return lookup;
|
|
318
184
|
}
|
|
319
|
-
#
|
|
320
|
-
|
|
185
|
+
#bind(data) {
|
|
186
|
+
const { id } = data;
|
|
187
|
+
const helpers = {
|
|
188
|
+
connect: (app, options = {}) => this.#connect(id, data, app, options),
|
|
189
|
+
pause: (options) => this.environments.pause(id, options),
|
|
190
|
+
resume: (options) => this.environments.resume(id, options),
|
|
191
|
+
delete: (options) => this.environments.delete(id, options),
|
|
192
|
+
refresh: () => this.environments.get(id),
|
|
193
|
+
snapshots: {
|
|
194
|
+
create: (input = {}, options) => this.snapshots.create({ ...input, environmentId: id }, options),
|
|
195
|
+
},
|
|
196
|
+
};
|
|
197
|
+
return Object.defineProperties({ ...data }, Object.fromEntries(Object.entries(helpers).map(([name, value]) => [
|
|
198
|
+
name,
|
|
199
|
+
{ value, enumerable: false },
|
|
200
|
+
])));
|
|
201
|
+
}
|
|
202
|
+
/** One read for the poller, which owns retries, timing and the caller's signal. */
|
|
203
|
+
#read(signal, run) {
|
|
204
|
+
return this.#call(signal, (call) => run({ ...call, retries: { strategy: 'none' } }));
|
|
321
205
|
}
|
|
322
206
|
/**
|
|
323
207
|
* Runs one API call under its own signal. Closing it when the call settles
|
|
324
208
|
* releases every attempt's timeout timer and listener.
|
|
325
209
|
*/
|
|
326
|
-
async #call(
|
|
327
|
-
const scope = linkSignal(
|
|
210
|
+
async #call(signal, run) {
|
|
211
|
+
const scope = linkSignal(signal);
|
|
328
212
|
const id = String(++this.#lastCall);
|
|
329
213
|
this.#callSignals.set(id, scope.signal);
|
|
330
214
|
try {
|
|
@@ -335,9 +219,7 @@ export class StateMachines {
|
|
|
335
219
|
}
|
|
336
220
|
catch (error) {
|
|
337
221
|
// A caller abort can surface as a raw TimeoutError while a body is read; it is never retryable.
|
|
338
|
-
throw toStateMachinesError(
|
|
339
|
-
? new CallerAbortedError(options.signal.reason)
|
|
340
|
-
: error);
|
|
222
|
+
throw toStateMachinesError(signal?.aborted ? new CallerAbortedError(signal.reason) : error);
|
|
341
223
|
}
|
|
342
224
|
finally {
|
|
343
225
|
this.#callSignals.delete(id);
|
|
@@ -360,14 +242,13 @@ function addAttemptTimeout(httpClient, timeoutMs, calls) {
|
|
|
360
242
|
httpClient.addHook('beforeRequest', (request) => {
|
|
361
243
|
const headers = new Headers(request.headers);
|
|
362
244
|
const call = calls.get(headers.get(CALL_HEADER) ?? '');
|
|
363
|
-
// The request's own signal still counts: a caller's hook may have set it.
|
|
364
245
|
const sources = call ? [call, request.signal] : [request.signal];
|
|
365
246
|
const aborted = sources.find(({ aborted }) => aborted);
|
|
366
247
|
headers.delete(CALL_HEADER);
|
|
367
248
|
if (aborted) {
|
|
368
249
|
throw new CallerAbortedError(aborted.reason);
|
|
369
250
|
}
|
|
370
|
-
const attempt = new Request(request, {
|
|
251
|
+
const attempt = new globalThis.Request(request, {
|
|
371
252
|
headers,
|
|
372
253
|
signal: linkSignal(sources, timeoutMs).signal,
|
|
373
254
|
});
|
|
@@ -382,56 +263,15 @@ function addAttemptTimeout(httpClient, timeoutMs, calls) {
|
|
|
382
263
|
}
|
|
383
264
|
});
|
|
384
265
|
}
|
|
385
|
-
function
|
|
386
|
-
return
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
return promise;
|
|
393
|
-
}
|
|
394
|
-
return new Promise((resolve, reject) => {
|
|
395
|
-
const onAbort = () => reject(signal.reason);
|
|
396
|
-
if (signal.aborted) {
|
|
397
|
-
onAbort();
|
|
398
|
-
return;
|
|
399
|
-
}
|
|
400
|
-
signal.addEventListener('abort', onAbort, { once: true });
|
|
401
|
-
promise
|
|
402
|
-
.then(resolve, reject)
|
|
403
|
-
.finally(() => signal.removeEventListener('abort', onAbort));
|
|
404
|
-
});
|
|
405
|
-
}
|
|
406
|
-
function pickActor(appKey, actors, actorId) {
|
|
407
|
-
const [first] = actors;
|
|
408
|
-
if (!first) {
|
|
409
|
-
throw new TypeError(`App ${appKey} has no actors.`);
|
|
410
|
-
}
|
|
411
|
-
if (actorId === undefined) {
|
|
412
|
-
return first;
|
|
413
|
-
}
|
|
414
|
-
const actor = actors.find(({ id }) => id === actorId);
|
|
415
|
-
if (!actor) {
|
|
416
|
-
throw new TypeError(`Unknown actor ${actorId} for ${appKey}. Choose one of: ${ids(actors)}.`);
|
|
417
|
-
}
|
|
418
|
-
return actor;
|
|
419
|
-
}
|
|
420
|
-
function pickApi(appKey, apis, apiId) {
|
|
421
|
-
const api = apiId
|
|
422
|
-
? apis.find(({ id }) => id === apiId)
|
|
423
|
-
: apis.length === 1
|
|
424
|
-
? apis[0]
|
|
425
|
-
: undefined;
|
|
426
|
-
if (!api) {
|
|
427
|
-
throw new TypeError(`Choose one API for ${appKey}: ${ids(apis) || 'none available'}.`);
|
|
428
|
-
}
|
|
429
|
-
return api;
|
|
430
|
-
}
|
|
431
|
-
function ids(choices) {
|
|
432
|
-
return choices.map(({ id }) => id).join(', ');
|
|
266
|
+
function waitOptions(options) {
|
|
267
|
+
return {
|
|
268
|
+
...(options.timeoutMs === undefined
|
|
269
|
+
? {}
|
|
270
|
+
: { timeoutMs: options.timeoutMs }),
|
|
271
|
+
...(options.signal ? { signal: options.signal } : {}),
|
|
272
|
+
};
|
|
433
273
|
}
|
|
434
274
|
function environmentApiKey() {
|
|
435
275
|
const runtime = globalThis;
|
|
436
|
-
return runtime.process?.env?.
|
|
276
|
+
return runtime.process?.env?.STATEMACHINES_API_KEY;
|
|
437
277
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Api } from '../models/api.js';
|
|
2
|
+
import type { Credentials as CredentialsData } from '../models/credentials.js';
|
|
3
|
+
/** The API's `Credentials`, plus `fetch` to call the app with them. */
|
|
4
|
+
export type Credentials = CredentialsData & {
|
|
5
|
+
/**
|
|
6
|
+
* Sends one request to the app: `path` is joined to `url`, `headers` are added, and
|
|
7
|
+
* `token` goes in the header of the API whose path matches (`Authorization: Bearer`
|
|
8
|
+
* for Salesforce REST and Bulk 2.0). Never retries, never follows redirects, never
|
|
9
|
+
* sends the State Machines API key. The SOAP session header is the caller's job.
|
|
10
|
+
*/
|
|
11
|
+
fetch(path: string, init?: RequestInit): Promise<Response>;
|
|
12
|
+
};
|
|
13
|
+
export declare function bindCredentials(data: CredentialsData, apis: readonly Api[], fetcher: typeof fetch | undefined): Credentials;
|