@statelyai/sdk 0.5.1 → 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 CHANGED
@@ -27,10 +27,9 @@ npm install @statelyai/sdk
27
27
  The embed supports three common deployment models:
28
28
 
29
29
  - Hosted Stately: pass an API key to `createStatelyEmbed()`
30
- - Same-origin deployments: rely on the host application's session/cookie auth
31
30
  - Self-hosted deployments: configure auth in the editor server and omit `apiKey` when no token is required
32
31
 
33
- ### With Stately (default)
32
+ ### Hosted Stately
34
33
 
35
34
  An API key is required. To get one:
36
35
 
@@ -50,29 +49,19 @@ const embed = createStatelyEmbed({
50
49
  });
51
50
  ```
52
51
 
53
- ### Same-origin embed (cookie auth)
54
-
55
- When the embed host and the editor share a domain, you can omit `apiKey` and rely on the host application's auth/session layer:
56
-
57
- ```ts
58
- const embed = createStatelyEmbed({
59
- baseUrl: process.env.NEXT_PUBLIC_BETA_EDITOR_URL ?? window.location.origin,
60
- });
61
- ```
62
-
63
52
  ### Self-hosting
64
53
 
65
54
  When self-hosting the editor, authentication is enforced by the editor server, not by this npm package.
66
55
 
67
56
  The common environment variables are:
68
57
 
69
- | Variable | Purpose |
70
- | --- | --- |
71
- | `AUTH_PROVIDER` | Auth strategy used by the editor host |
58
+ | Variable | Purpose |
59
+ | --------------------------- | ----------------------------------------------------------------------- |
60
+ | `AUTH_PROVIDER` | Auth strategy used by the editor host |
72
61
  | `EDITOR_SYNC_AUTH_REQUIRED` | Set to `false` to disable API-key checks for editor-sync endpoints only |
73
- | `STATELY_API_KEY` | Server-side API key for Stately data fetching |
74
- | `STATELY_API_URL` | Stately API base URL override |
75
- | `NEXT_PUBLIC_BASE_URL` | Public-facing editor URL |
62
+ | `STATELY_API_KEY` | Server-side API key for Stately data fetching |
63
+ | `STATELY_API_URL` | Stately API base URL override |
64
+ | `NEXT_PUBLIC_BASE_URL` | Public-facing editor URL |
76
65
 
77
66
  For a fully self-contained deployment with no auth, omit `apiKey` in the SDK and configure the host/editor to allow unauthenticated access:
78
67
 
@@ -143,9 +132,13 @@ The SDK ships root exports for the most common entry points and helpers:
143
132
 
144
133
  ```ts
