@usestatemachines/sdk 0.11.0 → 0.12.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.
Files changed (104) hide show
  1. package/README.md +80 -15
  2. package/agents/SKILL.md +9 -4
  3. package/agents/index.js +4 -4
  4. package/agents/llms.txt +7 -5
  5. package/esm/extensions/client.d.ts +56 -8
  6. package/esm/extensions/client.js +67 -5
  7. package/esm/extensions/credentials.js +4 -0
  8. package/esm/extensions/environment.d.ts +11 -2
  9. package/esm/extensions/errors.d.ts +33 -0
  10. package/esm/extensions/errors.js +53 -0
  11. package/esm/extensions/import-data.d.ts +43 -0
  12. package/esm/extensions/import-data.js +88 -0
  13. package/esm/extensions/index.d.ts +4 -3
  14. package/esm/extensions/index.js +1 -1
  15. package/esm/extensions/packaging.d.ts +1 -0
  16. package/esm/extensions/packaging.js +1 -0
  17. package/esm/extensions/zip.d.ts +8 -0
  18. package/esm/extensions/zip.js +121 -0
  19. package/esm/funcs/environments-actors.d.ts +11 -0
  20. package/esm/funcs/environments-actors.js +102 -0
  21. package/esm/funcs/get-import-file.d.ts +12 -0
  22. package/esm/funcs/get-import-file.js +97 -0
  23. package/esm/funcs/list-import-files.d.ts +12 -0
  24. package/esm/funcs/list-import-files.js +98 -0
  25. package/esm/funcs/upload-import.d.ts +12 -0
  26. package/esm/funcs/upload-import.js +96 -0
  27. package/esm/lib/config.d.ts +2 -2
  28. package/esm/lib/config.js +2 -2
  29. package/esm/models/absent-record.d.ts +7 -3
  30. package/esm/models/absent-record.js +3 -2
  31. package/esm/models/actor.d.ts +3 -0
  32. package/esm/models/app-user.d.ts +17 -0
  33. package/esm/models/app-user.js +18 -0
  34. package/esm/models/credentials.d.ts +6 -1
  35. package/esm/models/credentials.js +2 -0
  36. package/esm/models/environment.d.ts +4 -4
  37. package/esm/models/environment.js +3 -4
  38. package/esm/models/error.d.ts +7 -0
  39. package/esm/models/error.js +4 -0
  40. package/esm/models/filled-field.d.ts +14 -0
  41. package/esm/models/filled-field.js +16 -0
  42. package/esm/models/import-actor.d.ts +16 -0
  43. package/esm/models/import-actor.js +15 -0
  44. package/esm/models/import-file.d.ts +56 -0
  45. package/esm/models/import-file.js +67 -0
  46. package/esm/models/import-folder.d.ts +56 -0
  47. package/esm/models/import-folder.js +75 -0
  48. package/esm/models/import-problem.d.ts +4 -4
  49. package/esm/models/import-problem.js +1 -1
  50. package/esm/models/index.d.ts +18 -1
  51. package/esm/models/index.js +18 -1
  52. package/esm/models/known-difference.d.ts +21 -0
  53. package/esm/models/known-difference.js +16 -0
  54. package/esm/models/launch-ui-session.d.ts +12 -2
  55. package/esm/models/launch-ui-session.js +2 -1
  56. package/esm/models/made-id.d.ts +22 -0
  57. package/esm/models/made-id.js +17 -0
  58. package/esm/models/matched-record.d.ts +22 -0
  59. package/esm/models/matched-record.js +17 -0
  60. package/esm/models/object-load.d.ts +21 -0
  61. package/esm/models/object-load.js +17 -0
  62. package/esm/models/operations/create-credentials.d.ts +10 -0
  63. package/esm/models/operations/create-credentials.js +1 -0
  64. package/esm/models/operations/get-import-file.d.ts +13 -0
  65. package/esm/models/operations/get-import-file.js +12 -0
  66. package/esm/models/operations/index.d.ts +4 -0
  67. package/esm/models/operations/index.js +4 -0
  68. package/esm/models/operations/list-actors.d.ts +32 -0
  69. package/esm/models/operations/list-actors.js +26 -0
  70. package/esm/models/operations/list-import-files.d.ts +15 -0
  71. package/esm/models/operations/list-import-files.js +13 -0
  72. package/esm/models/operations/list-snapshots.d.ts +2 -2
  73. package/esm/models/operations/list-snapshots.js +1 -1
  74. package/esm/models/operations/upload-import.d.ts +13 -0
  75. package/esm/models/operations/upload-import.js +17 -0
  76. package/esm/models/problem-counts.d.ts +17 -0
  77. package/esm/models/problem-counts.js +14 -0
  78. package/esm/models/received-import.d.ts +9 -0
  79. package/esm/models/received-import.js +13 -0
  80. package/esm/models/record-source.d.ts +13 -0
  81. package/esm/models/{absent-record-source.js → record-source.js} +3 -3
  82. package/esm/models/snapshot-app-full-load-counts.d.ts +57 -0
  83. package/esm/models/snapshot-app-full-load-counts.js +25 -0
  84. package/esm/models/snapshot-app-full-load.d.ts +101 -0
  85. package/esm/models/snapshot-app-full-load.js +42 -0
  86. package/esm/models/snapshot-app-limited-load-counts.d.ts +16 -0
  87. package/esm/models/snapshot-app-limited-load-counts.js +14 -0
  88. package/esm/models/snapshot-app-limited-load.d.ts +18 -0
  89. package/esm/models/snapshot-app-limited-load.js +16 -0
  90. package/esm/models/snapshot-app-load-counts.d.ts +13 -0
  91. package/esm/models/snapshot-app-load-counts.js +15 -0
  92. package/esm/models/snapshot-app-load.d.ts +5 -12
  93. package/esm/models/snapshot-app-load.js +6 -6
  94. package/esm/models/snapshot-list-item.d.ts +53 -0
  95. package/esm/models/snapshot-list-item.js +42 -0
  96. package/esm/models/snapshot.d.ts +1 -1
  97. package/esm/models/version.d.ts +3 -0
  98. package/esm/sdk/environments.d.ts +1 -0
  99. package/esm/sdk/environments.js +4 -0
  100. package/esm/sdk/sdk.d.ts +3 -0
  101. package/esm/sdk/sdk.js +12 -0
  102. package/openapi.json +1868 -510
  103. package/package.json +7 -3
  104. package/esm/models/absent-record-source.d.ts +0 -13
