@rool-dev/svelte 0.10.2-dev.47747e3 → 0.10.2-dev.57158ea

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
@@ -2,8 +2,6 @@
2
2
 
3
3
  Svelte 5 bindings for Rool Spaces. Adds reactive state to the SDK using `$state` runes.
4
4
 
5
- > **Building a new Rool extension?** Start with [`@rool-dev/extension`](/extension/) — it includes a reactive channel and handles hosting for you. This package is for integrating Rool into an existing Svelte application that manages its own auth, routing, and build setup.
6
-
7
5
  **Requires Svelte 5.** For core concepts (objects, references, AI placeholders, undo/redo), see the [SDK documentation](../sdk/README.md).
8
6
 
9
7
  ## Installation
@@ -55,9 +53,10 @@ The Svelte wrapper adds reactive state on top of the SDK:
55
53
  | `rool.spacesError` | Error from loading spaces |
56
54
  | `rool.connectionState` | SSE connection state |
57
55
  | `rool.userStorage` | User storage (cross-device preferences) |
56
+ | `space.fileTree` | Canonical reactive WebDAV tree for `/`, including `/space` objects and `/rool-drive` user files |
58
57
  | `channel.interactions` | Channel interactions (auto-updates) |
59
- | `channel.objectLocations` | All object locations in the space (auto-updates on create/delete/move) |
60
- | `channel.collections` | Collection names from the schema (auto-updates) |
58
+ | `channel.objectLocations` | All object locations derived from `space.fileTree` |
59
+ | `channel.collections` | Collection directories derived from `space.fileTree` |
61
60
  | `channel.conversations` | Conversations in this channel (auto-updates on create/delete/rename) |
62
61
  | `thread.interactions` | Interactions for a specific conversation (auto-updates) |
63
62
  | `watch.objects` | Objects matching a filter (auto-updates) |
@@ -65,6 +64,22 @@ The Svelte wrapper adds reactive state on top of the SDK:
65
64
 
66
65
  Everything else passes through to the SDK directly. See the [SDK documentation](../sdk/README.md) for full API details.
67
66
 
67
+ ### Reactive File Tree
68
+
69
+ Every `ReactiveSpace` owns a canonical reactive WebDAV tree. It is kept current with server `filesChanged`/`filesReset` events and WebDAV `sync-collection`, so it covers both object files and user files without polling.
70
+
71
+ ```ts
72
+ const space = await rool.openSpace(spaceId);
73
+
74
+ space.fileTree.nodes; // ReactiveFileNode[]
75
+ space.fileTree.byPath['/space']; // lookup by machine/WebDAV path
76
+ space.fileTree.childrenOf('/'); // /space and /rool-drive
77
+ space.fileTree.childrenOf('/rool-drive');
78
+ space.fileTree.objectLocations(); // object locations from /space/**/*.json
79
+ ```
80
+
81
+ Use this tree when UI needs to react to both files and objects. Object helpers like `channel.object()`, `channel.watch()`, `channel.objectLocations`, and `channel.collections` are backed by this tree.
82
+
68
83
  ## API
69
84
 
70
85
  ### Lifecycle
@@ -161,7 +176,7 @@ space.close();
161
176
 
162
177
  ### ReactiveChannel
163
178
 
164
- `space.openChannel()` returns a `ReactiveChannel` — the SDK's `RoolChannel` with reactive `interactions` and `objectLocations`:
179
+ `space.openChannel()` returns a `ReactiveChannel` — the SDK's `RoolChannel` with reactive `interactions` and file-tree-backed object helpers:
165
180
 
166
181
  ```svelte
167
182
  <script>
@@ -258,12 +273,12 @@ Create auto-updating watches of objects filtered by field values:
258
273
  {/if}
259
274
  ```
260
275
 
261
- Watches automatically re-fetch when objects matching the filter are created, updated, or deleted. Since the SDK caches objects locally, re-fetches are typically instant (no network round-trip).
276
+ Watches automatically re-fetch when matching object files change in `space.fileTree`.
262
277
 
263
278
  **Lifecycle:** Watches are tied to their channel. Closing the channel stops all updates — existing watches will retain their last data but no longer refresh. Calling `channel.watch()` after `close()` throws.
264
279
 
265
280
  ```typescript
266
- // Watch options (same as findObjects, but no AI prompt)
281
+ // Watch options
267
282
  const articles = channel.watch({
268
283
  collection: 'article',
269
284
  where: { status: 'published' },
@@ -376,7 +391,6 @@ await channel.createObject('note', { text: 'Hello' }, { basename: 'welcome' })
376
391
  await channel.updateObject(location, { data: { text: 'Updated' } })
377
392
  await channel.moveObject(from, to)
378
393
  await channel.deleteObjects([location])
379
- await channel.findObjects({ collection: 'note' })
380
394
 
381
395
  // AI
382
396
  await channel.prompt('Summarize everything')
@@ -417,13 +431,10 @@ See the [SDK documentation](../sdk/README.md) for complete API details.
417
431
  ### Utilities
418
432
 
419
433
  ```typescript