145
134
  import {
135
+ createStatelyApiClient,
136
+ createStatelyApiUrl,
146
137
  createStatelyClient,
147
138
  createStatelyEmbed,
148
139
  createStatelyInspector,
140
+ createS3AssetUploadAdapter,
141
+ createSupabaseAssetUploadAdapter,
149
142
  fromStudioMachine,
150
143
  graphToMachineConfig,
151
144
  graphToXStateTS,
@@ -159,11 +152,21 @@ It also supports narrower subpath imports:
159
152
  import { createStatelyClient } from '@statelyai/sdk/studio';
160
153
  import { createStatelyInspector } from '@statelyai/sdk/inspect';
161
154
  import { createStatelyEmbed } from '@statelyai/sdk/embed';
155
+ import {
156
+ createStatelyApiClient,
157
+ createStatelyApiUrl,
158
+ } from '@statelyai/sdk/api';
162
159
  import { fromStudioMachine, toStudioMachine } from '@statelyai/sdk/graph';
163
- import { planSync, pullSync } from '@statelyai/sdk/sync';
160
+ import { planSync, pullSync, pushSync } from '@statelyai/sdk/sync';
161
+ import {
162
+ createS3AssetUploadAdapter,
163
+ createSupabaseAssetUploadAdapter,
164
+ } from '@statelyai/sdk/assetStorage';
164
165
  import type { GraphPatch } from '@statelyai/sdk/patchTypes';
165
166
  ```
166
167
 
168
+ The root package also exports `getStatelyPragma()`, `findStatelyPragmaAttachments()`, and `upsertStatelyPragma()` for working with canonical source annotations such as `// @statelyai id=machine-123`.
169
+
167
170
  ## Studio API Client
168
171
 
169
172
  ```ts
@@ -173,21 +176,84 @@ const studio = createStatelyClient({
173
176
  apiKey: process.env.STATELY_API_KEY,
174
177
  });
175
178
 
179
+ const createdProject = await studio.projects.create({
180
+ name: 'My project',
181
+ visibility: 'Private',
182
+ });
176
183
  const project = await studio.projects.get('project-id');
184
+ const projects = await studio.projects.list();
185
+ const createdMachine = await studio.machines.create({
186
+ projectVersionId: createdProject.projectVersionId!,
187
+ definition: digraphDefinition,
188
+ xstateVersion: 5,
189
+ });
177
190
  const machine = await studio.machines.get('machine-id', { version: '42' });
178
191
  const extracted = await studio.code.extractMachines(sourceCode);
179
192
  ```
180
193
 
194
+ `studio.projects.list(...)`, `studio.projects.create(...)`, and `studio.machines.create(...)` use the documented Studio REST API. `studio.projects.ensure(...)` is a client-side helper that uses the documented list/create endpoints to reuse an existing connected project when the repo metadata matches.
195
+
181
196
  <!-- public methods of StudioClient from src/studio.ts -->
182
197
 
183
198
  Available client methods:
184
199
 
185
- | Method | Description |
186
- | --- | --- |
187
- | `studio.auth.verify(apiKey?)` | Verify an API key against the registry API |
188
- | `studio.projects.get(projectId)` | Fetch a project and its machines |
189
- | `studio.machines.get(machineId, { version? })` | Fetch a machine, optionally pinned to a version |
190
- | `studio.code.extractMachines(code, { apiKey? })` | Extract machine configs from source text |
200
+ | Method | Description |
201
+ | ----------------------------------------------------------------------- | ------------------------------------------------------------------------ |
202
+ | `studio.auth.verify(apiKey?)` | Verify an API key against the registry API |
203
+ | `studio.projects.list()` | List accessible projects, including connected repo metadata when present |
204
+ | `studio.projects.create({ name, visibility, description?, keywords? })` | Create a new project through the published REST API |
205
+ | `studio.projects.ensure({ name, visibility, repo?, ... })` | Reuse an existing connected project or create one through the REST API |
206
+ | `studio.projects.get(projectId)` | Fetch a project and its machines |
207
+ | `studio.machines.create({ projectVersionId, ... })` | Create a machine through the published REST API |
208
+ | `studio.machines.createMany({ projectVersionId, ... })` | Compatibility wrapper around `create()` that returns a one-item array |
209
+ | `studio.machines.get(machineId, { version? })` | Fetch a machine, optionally pinned to a version |
210
+ | `studio.code.extractMachines(code, { apiKey? })` | Extract machine configs from source text |
211
+
212
+ ## Sync Helpers
213
+
214
+ `pushSync()` complements `planSync()` and `pullSync()` for local-to-Studio flows. It resolves a local source file, ensures there is a target project, creates the remote machine, and writes `// @statelyai id=...` back into XState source files.
215
+
216
+ ```ts
217
+ import { pushSync } from '@statelyai/sdk/sync';
218
+
219
+ const result = await pushSync({
220
+ source: './src/machines/toggle.ts',
221
+ apiKey: process.env.STATELY_API_KEY,
222
+ project: {
223
+ visibility: 'Private',
224
+ repo: {
225
+ url: 'https://github.com/statelyai/viz',
226
+ owner: 'statelyai',
227
+ repo: 'viz',
228
+ branch: 'main',
229
+ treeSha: 'abc123',
230
+ },
231
+ },
232
+ });
233
+ ```
234
+
235
+ Projects can also check in a `statelyai.json` file to describe which local sources belong to a Studio project. The published schema lives at `@statelyai/sdk/statelyai.schema.json` and the canonical schema id is `https://stately.ai/schemas/statelyai.json`.
236
+
237
+ ```json
238
+ {
239
+ "$schema": "https://stately.ai/schemas/statelyai.json",
240
+ "version": "1.0.0",
241
+ "projectId": "project_123",
242
+ "studioUrl": "https://stately.ai",
243
+ "defaultXStateVersion": 5,
244
+ "sources": [
245
+ {
246
+ "include": ["src/**/*.ts", "src/**/*.tsx"],
247
+ "exclude": ["**/*.test.ts", "**/dist/**"],
248
+ "format": "xstate"
249
+ },
250
+ {
251
+ "include": ["docs/**/*.mmd"],
252
+ "format": "mermaid"
253
+ }
254
+ ]
255
+ }
256
+ ```
191
257
 
192
258
  ## Inspector
193
259
 
@@ -211,18 +277,18 @@ actor.start();
211
277
 
212
278
  Key options:
213
279
 
214
- | Option | Description |
215
- | --- | --- |
216
- | `actor` | Root actor to adopt and inspect automatically |
217
- | `url` | Devtools relay URL. Defaults to `ws://localhost:4242` |
218
- | `autoOpen` | Whether to ask the relay to open the inspector UI |
219
- | `sessionId` | Override the relay session id |
220
- | `name` | Display name shown to the inspector |
221
- | `serializeSnapshot` | Customize snapshot serialization before sending it over the wire |
222
- | `extractMachineConfig` | Customize how machine config is derived from an actor |
223
- | `selectedActorId` | Focus a specific actor first |
224
- | `panels`, `theme`, `readOnly`, `depth` | Initial inspector UI options |
225
- | `transport` | Inject an existing transport instead of opening a new WebSocket |
280
+ | Option | Description |
281
+ | -------------------------------------- | ---------------------------------------------------------------- |
282
+ | `actor` | Root actor to adopt and inspect automatically |
283
+ | `url` | Devtools relay URL. Defaults to `ws://localhost:4242` |
284
+ | `autoOpen` | Whether to ask the relay to open the inspector UI |
285
+ | `sessionId` | Override the relay session id |
286
+ | `name` | Display name shown to the inspector |
287
+ | `serializeSnapshot` | Customize snapshot serialization before sending it over the wire |
288
+ | `extractMachineConfig` | Customize how machine config is derived from an actor |
289
+ | `selectedActorId` | Focus a specific actor first |
290
+ | `panels`, `theme`, `readOnly`, `depth` | Initial inspector UI options |
291
+ | `transport` | Inject an existing transport instead of opening a new WebSocket |
226
292
 
227
293
  Key methods:
228
294
 
@@ -241,17 +307,17 @@ Creates an embed instance.
241
307
 
242
308
  <!-- public options of StatelyEmbedOptions from src/embed.ts -->
243
309
 
244
- | Option | Type | Description |
245
- | --- | --- | --- |
246
- | `baseUrl` | `string` | **Required.** Base URL of the Stately app |
247
- | `apiKey` | `string` | API key for hosted Stately deployments |
248
- | `origin` | `string` | Optional strict target origin for `postMessage`; defaults to permissive wildcard messaging for local/self-hosted testing |
249
- | `assets` | `AssetConfig` | Asset upload configuration |
250
- | `onReady` | `() => void` | Called when the embed is ready |
251
- | `onLoaded` | `(graph) => void` | Called when a machine is loaded |
252
- | `onChange` | `(graph, machineConfig) => void` | Called on every change |
253
- | `onSave` | `(graph, machineConfig) => void` | Called on save |
254
- | `onError` | `({ code, message }) => void` | Called when the embed reports an error |
310
+ | Option | Type | Description |
311
+ | ---------- | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
312
+ | `baseUrl` | `string` | **Required.** Base URL of the Stately app |
313
+ | `apiKey` | `string` | API key for hosted Stately deployments |
314
+ | `origin` | `string` | Optional strict target origin for `postMessage`; defaults to permissive wildcard messaging for local/self-hosted testing |
315
+ | `assets` | `AssetConfig` | Asset upload configuration |
316
+ | `onReady` | `() => void` | Called when the embed is ready |
317
+ | `onLoaded` | `(graph) => void` | Called when a machine is loaded |
318
+ | `onChange` | `(graph, machineConfig) => void` | Called on every change |
319
+ | `onSave` | `(graph, machineConfig) => void` | Called on save |
320
+ | `onError` | `({ code, message }) => void` | Called when the embed reports an error |
255
321
 
256
322
  ### Embed methods
257
323
 
@@ -295,20 +361,20 @@ embed.init({
295
361
 
296
362
  `comments` accepts:
297
363
 
298
- | Field | Type | Description |
299
- | --- | --- | --- |
300
- | `roomId` | `string` | **Required.** Liveblocks room identifier |
301
- | `publicApiKey` | `string` | Liveblocks public key |
302
- | `authEndpoint` | `string` | Custom Liveblocks auth endpoint |
303
- | `baseUrl` | `string` | Custom Liveblocks base URL for self-hosting |
304
- | `userId` | `string \| null` | Optional user identity metadata |
364
+ | Field | Type | Description |
365
+ | -------------- | ---------------- | ------------------------------------------- |
366
+ | `roomId` | `string` | **Required.** Liveblocks room identifier |
367
+ | `publicApiKey` | `string` | Liveblocks public key |
368
+ | `authEndpoint` | `string` | Custom Liveblocks auth endpoint |
369
+ | `baseUrl` | `string` | Custom Liveblocks base URL for self-hosting |
370
+ | `userId` | `string \| null` | Optional user identity metadata |
305
371
 
306
372
  `unsavedIndicator` accepts:
307
373
 
308
- | Field | Type | Description |
309
- | --- | --- | --- |
310
- | `enabled` | `boolean` | Show the persistent "Save to apply" pill |
311
- | `mode` | `'structural' \| 'all'` | Track only structural graph edits or all edits |
374
+ | Field | Type | Description |
375
+ | --------- | ----------------------- | ---------------------------------------------- |
376
+ | `enabled` | `boolean` | Show the persistent "Save to apply" pill |
377
+ | `mode` | `'structural' \| 'all'` | Track only structural graph edits or all edits |
312
378
 
313
379
  #### `embed.updateMachine(machine, format?)`
314
380
 
@@ -331,16 +397,18 @@ embed.setSettings({
331
397
 
332
398
  Available core settings:
333
399
 
334
- | Path | Type | Default |
335
- | --- | --- | --- |
336
- | `appearance.colorMode` | `'light' \| 'dark' \| 'system'` | `'dark'` |
337
- | `canvas.showGrid` | `boolean` | `true` |
338
- | `canvas.viewMode` | `'graph' \| 'list'` | `'graph'` |
339
- | `canvas.enableSnapLines` | `boolean` | `true` |
340
- | `canvas.dimUnselected` | `boolean` | `true` |
341
- | `validation.showValidations` | `boolean` | `true` |
342
- | `autolayout.autoEnabled` | `boolean` | `false` |
343
- | `developer.devMode` | `boolean` | `false` |
400
+ <!-- core setting paths from ../../src/settings.ts -->
401
+
402
+ | Path | Type | Default |
403
+ | ---------------------------- | ------------------------------- | --------- |
404
+ | `appearance.colorMode` | `'light' \| 'dark' \| 'system'` | `'dark'` |
405
+ | `canvas.showGrid` | `boolean` | `true` |
406
+ | `canvas.viewMode` | `'graph' \| 'list'` | `'graph'` |
407
+ | `canvas.enableSnapLines` | `boolean` | `true` |
408
+ | `canvas.dimUnselected` | `boolean` | `true` |
409
+ | `validation.showValidations` | `boolean` | `true` |
410
+ | `layout.autolayout` | `boolean` | `false` |
411
+ | `developer.devMode` | `boolean` | `false` |
344
412
 
345
413
  #### `embed.export(format, options?)`
346
414
 
@@ -349,13 +417,13 @@ Export the current machine. Returns a promise.
349
417
  ```ts
350
418
  const xstateCode = await embed.export('xstate', { version: 5 });
351
419
  const digraph = await embed.export('digraph');
352
- const rtk = await embed.export('rtk');
420
+ const redux = await embed.export('redux');
353
421
  const aslYaml = await embed.export('asl-yaml');
354
422
  ```
355
423
 
356
424
  <!-- supported export formats from ExportFormatMap in src/protocol.ts -->
357
425
 
358
- Supported formats: `xstate`, `json`, `xgraph`, `digraph`, `mermaid`, `rtk`, `zustand`, `asl-json`, `asl-yaml`, `scxml`
426
+ Supported formats: `xstate`, `json`, `xgraph`, `digraph`, `mermaid`, `redux`, `zustand`, `asl-json`, `asl-yaml`, `scxml`
359
427
 
360
428
  #### `embed.on(event, handler)` / `embed.off(event, handler)`
361
429
 
@@ -400,11 +468,56 @@ const embed = createStatelyEmbed({
400
468
  });
401
469
  ```
402
470
 
403
- | Option | Type | Description |
404
- | --- | --- | --- |
405
- | `onUploadRequest` | `(file: File, context: { stateNodeId: string }) => Promise<UploadResult>` | **Required.** Called when the editor needs to upload a file |
406
- | `accept` | `string[]` | Accepted MIME types. Supports wildcards like `image/*` |
407
- | `maxFileSize` | `number` | Max file size in bytes. Defaults to `10_485_760` |
471
+ For reusable integrations, pass an upload adapter instead of wiring the callback inline:
472
+
473
+ ```ts
474
+ import { createStatelyEmbed, createS3AssetUploadAdapter } from '@statelyai/sdk';
475
+
476
+ const adapter = createS3AssetUploadAdapter({
477
+ bucket: 'assets',
478
+ publicBaseUrl: 'https://cdn.example.com/assets',
479
+ async getUploadTarget({ key, contentType }) {
480
+ const response = await fetch('/api/assets/presign', {
481
+ method: 'POST',
482
+ headers: { 'Content-Type': 'application/json' },
483
+ body: JSON.stringify({ key, contentType }),
484
+ });
485
+ return response.json();
486
+ },
487
+ });
488
+
489
+ const embed = createStatelyEmbed({
490
+ baseUrl: 'https://stately.ai',
491
+ assets: { adapter },
492
+ });
493
+ ```
494
+
495
+ Supabase storage can use the same adapter contract:
496
+
497
+ ```ts
498
+ import {
499
+ createStatelyEmbed,
500
+ createSupabaseAssetUploadAdapter,
501
+ } from '@statelyai/sdk';
502
+
503
+ const adapter = createSupabaseAssetUploadAdapter({
504
+ client: supabaseClient,
505
+ bucket: 'assets',
506
+ projectVersionId,
507
+ });
508
+
509
+ const embed = createStatelyEmbed({
510
+ baseUrl: 'https://stately.ai',
511
+ assets: { adapter },
512
+ });
513
+ ```
514
+
515
+ | Option | Type | Description |
516
+ | ----------------- | ------------------------------------------------------------------------- | ----------------------------------------------------------- |
517
+ | `onUploadRequest` | `(file: File, context: { stateNodeId: string }) => Promise<UploadResult>` | Called when the editor needs to upload a file |
518
+ | `adapter` | `AssetUploadAdapter` | Provider-specific uploader, such as the S3 or Supabase adapter |
519
+ | `accept` | `string[]` | Accepted MIME types. Supports wildcards like `image/*` |
520
+ | `maxFileSize` | `number` | Max file size in bytes. Defaults to `10_485_760` |
408
521
 
409
522
  `UploadResult`:
410
523
 
@@ -446,6 +559,8 @@ const digraph = toStudioMachine(graph);
446
559
  Other exported helpers:
447
560
 
448
561
  - `studioMachineConverter` for reusable format conversion
562
+ - `createStatelyApiUrl()` and `createStatelyApiClient()` for building and
563
+ calling self-hosted Viz API routes from a shared API base URL
449
564
  - `serializeJS()`, `raw()`, and `RawCode` for emitting JavaScript source
450
565
  - `jsonSchemaToTSType()`, `contextSchemaToTSType()`, and `eventsSchemaToTSType()` for generating inline TypeScript types from JSON Schema
451
566
  - `GraphPatch` and `ActionLocation` types from `@statelyai/sdk/patchTypes`
@@ -489,6 +604,9 @@ Installing the package also exposes a `statelyai` binary:
489
604
  ```bash
490
605
  npx statelyai open ./checkout.machine.ts
491
606
 
607
+ statelyai init
608
+ statelyai login
609
+ statelyai auth status
492
610
  statelyai plan ./checkout.machine.ts machine-id
493
611
  statelyai diff ./checkout.machine.ts machine-id --fail-on-changes
494
612
  statelyai pull machine-id ./checkout.machine.ts
@@ -499,12 +617,16 @@ For one-off use, `npx statelyai ...` installs the small `statelyai` CLI package,
499
617
 
500
618
  Available commands:
501
619
 
502
- | Command | Description |
503
- | --- | --- |
504
- | `statelyai plan <source> <target>` | Print a semantic sync summary |
505
- | `statelyai diff <source> <target>` | Diff two locators and optionally fail on changes |
506
- | `statelyai pull <source> <target>` | Materialize a source into a local target file |
507
- | `statelyai open <file>` | Open a local file in a browser-backed visual editor session |
620
+ | Command | Description |
621
+ | ---------------------------------- | --------------------------------------------------------------------------- |
622
+ | `statelyai init` | Create or reuse a Studio project for the current directory and write `statelyai.json` |
623
+ | `statelyai login` | Store an API key for future CLI use |
624
+ | `statelyai logout` | Remove a stored API key |
625
+ | `statelyai auth status` | Show whether the CLI would use an environment variable or stored credential |
626
+ | `statelyai plan <source> <target>` | Print a semantic sync summary |
627
+ | `statelyai diff <source> <target>` | Diff two locators and optionally fail on changes |
628
+ | `statelyai pull <source> <target>` | Materialize a source into a local target file |
629
+ | `statelyai open <file>` | Open a local file in a browser-backed visual editor session |
508
630
 
509
631
  Common flags:
510
632
 
@@ -512,7 +634,9 @@ Common flags:
512
634
  - `--base-url` for self-hosted or non-default Stately deployments
513
635
  - `--fail-on-changes` to return a nonzero exit code when a diff is detected
514
636
 
515
- `statelyai open` also supports `--api-key`, `--editor-url`, `--host`, `--port`, `--no-open`, and `--debug`. It watches the local file on disk and sends source snapshots to `/api/editor-sync/*` endpoints, which return the text replacements to apply locally. Pass `--api-key` or set `STATELY_API_KEY` when the editor server requires auth. Self-hosted servers can disable editor-sync API-key checks with `EDITOR_SYNC_AUTH_REQUIRED=false`. The private source reconciliation engine is not bundled into the published CLI.
637
+ The CLI resolves credentials in this order: `--api-key`, then `STATELY_API_KEY`/`NEXT_PUBLIC_STATELY_API_KEY`, then the key stored by `statelyai login`. `login` stores the key in the OS credential store when available, with a private file fallback.
638
+
639
+ `statelyai open` also supports `--api-key`, `--editor-url`, `--host`, `--port`, `--no-open`, and `--debug`. It watches the local file on disk and sends source snapshots to `/api/editor-sync/*` endpoints, which return the text replacements to apply locally. When the source file contains `// @statelyai id=...` and an API key is available, the editor session also reuses the referenced remote machine layout while continuing to treat the local source as the semantic source of truth. Pass `--api-key`, set `STATELY_API_KEY`, or run `statelyai login` when the editor server requires auth. Self-hosted servers can disable editor-sync API-key checks with `EDITOR_SYNC_AUTH_REQUIRED=false`. The private source reconciliation engine is not bundled into the published CLI.
516
640
 
517
641
  ## Transport Helpers
518
642
 
package/dist/api.d.mts ADDED
@@ -0,0 +1,20 @@
1
+ //#region src/api.d.ts
2
+ interface StatelyApiUrlOptions {
3
+ baseUrl?: string | null;
4
+ }
5
+ interface StatelyApiClientOptions extends StatelyApiUrlOptions {
6
+ fetch?: typeof fetch;
7
+ }
8
+ declare class StatelyApiError extends Error {
9
+ readonly status: number;
10
+ readonly data: unknown;
11
+ constructor(message: string, status: number, data: unknown);
12
+ }
13
+ declare function createStatelyApiUrl(path: string, options?: StatelyApiUrlOptions): string;
14
+ declare function createStatelyApiClient(options?: StatelyApiClientOptions): {
15
+ url(path: string): string;
16
+ request: <T>(path: string, init?: RequestInit) => Promise<T>;
17
+ post<T>(path: string, body: unknown, init?: RequestInit): Promise<T>;
18
+ };
19
+ //#endregion
20
+ export { StatelyApiClientOptions, StatelyApiError, StatelyApiUrlOptions, createStatelyApiClient, createStatelyApiUrl };
package/dist/api.mjs ADDED
@@ -0,0 +1,56 @@
1
+ //#region src/api.ts
2
+ var StatelyApiError = class extends Error {
3
+ status;
4
+ data;
5
+ constructor(message, status, data) {
6
+ super(message);
7
+ this.name = "StatelyApiError";
8
+ this.status = status;
9
+ this.data = data;
10
+ }
11
+ };
12
+ function getFetch(fetchImpl) {
13
+ const resolvedFetch = fetchImpl ?? globalThis.fetch;
14
+ if (!resolvedFetch) throw new Error("No fetch implementation available. Pass one via createStatelyApiClient({ fetch }).");
15
+ return resolvedFetch;
16
+ }
17
+ function getErrorMessage(data, status) {
18
+ if (typeof data === "object" && data !== null && "error" in data && typeof data.error === "string") return data.error;
19
+ return `HTTP ${status}`;
20
+ }
21
+ async function parseJson(response) {
22
+ if (!response.headers.get("content-type")?.includes("application/json")) return null;
23
+ return response.json().catch(() => null);
24
+ }
25
+ function createStatelyApiUrl(path, options) {
26
+ return `${(options?.baseUrl ?? "/api").replace(/\/+$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
27
+ }
28
+ function createStatelyApiClient(options = {}) {
29
+ const fetchImpl = getFetch(options.fetch);
30
+ async function request(path, init) {
31
+ const response = await fetchImpl(createStatelyApiUrl(path, options), init);
32
+ const data = await parseJson(response);
33
+ if (!response.ok) throw new StatelyApiError(getErrorMessage(data, response.status), response.status, data);
34
+ return data;
35
+ }
36
+ return {
37
+ url(path) {
38
+ return createStatelyApiUrl(path, options);
39
+ },
40
+ request,
41
+ post(path, body, init) {
42
+ return request(path, {
43
+ ...init,
44
+ method: init?.method ?? "POST",
45
+ headers: {
46
+ "content-type": "application/json",
47
+ ...init?.headers
48
+ },
49
+ body: JSON.stringify(body)
50
+ });
51
+ }
52
+ };
53
+ }
54
+
55
+ //#endregion
56
+ export { StatelyApiError, createStatelyApiClient, createStatelyApiUrl };
@@ -0,0 +1,73 @@
1
+ import { m as UploadResult } from "./protocol-CDoCcaIP.mjs";
2
+
3
+ //#region src/assetStorage.d.ts
4
+ interface AssetUploadContext {
5
+ stateNodeId: string;
6
+ }
7
+ interface AssetUploadRequest extends AssetUploadContext {
8
+ file: File;
9
+ }
10
+ interface AssetUploadAdapter {
11
+ upload(request: AssetUploadRequest): Promise<UploadResult>;
12
+ accept?: string[];
13
+ maxFileSize?: number;
14
+ }
15
+ type AssetObjectKeyFactory = (request: AssetUploadRequest) => string | Promise<string>;
16
+ interface S3UploadTarget {
17
+ uploadUrl: string;
18
+ publicUrl?: string;
19
+ method?: 'PUT' | 'POST';
20
+ headers?: Record<string, string>;
21
+ fields?: Record<string, string>;
22
+ }
23
+ interface CreateS3AssetUploadAdapterOptions {
24
+ bucket?: string;
25
+ publicBaseUrl?: string;
26
+ accept?: string[];
27
+ maxFileSize?: number;
28
+ key?: AssetObjectKeyFactory;
29
+ getUploadTarget: (request: AssetUploadRequest & {
30
+ key: string;
31
+ contentType: string;
32
+ bucket?: string;
33
+ }) => Promise<S3UploadTarget>;
34
+ }
35
+ interface SupabaseStorageBucket {
36
+ upload(path: string, file: File, options?: {
37
+ cacheControl?: string;
38
+ contentType?: string;
39
+ upsert?: boolean;
40
+ }): Promise<{
41
+ data: {
42
+ path: string;
43
+ } | null;
44
+ error: Error | {
45
+ message: string;
46
+ } | null;
47
+ }>;
48
+ getPublicUrl?(path: string): {
49
+ data: {
50
+ publicUrl: string;
51
+ };
52
+ };
53
+ }
54
+ interface SupabaseStorageClient {
55
+ storage: {
56
+ from(bucket: string): SupabaseStorageBucket;
57
+ };
58
+ }
59
+ interface CreateSupabaseAssetUploadAdapterOptions {
60
+ client: SupabaseStorageClient;
61
+ bucket?: string;
62
+ publicBaseUrl?: string;
63
+ projectVersionId?: string;
64
+ accept?: string[];
65
+ maxFileSize?: number;
66
+ cacheControl?: string;
67
+ upsert?: boolean;
68
+ key?: AssetObjectKeyFactory;
69
+ }
70
+ declare function createS3AssetUploadAdapter(options: CreateS3AssetUploadAdapterOptions): AssetUploadAdapter;
71
+ declare function createSupabaseAssetUploadAdapter(options: CreateSupabaseAssetUploadAdapterOptions): AssetUploadAdapter;
72
+ //#endregion
73
+ export { AssetObjectKeyFactory, AssetUploadAdapter, AssetUploadContext, AssetUploadRequest, CreateS3AssetUploadAdapterOptions, CreateSupabaseAssetUploadAdapterOptions, S3UploadTarget, SupabaseStorageClient, createS3AssetUploadAdapter, createSupabaseAssetUploadAdapter };