@@ -1,10 +1,12 @@
1
1
  import type { App } from '../models/app.js';
2
+ import type { AppUser } from '../models/app-user.js';
2
3
  import type { AuditEvent } from '../models/audit-event.js';
3
4
  import type { CreateEnvironment } from '../models/create-environment.js';
4
5
  import type { Import } from '../models/import.js';
5
6
  import type { Me } from '../models/me.js';
6
7
  import type { CreateCredentialsRequestBody } from '../models/operations/create-credentials.js';
7
8
  import type { GetRequestStatsRequest } from '../models/operations/get-request-stats.js';
9
+ import type { ListActorsRequest } from '../models/operations/list-actors.js';
8
10
  import type { ListAuditEventsRequest } from '../models/operations/list-audit-events.js';
9
11
  import type { ListEnvironmentsRequest } from '../models/operations/list-environments.js';
10
12
  import type { ListImportsRequest } from '../models/operations/list-imports.js';
@@ -16,10 +18,13 @@ import type { RequestT as Request } from '../models/request.js';
16
18
  import type { RequestDetail } from '../models/request-detail.js';
17
19
  import type { RequestStats } from '../models/request-stats.js';
18
20
  import type { Snapshot } from '../models/snapshot.js';
21
+ import type { SnapshotListItem } from '../models/snapshot-list-item.js';
19
22
  import type { Version } from '../models/version.js';
20
23
  import type { Workspace } from '../models/workspace.js';
21
24
  import { type Credentials } from './credentials.js';
22
25
  import type { Environment } from './environment.js';
26
+ import { ActorCannotSignInError, ActorNotFoundError } from './errors.js';
27
+ import { type ImportData } from './import-data.js';
23
28
  import { type KnownEnvironmentStatus, type KnownSnapshotStatus, type WaitOptions } from './wait.js';