420
- import { generateBasename, loc, parseLocation, normalizeLocation } from '@rool-dev/svelte';
421
-
422
- // 6-character alphanumeric basename
423
- const basename = generateBasename();
434
+ import { loc, parseLocation, normalizeLocation } from '@rool-dev/svelte';
424
435
 
425
436
  // Build / parse location strings
426
- const location = loc('article', basename); // '/space/article/<basename>.json'
437
+ const location = loc('article', 'welcome'); // '/space/article/welcome.json'
427
438
  const parts = parseLocation(location); // { collection, basename }
428
439
  const canonical = normalizeLocation('article/welcome'); // '/space/article/welcome.json'
429
440
  ```
@@ -450,7 +461,6 @@ import type {
450
461
  ConversationInfo,
451
462
  CurrentUser,
452
463
  Interaction,
453
- FindObjectsOptions,
454
464
  PromptOptions,
455
465
  CreateObjectOptions,
456
466
  UpdateObjectOptions,
@@ -461,11 +471,6 @@ import type {
461
471
  SpaceSchema,
462
472
  SpaceMember,
463
473
  UserResult,
464
- PublishedExtensionInfo,
465
- PublishExtensionOptions,
466
- ExtensionManifest,
467
- FindExtensionsOptions,
468
-
469
474
  } from '@rool-dev/svelte';
470
475
  ```
471
476
 
@@ -1,7 +1,8 @@
1
1
  import type { RoolChannel, RoolSpace, Interaction, RoolObject, ChannelInfo, ConversationInfo, ConversationHandle } from '@rool-dev/sdk';
2
+ import { ReactiveFileTree } from './file-tree.svelte.js';
2
3
  /**
3
4
  * Options for creating a reactive watch.
4
- * Same as FindObjectsOptions but without `prompt` (AI queries are too slow for reactive updates).
5
+ * Structured object filter for reactive updates.
5
6
  */
