@usestatemachines/sdk 0.1.1 → 0.2.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/README.md +175 -75
- package/agents/SKILL.md +24 -44
- package/agents/index.js +7 -7
- package/agents/llms.txt +18 -39
- package/agents/prompt.md +11 -34
- package/esm/extensions/apps.d.ts +8 -0
- package/esm/extensions/apps.js +23 -0
- package/esm/extensions/client.d.ts +33 -3
- package/esm/extensions/client.js +144 -28
- package/esm/extensions/errors.d.ts +24 -5
- package/esm/extensions/errors.js +3 -2
- package/esm/extensions/index.d.ts +3 -1
- package/esm/extensions/index.js +1 -0
- package/esm/extensions/running-environment.d.ts +29 -0
- package/esm/extensions/running-environment.js +35 -0
- package/esm/extensions/signal.d.ts +1 -2
- package/esm/extensions/signal.js +9 -4
- package/esm/extensions/wait.d.ts +1 -0
- package/esm/extensions/wait.js +1 -1
- package/esm/funcs/create-environment-definition.d.ts +11 -0
- package/esm/funcs/create-environment-definition.js +94 -0
- package/esm/lib/config.d.ts +2 -2
- package/esm/lib/config.js +2 -2
- package/esm/models/connection-secret.d.ts +16 -0
- package/esm/models/connection-secret.js +13 -0
- package/esm/models/connection.d.ts +14 -0
- package/esm/models/connection.js +14 -0
- package/esm/models/error-response.d.ts +4 -0
- package/esm/models/error-response.js +4 -0
- package/esm/models/operations/create-environment-definition.d.ts +143 -0
- package/esm/models/operations/create-environment-definition.js +90 -0
- package/esm/models/operations/index.d.ts +1 -0
- package/esm/models/operations/index.js +1 -0
- package/esm/models/operations/reveal-connection.d.ts +26 -4
- package/esm/models/operations/reveal-connection.js +28 -2
- package/esm/sdk/sdk.d.ts +3 -1
- package/esm/sdk/sdk.js +5 -0
- package/openapi.json +394 -7
- package/package.json +1 -1
package/esm/extensions/client.js
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
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 { expandApps } from './apps.js';
|
|
4
5
|
import { Connection } from './connection.js';
|
|
5
|
-
import { StateMachinesError, toStateMachinesError } from './errors.js';
|
|
6
|
+
import { EnvironmentFailedError, StateMachinesError, TimeoutError, toStateMachinesError, } from './errors.js';
|
|
7
|
+
import { RunningEnvironment } from './running-environment.js';
|
|
6
8
|
import { linkSignal } from './signal.js';
|
|
7
|
-
import { disposed, poll, ready } from './wait.js';
|
|
9
|
+
import { defaultTimeoutMs, disposed, poll, ready, } from './wait.js';
|
|
10
|
+
const stopAfterFailureMs = 30000;
|
|
8
11
|
/** Thrown from a hook so the generated retry loop stops, whatever the abort reason. */
|
|
9
12
|
class CallerAbortedError extends Error {
|
|
10
13
|
name = 'CallerAbortedError';
|
|
@@ -16,6 +19,8 @@ export class StateMachines {
|
|
|
16
19
|
#sdk;
|
|
17
20
|
#fetch;
|
|
18
21
|
#workspaceId;
|
|
22
|
+
#callSignals = new Map();
|
|
23
|
+
#lastCall = 0;
|
|
19
24
|
#credentialWorkspace;
|
|
20
25
|
constructor(options = {}) {
|
|
21
26
|
const apiKey = options.apiKey ?? environmentApiKey();
|
|
@@ -37,7 +42,7 @@ export class StateMachines {
|
|
|
37
42
|
}
|
|
38
43
|
const httpClient = options.httpClient?.clone() ??
|
|
39
44
|
new HTTPClient(fetcher ? { fetcher: (input) => fetcher(input) } : {});
|
|
40
|
-
addAttemptTimeout(httpClient, timeoutMs);
|
|
45
|
+
addAttemptTimeout(httpClient, timeoutMs, this.#callSignals);
|
|
41
46
|
this.#fetch = fetcher;
|
|
42
47
|
this.#workspaceId = options.workspaceId;
|
|
43
48
|
this.#sdk = new Generated({
|
|
@@ -66,13 +71,56 @@ export class StateMachines {
|
|
|
66
71
|
return this.#sdk.environments.list({ ...filters, workspaceId: resolved }, call);
|
|
67
72
|
}),
|
|
68
73
|
get: (environmentId, options) => this.#unwrap(options, (call) => this.#sdk.environments.get({ environmentId }, call)),
|
|
69
|
-
/**
|
|
74
|
+
/**
|
|
75
|
+
* Creates an environment and waits until it's running. If the wait fails, stops the
|
|
76
|
+
* environment (unless the caller passed its own `idempotencyKey`), then rethrows the
|
|
77
|
+
* error with `environmentId`, `stopped` and `stopError`.
|
|
78
|
+
*/
|
|
79
|
+
start: async (input, options = {}) => {
|
|
80
|
+
const { readyTimeoutMs, ...createOptions } = options;
|
|
81
|
+
const { idempotencyKey, signal } = options;
|
|
82
|
+
const timeoutMs = readyTimeoutMs ?? defaultTimeoutMs;
|
|
83
|
+
if (!(timeoutMs > 0)) {
|
|
84
|
+
throw new RangeError('readyTimeoutMs must be more than 0.');
|
|
85
|
+
}
|
|
86
|
+
const created = await this.environments.create(input, createOptions);
|
|
87
|
+
try {
|
|
88
|
+
const environment = await this.environments.waitUntilReady(created.id, {
|
|
89
|
+
timeoutMs,
|
|
90
|
+
...(signal ? { signal } : {}),
|
|
91
|
+
});
|
|
92
|
+
return new RunningEnvironment(this, environment);
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
// The API replays a create by key, returning the same environment to another
|
|
96
|
+
// start() that may still be using it, so only the SDK's own key allows a stop.
|
|
97
|
+
const outcome = idempotencyKey === undefined
|
|
98
|
+
? await this.#stopAfterFailure(created.id)
|
|
99
|
+
: { environmentId: created.id, stopped: false };
|
|
100
|
+
const isCallerReason = signal?.aborted && Object.is(error, signal.reason);
|
|
101
|
+
if (isCallerReason) {
|
|
102
|
+
if (outcome.stopped) {
|
|
103
|
+
throw error;
|
|
104
|
+
}
|
|
105
|
+
throw Object.assign(new StateMachinesError(new CallerAbortedError(error)), outcome);
|
|
106
|
+
}
|
|
107
|
+
if (isStartError(error) && Object.isExtensible(error)) {
|
|
108
|
+
Object.assign(error, outcome);
|
|
109
|
+
}
|
|
110
|
+
throw error;
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
/**
|
|
114
|
+
* A string app is shorthand for `{ key: <the string>, appId: <the string> }`. Every
|
|
115
|
+
* failure carries the `idempotencyKey`; replaying the create with it is safe.
|
|
116
|
+
*/
|
|
70
117
|
create: async (input, options = {}) => {
|
|
71
118
|
const idempotencyKey = options.idempotencyKey ?? crypto.randomUUID();
|
|
72
119
|
try {
|
|
120
|
+
const body = expandApps(input);
|
|
73
121
|
return await this.#call(options, async (call) => {
|
|
74
122
|
const workspaceId = await this.#workspace(options.workspaceId, call.signal);
|
|
75
|
-
const { data } = await this.#sdk.environments.create({ workspaceId, idempotencyKey, body
|
|
123
|
+
const { data } = await this.#sdk.environments.create({ workspaceId, idempotencyKey, body }, call);
|
|
76
124
|
const [environment] = data;
|
|
77
125
|
if (!environment) {
|
|
78
126
|
throw new Error('Invalid response from the State API: the create returned no environment.');
|
|
@@ -87,23 +135,51 @@ export class StateMachines {
|
|
|
87
135
|
},
|
|
88
136
|
stop: (environmentId, options) => this.#unwrap(options, (call) => this.#sdk.environments.stop({ environmentId }, call)),
|
|
89
137
|
events: (environmentId, query = {}, options) => this.#call(options, (call) => this.#sdk.environments.events({ ...query, environmentId }, call)),
|
|
138
|
+
/** The app's users, in the release's order. */
|
|
139
|
+
actors: async (environmentId, appKey, options) => (await this.environments.getConnection(environmentId, appKey, options))
|
|
140
|
+
.actors,
|
|
90
141
|
getConnection: (environmentId, appKey, options) => this.#unwrap(options, (call) => this.#sdk.environments.getConnection({ environmentId, appKey }, call)),
|
|
91
|
-
reveal: (environmentId, appKey, actorId, options) => this.#
|
|
142
|
+
reveal: (environmentId, appKey, actorId, options) => this.#reveal(environmentId, appKey, { actorId }, options),
|
|
92
143
|
/** Resolves when the environment is running. Never stops it. */
|
|
93
144
|
waitUntilReady: (environmentId, options) => poll((signal) => this.#poll(environmentId, signal), ready, options),
|
|
94
145
|
/** Resolves when the environment ended and every sandbox is confirmed disposed. */
|
|
95
146
|
waitUntilStopped: (environmentId, options) => poll((signal) => this.#poll(environmentId, signal), disposed, options),
|
|
147
|
+
/**
|
|
148
|
+
* actorId defaults to the actor of the environment's declared default connection, or
|
|
149
|
+
* else the app's first actor (for Salesforce, the administrator). Pick another from
|
|
150
|
+
* actors() to act with that user's permissions.
|
|
151
|
+
*/
|
|
96
152
|
connect: async (environmentId, appKey, options = {}) => {
|
|
97
153
|
const details = await this.environments.getConnection(environmentId, appKey, options);
|
|
98
154
|
if (details.status !== 'ready' || !details.baseUrl) {
|
|
99
155
|
throw new TypeError(`App ${appKey} is not ready to connect (${details.status}).`);
|
|
100
156
|
}
|
|
101
|
-
|
|
102
|
-
const
|
|
103
|
-
|
|
157
|
+
// The API resolves { actorId } to that actor's first connection, not the declared one.
|
|
158
|
+
const body = options.actorId === undefined && details.defaultConnection
|
|
159
|
+
? { connectionKey: details.defaultConnection }
|
|
160
|
+
: { actorId: pickActor(appKey, details.actors, options.actorId).id };
|
|
161
|
+
const api = pickApi(appKey, details.apis, options.apiId);
|
|
162
|
+
const secret = await this.#reveal(environmentId, appKey, body, options);
|
|
104
163
|
return new Connection(details.baseUrl, api, secret, this.#fetch);
|
|
105
164
|
},
|
|
106
165
|
};
|
|
166
|
+
#reveal(environmentId, appKey, body, options) {
|
|
167
|
+
return this.#unwrap(options, (call) => this.#sdk.environments.reveal({ environmentId, appKey, body }, call));
|
|
168
|
+
}
|
|
169
|
+
async #stopAfterFailure(environmentId) {
|
|
170
|
+
const budget = linkSignal(undefined, stopAfterFailureMs);
|
|
171
|
+
try {
|
|
172
|
+
// abortable() ends the wait at the budget even during a retry delay.
|
|
173
|
+
await abortable(this.environments.stop(environmentId, { signal: budget.signal }), budget.signal);
|
|
174
|
+
return { environmentId, stopped: true };
|
|
175
|
+
}
|
|
176
|
+
catch (stopError) {
|
|
177
|
+
return { environmentId, stopped: false, stopError };
|
|
178
|
+
}
|
|
179
|
+
finally {
|
|
180
|
+
budget.dispose();
|
|
181
|
+
}
|
|
182
|
+
}
|
|
107
183
|
/** One read for the poller, which owns retries, timing and the caller's signal. */
|
|
108
184
|
#poll(environmentId, signal) {
|
|
109
185
|
return this.#unwrap({ signal }, (call) => this.#sdk.environments.get({ environmentId }, { ...call, retries: { strategy: 'none' } }));
|
|
@@ -141,8 +217,13 @@ export class StateMachines {
|
|
|
141
217
|
*/
|
|
142
218
|
async #call(options, run) {
|
|
143
219
|
const scope = linkSignal(options?.signal);
|
|
220
|
+
const id = String(++this.#lastCall);
|
|
221
|
+
this.#callSignals.set(id, scope.signal);
|
|
144
222
|
try {
|
|
145
|
-
return await run({
|
|
223
|
+
return await run({
|
|
224
|
+
signal: scope.signal,
|
|
225
|
+
headers: { [CALL_HEADER]: id },
|
|
226
|
+
});
|
|
146
227
|
}
|
|
147
228
|
catch (error) {
|
|
148
229
|
// A caller abort can surface as a raw TimeoutError while a body is read; it is never retryable.
|
|
@@ -151,35 +232,53 @@ export class StateMachines {
|
|
|
151
232
|
: error);
|
|
152
233
|
}
|
|
153
234
|
finally {
|
|
235
|
+
this.#callSignals.delete(id);
|
|
154
236
|
scope.close();
|
|
155
237
|
}
|
|
156
238
|
}
|
|
157
239
|
}
|
|
158
240
|
/**
|
|
159
|
-
*
|
|
241
|
+
* Names the call a request belongs to. Never sent: the attempt hook removes it.
|
|
242
|
+
* Needed because the generated loop clones each attempt, and after a garbage
|
|
243
|
+
* collection a clone's signal no longer follows the call's (Node 20 and 24).
|
|
244
|
+
*/
|
|
245
|
+
export const CALL_HEADER = 'x-statemachines-call';
|
|
246
|
+
/**
|
|
247
|
+
* Gives each attempt its own timeout, linked to its call's signal. The generated
|
|
160
248
|
* `timeoutMs` is never used: it is dropped when a caller passes a signal.
|
|
161
249
|
*/
|
|
162
|
-
function addAttemptTimeout(httpClient, timeoutMs) {
|
|
250
|
+
function addAttemptTimeout(httpClient, timeoutMs, calls) {
|
|
163
251
|
const callers = new WeakMap();
|
|
164
252
|
httpClient.addHook('beforeRequest', (request) => {
|
|
165
|
-
const
|
|
166
|
-
|
|
167
|
-
|
|
253
|
+
const headers = new Headers(request.headers);
|
|
254
|
+
const call = calls.get(headers.get(CALL_HEADER) ?? '');
|
|
255
|
+
// The request's own signal still counts: a caller's hook may have set it.
|
|
256
|
+
const sources = call ? [call, request.signal] : [request.signal];
|
|
257
|
+
const aborted = sources.find(({ aborted }) => aborted);
|
|
258
|
+
headers.delete(CALL_HEADER);
|
|
259
|
+
if (aborted) {
|
|
260
|
+
throw new CallerAbortedError(aborted.reason);
|
|
168
261
|
}
|
|
169
262
|
const attempt = new Request(request, {
|
|
170
|
-
|
|
263
|
+
headers,
|
|
264
|
+
signal: linkSignal(sources, timeoutMs).signal,
|
|
171
265
|
});
|
|
172
|
-
callers.set(attempt,
|
|
266
|
+
callers.set(attempt, sources);
|
|
173
267
|
return attempt;
|
|
174
268
|
});
|
|
175
269
|
// Without this, a timeout-shaped abort reason looks like a retryable timeout to the generated loop.
|
|
176
270
|
httpClient.addHook('requestError', (_error, request) => {
|
|
177
|
-
const
|
|
178
|
-
if (
|
|
179
|
-
throw new CallerAbortedError(
|
|
271
|
+
const aborted = callers.get(request)?.find(({ aborted }) => aborted);
|
|
272
|
+
if (aborted) {
|
|
273
|
+
throw new CallerAbortedError(aborted.reason);
|
|
180
274
|
}
|
|
181
275
|
});
|
|
182
276
|
}
|
|
277
|
+
function isStartError(error) {
|
|
278
|
+
return (error instanceof StateMachinesError ||
|
|
279
|
+
error instanceof EnvironmentFailedError ||
|
|
280
|
+
error instanceof TimeoutError);
|
|
281
|
+
}
|
|
183
282
|
function abortable(promise, signal) {
|
|
184
283
|
if (!signal) {
|
|
185
284
|
return promise;
|
|
@@ -196,16 +295,33 @@ function abortable(promise, signal) {
|
|
|
196
295
|
.finally(() => signal.removeEventListener('abort', onAbort));
|
|
197
296
|
});
|
|
198
297
|
}
|
|
199
|
-
function
|
|
200
|
-
const
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
298
|
+
function pickActor(appKey, actors, actorId) {
|
|
299
|
+
const [first] = actors;
|
|
300
|
+
if (!first) {
|
|
301
|
+
throw new TypeError(`App ${appKey} has no actors.`);
|
|
302
|
+
}
|
|
303
|
+
if (actorId === undefined) {
|
|
304
|
+
return first;
|
|
305
|
+
}
|
|
306
|
+
const actor = actors.find(({ id }) => id === actorId);
|
|
307
|
+
if (!actor) {
|
|
308
|
+
throw new TypeError(`Unknown actor ${actorId} for ${appKey}. Choose one of: ${ids(actors)}.`);
|
|
309
|
+
}
|
|
310
|
+
return actor;
|
|
311
|
+
}
|
|
312
|
+
function pickApi(appKey, apis, apiId) {
|
|
313
|
+
const api = apiId
|
|
314
|
+
? apis.find(({ id }) => id === apiId)
|
|
315
|
+
: apis.length === 1
|
|
316
|
+
? apis[0]
|
|
204
317
|
: undefined;
|
|
205
|
-
if (!
|
|
206
|
-
throw new TypeError(`Choose one ${
|
|
318
|
+
if (!api) {
|
|
319
|
+
throw new TypeError(`Choose one API for ${appKey}: ${ids(apis) || 'none available'}.`);
|
|
207
320
|
}
|
|
208
|
-
return
|
|
321
|
+
return api;
|
|
322
|
+
}
|
|
323
|
+
function ids(choices) {
|
|
324
|
+
return choices.map(({ id }) => id).join(', ');
|
|
209
325
|
}
|
|
210
326
|
function environmentApiKey() {
|
|
211
327
|
const runtime = globalThis;
|
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
import type { Environment } from '../models/environment.js';
|
|
2
2
|
import type { Code } from '../models/error-response.js';
|
|
3
|
+
/** What `environments.start()` adds to the error it rethrows after a failed wait. */
|
|
4
|
+
export interface StartFailure {
|
|
5
|
+
/** The environment the start created. */
|
|
6
|
+
readonly environmentId?: string;
|
|
7
|
+
/** Whether the stop request succeeded. Disposal may still be in progress. */
|
|
8
|
+
readonly stopped?: boolean;
|
|
9
|
+
/** Why the stop request failed, when it did. */
|
|
10
|
+
readonly stopError?: unknown;
|
|
11
|
+
}
|
|
3
12
|
interface Details {
|
|
4
13
|
readonly message: string;
|
|
5
14
|
readonly cause?: unknown;
|
|
@@ -12,11 +21,15 @@ interface Details {
|
|
|
12
21
|
readonly idempotencyKey?: string;
|
|
13
22
|
}
|
|
14
23
|
/**
|
|
15
|
-
* Any failed API call: an error response, an invalid response,
|
|
16
|
-
*
|
|
24
|
+
* Any failed API call: an error response, an invalid response, no response at all,
|
|
25
|
+
* or input the SDK rejected before sending (`status` null for the last three). The
|
|
26
|
+
* message never includes a response body.
|
|
17
27
|
*/
|
|
18
|
-
export declare class StateMachinesError extends Error implements Details {
|
|
28
|
+
export declare class StateMachinesError extends Error implements Details, StartFailure {
|
|
19
29
|
readonly name = "StateMachinesError";
|
|
30
|
+
readonly environmentId?: string;
|
|
31
|
+
readonly stopped?: boolean;
|
|
32
|
+
readonly stopError?: unknown;
|
|
20
33
|
readonly status: number | null;
|
|
21
34
|
readonly code: Code | null;
|
|
22
35
|
readonly requestId: string | null;
|
|
@@ -33,9 +46,12 @@ export declare class StateMachinesError extends Error implements Details {
|
|
|
33
46
|
});
|
|
34
47
|
}
|
|
35
48
|
export declare function toStateMachinesError(error: unknown): StateMachinesError;
|
|
36
|
-
export declare class EnvironmentFailedError extends Error {
|
|
49
|
+
export declare class EnvironmentFailedError extends Error implements StartFailure {
|
|
37
50
|
readonly environment: Environment;
|
|
38
51
|
readonly name = "EnvironmentFailedError";
|
|
52
|
+
readonly environmentId?: string;
|
|
53
|
+
readonly stopped?: boolean;
|
|
54
|
+
readonly stopError?: unknown;
|
|
39
55
|
constructor(environment: Environment);
|
|
40
56
|
}
|
|
41
57
|
export declare class DisposalIncompleteError extends Error {
|
|
@@ -43,10 +59,13 @@ export declare class DisposalIncompleteError extends Error {
|
|
|
43
59
|
readonly name = "DisposalIncompleteError";
|
|
44
60
|
constructor(environment: Environment);
|
|
45
61
|
}
|
|
46
|
-
export declare class TimeoutError extends Error {
|
|
62
|
+
export declare class TimeoutError extends Error implements StartFailure {
|
|
47
63
|
readonly timeoutMs: number;
|
|
48
64
|
readonly environment: Environment | null;
|
|
49
65
|
readonly name = "TimeoutError";
|
|
66
|
+
readonly environmentId?: string;
|
|
67
|
+
readonly stopped?: boolean;
|
|
68
|
+
readonly stopError?: unknown;
|
|
50
69
|
constructor(timeoutMs: number, environment: Environment | null);
|
|
51
70
|
}
|
|
52
71
|
export {};
|
package/esm/extensions/errors.js
CHANGED
|
@@ -3,8 +3,9 @@ import { ConnectionError, RequestTimeoutError, } from '../models/errors/http-cli
|
|
|
3
3
|
import { ResponseValidationError } from '../models/errors/response-validation-error.js';
|
|
4
4
|
import { StateMachinesHTTPError } from '../models/errors/state-machines-http-error.js';
|
|
5
5
|
/**
|
|
6
|
-
* Any failed API call: an error response, an invalid response,
|
|
7
|
-
*
|
|
6
|
+
* Any failed API call: an error response, an invalid response, no response at all,
|
|
7
|
+
* or input the SDK rejected before sending (`status` null for the last three). The
|
|
8
|
+
* message never includes a response body.
|
|
8
9
|
*/
|
|
9
10
|
export class StateMachinesError extends Error {
|
|
10
11
|
name = 'StateMachinesError';
|
|
@@ -4,8 +4,10 @@ export { ConnectionError, ErrorResponse, HTTPClientError, InvalidRequestError, R
|
|
|
4
4
|
export type { ApiProfile, App, Catalog, Connection as ConnectionDetails, ConnectionSecret, CreateEnvironmentInput, Credential, Environment, EnvironmentApp, Event, EventPage, Release, ReleaseActor, Workspace, } from '../models/index.js';
|
|
5
5
|
export { Code as ErrorCode, Disposal, EnvironmentStatus, StopReason, } from '../models/index.js';
|
|
6
6
|
export { Status as EnvironmentListStatus } from '../models/operations/list-environments.js';
|
|
7
|
-
export type {
|
|
7
|
+
export type { AppInput, EnvironmentInput } from './apps.js';
|
|
8
|
+
export type { CallOptions, ConnectOptions, CreateOptions, ListEnvironmentsQuery, Page, StartOptions, StateMachinesOptions, } from './client.js';
|
|
8
9
|
export { StateMachines } from './client.js';
|
|
9
10
|
export { Connection, formatActorHeader } from './connection.js';
|
|
10
11
|
export { DisposalIncompleteError, EnvironmentFailedError, StateMachinesError, TimeoutError, } from './errors.js';
|
|
12
|
+
export { RunningEnvironment } from './running-environment.js';
|
|
11
13
|
export type { WaitOptions } from './wait.js';
|
package/esm/extensions/index.js
CHANGED
|
@@ -5,3 +5,4 @@ export { Status as EnvironmentListStatus } from '../models/operations/list-envir
|
|
|
5
5
|
export { StateMachines } from './client.js';
|
|
6
6
|
export { Connection, formatActorHeader } from './connection.js';
|
|
7
7
|
export { DisposalIncompleteError, EnvironmentFailedError, StateMachinesError, TimeoutError, } from './errors.js';
|
|
8
|
+
export { RunningEnvironment } from './running-environment.js';
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { Environment } from '../models/environment.js';
|
|
2
|
+
import type { ReleaseActor } from '../models/release-actor.js';
|
|
3
|
+
import type { CallOptions, ConnectOptions, StateMachines } from './client.js';
|
|
4
|
+
import type { Connection } from './connection.js';
|
|
5
|
+
import type { WaitOptions } from './wait.js';
|
|
6
|
+
/** A started environment. It remains the handle after `stop()`. */
|
|
7
|
+
export declare class RunningEnvironment {
|
|
8
|
+
#private;
|
|
9
|
+
readonly id: string;
|
|
10
|
+
/** The record when `start()` resolved. Use `sm.environments.get(id)` for fresh state. */
|
|
11
|
+
readonly environment: Environment;
|
|
12
|
+
constructor(sm: StateMachines, environment: Environment);
|
|
13
|
+
/**
|
|
14
|
+
* actorId defaults to the actor of the environment's declared default connection, or
|
|
15
|
+
* else the app's first actor (for Salesforce, the administrator). Pick another from
|
|
16
|
+
* actors() to act with that user's permissions.
|
|
17
|
+
*/
|
|
18
|
+
connect(appKey: string, options?: ConnectOptions): Promise<Connection>;
|
|
19
|
+
/** The app's users, in the release's order. */
|
|
20
|
+
actors(appKey: string, options?: CallOptions): Promise<ReleaseActor[]>;
|
|
21
|
+
/** Safe to call twice. Doesn't wait for disposal: use `waitUntilStopped()`. */
|
|
22
|
+
stop(options?: CallOptions): Promise<Environment>;
|
|
23
|
+
/** Resolves when the environment ended and every sandbox is confirmed disposed. */
|
|
24
|
+
waitUntilStopped(options?: WaitOptions): Promise<Environment>;
|
|
25
|
+
toJSON(): {
|
|
26
|
+
id: string;
|
|
27
|
+
environment: Environment;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/** A started environment. It remains the handle after `stop()`. */
|
|
2
|
+
export class RunningEnvironment {
|
|
3
|
+
id;
|
|
4
|
+
/** The record when `start()` resolved. Use `sm.environments.get(id)` for fresh state. */
|
|
5
|
+
environment;
|
|
6
|
+
#environments;
|
|
7
|
+
constructor(sm, environment) {
|
|
8
|
+
this.id = environment.id;
|
|
9
|
+
this.environment = environment;
|
|
10
|
+
this.#environments = sm.environments;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* actorId defaults to the actor of the environment's declared default connection, or
|
|
14
|
+
* else the app's first actor (for Salesforce, the administrator). Pick another from
|
|
15
|
+
* actors() to act with that user's permissions.
|
|
16
|
+
*/
|
|
17
|
+
connect(appKey, options) {
|
|
18
|
+
return this.#environments.connect(this.id, appKey, options);
|
|
19
|
+
}
|
|
20
|
+
/** The app's users, in the release's order. */
|
|
21
|
+
actors(appKey, options) {
|
|
22
|
+
return this.#environments.actors(this.id, appKey, options);
|
|
23
|
+
}
|
|
24
|
+
/** Safe to call twice. Doesn't wait for disposal: use `waitUntilStopped()`. */
|
|
25
|
+
stop(options) {
|
|
26
|
+
return this.#environments.stop(this.id, options);
|
|
27
|
+
}
|
|
28
|
+
/** Resolves when the environment ended and every sandbox is confirmed disposed. */
|
|
29
|
+
waitUntilStopped(options) {
|
|
30
|
+
return this.#environments.waitUntilStopped(this.id, options);
|
|
31
|
+
}
|
|
32
|
+
toJSON() {
|
|
33
|
+
return { id: this.id, environment: this.environment };
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
/** A signal that aborts on the parent's abort, after `timeoutMs`, or on `close()`. */
|
|
2
1
|
export interface LinkedSignal {
|
|
3
2
|
readonly signal: AbortSignal;
|
|
4
3
|
/** Releases the timer and the parent listener without aborting. */
|
|
@@ -11,4 +10,4 @@ export interface LinkedSignal {
|
|
|
11
10
|
* on Node 20.20 in our probes. The timer and the listener hold the controller, so
|
|
12
11
|
* the abort reaches in-flight requests.
|
|
13
12
|
*/
|
|
14
|
-
export declare function linkSignal(parent: AbortSignal | undefined, timeoutMs?: number): LinkedSignal;
|
|
13
|
+
export declare function linkSignal(parent: AbortSignal | undefined | readonly AbortSignal[], timeoutMs?: number): LinkedSignal;
|
package/esm/extensions/signal.js
CHANGED
|
@@ -4,22 +4,27 @@
|
|
|
4
4
|
* the abort reaches in-flight requests.
|
|
5
5
|
*/
|
|
6
6
|
export function linkSignal(parent, timeoutMs) {
|
|
7
|
+
const parents = parent === undefined ? [] : [parent].flat();
|
|
7
8
|
const controller = new AbortController();
|
|
8
9
|
const timer = timeoutMs === undefined
|
|
9
10
|
? undefined
|
|
10
11
|
: setTimeout(() => controller.abort(new DOMException(`Timed out after ${timeoutMs} ms.`, 'TimeoutError')), timeoutMs);
|
|
11
|
-
const onAbort = () => controller.abort(
|
|
12
|
+
const onAbort = () => controller.abort(parents.find(({ aborted }) => aborted)?.reason);
|
|
12
13
|
const dispose = () => {
|
|
13
14
|
clearTimeout(timer);
|
|
14
|
-
|
|
15
|
+
for (const each of parents) {
|
|
16
|
+
each.removeEventListener('abort', onAbort);
|
|
17
|
+
}
|
|
15
18
|
};
|
|
16
19
|
timer?.unref?.();
|
|
17
20
|
controller.signal.addEventListener('abort', dispose, { once: true });
|
|
18
|
-
if (
|
|
21
|
+
if (parents.some(({ aborted }) => aborted)) {
|
|
19
22
|
onAbort();
|
|
20
23
|
}
|
|
21
24
|
else {
|
|
22
|
-
|
|
25
|
+
for (const each of parents) {
|
|
26
|
+
each.addEventListener('abort', onAbort, { once: true });
|
|
27
|
+
}
|
|
23
28
|
}
|
|
24
29
|
return {
|
|
25
30
|
signal: controller.signal,
|
package/esm/extensions/wait.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ export interface WaitOptions {
|
|
|
7
7
|
}
|
|
8
8
|
type Read = (signal: AbortSignal) => Promise<Environment>;
|
|
9
9
|
type Decide = (environment: Environment) => boolean;
|
|
10
|
+
export declare const defaultTimeoutMs = 600000;
|
|
10
11
|
/**
|
|
11
12
|
* Reads until `done` returns true. `done` throws to end the wait with a failure.
|
|
12
13
|
* Transient read failures are retried with backoff until the deadline.
|
package/esm/extensions/wait.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { DisposalIncompleteError, EnvironmentFailedError, TimeoutError, toStateMachinesError, } from './errors.js';
|
|
2
2
|
import { linkSignal } from './signal.js';
|
|
3
|
-
const defaultTimeoutMs = 600000;
|
|
3
|
+
export const defaultTimeoutMs = 600000;
|
|
4
4
|
const readTimeoutMs = 30000;
|
|
5
5
|
/**
|
|
6
6
|
* Reads until `done` returns true. `done` throws to end the wait with a failure.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { StateMachinesCore } from "../core.js";
|
|
2
|
+
import { RequestOptions } from "../lib/sdks.js";
|
|
3
|
+
import { ConnectionError, InvalidRequestError, RequestAbortedError, RequestTimeoutError, UnexpectedClientError } from "../models/errors/http-client-errors.js";
|
|
4
|
+
import * as errors from "../models/errors/index.js";
|
|
5
|
+
import { ResponseValidationError } from "../models/errors/response-validation-error.js";
|
|
6
|
+
import { SDKValidationError } from "../models/errors/sdk-validation-error.js";
|
|
7
|
+
import { StateMachinesHTTPError } from "../models/errors/state-machines-http-error.js";
|
|
8
|
+
import * as operations from "../models/operations/index.js";
|
|
9
|
+
import { APIPromise } from "../types/async.js";
|
|
10
|
+
import { Result } from "../types/fp.js";
|
|
11
|
+
export declare function createEnvironmentDefinition(client: StateMachinesCore, request: operations.CreateEnvironmentDefinitionRequest, options?: RequestOptions): APIPromise<Result<operations.CreateEnvironmentDefinitionResponse, errors.ErrorResponse | StateMachinesHTTPError | ResponseValidationError | ConnectionError | RequestAbortedError | RequestTimeoutError | InvalidRequestError | UnexpectedClientError | SDKValidationError>>;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.
|
|
3
|
+
*/
|
|
4
|
+
import * as z from "zod/v4-mini";
|
|
5
|
+
import { encodeJSON, encodeSimple } from "../lib/encodings.js";
|
|
6
|
+
import { matchStatusCode } from "../lib/http.js";
|
|
7
|
+
import * as M from "../lib/matchers.js";
|
|
8
|
+
import { compactMap } from "../lib/primitives.js";
|
|
9
|
+
import { safeParse } from "../lib/schemas.js";
|
|
10
|
+
import { extractSecurity, resolveGlobalSecurity } from "../lib/security.js";
|
|
11
|
+
import { pathToFunc } from "../lib/url.js";
|
|
12
|
+
import * as errors from "../models/errors/index.js";
|
|
13
|
+
import * as operations from "../models/operations/index.js";
|
|
14
|
+
import { APIPromise } from "../types/async.js";
|
|
15
|
+
export function createEnvironmentDefinition(client, request, options) {
|
|
16
|
+
return new APIPromise($do(client, request, options));
|
|
17
|
+
}
|
|
18
|
+
async function $do(client, request, options) {
|
|
19
|
+
const parsed = safeParse(request, (value) => z.parse(operations.CreateEnvironmentDefinitionRequest$outboundSchema, value), "Input validation failed");
|
|
20
|
+
if (!parsed.ok) {
|
|
21
|
+
return [parsed, { status: "invalid" }];
|
|
22
|
+
}
|
|
23
|
+
const payload = parsed.value;
|
|
24
|
+
const body = encodeJSON("body", payload.body, { explode: true });
|
|
25
|
+
const pathParams = {
|
|
26
|
+
workspaceId: encodeSimple("workspaceId", payload.workspaceId, {
|
|
27
|
+
explode: false,
|
|
28
|
+
charEncoding: "percent",
|
|
29
|
+
}),
|
|
30
|
+
};
|
|
31
|
+
const path = pathToFunc("/v1/workspaces/{workspaceId}/environment-definitions")(pathParams);
|
|
32
|
+
const headers = new Headers(compactMap({
|
|
33
|
+
"Content-Type": "application/json",
|
|
34
|
+
Accept: "application/json",
|
|
35
|
+
"idempotency-key": encodeSimple("idempotency-key", payload["idempotency-key"], { explode: false, charEncoding: "none" }),
|
|
36
|
+
}));
|
|
37
|
+
const secConfig = await extractSecurity(client._options.apiKey);
|
|
38
|
+
const securityInput = secConfig == null ? {} : { apiKey: secConfig };
|
|
39
|
+
const requestSecurity = resolveGlobalSecurity(securityInput);
|
|
40
|
+
const context = {
|
|
41
|
+
options: client._options,
|
|
42
|
+
baseURL: options?.serverURL ?? client._baseURL ?? "",
|
|
43
|
+
operationID: "createEnvironmentDefinition",
|
|
44
|
+
oAuth2Scopes: null,
|
|
45
|
+
resolvedSecurity: requestSecurity,
|
|
46
|
+
securitySource: client._options.apiKey,
|
|
47
|
+
retryConfig: options?.retries
|
|
48
|
+
|| client._options.retryConfig
|
|
49
|
+
|| {
|
|
50
|
+
strategy: "backoff",
|
|
51
|
+
backoff: {
|
|
52
|
+
initialInterval: 1000,
|
|
53
|
+
maxInterval: 5000,
|
|
54
|
+
exponent: 1.5,
|
|
55
|
+
maxElapsedTime: 600000,
|
|
56
|
+
},
|
|
57
|
+
retryConnectionErrors: true,
|
|
58
|
+
}
|
|
59
|
+
|| { strategy: "none" },
|
|
60
|
+
retryCodes: options?.retryCodes || ["502", "503", "504"],
|
|
61
|
+
};
|
|
62
|
+
const requestRes = client._createRequest(context, {
|
|
63
|
+
security: requestSecurity,
|
|
64
|
+
method: "POST",
|
|
65
|
+
baseURL: options?.serverURL,
|
|
66
|
+
path: path,
|
|
67
|
+
headers: headers,
|
|
68
|
+
body: body,
|
|
69
|
+
userAgent: client._options.userAgent,
|
|
70
|
+
timeoutMs: options?.timeoutMs || client._options.timeoutMs || -1,
|
|
71
|
+
}, options);
|
|
72
|
+
if (!requestRes.ok) {
|
|
73
|
+
return [requestRes, { status: "invalid" }];
|
|
74
|
+
}
|
|
75
|
+
const req = requestRes.value;
|
|
76
|
+
const doResult = await client._do(req, {
|
|
77
|
+
context,
|
|
78
|
+
isErrorStatusCode: (statusCode) => matchStatusCode({ status: statusCode }, ["4XX", "5XX"]),
|
|
79
|
+
retryConfig: context.retryConfig,
|
|
80
|
+
retryCodes: context.retryCodes,
|
|
81
|
+
});
|
|
82
|
+
if (!doResult.ok) {
|
|
83
|
+
return [doResult, { status: "request-error", request: req }];
|
|
84
|
+
}
|
|
85
|
+
const response = doResult.value;
|
|
86
|
+
const responseFields = {
|
|
87
|
+
HttpMeta: { Response: response, Request: req },
|
|
88
|
+
};
|
|
89
|
+
const [result] = await M.match(M.json(202, operations.CreateEnvironmentDefinitionResponse$inboundSchema), M.jsonErr([400, 401, 403, 404, 409, 413, 422, 429], errors.ErrorResponse$inboundSchema), M.jsonErr([500, 503], errors.ErrorResponse$inboundSchema), M.fail("4XX"), M.fail("5XX"))(response, req, { extraFields: responseFields });
|
|
90
|
+
if (!result.ok) {
|
|
91
|
+
return [result, { status: "complete", request: req, response }];
|
|
92
|
+
}
|
|
93
|
+
return [result, { status: "complete", request: req, response }];
|
|
94
|
+
}
|
package/esm/lib/config.d.ts
CHANGED
|
@@ -31,7 +31,7 @@ export declare function serverURLFromOptions(options: SDKOptions): URL | null;
|
|
|
31
31
|
export declare const SDK_METADATA: {
|
|
32
32
|
readonly language: "typescript";
|
|
33
33
|
readonly openapiDocVersion: "1.0.0";
|
|
34
|
-
readonly sdkVersion: "0.
|
|
34
|
+
readonly sdkVersion: "0.2.0";
|
|
35
35
|
readonly genVersion: "2.941.0";
|
|
36
|
-
readonly userAgent: "speakeasy-sdk/typescript 0.
|
|
36
|
+
readonly userAgent: "speakeasy-sdk/typescript 0.2.0 2.941.0 1.0.0 @usestatemachines/sdk";
|
|
37
37
|
};
|
package/esm/lib/config.js
CHANGED
|
@@ -24,7 +24,7 @@ export function serverURLFromOptions(options) {
|
|
|
24
24
|
export const SDK_METADATA = {
|
|
25
25
|
language: "typescript",
|
|
26
26
|
openapiDocVersion: "1.0.0",
|
|
27
|
-
sdkVersion: "0.
|
|
27
|
+
sdkVersion: "0.2.0",
|
|
28
28
|
genVersion: "2.941.0",
|
|
29
|
-
userAgent: "speakeasy-sdk/typescript 0.
|
|
29
|
+
userAgent: "speakeasy-sdk/typescript 0.2.0 2.941.0 1.0.0 @usestatemachines/sdk",
|
|
30
30
|
};
|
|
@@ -1,14 +1,30 @@
|
|
|
1
1
|
import * as z from "zod/v4-mini";
|
|
2
2
|
import { Result as SafeParseResult } from "../types/fp.js";
|
|
3
3
|
import { SDKValidationError } from "./errors/sdk-validation-error.js";
|
|
4
|
+
export type Native = {
|
|
5
|
+
authentication: string;
|
|
6
|
+
baseUrl: string;
|
|
7
|
+
credentials: {
|
|
8
|
+
[k: string]: string;
|
|
9
|
+
};
|
|
10
|
+
key: string;
|
|
11
|
+
parameters: {
|
|
12
|
+
[k: string]: string;
|
|
13
|
+
};
|
|
14
|
+
};
|
|
4
15
|
export type ConnectionSecret = {
|
|
5
16
|
actorId: string;
|
|
6
17
|
actorToken: string;
|
|
7
18
|
appKey: string;
|
|
19
|
+
connectionKey: string | null;
|
|
8
20
|
environmentId: string;
|
|
9
21
|
environmentToken: string;
|
|
10
22
|
expiresAt: Date;
|
|
23
|
+
native?: Native | undefined;
|
|
11
24
|
};
|
|
12
25
|
/** @internal */
|
|
26
|
+
export declare const Native$inboundSchema: z.ZodMiniType<Native, unknown>;
|
|
27
|
+
export declare function nativeFromJSON(jsonString: string): SafeParseResult<Native, SDKValidationError>;
|
|
28
|
+
/** @internal */
|
|
13
29
|
export declare const ConnectionSecret$inboundSchema: z.ZodMiniType<ConnectionSecret, unknown>;
|
|
14
30
|
export declare function connectionSecretFromJSON(jsonString: string): SafeParseResult<ConnectionSecret, SDKValidationError>;
|