24
29
  export interface StateMachinesOptions {
25
30
  /** An API key or a member's access token. Defaults to `STATEMACHINES_API_KEY` where a `process` exists. */
@@ -50,13 +55,34 @@ export interface UploadImportOptions extends SignalOptions {
50
55
  /** A repeat with the same key and the same bytes finds the same import. Defaults to a new UUID. */
51
56
  idempotencyKey?: string;
52
57
  }
58
+ /** The input of `snapshots.create` that builds the snapshot from the data of an import. */
59
+ interface CreateSnapshotFromData {
60
+ /** The manifest of the import, with each app's records in it. */
61
+ import: ImportData;
62
+ name?: string | null;
63
+ /** The workspace of the import and the snapshot. Defaults to the client's `workspaceId`; an API key has its own. */
64
+ workspaceId?: string;
65
+ }
53
66
  /**
54
- * The body of the credentials call. `actorId` defaults to the app's default
55
- * actor (for Salesforce, the administrator). `services` names more services
56
- * to list, by ID. The credentials always list every `public` service, and a
67
+ * The body of the credentials call. `as` names the user to act as, by email,
68
+ * username or ID. Without it, the credentials act as the app's default user:
69
+ * the first user that the snapshot's import names in `actors`, or else the
70
+ * app's administrator. `services` names more services to
71
+ * list, by ID. The credentials always list every `public` service, and a
57
72
  * `preview` service only when `services` names it.
58
73
  */
59
- export type ConnectOptions = Pick<CreateCredentialsRequestBody, 'actorId' | 'services'>;
74
+ export type ConnectOptions = Pick<CreateCredentialsRequestBody, 'as' | 'actorId' | 'services'>;
75
+ export interface ConnectAllOptions {
76
+ /** An email, a username or an ID, which each app looks up among its own users. */
77
+ as: string;
78
+ }
79
+ /** Credentials for each app that lets the user act, and the refusal of each other app. */
80
+ export interface ConnectAllResult {
81
+ /** By app name. */
82
+ readonly credentials: Readonly<Record<string, Credentials>>;
83
+ /** In the order of the environment's apps. */
84
+ readonly errors: readonly (ActorNotFoundError | ActorCannotSignInError)[];
85
+ }
60
86
  export interface Page<T> {
61
87
  data: T[];
62
88
  nextCursor: string | null;
@@ -66,6 +92,8 @@ export type PageQuery = {
66
92
  cursor?: string;
67
93
  };
68
94
  export type ListEnvironmentsQuery = ListEnvironmentsRequest;
95
+ /** `search` matches part of a name, an email or a username in any case, or a whole ID. */
96
+ export type ListActorsQuery = Omit<ListActorsRequest, 'environmentId' | 'appName'>;
69
97
  export type ListSnapshotsQuery = ListSnapshotsRequest;
70
98
  export type ListImportsQuery = ListImportsRequest;
71
99
  export type ListAuditEventsQuery = ListAuditEventsRequest;
@@ -101,8 +129,14 @@ export declare class StateMachines {
101
129
  * another call: `EnvironmentFailedError` if it failed, else `UnexpectedStatusError`.
102
130
  */
103
131
  wait: (environmentId: string, options: WaitOptions<KnownEnvironmentStatus>) => Promise<Environment>;
104
- /** Credentials for one app of the environment. */
132
+ /**
133
+ * Credentials for one app of the environment. A user that the app does not have
134
+ * throws `ActorNotFoundError`, and one it does not let sign in throws
135
+ * `ActorCannotSignInError`.
136
+ */
105
137
  connect: (environmentId: string, appName: string, options?: ConnectOptions) => Promise<Credentials>;
138
+ /** One page of the users who can act in one app of a running environment, the default user first. */
139
+ actors: (environmentId: string, appName: string, query?: ListActorsQuery) => Promise<Page<AppUser>>;
106
140
  };
107
141
  readonly snapshots: {
108
142
  /**
@@ -110,16 +144,29 @@ export declare class StateMachines {
110
144
  * and, unless `wait` is false, waits until it is `ready`. A snapshot from an import
111
145
  * takes every app of the import, each on its default version, with empty setup and
112
146
  * services. An import that an app refuses throws `SnapshotFailedError` with its problems.
147
+ *
148
+ * `{ import }` takes an import as one object, which is the manifest with each app's
149
+ * records in it. The SDK writes the object as a zip file, uploads it as `imports.upload`
150
+ * does, and builds the snapshot from the import. The zip file holds each object's records
151
+ * in `<app>/records/<Object>.jsonl`, one record per line, so a problem at line N of that
152
+ * file names `apps.<app>.records.<Object>[N - 1]`. Data that the SDK cannot write as a
153
+ * zip file throws `StateMachinesError` with `code: 'invalid_request'` before any request.
154
+ * An import that its check leaves `invalid` throws `ImportInvalidError`, and the SDK
155
+ * creates no snapshot. The import and the snapshot share one idempotency key, so a
156
+ * retry with the same key and the same data finds both.
113
157
  */
114
- create: (input: {
158
+ create: (input: CreateSnapshotFromData | {
115
159
  environmentId: string;
116
160
  name?: string | null;
117
161
  } | {
118
162
  importId: string;
119
163
  name?: string | null;
120
164
  }, options?: CreateEnvironmentOptions) => Promise<Snapshot>;
121
- /** Newest first. Leaves deleted snapshots out unless `status` asks for them. */
122
- list: (query?: ListSnapshotsRequest) => Promise<Page<Snapshot>>;
165
+ /**
166
+ * Newest first. Leaves deleted snapshots out unless `status` asks for them.
167
+ * Each app's load holds its counts only. `get` answers its lists too.
168
+ */
169
+ list: (query?: ListSnapshotsRequest) => Promise<Page<SnapshotListItem>>;
123
170
  get: (snapshotId: string) => Promise<Snapshot>;
124
171
  /** `null` clears the name. */
125
172
  update: (snapshotId: string, body: {
@@ -165,3 +212,4 @@ export declare class StateMachines {
165
212
  * collection a clone's signal no longer follows the call's (Node 20 and 24).
166
213
  */
167
214
  export declare const CALL_HEADER = "x-statemachines-call";
215
+ export {};
@@ -2,7 +2,8 @@ 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
4
  import { bindCredentials } from './credentials.js';
5
- import { CallerAbortedError, StateMachinesError, toStateMachinesError, uploadRefused, uploadUnanswered, } from './errors.js';
5
+ import { ActorCannotSignInError, ActorNotFoundError, actorError, CallerAbortedError, ImportInvalidError, StateMachinesError, toStateMachinesError, uploadRefused, uploadUnanswered, } from './errors.js';
6
+ import { zipImport } from './import-data.js';
6
7
  import { linkSignal } from './signal.js';
7
8
  import { environmentAt, poll, snapshotAt, } from './wait.js';
8
9
  export class StateMachines {
@@ -79,8 +80,14 @@ export class StateMachines {
79
80
  * another call: `EnvironmentFailedError` if it failed, else `UnexpectedStatusError`.
80
81
  */
81
82
  wait: async (environmentId, options) => this.#bind(await poll(environmentId, (signal) => this.#read(signal, (call) => this.#sdk.environments.get({ environmentId }, call)), environmentAt(options.status), options)),
82
- /** Credentials for one app of the environment. */
83
+ /**
84
+ * Credentials for one app of the environment. A user that the app does not have
85
+ * throws `ActorNotFoundError`, and one it does not let sign in throws
86
+ * `ActorCannotSignInError`.
87
+ */
83
88
  connect: (environmentId, appName, options = {}) => this.#connect(environmentId, appName, options),
89
+ /** One page of the users who can act in one app of a running environment, the default user first. */
90
+ actors: (environmentId, appName, query = {}) => this.#call(undefined, (call) => this.#sdk.environments.actors({ ...query, environmentId, appName }, call)),
84
91
  };
85
92
  snapshots = {
86
93
  /**
@@ -88,10 +95,24 @@ export class StateMachines {
88
95
  * and, unless `wait` is false, waits until it is `ready`. A snapshot from an import
89
96
  * takes every app of the import, each on its default version, with empty setup and
90
97
  * services. An import that an app refuses throws `SnapshotFailedError` with its problems.
98
+ *
99
+ * `{ import }` takes an import as one object, which is the manifest with each app's
100
+ * records in it. The SDK writes the object as a zip file, uploads it as `imports.upload`
101
+ * does, and builds the snapshot from the import. The zip file holds each object's records
102
+ * in `<app>/records/<Object>.jsonl`, one record per line, so a problem at line N of that
103
+ * file names `apps.<app>.records.<Object>[N - 1]`. Data that the SDK cannot write as a
104
+ * zip file throws `StateMachinesError` with `code: 'invalid_request'` before any request.
105
+ * An import that its check leaves `invalid` throws `ImportInvalidError`, and the SDK
106
+ * creates no snapshot. The import and the snapshot share one idempotency key, so a
107
+ * retry with the same key and the same data finds both.
91
108
  */
92
109
  create: async (input, options = {}) => {
110
+ const { signal } = options;
93
111
  const idempotencyKey = options.idempotencyKey ?? crypto.randomUUID();
94
- const created = await this.#call(options.signal, (call) => this.#sdk.snapshots.create({ idempotencyKey, body: input }, call));
112
+ const body = 'import' in input
113
+ ? await this.#fromData(input, idempotencyKey, signal)
114
+ : input;
115
+ const created = await this.#call(signal, (call) => this.#sdk.snapshots.create({ idempotencyKey, body }, call));
95
116
  return options.wait === false
96
117
  ? created
97
118
  : this.snapshots.wait(created.id, {
@@ -99,7 +120,10 @@ export class StateMachines {
99
120
  ...waitOptions(options),
100
121
  });
101
122
  },
102
- /** Newest first. Leaves deleted snapshots out unless `status` asks for them. */
123
+ /**
124
+ * Newest first. Leaves deleted snapshots out unless `status` asks for them.
125
+ * Each app's load holds its counts only. `get` answers its lists too.
126
+ */
103
127
  list: (query = {}) => this.#call(undefined, (call) => this.#sdk.snapshots.list(this.#inWorkspace(query), call)),
104
128
  get: (snapshotId) => this.#call(undefined, (call) => this.#sdk.snapshots.get({ snapshotId }, call)),
105
129
  /** `null` clears the name. */
@@ -166,12 +190,48 @@ export class StateMachines {
166
190
  }
167
191
  async #connect(environmentId, appName, options) {
168
192
  const body = {
193
+ ...(options.as === undefined ? {} : { as: options.as }),
169
194
  ...(options.actorId === undefined ? {} : { actorId: options.actorId }),
170
195
  ...(options.services === undefined ? {} : { services: options.services }),
171
196
  };
172
- const credentials = await this.#call(undefined, (call) => this.#sdk.environments.connect({ environmentId, appName, body }, call));
197
+ // Typed inside the call, because the error that `#call` throws no longer holds the response body.
198
+ const credentials = await this.#call(undefined, (call) => this.#sdk.environments
199
+ .connect({ environmentId, appName, body }, call)
200
+ .catch((error) => {
201
+ throw actorError(error, appName);
202
+ }));
173
203
  return bindCredentials(credentials, this.#fetch);
174
204
  }
205
+ async #connectAll(environment, { as }) {
206
+ const outcomes = await Promise.allSettled(environment.apps.map((app) => this.#connect(environment.id, app.name, { as })));
207
+ const credentials = {};
208
+ const errors = [];
209
+ for (const outcome of outcomes) {
210
+ if (outcome.status === 'fulfilled') {
211
+ credentials[outcome.value.appName] = outcome.value;
212
+ }
213
+ else if (outcome.reason instanceof ActorNotFoundError ||
214
+ outcome.reason instanceof ActorCannotSignInError) {
215
+ errors.push(outcome.reason);
216
+ }
217
+ else {
218
+ throw outcome.reason;
219
+ }
220
+ }
221
+ return { credentials, errors };
222
+ }
223
+ /** Uploads the data as an import under `idempotencyKey`, and answers the body that builds the snapshot from it. */
224
+ async #fromData({ import: data, workspaceId, ...snapshot }, idempotencyKey, signal) {
225
+ const imported = await this.imports.upload(zipImport(data), {
226
+ ...(workspaceId === undefined ? {} : { workspaceId }),
227
+ ...(signal ? { signal } : {}),
228
+ idempotencyKey,
229
+ });
230
+ if (imported.status === 'invalid') {
231
+ throw new ImportInvalidError(imported);
232
+ }
233
+ return { ...snapshot, importId: imported.id };
234
+ }
175
235
  async #send(upload, zip, signal) {
176
236
  const fetcher = this.#fetch ?? fetch;
177
237
  const scope = linkSignal(signal);
@@ -203,7 +263,9 @@ export class StateMachines {
203
263
  #bind(data) {
204
264
  const { id } = data;
205
265
  const helpers = {
266
+ actors: (appName, query) => this.environments.actors(id, appName, query),
206
267
  connect: (appName, options = {}) => this.#connect(id, appName, options),
268
+ connectAll: (options) => this.#connectAll(data, options),
207
269
  delete: (options) => this.environments.delete(id, options),
208
270
  refresh: () => this.environments.get(id),
209
271
  snapshots: {
@@ -27,6 +27,10 @@ class BoundCredentials {
27
27
  this.services = data.services;
28
28
  this.token = data.token;
29
29
  this.#fetcher = fetcher;
30
+ // Set only when present, so JSON and a spread hold the API's fields.
31
+ if (data.actor) {
32
+ this.actor = data.actor;
33
+ }
30
34
  const api = data.services.find((candidate) => candidate.id === 'api');
31
35
  this.#api = api
32
36
  ? { base: baseUrl(api.url), headers: { ...api.headers } }
@@ -1,6 +1,7 @@
1
+ import type { AppUser } from '../models/app-user.js';
1
2
  import type { Environment as EnvironmentData } from '../models/environment.js';
2
3
  import type { Snapshot } from '../models/snapshot.js';
3
- import type { ConnectOptions, CreateSnapshotOptions, SignalOptions } from './client.js';
4
+ import type { ConnectAllOptions, ConnectAllResult, ConnectOptions, CreateSnapshotOptions, ListActorsQuery, Page, SignalOptions } from './client.js';
4
5
  import type { Credentials } from './credentials.js';
5
6
  /**
6
7
  * An environment as the API returned it, with helpers bound to it. The helpers are not
@@ -8,8 +9,16 @@ import type { Credentials } from './credentials.js';
8
9
  */
9
10
  export type Environment = EnvironmentData & EnvironmentHelpers;
10
11
  export interface EnvironmentHelpers {
11
- /** Credentials for one app; `actorId` defaults to the app's default actor. */
12
+ /** Credentials for one app, acting as the user that `as` names, else as the app's default user. */
12
13
  connect(appName: string, options?: ConnectOptions): Promise<Credentials>;
14
+ /**
15
+ * Credentials for each app that lets the user that `as` names act. An app that
16
+ * does not have the user, or does not let the user sign in, adds its error to
17
+ * `errors`. Any other error throws.
18
+ */
19
+ connectAll(options: ConnectAllOptions): Promise<ConnectAllResult>;
20
+ /** One page of the users who can act in one app, the default user first. */
21
+ actors(appName: string, query?: ListActorsQuery): Promise<Page<AppUser>>;
13
22
  delete(options?: SignalOptions): Promise<Environment>;
14
23
  /** Reads the environment again. */
15
24
  refresh(): Promise<Environment>;
@@ -1,5 +1,7 @@
1
+ import type { AppUser } from '../models/app-user.js';
1
2
  import type { Environment as EnvironmentData } from '../models/environment.js';
2
3
  import type { ErrorCode } from '../models/error.js';
4
+ import type { Import } from '../models/import.js';
3
5
  import type { ImportProblem } from '../models/import-problem.js';
4
6
  import type { Snapshot } from '../models/snapshot.js';
5
7
  export interface ErrorDetails {
@@ -42,6 +44,37 @@ export declare class SnapshotFailedError extends StateMachinesError {
42
44
  readonly problems: readonly ImportProblem[];
43
45
  constructor(snapshot: Snapshot);
44
46
  }
47
+ /** An import that `snapshots.create` uploaded and its check left `invalid`, so the SDK created no snapshot. */
48
+ export declare class ImportInvalidError extends StateMachinesError {
49
+ readonly name = "ImportInvalidError";
50
+ readonly import: Import;
51
+ /** The first problems that the check found, errors before warnings. `import.problemCount` counts them all. */
52
+ readonly problems: readonly ImportProblem[];
53
+ constructor(invalid: Import);
54
+ }
55
+ /** The app has no user with the email, username or ID that the call sent as `as`. */
56
+ export declare class ActorNotFoundError extends StateMachinesError {
57
+ readonly appName: string;
58
+ /** The users who can act in the app that are nearest to `as`, nearest first. */
59
+ readonly nearest: readonly AppUser[];
60
+ readonly name = "ActorNotFoundError";
61
+ readonly code: 'actor_not_found';
62
+ constructor(error: StateMachinesError, appName: string,
63
+ /** The users who can act in the app that are nearest to `as`, nearest first. */
64
+ nearest: readonly AppUser[]);
65
+ }
66
+ /** The app has the user, and does not let the user sign in now, for the reason in `fields.as`. */
67
+ export declare class ActorCannotSignInError extends StateMachinesError {
68
+ readonly appName: string;
69
+ readonly name = "ActorCannotSignInError";
70
+ readonly code: 'actor_cannot_sign_in';
71
+ constructor(error: StateMachinesError, appName: string);
72
+ }
73
+ /**
74
+ * The typed error for an answer that refuses the user a credentials call
75
+ * names, else the error that any call fails with.
76
+ */
77
+ export declare function actorError(error: unknown, appName: string): StateMachinesError;
45
78
  /** The resource reached a status from which the awaited one needs a call of yours. */
46
79
  export declare class UnexpectedStatusError extends Error {
47
80
  readonly resource: EnvironmentData | Snapshot;
@@ -92,6 +92,59 @@ export class SnapshotFailedError extends StateMachinesError {
92
92
  this.problems = problems;
93
93
  }
94
94
  }
95
+ /** An import that `snapshots.create` uploaded and its check left `invalid`, so the SDK created no snapshot. */
96
+ export class ImportInvalidError extends StateMachinesError {
97
+ name = 'ImportInvalidError';
98
+ import;
99
+ /** The first problems that the check found, errors before warnings. `import.problemCount` counts them all. */
100
+ problems;
101
+ constructor(invalid) {
102
+ super({
103
+ ...noResponse,
104
+ message: `Import ${invalid.id} is invalid.${firstProblem(invalid.problems)}`,
105
+ });
106
+ this.import = invalid;
107
+ this.problems = invalid.problems;
108
+ }
109
+ }
110
+ /** The app has no user with the email, username or ID that the call sent as `as`. */
111
+ export class ActorNotFoundError extends StateMachinesError {
112
+ appName;
113
+ nearest;
114
+ name = 'ActorNotFoundError';
115
+ constructor(error, appName,
116
+ /** The users who can act in the app that are nearest to `as`, nearest first. */
117
+ nearest) {
118
+ super(error);
119
+ this.appName = appName;
120
+ this.nearest = nearest;
121
+ }
122
+ }
123
+ /** The app has the user, and does not let the user sign in now, for the reason in `fields.as`. */
124
+ export class ActorCannotSignInError extends StateMachinesError {
125
+ appName;
126
+ name = 'ActorCannotSignInError';
127
+ constructor(error, appName) {
128
+ super(error);
129
+ this.appName = appName;
130
+ }
131
+ }
132
+ /**
133
+ * The typed error for an answer that refuses the user a credentials call
134
+ * names, else the error that any call fails with.
135
+ */
136
+ export function actorError(error, appName) {
137
+ const failure = toStateMachinesError(error);
138
+ const body = error instanceof ErrorT ? error.error : null;
139
+ switch (body?.code) {
140
+ case 'actor_not_found':
141
+ return new ActorNotFoundError(failure, appName, body.nearest ?? []);
142
+ case 'actor_cannot_sign_in':
143
+ return new ActorCannotSignInError(failure, appName);
144
+ default:
145
+ return failure;
146
+ }
147
+ }
95
148
  /** The resource reached a status from which the awaited one needs a call of yours. */
96
149
  export class UnexpectedStatusError extends Error {
97
150
  resource;
@@ -0,0 +1,43 @@
1
+ /** An import as one object, which is its manifest with each app's records and content in it. */
2
+ export interface ImportData {
3
+ readonly format: 'statemachines.import/v1';
4
+ /** The import's name. */
5
+ readonly name: string;
6
+ /** By the app's name in the import, such as `salesforce`. */
7
+ readonly apps: Readonly<Record<string, ImportAppData>>;
8
+ }
9
+ /** One app of an import: its settings, its records and the files that its records name. */
10
+ export interface ImportAppData {
11
+ /** Defaults to the app's name in the import. */
12
+ readonly appId?: string;
13
+ /**
14
+ * What the load does with a record that cannot load. `refuse`, the default,
15
+ * fails the snapshot. `skipRecord` leaves the record out, with each record
16
+ * that references it.
17
+ */
18
+ readonly loadMode?: 'skipRecord' | 'refuse';
19
+ /** The users to act as, by email, username or ID. */
20
+ readonly actors?: readonly string[];
21
+ /** The objects that the load leaves out, and the fields that it leaves out by object. */
22
+ readonly skip?: {
23
+ readonly objects?: readonly string[];
24
+ readonly fields?: Readonly<Record<string, readonly string[]>>;
25
+ };
26
+ /** The records in the app's own JSON, by object, such as `Account`. */
27
+ readonly records?: Readonly<Record<string, readonly Readonly<Record<string, unknown>>[]>>;
28
+ /**
29
+ * The bytes of the files that the app's records name, by path inside the
30
+ * app's `content/` folder, such as Box's `file_version/41500000004`.
31
+ */
32
+ readonly content?: Readonly<Record<string, Uint8Array>>;
33
+ }
34
+ /**
35
+ * The zip file of `data` in the folder form. `statemachines.json` holds the
36
+ * manifest without each app's `records` and `content`. Each object's records
37
+ * go to `<app>/records/<Object>.jsonl`, one record per line, so line N of the
38
+ * file names the record at index N - 1. Each content file goes to
39
+ * `<app>/content/<path>`. Data in a shape that the folder form cannot hold
40
+ * throws `invalid_request`, with the path of each wrong field. The API checks
41
+ * the rest.
42
+ */
43
+ export declare function zipImport(data: ImportData): Uint8Array<ArrayBuffer>;
@@ -0,0 +1,88 @@
1
+ import { invalidInput } from './errors.js';
2
+ import { zipFiles } from './zip.js';
3
+ const PLAIN_OBJECT = 'Expected a plain object.';
4
+ const utf8 = new TextEncoder();
5
+ /**
6
+ * The zip file of `data` in the folder form. `statemachines.json` holds the
7
+ * manifest without each app's `records` and `content`. Each object's records
8
+ * go to `<app>/records/<Object>.jsonl`, one record per line, so line N of the
9
+ * file names the record at index N - 1. Each content file goes to
10
+ * `<app>/content/<path>`. Data in a shape that the folder form cannot hold
11
+ * throws `invalid_request`, with the path of each wrong field. The API checks
12
+ * the rest.
13
+ */
14
+ export function zipImport(data) {
15
+ const fields = shapeProblems(data);
16
+ if (Object.keys(fields).length > 0) {
17
+ throw invalidInput('The import data is invalid.', fields);
18
+ }
19
+ return zipFiles(folderFiles(data));
20
+ }
21
+ /** The fields of `data` that the folder form cannot hold, by dotted path. */
22
+ function shapeProblems(data) {
23
+ const fields = {};
24
+ const add = (path, message) => {
25
+ fields[path] = [...(fields[path] ?? []), message];
26
+ };
27
+ const entriesAt = (value, path) => {
28
+ if (isPlainObject(value)) {
29
+ return Object.entries(value);
30
+ }
31
+ add(path, PLAIN_OBJECT);
32
+ return [];
33
+ };
34
+ if (!isPlainObject(data)) {
35
+ add('import', PLAIN_OBJECT);
36
+ return fields;
37
+ }
38
+ const { apps } = data;
39
+ for (const [name, app] of entriesAt(apps, 'import.apps')) {
40
+ const at = `import.apps.${name}`;
41
+ if (!isPlainObject(app)) {
42
+ add(at, PLAIN_OBJECT);
43
+ continue;
44
+ }
45
+ const { records = {}, content = {} } = app;
46
+ for (const [object, list] of entriesAt(records, `${at}.records`)) {
47
+ if (!Array.isArray(list)) {
48
+ add(`${at}.records.${object}`, 'Expected an array.');
49
+ continue;
50
+ }
51
+ for (const [index, record] of list.entries()) {
52
+ if (!isPlainObject(record)) {
53
+ add(`${at}.records.${object}.${index}`, PLAIN_OBJECT);
54
+ }
55
+ }
56
+ }
57
+ for (const [path, bytes] of entriesAt(content, `${at}.content`)) {
58
+ if (!(bytes instanceof Uint8Array)) {
59
+ add(`${at}.content.${path}`, 'Expected a Uint8Array.');
60
+ }
61
+ }
62
+ }
63
+ return fields;
64
+ }
65
+ function folderFiles(data) {
66
+ const files = new Map();
67
+ const apps = {};
68
+ for (const [name, app] of Object.entries(data.apps)) {
69
+ const { records = {}, content = {}, ...settings } = app;
70
+ apps[name] = settings;
71
+ for (const [object, list] of Object.entries(records)) {
72
+ files.set(`${name}/records/${object}.jsonl`, utf8.encode(list.map((record) => `${JSON.stringify(record)}\n`).join('')));
73
+ }
74
+ for (const [path, bytes] of Object.entries(content)) {
75
+ files.set(`${name}/content/${path}`, bytes);
76
+ }
77
+ }
78
+ // The spread keeps any field that the manifest refuses, so the API names it.
79
+ files.set('statemachines.json', utf8.encode(`${JSON.stringify({ ...data, apps }, null, 2)}\n`));
80
+ return files;
81
+ }
82
+ function isPlainObject(value) {
83
+ if (typeof value !== 'object' || value === null) {
84
+ return false;
85
+ }
86
+ const prototype = Object.getPrototypeOf(value);
87
+ return prototype === Object.prototype || prototype === null;
88
+ }
@@ -1,8 +1,9 @@
1
- export type { Actor, App, AppEntry, AuditEvent, BodyPreview, CreateEnvironment, CreateEnvironmentApp, EnvironmentApp, EnvironmentFailure, EnvironmentFailureCode, EnvironmentStatus, ErrorCode, Import, ImportApp, ImportProblem, ImportStatus, Me, Permission, Principal, RequestDetail, RequestStats, RequestT as Request, Snapshot, SnapshotStatus, Version, Workspace, } from '../models/index.js';
2
- export type { ConnectOptions, CreateEnvironmentOptions, CreateSnapshotOptions, ListAuditEventsQuery, ListEnvironmentsQuery, ListImportsQuery, ListRequestsQuery, ListSnapshotsQuery, ListWorkspacesQuery, Page, PageQuery, RequestStatsQuery, SignalOptions, StateMachinesOptions, UploadImportOptions, } from './client.js';
1
+ export type { AbsentReason, AbsentRecord, Actor, App, AppEntry, AppUser, AuditEvent, BodyPreview, CreateEnvironment, CreateEnvironmentApp, EnvironmentApp, EnvironmentFailure, EnvironmentFailureCode, EnvironmentStatus, ErrorCode, FilledField, Import, ImportActor, ImportApp, ImportProblem, ImportStatus, KnownDifference, MadeId, MatchedRecord, Me, ObjectLoad, Permission, Principal, ProblemCounts, RecordSource, RequestDetail, RequestStats, RequestT as Request, Snapshot, SnapshotAppLoad, SnapshotAppLoadCounts, SnapshotListItem, SnapshotStatus, Version, Workspace, } from '../models/index.js';
2
+ export type { ConnectAllOptions, ConnectAllResult, ConnectOptions, CreateEnvironmentOptions, CreateSnapshotOptions, ListActorsQuery, ListAuditEventsQuery, ListEnvironmentsQuery, ListImportsQuery, ListRequestsQuery, ListSnapshotsQuery, ListWorkspacesQuery, Page, PageQuery, RequestStatsQuery, SignalOptions, StateMachinesOptions, UploadImportOptions, } from './client.js';
3
3
  export { StateMachines } from './client.js';
4
4
  export type { Credentials, McpServerCredentials, ServiceCredentials, } from './credentials.js';
5
5
  export type { Environment, EnvironmentHelpers } from './environment.js';
6
- export { EnvironmentFailedError, SnapshotFailedError, StateMachinesError, UnexpectedStatusError, WaitTimeoutError, } from './errors.js';
6
+ export { ActorCannotSignInError, ActorNotFoundError, EnvironmentFailedError, ImportInvalidError, SnapshotFailedError, StateMachinesError, UnexpectedStatusError, WaitTimeoutError, } from './errors.js';
7
+ export type { ImportAppData, ImportData } from './import-data.js';
7
8
  export type { WaitOptions } from './wait.js';
8
9
  export { parseEnvironmentYaml } from './yaml.js';
@@ -1,3 +1,3 @@
1
1
  export { StateMachines } from './client.js';
2
- export { EnvironmentFailedError, SnapshotFailedError, StateMachinesError, UnexpectedStatusError, WaitTimeoutError, } from './errors.js';
2
+ export { ActorCannotSignInError, ActorNotFoundError, EnvironmentFailedError, ImportInvalidError, SnapshotFailedError, StateMachinesError, UnexpectedStatusError, WaitTimeoutError, } from './errors.js';
3
3
  export { parseEnvironmentYaml } from './yaml.js';
@@ -0,0 +1 @@
1
+ export { zipFiles } from './zip.js';
@@ -0,0 +1 @@
1
+ export { zipFiles } from './zip.js';
@@ -0,0 +1,8 @@
1
+ /**
2
+ * A zip file of `files`, keyed by their paths, in the order of their paths.
3
+ * Each file is stored, with a UTF-8 name, the earliest MS-DOS time, and no
4
+ * extra field, so the same files always give the same bytes. It refuses what
5
+ * needs ZIP64. It needs no `node:zlib`, because the SDK imports no Node
6
+ * module and runs in Cloudflare Workers.
7
+ */
8
+ export declare function zipFiles(files: ReadonlyMap<string, Uint8Array>): Uint8Array<ArrayBuffer>;