6
7
  export interface WatchOptions {
7
8
  /** Field requirements for exact matching */
@@ -14,16 +15,14 @@ export interface WatchOptions {
14
15
  order?: 'asc' | 'desc';
15
16
  }
16
17
  /**
17
- * A reactive watch of objects that auto-updates when matching objects change.
18
+ * A reactive watch of objects that auto-updates when matching object files change.
18
19
  */
19
20
  declare class ReactiveWatchImpl {
20
21
  #private;
21
22
  objects: RoolObject[];
22
23
  loading: boolean;
23
- constructor(channel: RoolChannel, options: WatchOptions);
24
- /**
25
- * Re-fetch the watched objects from the channel.
26
- */
24
+ constructor(channel: RoolChannel, fileTree: ReactiveFileTree, options: WatchOptions);
25
+ /** Re-fetch matching objects using the canonical file tree for locations. */
27
26
  refresh(): Promise<void>;
28
27
  close(): void;
29
28
  }
@@ -35,7 +34,7 @@ declare class ReactiveObjectImpl {
35
34
  #private;
36
35
  data: RoolObject | undefined;
37
36
  loading: boolean;
38
- constructor(channel: RoolChannel, location: string);
37
+ constructor(channel: RoolChannel, fileTree: ReactiveFileTree, location: string);
39
38
  refresh(): Promise<void>;
40
39
  close(): void;
41
40
  }
@@ -52,10 +51,6 @@ declare class ReactiveConversationHandleImpl {
52
51
  getSystemInstruction(): string | undefined;
53
52
  setSystemInstruction(...args: Parameters<ConversationHandle['setSystemInstruction']>): Promise<void>;
54
53
  rename(...args: Parameters<ConversationHandle['rename']>): Promise<void>;
55
- findObjects(...args: Parameters<ConversationHandle['findObjects']>): Promise<{
56
- objects: RoolObject[];
57
- message: string;
58
- }>;
59
54
  createObject(...args: Parameters<ConversationHandle['createObject']>): Promise<{
60
55
  object: RoolObject;
61
56
  message: string;
@@ -90,7 +85,7 @@ declare class ReactiveChannelImpl {
90
85
  objectLocations: string[];
91
86
  collections: string[];
92
87
  conversations: ConversationInfo[];
93
- constructor(channel: RoolChannel);
88
+ constructor(channel: RoolChannel, fileTree: ReactiveFileTree);
94
89
  get id(): string;
95
90
  get name(): string;
96
91
  get role(): import("@rool-dev/sdk").RoolUserRole;
@@ -99,17 +94,11 @@ declare class ReactiveChannelImpl {
99
94
  get channelName(): string | null;
100
95
  get isReadOnly(): boolean;
101
96
  get linkAccess(): import("@rool-dev/sdk").LinkAccess;
102
- get extensionUrl(): string | null;
103
- get manifest(): import("@rool-dev/sdk").ExtensionManifest | null;
104
97
  get isClosed(): boolean;
105
98
  close(): void;
106
99
  getObject(...args: Parameters<RoolChannel['getObject']>): Promise<RoolObject | undefined>;
100
+ getObjects(...args: Parameters<RoolChannel['getObjects']>): Promise<import("@rool-dev/sdk").GetObjectsResult>;
107
101
  stat(...args: Parameters<RoolChannel['stat']>): import("@rool-dev/sdk").RoolObjectStat | undefined;
108
- findObjects(...args: Parameters<RoolChannel['findObjects']>): Promise<{
109
- objects: RoolObject[];
110
- message: string;
111
- }>;
112
- getObjectLocations(...args: Parameters<RoolChannel['getObjectLocations']>): string[];
113
102
  createObject(...args: Parameters<RoolChannel['createObject']>): Promise<{
114
103
  object: RoolObject;
115
104
  message: string;
@@ -163,7 +152,7 @@ declare class ReactiveChannelImpl {
163
152
  */
164
153
  watch(options: WatchOptions): ReactiveWatch;
165
154
  }
166
- export declare function wrapChannel(channel: RoolChannel): ReactiveChannel;
155
+ export declare function wrapChannel(channel: RoolChannel, fileTree: ReactiveFileTree): ReactiveChannel;
167
156
  export type ReactiveChannel = ReactiveChannelImpl;
168
157
  /**
169
158
  * A reactive list of channels for a space that auto-updates via SSE events.
@@ -1 +1 @@
1
- {"version":3,"file":"channel.svelte.d.ts","sourceRoot":"","sources":["../src/channel.svelte.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"channel.svelte.d.ts","sourceRoot":"","sources":["../src/channel.svelte.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,WAAW,EACX,SAAS,EACT,WAAW,EACX,UAAU,EACV,WAAW,EACX,gBAAgB,EAChB,kBAAkB,EAEnB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,gBAAgB,EAAqD,MAAM,uBAAuB,CAAC;AAE5G;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,4CAA4C;IAC5C,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,iCAAiC;IACjC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gCAAgC;IAChC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kEAAkE;IAClE,KAAK,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC;CACxB;AAyCD;;GAEG;AACH,cAAM,iBAAiB;;IAOrB,OAAO,eAA4B;IACnC,OAAO,UAAgB;gBAEX,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,gBAAgB,EAAE,OAAO,EAAE,YAAY;IAgBnF,6EAA6E;IACvE,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAS9B,KAAK,IAAI,IAAI;CAId;AAED,MAAM,MAAM,aAAa,GAAG,iBAAiB,CAAC;AAE9C;;GAEG;AACH,cAAM,kBAAkB;;IAOtB,IAAI,yBAA6C;IACjD,OAAO,UAAgB;gBAEX,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM;IAoBxE,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAS9B,KAAK,IAAI,IAAI;CAId;AAED,MAAM,MAAM,cAAc,GAAG,kBAAkB,CAAC;AAMhD,cAAM,8BAA8B;;IAMlC,YAAY,gBAA6B;gBAE7B,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM;IAqBxD,IAAI,cAAc,IAAI,MAAM,CAAiC;IAG7D,eAAe;IACf,OAAO;IACP,IAAI,YAAY,uBAAwC;IACxD,aAAa,CAAC,aAAa,EAAE,MAAM;IACnC,oBAAoB;IACpB,oBAAoB,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,kBAAkB,CAAC,sBAAsB,CAAC,CAAC;IACpF,MAAM,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAC;IAGxD,YAAY,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,kBAAkB,CAAC,cAAc,CAAC,CAAC;;;;IACpE,YAAY,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,kBAAkB,CAAC,cAAc,CAAC,CAAC;;;;IACpE,UAAU,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,kBAAkB,CAAC,YAAY,CAAC,CAAC;;;;IAChE,aAAa,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,kBAAkB,CAAC,eAAe,CAAC,CAAC;IAGtE,MAAM,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAC;;;;IAGxD,gBAAgB,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,kBAAkB,CAAC,kBAAkB,CAAC,CAAC;IAC5E,eAAe,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,kBAAkB,CAAC,iBAAiB,CAAC,CAAC;IAC1E,cAAc,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,kBAAkB,CAAC,gBAAgB,CAAC,CAAC;IAGxE,WAAW,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,kBAAkB,CAAC,aAAa,CAAC,CAAC;IAElE,KAAK,IAAI,IAAI;CAId;AAED,MAAM,MAAM,0BAA0B,GAAG,8BAA8B,CAAC;AAExE;;;GAGG;AACH,cAAM,mBAAmB;;IAOvB,YAAY,gBAA6B;IACzC,eAAe,WAAwB;IACvC,WAAW,WAAwB;IACnC,aAAa,qBAAkC;gBAEnC,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,gBAAgB;IAyC5D,IAAI,EAAE,WAA+B;IACrC,IAAI,IAAI,WAAiC;IACzC,IAAI,IAAI,yCAAiC;IACzC,IAAI,MAAM,WAAmC;IAC7C,IAAI,SAAS,WAAsC;IACnD,IAAI,WAAW,kBAAwC;IACvD,IAAI,UAAU,YAAuC;IACrD,IAAI,UAAU,uCAAuC;IAErD,IAAI,QAAQ,YAA2B;IAEvC,KAAK;IASL,SAAS,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC;IACvD,UAAU,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,WAAW,CAAC,YAAY,CAAC,CAAC;IACzD,IAAI,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;IAC7C,YAAY,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,WAAW,CAAC,cAAc,CAAC,CAAC;;;;IAC7D,YAAY,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,WAAW,CAAC,cAAc,CAAC,CAAC;;;;IAC7D,UAAU,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,WAAW,CAAC,YAAY,CAAC,CAAC;;;;IACzD,aAAa,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,WAAW,CAAC,eAAe,CAAC,CAAC;IAG/D,MAAM,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;;;;IAGjD,UAAU,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,WAAW,CAAC,YAAY,CAAC,CAAC;IACzD,OAAO;IACP,OAAO;IACP,IAAI;IACJ,IAAI;IACJ,YAAY;IAGZ,WAAW,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC;IAC3D,WAAW,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC;IAC3D,cAAc;IAGd,eAAe;IACf,OAAO;IACP,IAAI,YAAY,uBAAyC;IACzD,aAAa,CAAC,aAAa,EAAE,MAAM;IACnC,oBAAoB;IACpB,oBAAoB,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,WAAW,CAAC,sBAAsB,CAAC,CAAC;IAC7E,gBAAgB;IAChB,kBAAkB,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,WAAW,CAAC,oBAAoB,CAAC,CAAC;IACzE,kBAAkB,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,WAAW,CAAC,oBAAoB,CAAC,CAAC;IAGzE,SAAS;IACT,gBAAgB,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,WAAW,CAAC,kBAAkB,CAAC,CAAC;IACrE,eAAe,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,WAAW,CAAC,iBAAiB,CAAC,CAAC;IACnE,cAAc,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,WAAW,CAAC,gBAAgB,CAAC,CAAC;IAGjE,KAAK,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;IAG/C,MAAM,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;IAGjD,YAAY,CAAC,cAAc,EAAE,MAAM,GAAG,0BAA0B;IAMhE,EAAE,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;IACzC,GAAG,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;IAI3C;;OAEG;IACH,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,cAAc;IAKxC;;OAEG;IACH,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,aAAa;CAK5C;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,gBAAgB,GAAG,eAAe,CAE7F;AAED,MAAM,MAAM,eAAe,GAAG,mBAAmB,CAAC;AAElD;;GAEG;AACH,cAAM,uBAAuB;;IAK3B,IAAI,gBAA6B;IACjC,OAAO,UAAgB;gBAEX,cAAc,EAAE,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC;IAoCpD,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAW9B,KAAK,IAAI,IAAI;CAId;AAED,wBAAgB,iBAAiB,CAAC,cAAc,EAAE,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC,GAAG,mBAAmB,CAErG;AAED,MAAM,MAAM,mBAAmB,GAAG,uBAAuB,CAAC"}
@@ -1,122 +1,76 @@
1
+ import { normalizeLocation } from '@rool-dev/sdk';
2
+ function eventTouchesObject(event, location, collection) {
3
+ if (event.reset)
4
+ return true;
5
+ for (const path of [...event.changedPaths, ...event.deletedPaths]) {
6
+ if (location && path === location)
7
+ return true;
8
+ if (!location && path.startsWith('/space/') && path.endsWith('.json')) {
9
+ if (!collection || path.startsWith(`/space/${collection}/`))
10
+ return true;
11
+ }
12
+ }
13
+ return false;
14
+ }
15
+ function sameJsonValue(a, b) {
16
+ return JSON.stringify(a) === JSON.stringify(b);
17
+ }
18
+ async function watchObjectsFromTree(channel, fileTree, options) {
19
+ if (fileTree.loading)
20
+ await fileTree.ready();
21
+ const locations = fileTree.objectLocations({ collection: options.collection, order: options.order });
22
+ const objects = [];
23
+ for (const location of locations) {
24
+ const object = await channel.getObject(location);
25
+ if (!object)
26
+ continue;
27
+ if (options.where) {
28
+ let matches = true;
29
+ for (const [key, value] of Object.entries(options.where)) {
30
+ if (!sameJsonValue(object.body[key], value)) {
31
+ matches = false;
32
+ break;
33
+ }
34
+ }
35
+ if (!matches)
36
+ continue;
37
+ }
38
+ objects.push(object);
39
+ if (options.limit !== undefined && objects.length >= options.limit)
40
+ break;
41
+ }
42
+ return objects;
43
+ }
1
44
  /**
2
- * A reactive watch of objects that auto-updates when matching objects change.
45
+ * A reactive watch of objects that auto-updates when matching object files change.
3
46
  */
4
47
  class ReactiveWatchImpl {
5
48
  #channel;
49
+ #fileTree;
6
50
  #options;
7
51
  #unsubscribers = [];
8
- #currentLocations = new Set();
9
52
  // Reactive state
10
53
  objects = $state([]);
11
54
  loading = $state(true);
12
- constructor(channel, options) {
55
+ constructor(channel, fileTree, options) {
13
56
  this.#channel = channel;
57
+ this.#fileTree = fileTree;
14
58
  this.#options = options;
15
59
  this.#setup();
16
60
  }
17
61
  #setup() {
18
- // Initial fetch
19
62
  this.refresh();
20
- const onObjectCreated = ({ object }) => {
21
- if (this.#matches(object)) {
22
- this.refresh();
23
- }
24
- };
25
- this.#channel.on('objectCreated', onObjectCreated);
26
- this.#unsubscribers.push(() => this.#channel.off('objectCreated', onObjectCreated));
27
- const onObjectUpdated = ({ location, object }) => {
28
- const wasInCollection = this.#currentLocations.has(location);
29
- const nowMatches = this.#matches(object);
30
- if (wasInCollection && nowMatches) {
31
- // Update in place (merge to preserve fields from partial optimistic updates)
32
- const index = this.objects.findIndex((o) => o.location === location);
33
- if (index !== -1) {
34
- this.objects[index] = {
35
- ...this.objects[index],
36
- ...object,
37
- body: { ...this.objects[index].body, ...object.body },
38
- };
39
- }
40
- }
41
- else if (wasInCollection && !nowMatches) {
42
- // Check if the mismatch is due to missing keys in body (partial optimistic update)
43
- const where = this.#options.where;
44
- const isPartialUpdate = where && Object.keys(where).some((key) => !(key in object.body));
45
- if (isPartialUpdate) {
46
- const index = this.objects.findIndex((o) => o.location === location);
47
- if (index !== -1) {
48
- this.objects[index] = {
49
- ...this.objects[index],
50
- ...object,
51
- body: { ...this.objects[index].body, ...object.body },
52
- };
53
- }
54
- }
55
- else {
56
- // Genuine mismatch — remove from collection
57
- this.objects = this.objects.filter((o) => o.location !== location);
58
- this.#currentLocations.delete(location);
59
- }
60
- }
61
- else if (!wasInCollection && nowMatches) {
62
- // Add to collection (re-fetch to respect limit/order)
63
- this.refresh();
64
- }
65
- };
66
- this.#channel.on('objectUpdated', onObjectUpdated);
67
- this.#unsubscribers.push(() => this.#channel.off('objectUpdated', onObjectUpdated));
68
- const onObjectDeleted = ({ location }) => {
69
- if (this.#currentLocations.has(location)) {
70
- this.objects = this.objects.filter((o) => o.location !== location);
71
- this.#currentLocations.delete(location);
72
- }
73
- };
74
- this.#channel.on('objectDeleted', onObjectDeleted);
75
- this.#unsubscribers.push(() => this.#channel.off('objectDeleted', onObjectDeleted));
76
- const onObjectMoved = ({ from, object }) => {
77
- const wasInCollection = this.#currentLocations.has(from);
78
- const nowMatches = this.#matches(object);
79
- if (wasInCollection || nowMatches) {
80
- this.refresh();
81
- }
82
- };
83
- this.#channel.on('objectMoved', onObjectMoved);
84
- this.#unsubscribers.push(() => this.#channel.off('objectMoved', onObjectMoved));
85
- const onReset = () => this.refresh();
86
- this.#channel.on('reset', onReset);
87
- this.#unsubscribers.push(() => this.#channel.off('reset', onReset));
63
+ const unsubscribe = this.#fileTree.subscribe((event) => {
64
+ if (eventTouchesObject(event, undefined, this.#options.collection))
65
+ void this.refresh();
66
+ });
67
+ this.#unsubscribers.push(unsubscribe);
88
68
  }
89
- /**
90
- * Check if an object matches the filter (collection + where on body).
91
- */
92
- #matches(object) {
93
- if (this.#options.collection && object.collection !== this.#options.collection)
94
- return false;
95
- const where = this.#options.where;
96
- if (!where)
97
- return true;
98
- for (const [key, value] of Object.entries(where)) {
99
- if (object.body[key] !== value)
100
- return false;
101
- }
102
- return true;
103
- }
104
- /**
105
- * Re-fetch the watched objects from the channel.
106
- */
69
+ /** Re-fetch matching objects using the canonical file tree for locations. */
107
70
  async refresh() {
108
71
  this.loading = true;
109
72
  try {
110
- const findOptions = {
111
- where: this.#options.where,
112
- collection: this.#options.collection,
113
- limit: this.#options.limit,
114
- order: this.#options.order,
115
- ephemeral: true,
116
- };
117
- const { objects } = await this.#channel.findObjects(findOptions);
118
- this.objects = objects;
119
- this.#currentLocations = new Set(objects.map((o) => o.location));
73
+ this.objects = await watchObjectsFromTree(this.#channel, this.#fileTree, this.#options);
120
74
  }
121
75
  finally {
122
76
  this.loading = false;
@@ -133,53 +87,29 @@ class ReactiveWatchImpl {
133
87
  */
134
88
  class ReactiveObjectImpl {
135
89
  #channel;
90
+ #fileTree;
136
91
  #location;
137
92
  #unsubscribers = [];
138
93
  // Reactive state
139
94
  data = $state(undefined);
140
95
  loading = $state(true);
141
- constructor(channel, location) {
96
+ constructor(channel, fileTree, location) {
142
97
  this.#channel = channel;
143
- this.#location = location;
98
+ this.#fileTree = fileTree;
99
+ this.#location = normalizeLocation(location);
144
100
  this.#setup();
145
101
  }
146
102
  #setup() {
147
103
  this.refresh();
148
- const onObjectUpdated = ({ location, object }) => {
149
- if (location === this.#location) {
150
- this.data = object;
151
- }
152
- };
153
- this.#channel.on('objectUpdated', onObjectUpdated);
154
- this.#unsubscribers.push(() => this.#channel.off('objectUpdated', onObjectUpdated));
155
- const onObjectCreated = ({ location, object }) => {
156
- if (location === this.#location) {
157
- this.data = object;
158
- }
159
- };
160
- this.#channel.on('objectCreated', onObjectCreated);
161
- this.#unsubscribers.push(() => this.#channel.off('objectCreated', onObjectCreated));
162
- const onObjectDeleted = ({ location }) => {
163
- if (location === this.#location) {
164
- this.data = undefined;
165
- }
166
- };
167
- this.#channel.on('objectDeleted', onObjectDeleted);
168
- this.#unsubscribers.push(() => this.#channel.off('objectDeleted', onObjectDeleted));
169
- const onObjectMoved = ({ from, to, object }) => {
170
- if (from === this.#location) {
171
- // Object moved away from this location; data is gone.
104
+ const unsubscribe = this.#fileTree.subscribe((event) => {
105
+ if (event.deletedPaths.has(this.#location)) {
172
106
  this.data = undefined;
107
+ return;
173
108
  }
174
- else if (to === this.#location) {
175
- this.data = object;
176
- }
177
- };
178
- this.#channel.on('objectMoved', onObjectMoved);
179
- this.#unsubscribers.push(() => this.#channel.off('objectMoved', onObjectMoved));
180
- const onReset = () => this.refresh();
181
- this.#channel.on('reset', onReset);
182
- this.#unsubscribers.push(() => this.#channel.off('reset', onReset));
109
+ if (eventTouchesObject(event, this.#location))
110
+ void this.refresh();
111
+ });
112
+ this.#unsubscribers.push(unsubscribe);
183
113
  }
184
114
  async refresh() {
185
115
  this.loading = true;
@@ -232,7 +162,6 @@ class ReactiveConversationHandleImpl {
232
162
  setSystemInstruction(...args) { return this.#handle.setSystemInstruction(...args); }
233
163
  rename(...args) { return this.#handle.rename(...args); }
234
164
  // Object operations
235
- findObjects(...args) { return this.#handle.findObjects(...args); }
236
165
  createObject(...args) { return this.#handle.createObject(...args); }
237
166
  updateObject(...args) { return this.#handle.updateObject(...args); }
238
167
  moveObject(...args) { return this.#handle.moveObject(...args); }
@@ -257,6 +186,7 @@ class ReactiveConversationHandleImpl {
257
186
  */
258
187
  class ReactiveChannelImpl {
259
188
  #channel;
189
+ #fileTree;
260
190
  #unsubscribers = [];
261
191
  #closed = false;
262
192
  // Reactive state
@@ -264,14 +194,16 @@ class ReactiveChannelImpl {
264
194
  objectLocations = $state([]);
265
195
  collections = $state([]);
266
196
  conversations = $state([]);
267
- constructor(channel) {
197
+ constructor(channel, fileTree) {
268
198
  this.#channel = channel;
199
+ this.#fileTree = fileTree;
269
200
  this.interactions = channel.getInteractions();
270
- this.objectLocations = channel.getObjectLocations();
271
- this.collections = Object.keys(channel.getSchema());
201
+ this.objectLocations = fileTree.objectLocations();
202
+ this.collections = fileTree.collections();
272
203
  this.conversations = channel.getConversations();
273
204
  const onChannelUpdated = () => {
274
205
  this.interactions = channel.getInteractions();
206
+ this.conversations = channel.getConversations();
275
207
  };
276
208
  channel.on('channelUpdated', onChannelUpdated);
277
209
  this.#unsubscribers.push(() => channel.off('channelUpdated', onChannelUpdated));
@@ -280,24 +212,18 @@ class ReactiveChannelImpl {
280
212
  };
281
213
  channel.on('conversationUpdated', onConversationUpdated);
282
214
  this.#unsubscribers.push(() => channel.off('conversationUpdated', onConversationUpdated));
283
- const refreshObjectLocations = () => {
284
- this.objectLocations = channel.getObjectLocations();
215
+ const refreshFromFileTree = () => {
216
+ this.objectLocations = fileTree.objectLocations();
217
+ this.collections = fileTree.collections();
285
218
  };
286
- channel.on('objectCreated', refreshObjectLocations);
287
- this.#unsubscribers.push(() => channel.off('objectCreated', refreshObjectLocations));
288
- channel.on('objectDeleted', refreshObjectLocations);
289
- this.#unsubscribers.push(() => channel.off('objectDeleted', refreshObjectLocations));
290
- channel.on('objectMoved', refreshObjectLocations);
291
- this.#unsubscribers.push(() => channel.off('objectMoved', refreshObjectLocations));
292
- const onSchemaUpdated = () => {
293
- this.collections = Object.keys(channel.getSchema());
294
- };
295
- channel.on('schemaUpdated', onSchemaUpdated);
296
- this.#unsubscribers.push(() => channel.off('schemaUpdated', onSchemaUpdated));
219
+ this.#unsubscribers.push(fileTree.subscribe((event) => {
220
+ if (event.reset || eventTouchesObject(event) || [...event.changedPaths, ...event.deletedPaths].some((path) => path === '/space' || path.startsWith('/space/'))) {
221
+ refreshFromFileTree();
222
+ }
223
+ }));
297
224
  const onReset = () => {
298
225
  this.interactions = channel.getInteractions();
299
- this.objectLocations = channel.getObjectLocations();
300
- this.collections = Object.keys(channel.getSchema());
226
+ refreshFromFileTree();
301
227
  this.conversations = channel.getConversations();
302
228
  };
303
229
  channel.on('reset', onReset);
@@ -312,8 +238,6 @@ class ReactiveChannelImpl {
312
238
  get channelName() { return this.#channel.channelName; }
313
239
  get isReadOnly() { return this.#channel.isReadOnly; }
314
240
  get linkAccess() { return this.#channel.linkAccess; }
315
- get extensionUrl() { return this.#channel.extensionUrl; }
316
- get manifest() { return this.#channel.manifest; }
317
241
  get isClosed() { return this.#closed; }
318
242
  close() {
319
243
  if (this.#closed)
@@ -326,9 +250,8 @@ class ReactiveChannelImpl {
326
250
  }
327
251
  // Object operations
328
252
  getObject(...args) { return this.#channel.getObject(...args); }
253
+ getObjects(...args) { return this.#channel.getObjects(...args); }
329
254
  stat(...args) { return this.#channel.stat(...args); }
330
- findObjects(...args) { return this.#channel.findObjects(...args); }
331
- getObjectLocations(...args) { return this.#channel.getObjectLocations(...args); }
332
255
  createObject(...args) { return this.#channel.createObject(...args); }
333
256
  updateObject(...args) { return this.#channel.updateObject(...args); }
334
257
  moveObject(...args) { return this.#channel.moveObject(...args); }
@@ -381,7 +304,7 @@ class ReactiveChannelImpl {
381
304
  object(location) {
382
305
  if (this.#closed)
383
306
  throw new Error('Cannot create reactive object: channel is closed');
384
- return new ReactiveObjectImpl(this.#channel, location);
307
+ return new ReactiveObjectImpl(this.#channel, this.#fileTree, location);
385
308
  }
386
309
  /**
387
310
  * Create a reactive watch that auto-updates when matching objects change.
@@ -389,11 +312,11 @@ class ReactiveChannelImpl {
389
312
  watch(options) {
390
313
  if (this.#closed)
391
314
  throw new Error('Cannot create reactive watch: channel is closed');
392
- return new ReactiveWatchImpl(this.#channel, options);
315
+ return new ReactiveWatchImpl(this.#channel, this.#fileTree, options);
393
316
  }
394
317
  }
395
- export function wrapChannel(channel) {
396
- return new ReactiveChannelImpl(channel);
318
+ export function wrapChannel(channel, fileTree) {
319
+ return new ReactiveChannelImpl(channel, fileTree);
397
320
  }
398
321
  /**
399
322
  * A reactive list of channels for a space that auto-updates via SSE events.
@@ -0,0 +1,91 @@
1
+ import type { RoolSpace, WebDAVDepth, WebDAVPropName, WebDAVResponse, WebDAVSyncLevel } from '@rool-dev/sdk';
2
+ export type ReactiveFilePath = '/' | `/space${string}` | `/rool-drive${string}`;
3
+ export type ReactiveFileRoot = '' | 'space' | 'rool-drive';
4
+ export interface ReactiveFileNode {
5
+ /** Stable node id. Same as `path`. */
6
+ id: ReactiveFilePath;
7
+ /** Machine/WebDAV path (`/`, `/space/...`, `/rool-drive/...`). */
8
+ path: ReactiveFilePath;
9
+ /** Parent path, or `null` for `/`. */
10
+ parent: ReactiveFilePath | null;
11
+ /** Last path segment, decoded by the server when available. */
12
+ name: string;
13
+ /** Which top-level filesystem this node belongs to. `/` has `root: ''`. */
14
+ root: ReactiveFileRoot;
15
+ isCollection: boolean;
16
+ size: number | null;
17
+ contentType: string | null;
18
+ etag: string | null;
19
+ modifiedAt: number | null;
20
+ href: string | null;
21
+ }
22
+ export interface ReactiveFileTreeEvent {
23
+ /** `true` when the tree was replaced from a full snapshot. */
24
+ reset: boolean;
25
+ changedPaths: Set<ReactiveFilePath>;
26
+ deletedPaths: Set<ReactiveFilePath>;
27
+ token: string | null;
28
+ }
29
+ export interface ReactiveFileTreeSyncResult extends ReactiveFileTreeEvent {
30
+ changed: boolean;
31
+ }
32
+ export interface ReactiveFileTreeTransport {
33
+ propfind(path: string, options: {
34
+ depth: WebDAVDepth;
35
+ props?: WebDAVPropName[];
36
+ signal?: AbortSignal;
37
+ }): Promise<{
38
+ responses: WebDAVResponse[];
39
+ }>;
40
+ syncCollection(path: string, options: {
41
+ token?: string | null;
42
+ level: WebDAVSyncLevel;
43
+ props?: WebDAVPropName[];
44
+ limit?: number;
45
+ signal?: AbortSignal;
46
+ }): Promise<{
47
+ token: string;
48
+ responses: WebDAVResponse[];
49
+ }>;
50
+ }
51
+ type Listener = (event: ReactiveFileTreeEvent) => void;
52
+ /**
53
+ * Canonical Svelte-owned tree for the whole per-space WebDAV filesystem.
54
+ *
55
+ * It watches the SDK's coarse `filesChanged` / `filesReset` events and
56
+ * reconciles with WebDAV `sync-collection`. Consumers that care about both
57
+ * object files (`/space/...`) and user files (`/rool-drive/...`) should depend
58
+ * on this tree.
59
+ */
60
+ export declare class ReactiveFileTree {
61
+ #private;
62
+ nodes: ReactiveFileNode[];
63
+ byPath: Record<string, ReactiveFileNode>;
64
+ token: string | null;
65
+ version: number;
66
+ loading: boolean;
67
+ syncing: boolean;
68
+ error: Error | null;
69
+ constructor(space: RoolSpace);
70
+ get isClosed(): boolean;
71
+ get root(): ReactiveFilePath;
72
+ subscribe(listener: Listener): () => void;
73
+ ready(): Promise<void>;
74
+ get(path: string): ReactiveFileNode | undefined;
75
+ has(path: string): boolean;
76
+ childrenOf(path: string): ReactiveFileNode[];
77
+ descendantsOf(path: string): ReactiveFileNode[];
78
+ /** Object file locations sorted by modified time descending. */
79
+ objectLocations(options?: {
80
+ collection?: string;
81
+ order?: 'asc' | 'desc';
82
+ limit?: number;
83
+ }): string[];
84
+ collections(): string[];
85
+ loadSnapshot(): Promise<ReactiveFileTreeSyncResult>;
86
+ sync(): Promise<ReactiveFileTreeSyncResult>;
87
+ refresh(): Promise<ReactiveFileTreeSyncResult>;
88
+ close(): void;
89
+ }
90
+ export {};
91
+ //# sourceMappingURL=file-tree.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-tree.svelte.d.ts","sourceRoot":"","sources":["../src/file-tree.svelte.ts"],"names":[],"mappings":"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"}