@roughapp/feature 0.2.1 → 0.4.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/CHANGELOG.md CHANGED
@@ -5,6 +5,66 @@ All notable changes to `@roughapp/feature`.
5
5
  The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
6
6
  This package is pre-1.0, so a minor version bump can contain breaking changes.
7
7
 
8
+ ## 0.3.0 - 2026-08-10
9
+
10
+ **This release has breaking API changes.** Rough now uses an explicit client for
11
+ each project instead of global initialization. Apps can safely show features
12
+ from multiple Rough projects at the same time, and each client has a clear,
13
+ awaitable lifecycle.
14
+
15
+ ### Added
16
+
17
+ - **`createRoughClient({ projectId, baseUrl?, fetchUserToken })`** creates and
18
+ starts a client for one project. Keep the client for as long as your app needs
19
+ that project, then call `await client.destroy()`.
20
+ - **`whenRoughClientReady({ client })`** lets you wait for startup or handle a
21
+ startup error.
22
+ - **`openRoughCreate({ target })`** lets you attach the create modal inside the
23
+ element that scopes your Rough theme. It defaults to `document.body`.
24
+
25
+ ### Changed
26
+
27
+ - **All stateful functions and components now take a client.** Pass `client` and
28
+ `surface` to `getRoughFeatures()`, `openRoughCreate()`, `<rough-surface>`,
29
+ `<rough-feature>`, `<rough-edit-button>` and the modal elements.
30
+ - **Cleanup methods are asynchronous and safe to call more than once.** Await
31
+ `client.destroy()`, `subscription.unsubscribe()` and `modal.close()` when you
32
+ need to know that cleanup has finished.
33
+ - **Create one client and share it for each signed-in person and project.** A
34
+ second client for the same `baseUrl`, `projectId` and person fails with
35
+ `RoughReplicacheIdentityConflictError`. Clients for different projects or
36
+ different signed-in people can run together.
37
+ - **`openRoughCreate()` no longer requires a mounted Rough component.** You can
38
+ open it directly with a client and surface.
39
+
40
+ ### Removed
41
+
42
+ - **`initRough()` has been removed.** There is no default or global client.
43
+ - **`defineSurface()` has been replaced by `defineRoughSurface()`.** Rename
44
+ `toolList` to `tools` when updating your surface definitions.
45
+ - **`registerSurfaceEntry` has been removed.** You no longer need to register a
46
+ surface before using it.
47
+
48
+ ### Migrating
49
+
50
+ ```ts
51
+ // Before
52
+ initRough({ projectId, fetchUserToken })
53
+ const surface = defineSurface({ key, name, description, toolList })
54
+ const unsubscribe = getRoughFeatures(surface, onFeatures)
55
+ openRoughCreate(surface, { projectId })
56
+
57
+ // After
58
+ const client = createRoughClient({ projectId, fetchUserToken })
59
+ const surface = defineRoughSurface({ key, name, description, tools })
60
+ const subscription = getRoughFeatures({ client, surface, onFeatures })
61
+ const modal = await openRoughCreate({ client, surface })
62
+
63
+ await modal.close()
64
+ await subscription.unsubscribe()
65
+ await client.destroy()
66
+ ```
67
+
8
68
  ## 0.2.1 - 2026-08-05
9
69
 
10
70
  Add `CHANGELOG.md` to the published package.
package/README.md CHANGED
@@ -10,16 +10,14 @@ of custom elements (including `<rough-surface>`).
10
10
  ## Install
11
11
 
12
12
  ```bash
13
- pnpm add @roughapp/feature
13
+ pnpm add @roughapp/feature zod
14
14
  ```
15
15
 
16
16
  This package targets **npm + a modern bundler** (Vite, Webpack, Rspack, …). It
17
17
  is ESM-only and does not support direct `<script>`/CDN usage in this release.
18
18
 
19
- `svelte`, `zod`, `capnweb`, `@andypf/json-viewer`, and
20
- `@stayradiated/error-boundary` are installed automatically as runtime
21
- dependencies — you do not need to add them yourself, though you can import `zod`
22
- directly (see below).
19
+ Install `zod` directly because your tool definitions import it. The package
20
+ installs its other runtime dependencies automatically.
23
21
 
24
22
  ## Import the stylesheet
25
23
 
@@ -40,14 +38,19 @@ A surface describes a place in your product where Rough features appear, plus
40
38
  the tools the feature can call. Import `z` from `zod` directly for tool schemas:
41
39
 
42
40
  ```ts
43
- import { defineSurface, Query, Mutation, Subscription } from '@roughapp/feature'
41
+ import {
42
+ defineRoughSurface,
43
+ Query,
44
+ Mutation,
45
+ Subscription,
46
+ } from '@roughapp/feature'
44
47
  import { z } from 'zod'
45
48
 
46
- export const inboxSurface = defineSurface({
49
+ export const inboxSurface = defineRoughSurface({
47
50
  key: 'inbox',
48
51
  name: 'Inbox',
49
52
  description: 'The main message inbox.',
50
- toolList: [
53
+ tools: [
51
54
  new Query({
52
55
  id: 'listMessages',
53
56
  name: 'List Messages',
@@ -60,7 +63,8 @@ export const inboxSurface = defineSurface({
60
63
  return []
61
64
  },
62
65
  }),
63
- // Mutation and Subscription take the same options shape.
66
+ // Mutation uses the same fields. A Subscription implementation receives
67
+ // a callback before the input.
64
68
  ],
65
69
  })
66
70
  ```
@@ -68,65 +72,137 @@ export const inboxSurface = defineSurface({
68
72
  `Query`, `Mutation`, and `Subscription` are re-exported from
69
73
  `@roughapp/bridge` for convenience.
70
74
 
71
- ### Initialize the SDK
75
+ `defineRoughSurface()` validates and freezes the surface and its tools array.
76
+ The definition holds no client, project id or connection state, so you can hand
77
+ the same value to clients for two different projects at once.
78
+
79
+ ### Create a client
80
+
81
+ `createRoughClient()` returns synchronously and immediately starts that
82
+ project's authentication, local database and first sync. You own the client
83
+ until you destroy it.
72
84
 
73
85
  ```ts
74
- import { initRough } from '@roughapp/feature'
86
+ import { createRoughClient } from '@roughapp/feature'
75
87
 
76
- initRough({
88
+ const client = createRoughClient({
77
89
  projectId: 'proj_123',
78
90
  fetchUserToken: async () => myAppSession.getRoughToken(),
79
91
  // baseUrl is optional; defaults to the Rough production API.
80
92
  })
81
93
  ```
82
94
 
95
+ Create the client at whatever owns the project in your app: a route, a provider
96
+ component, a page controller. Share that one client with everything below it
97
+ rather than creating a second. Within one JavaScript realm, create only one live
98
+ client for each `<baseUrl, projectId, personId>` identity. If you create another,
99
+ its startup fails with `RoughReplicacheIdentityConflictError`.
100
+
101
+ ### Destroy it when you are done
102
+
103
+ ```ts
104
+ await client.destroy()
105
+ ```
106
+
107
+ `destroy()` is the only lifecycle method, and it works everywhere. It is
108
+ idempotent, returns the same promise every time, closes every subscription and
109
+ modal the client still owns, and does not resolve until all of that has
110
+ finished. A framework unmount hook may use `void client.destroy()`; tests and
111
+ controlled route transitions should await it.
112
+
113
+ The client implements no disposal protocol. Teardown here is genuinely
114
+ asynchronous, and there is one way to ask for it.
115
+
116
+ Startup runs in the background. If you want to observe it:
117
+
118
+ ```ts
119
+ import { whenRoughClientReady } from '@roughapp/feature'
120
+
121
+ await whenRoughClientReady({ client })
122
+ ```
123
+
124
+ A client that fails startup keeps that error and replays it from every later
125
+ operation. It is not restarted; destroy it and create a new one.
126
+
83
127
  ### Render a surface
84
128
 
85
129
  Use the `<rough-surface>` custom element, or the `RoughSurface` component
86
- export. Set the `surface` property to a `defineSurface(...)` result:
130
+ export. Set both the client and the surface:
87
131
 
88
132
  ```ts
89
133
  import '@roughapp/feature'
90
134
 
91
135
  const el = document.createElement('rough-surface')
136
+ el.client = client
92
137
  el.surface = inboxSurface
93
138
  document.querySelector('#rough-slot')?.append(el)
94
139
  ```
95
140
 
96
141
  ### List features and open the create flow
97
142
 
143
+ Operations are direct exports and take the client in their options. Neither
144
+ requires anything to have mounted first.
145
+
98
146
  ```ts
99
147
  import { getRoughFeatures, openRoughCreate } from '@roughapp/feature'
100
148
 
101
149
  // Subscribe to the published features for a surface.
102
- const unsubscribe = getRoughFeatures(inboxSurface, (features) => {
103
- console.log(features)
150
+ const subscription = getRoughFeatures({
151
+ client,
152
+ surface: inboxSurface,
153
+ onFeatures: (features) => {
154
+ console.log(features)
155
+ },
156
+ onError: (error) => {
157
+ console.error(error)
158
+ },
104
159
  })
105
160
 
106
- // Open the "create a feature" modal for a surface.
107
- openRoughCreate(inboxSurface, { projectId: 'proj_123' })
161
+ // Optional: wait for the first feature batch.
162
+ await subscription.ready
163
+
164
+ // Open the "create a feature" modal.
165
+ const modal = await openRoughCreate({
166
+ client,
167
+ surface: inboxSurface,
168
+ // Where the modal attaches. Defaults to document.body. Pass the element that
169
+ // scopes your Rough theme if you scope it to a subtree.
170
+ target: document.querySelector('#rough-root') ?? undefined,
171
+ })
172
+
173
+ await modal.close()
174
+ await subscription.unsubscribe()
108
175
  ```
109
176
 
177
+ Every cleanup handle returns a promise, is safe to call twice, and returns the
178
+ same promise on the second call.
179
+
110
180
  ## Exports
111
181
 
112
182
  Recommended, stable-ish customer API:
113
183
 
114
- - `initRough`, `defineSurface` (+ `SurfaceDefinition` type)
115
- - `getRoughFeatures`, `openRoughCreate`
184
+ - `createRoughClient`, `whenRoughClientReady` (+ `RoughClient`,
185
+ `RoughClientOptions` types)
186
+ - `defineRoughSurface` (+ `RoughSurfaceDefinition` type)
187
+ - `getRoughFeatures` (+ `GetRoughFeaturesOptions`,
188
+ `RoughFeatureSubscription` types)
189
+ - `openRoughCreate` (+ `OpenRoughCreateOptions`, `RoughModalHandle` types)
116
190
  - `RoughSurface` / `<rough-surface>`
117
191
  - `Query`, `Mutation`, `Subscription` (re-exported from `@roughapp/bridge`)
192
+ - Errors worth branching on: `RoughClientDestroyedError`,
193
+ `RoughReplicacheIdentityConflictError`, `RoughSurfaceContractConflictError`,
194
+ `RoughClientDestroyError`, `RoughInvalidClientError`
118
195
 
119
- Advanced / incidental exports — these exist but are **not** intended as stable
120
- customer dependencies during the pre-1.0 series:
196
+ Advanced / incidental exports are **not** intended as stable customer
197
+ dependencies during the pre-1.0 series:
121
198
 
122
199
  - Custom-element components: `RoughCreateModal` (`<rough-create-modal>`),
123
200
  `RoughEditButton` (`<rough-edit-button>`), `RoughFeature` (`<rough-feature>`)
124
201
  (the `<rough-edit-modal>` element registers transitively).
125
202
  - UI building blocks: `PrimaryButton`, `SecondaryButton`, `ResizeHandle`,
126
203
  `SpriteBuildMenu`, `SpriteFrame`.
127
- - `registerSurfaceEntry`.
128
- - Types: `Sprite`, `SpriteBuild`, `JsonValue`, `SpriteFrameDatastore`,
129
- `SpriteFrameDatastoreContext`.
204
+ - Types: `Sprite`, `SpriteBuild`, `JsonValue`, `RoughCleanup`,
205
+ `FetchUserTokenFn`, `SpriteFrameDatastore`, `SpriteFrameDatastoreContext`.
130
206
 
131
207
  ## License
132
208
 
package/index.d.ts CHANGED
@@ -284,13 +284,22 @@ type SpriteId = string & { __brand: 'public.sprite' };
284
284
  /** Identifier type for public.sprite_build */
285
285
  type SpriteBuildId = string & { __brand: 'public.sprite_build' };
286
286
 
287
+ declare global {
288
+ var __TANSTACK_EVENT_TARGET__: EventTarget | null;
289
+ }
290
+
291
+ declare global {
292
+ var __TANSTACK_AI_DEVTOOLS_RUNTIME_ID__: string | undefined;
293
+ }
294
+
287
295
  type SpriteBuild = {
288
296
  id: SpriteBuildId;
289
297
  spriteId: SpriteId;
290
298
  parentSpriteBuildId: SpriteBuildId | null;
291
299
  createdByPersonId: PersonId;
292
300
  prompt: string;
293
- status: 'PENDING' | 'IN_PROGRESS' | 'READY' | 'ERROR';
301
+ status: 'PENDING' | 'IN_PROGRESS' | 'READY' | 'ERROR' | 'CANCELED';
302
+ cancelRequestedAt: number | null;
294
303
  artifactUrl: string | null;
295
304
  sourceUrl: string | null;
296
305
  startedAt: number | null;
@@ -307,35 +316,167 @@ type Sprite = {
307
316
  publishedSpriteBuildId: SpriteBuildId | null;
308
317
  };
309
318
 
310
- type SurfaceDefinition = {
311
- key: string;
319
+ /**
320
+ * An immutable, project-independent surface contract.
321
+ *
322
+ * A definition holds no client, project id, server surface id, registration
323
+ * state, subscription, or lifecycle hook. That is what lets the same value be
324
+ * handed to two clients for two different projects at once: each resolves it
325
+ * against its own project and caches the canonical id privately.
326
+ */
327
+ type RoughSurfaceDefinition<TKey extends string = string, TTools extends readonly AnyTool[] = readonly AnyTool[]> = Readonly<{
328
+ key: TKey;
312
329
  name: string;
313
330
  description: string;
314
- toolList: readonly AnyTool[];
331
+ tools: TTools;
332
+ }>;
333
+ type DefineRoughSurfaceOptions<TKey extends string, TTools extends readonly AnyTool[]> = {
334
+ key: TKey;
335
+ name: string;
336
+ description: string;
337
+ tools: TTools;
315
338
  };
316
- declare const defineSurface: (config: SurfaceDefinition) => SurfaceDefinition;
317
-
318
- declare const getRoughFeatures: (surface: SurfaceDefinition, callback: (features: Sprite[]) => void) => (() => void);
339
+ declare const defineRoughSurface: <const TKey extends string, const TTools extends readonly AnyTool[]>(options: DefineRoughSurfaceOptions<TKey, TTools>) => RoughSurfaceDefinition<TKey, TTools>;
319
340
 
320
341
  type FetchUserTokenFn = () => string | Promise<string>;
321
342
 
322
- type SurfaceEntry = {
323
- surfaceId: SurfaceId;
324
- toolList: readonly AnyTool[];
325
- };
326
- declare const registerSurfaceEntry: (key: string, entry: SurfaceEntry) => (() => void);
327
-
328
- type InitRoughOptions = {
329
- baseUrl?: string;
343
+ type RoughClientOptions = {
330
344
  projectId: string;
345
+ baseUrl?: string;
331
346
  fetchUserToken: FetchUserTokenFn;
332
347
  };
333
- declare const initRough: (options: InitRoughOptions) => void;
348
+ /**
349
+ * A handle to one project's live Rough runtime.
350
+ *
351
+ * The client is an opaque capability: it exposes identity and lifecycle, not
352
+ * behavior. Behavior lives in the package's function exports, which take the
353
+ * client in their options.
354
+ */
355
+ type RoughClient = {
356
+ readonly projectId: string;
357
+ destroy: () => Promise<void>;
358
+ };
359
+ /**
360
+ * Creates and immediately starts a client for one Rough project.
361
+ *
362
+ * Returns synchronously so a framework provider can own the value in the same
363
+ * tick it renders, and so a client whose auth or Replicache startup is still
364
+ * pending can still be destroyed. Startup runs in the background; observe it
365
+ * with `whenRoughClientReady({ client })` if you need to.
366
+ *
367
+ * The host owns the result until it calls `client.destroy()`. There is no
368
+ * release, restart, or reuse: a failed client is destroyed and replaced.
369
+ */
370
+ declare const createRoughClient: (options: RoughClientOptions) => RoughClient;
371
+ /**
372
+ * Awaits the client's eager startup.
373
+ *
374
+ * Rejects with the retained startup error if it failed. Operations do this
375
+ * internally, so hosts only need it when they want to show startup state or
376
+ * when a test needs a deterministic point to await.
377
+ */
378
+ declare const whenRoughClientReady: (options: {
379
+ client: RoughClient;
380
+ }) => Promise<void>;
381
+
382
+ /**
383
+ * Errors that hosts are expected to branch on.
384
+ *
385
+ * These are exported from the package root so a host can distinguish "you used
386
+ * a client you already destroyed" (a programming error) from "another client
387
+ * already owns this local database" (a coordination error the host fixes by
388
+ * sharing one client).
389
+ */
390
+ /** Thrown when an operation is started on a destroying or destroyed client. */
391
+ declare class RoughClientDestroyedError extends Error {
392
+ readonly name = "RoughClientDestroyedError";
393
+ constructor(message?: string);
394
+ }
395
+ /**
396
+ * Thrown during startup when another live client in this JavaScript realm
397
+ * already owns the `<baseUrl, projectId, personId>` Replicache identity.
398
+ */
399
+ declare class RoughReplicacheIdentityConflictError extends Error {
400
+ readonly name = "RoughReplicacheIdentityConflictError";
401
+ readonly replicacheName: string;
402
+ constructor(options: {
403
+ replicacheName: string;
404
+ });
405
+ }
406
+ /**
407
+ * Thrown when two concurrent operations disagree about the serialized contract
408
+ * of one surface key on the same client.
409
+ */
410
+ declare class RoughSurfaceContractConflictError extends Error {
411
+ readonly name = "RoughSurfaceContractConflictError";
412
+ readonly surfaceKey: string;
413
+ constructor(options: {
414
+ surfaceKey: string;
415
+ });
416
+ }
417
+ /**
418
+ * Rejection value of `client.destroy()` when at least one cleanup stage failed.
419
+ *
420
+ * `destroy()` always attempts every stage, so this is reported only after all
421
+ * of them have settled. `errors` holds one entry per failed stage.
422
+ */
423
+ declare class RoughClientDestroyError extends Error {
424
+ readonly name = "RoughClientDestroyError";
425
+ readonly errors: readonly Error[];
426
+ constructor(options: {
427
+ errors: readonly Error[];
428
+ });
429
+ }
430
+ /** Thrown when a value that is not a Rough client is passed as `client`. */
431
+ declare class RoughInvalidClientError extends Error {
432
+ readonly name = "RoughInvalidClientError";
433
+ constructor(message?: string);
434
+ }
435
+
436
+ /**
437
+ * Every cleanup handle in the public API has this shape.
438
+ *
439
+ * It is a promise rather than `void` on purpose. Un-awaitable teardown is what
440
+ * lets Replicache closes, store watches, and mounted modals outlive the thing
441
+ * that owned them, which shows up as work still running during a test
442
+ * environment teardown long after the assertions passed. Calling a cleanup
443
+ * twice is always safe: the second call returns the first call's promise.
444
+ */
445
+ type RoughCleanup = () => Promise<void>;
446
+
447
+ type GetRoughFeaturesOptions = {
448
+ client: RoughClient;
449
+ surface: RoughSurfaceDefinition;
450
+ onFeatures: (features: Sprite[]) => void;
451
+ onError?: (error: Error) => void;
452
+ signal?: AbortSignal;
453
+ };
454
+ type RoughFeatureSubscription = {
455
+ /**
456
+ * Resolves after the first feature batch is published. Rejects if startup or
457
+ * surface resolution failed.
458
+ */
459
+ readonly ready: Promise<void>;
460
+ unsubscribe: RoughCleanup;
461
+ };
462
+ /** Subscribes to published features for a surface. */
463
+ declare const getRoughFeatures: (options: GetRoughFeaturesOptions) => RoughFeatureSubscription;
334
464
 
335
465
  type OpenRoughCreateOptions = {
336
- projectId?: string;
466
+ client: RoughClient;
467
+ surface: RoughSurfaceDefinition;
468
+ /** Portal target. Use when Rough theme variables are scoped below document.body. */
469
+ target?: HTMLElement;
470
+ signal?: AbortSignal;
471
+ };
472
+ type RoughModalHandle = {
473
+ close: RoughCleanup;
337
474
  };
338
- declare const openRoughCreate: (surface: SurfaceDefinition, options?: OpenRoughCreateOptions) => void;
475
+ /**
476
+ * Opens the Feature Builder for a surface. Resolves the surface itself, so no
477
+ * `<RoughSurface>` need be mounted first.
478
+ */
479
+ declare const openRoughCreate: (options: OpenRoughCreateOptions) => Promise<RoughModalHandle>;
339
480
 
340
481
  type Props$9 = {
341
482
  children?: Snippet;
@@ -377,18 +518,21 @@ declare const ResizeHandle: svelte.Component<Props$8, {}, "">;
377
518
  type ResizeHandle = ReturnType<typeof ResizeHandle>;
378
519
 
379
520
  type Props$7 = {
380
- toolList: readonly AnyTool[];
521
+ client: RoughClient;
522
+ surface: RoughSurfaceDefinition;
381
523
  surfaceId: SurfaceId;
382
- projectId?: string;
524
+ /** Portal target; use when Rough theme variables are scoped to a subtree. */
525
+ portalTarget?: HTMLElement;
383
526
  onclose?: () => void;
384
527
  };
385
528
  declare const RoughCreateModal: svelte.Component<Props$7, {}, "">;
386
529
  type RoughCreateModal = ReturnType<typeof RoughCreateModal>;
387
530
 
388
531
  type Props$6 = {
389
- toolList: readonly AnyTool[];
532
+ client: RoughClient;
533
+ surface: RoughSurfaceDefinition;
534
+ spriteId: SpriteId;
390
535
  label?: string;
391
- spriteId: string;
392
536
  };
393
537
  declare const RoughEditButton: svelte.Component<Props$6, {}, "">;
394
538
  type RoughEditButton = ReturnType<typeof RoughEditButton>;
@@ -407,16 +551,18 @@ type SpriteFrameDatastoreContext = {
407
551
  };
408
552
 
409
553
  type Props$5 = {
554
+ client: RoughClient;
555
+ surface: RoughSurfaceDefinition;
410
556
  featureId: SpriteId;
411
557
  buildId: SpriteBuildId;
412
- surfaceKey: string;
413
558
  datastore?: SpriteFrameDatastore;
414
559
  };
415
560
  declare const RoughFeature: svelte.Component<Props$5, {}, "">;
416
561
  type RoughFeature = ReturnType<typeof RoughFeature>;
417
562
 
418
563
  type Props$4 = {
419
- surface: SurfaceDefinition;
564
+ client: RoughClient;
565
+ surface: RoughSurfaceDefinition;
420
566
  getDatastore?: (context: SpriteFrameDatastoreContext) => SpriteFrameDatastore | undefined;
421
567
  };
422
568
  declare const RoughSurface: svelte.Component<Props$4, {}, "">;
@@ -440,16 +586,16 @@ declare const SecondaryButton: svelte.Component<Props$3, {}, "">;
440
586
  type SecondaryButton = ReturnType<typeof SecondaryButton>;
441
587
 
442
588
  type Props$2 = {
589
+ client: RoughClient;
443
590
  surfaceId: SurfaceId;
444
591
  onselect?: (sprite: Sprite, spriteBuild: SpriteBuild) => Promise<void> | void;
445
592
  };
446
593
  declare const SpriteBuildMenu: svelte.Component<Props$2, {}, "">;
447
594
  type SpriteBuildMenu = ReturnType<typeof SpriteBuildMenu>;
448
595
 
449
- type Props$1 = {
596
+ type BaseProps = {
450
597
  spriteId: string;
451
598
  spriteBuildId: SpriteBuildId;
452
- artifactUrl?: string;
453
599
  toolList: readonly AnyTool[];
454
600
  datastore?: SpriteFrameDatastore;
455
601
  isMock?: boolean;
@@ -457,12 +603,23 @@ type Props$1 = {
457
603
  minHeight?: number;
458
604
  maxHeight?: number;
459
605
  };
606
+ /** A client is required unless artifactUrl is provided explicitly. */
607
+ type Props$1 = BaseProps & ({
608
+ artifactUrl: string;
609
+ client?: undefined;
610
+ } | {
611
+ artifactUrl?: undefined;
612
+ client: RoughClient;
613
+ });
460
614
  declare const SpriteFrame: svelte.Component<Props$1, {}, "">;
461
615
  type SpriteFrame = ReturnType<typeof SpriteFrame>;
462
616
 
463
617
  type Props = {
464
- toolList: readonly AnyTool[];
465
- spriteId: string;
618
+ client: RoughClient;
619
+ surface: RoughSurfaceDefinition;
620
+ spriteId: SpriteId;
621
+ /** Where the dialog attaches. Decides which `--rough-*` values it inherits. */
622
+ portalTarget?: HTMLElement;
466
623
  onclose?: () => void;
467
624
  };
468
625
  declare const RoughEditModal: svelte.Component<Props, {}, "">;
@@ -494,5 +651,5 @@ declare global {
494
651
  }
495
652
  }
496
653
 
497
- export { Mutation, PrimaryButton, Query, ResizeHandle, RoughCreateModal, RoughEditButton, RoughFeature, RoughSurface, SecondaryButton, SpriteBuildMenu, SpriteFrame, Subscription, defineSurface, getRoughFeatures, initRough, openRoughCreate, registerSurfaceEntry };
498
- export type { JsonValue, RoughCreateModalElement, RoughEditButtonElement, RoughEditModalElement, RoughFeatureElement, RoughSurfaceElement, Sprite, SpriteBuild, SpriteFrameDatastore, SpriteFrameDatastoreContext, SurfaceDefinition };
654
+ export { Mutation, PrimaryButton, Query, ResizeHandle, RoughClientDestroyError, RoughClientDestroyedError, RoughCreateModal, RoughEditButton, RoughFeature, RoughInvalidClientError, RoughReplicacheIdentityConflictError, RoughSurface, RoughSurfaceContractConflictError, SecondaryButton, SpriteBuildMenu, SpriteFrame, Subscription, createRoughClient, defineRoughSurface, getRoughFeatures, openRoughCreate, whenRoughClientReady };
655
+ export type { FetchUserTokenFn, GetRoughFeaturesOptions, JsonValue, OpenRoughCreateOptions, RoughCleanup, RoughClient, RoughClientOptions, RoughCreateModalElement, RoughEditButtonElement, RoughEditModalElement, RoughFeatureElement, RoughFeatureSubscription, RoughModalHandle, RoughSurfaceDefinition, RoughSurfaceElement, Sprite, SpriteBuild, SpriteFrameDatastore, SpriteFrameDatastoreContext };