@rool-dev/svelte 0.1.11-dev.1dedc51 → 0.1.12-dev.f0f1757

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
@@ -50,6 +50,8 @@ The Svelte wrapper adds reactive state on top of the SDK:
50
50
  | `rool.spacesError` | Error from loading spaces |
51
51
  | `rool.connectionState` | SSE connection state |
52
52
  | `space.interactions` | Conversation interactions (auto-updates) |
53
+ | `collection.objects` | Objects matching a filter (auto-updates) |
54
+ | `collection.loading` | Whether collection is loading |
53
55
 
54
56
  Everything else passes through to the SDK directly. See the [SDK documentation](../sdk/README.md) for full API details.
55
57
 
@@ -130,6 +132,52 @@ space.close();
130
132
  {/if}
131
133
  ```
132
134
 
135
+ ### Reactive Collections
136
+
137
+ Create auto-updating collections of objects filtered by field values:
138
+
139
+ ```svelte
140
+ <script>
141
+ let space = $state(null);
142
+ let articles = $state(null);
143
+
144
+ async function open(id) {
145
+ space = await rool.openSpace(id);
146
+ // Create a reactive collection of all objects where type === 'article'
147
+ articles = space.collection({ where: { type: 'article' } });
148
+ }
149
+ </script>
150
+
151
+ {#if articles}
152
+ {#if articles.loading}
153
+ <p>Loading...</p>
154
+ {:else}
155
+ {#each articles.objects as article}
156
+ <div>{article.title}</div>
157
+ {/each}
158
+ {/if}
159
+ {/if}
160
+ ```
161
+
162
+ Collections 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).
163
+
164
+ ```typescript
165
+ // Collection options (same as findObjects, but no AI prompt)
166
+ const articles = space.collection({
167
+ where: { type: 'article', status: 'published' },
168
+ order: 'desc', // by modifiedAt (default)
169
+ limit: 20,
170
+ });
171
+
172
+ // Reactive state
173
+ articles.objects // $state<RoolObject[]>
174
+ articles.loading // $state<boolean>
175
+
176
+ // Methods
177
+ articles.refresh() // Manual re-fetch
178
+ articles.close() // Stop listening for updates
179
+ ```
180
+
133
181
  ### Using the SDK
134
182
 
135
183
  All `RoolSpace` methods and properties are available on `ReactiveSpace`:
@@ -183,7 +231,7 @@ const id = generateId();
183
231
 
184
232
  ```typescript
185
233
  // Package types
186
- import type { Rool, ReactiveSpace } from '@rool-dev/svelte';
234
+ import type { Rool, ReactiveSpace, ReactiveCollection, CollectionOptions } from '@rool-dev/svelte';
187
235
 
188
236
  // Re-exported from @rool-dev/sdk
189
237
  import type {
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  export { createRool, generateId } from './rool.svelte.js';
2
2
  export { wrapSpace } from './space.svelte.js';
3
3
  export type { Rool } from './rool.svelte.js';
4
- export type { ReactiveSpace } from './space.svelte.js';
4
+ export type { ReactiveSpace, ReactiveCollection, CollectionOptions } from './space.svelte.js';
5
5
  export type { RoolClientConfig, RoolSpace, RoolSpaceInfo, RoolObject, RoolUserRole, ConnectionState, ConversationInfo, CurrentUser, Interaction, FindObjectsOptions, PromptOptions, CreateObjectOptions, UpdateObjectOptions, } from '@rool-dev/sdk';
6
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAG1D,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAG9C,YAAY,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC7C,YAAY,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAGvD,YAAY,EACV,gBAAgB,EAChB,SAAS,EACT,aAAa,EACb,UAAU,EACV,YAAY,EACZ,eAAe,EACf,gBAAgB,EAChB,WAAW,EACX,WAAW,EACX,kBAAkB,EAClB,aAAa,EACb,mBAAmB,EACnB,mBAAmB,GACpB,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAG1D,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAG9C,YAAY,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC7C,YAAY,EAAE,aAAa,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAG9F,YAAY,EACV,gBAAgB,EAChB,SAAS,EACT,aAAa,EACb,UAAU,EACV,YAAY,EACZ,eAAe,EACf,gBAAgB,EAChB,WAAW,EACX,WAAW,EACX,kBAAkB,EAClB,aAAa,EACb,mBAAmB,EACnB,mBAAmB,GACpB,MAAM,eAAe,CAAC"}
@@ -1,4 +1,34 @@
1
- import type { RoolSpace, Interaction } from '@rool-dev/sdk';
1
+ import type { RoolSpace, Interaction, RoolObject } from '@rool-dev/sdk';
2
+ /**
3
+ * Options for creating a reactive collection.
4
+ * Same as FindObjectsOptions but without `prompt` (AI queries are too slow for reactive updates).
5
+ */
6
+ export interface CollectionOptions {
7
+ /** Field requirements for exact matching */
8
+ where?: Record<string, unknown>;
9
+ /** Maximum number of objects */
10
+ limit?: number;
11
+ /** Sort order by modifiedAt: 'asc' or 'desc' (default: 'desc') */
12
+ order?: 'asc' | 'desc';
13
+ }
14
+ /**
15
+ * A reactive collection of objects that auto-updates when matching objects change.
16
+ */
17
+ declare class ReactiveCollectionImpl {
18
+ #private;
19
+ objects: RoolObject[];
20
+ loading: boolean;
21
+ constructor(space: RoolSpace, options: CollectionOptions);
22
+ /**
23
+ * Re-fetch the collection from the space.
24
+ */
25
+ refresh(): Promise<void>;
26
+ /**
27
+ * Stop listening for updates and clean up.
28
+ */
29
+ close(): void;
30
+ }
31
+ export type ReactiveCollection = ReactiveCollectionImpl;
2
32
  /**
3
33
  * Minimal wrapper that adds reactive `interactions` to RoolSpace.
4
34
  * All other properties and methods are proxied to the underlying space.
@@ -14,29 +44,29 @@ declare class ReactiveSpaceImpl {
14
44
  get conversationId(): string;
15
45
  set conversationId(id: string);
16
46
  close(): void;
17
- getObject(...args: Parameters<RoolSpace['getObject']>): Promise<import("@rool-dev/sdk").RoolObject | undefined>;
47
+ getObject(...args: Parameters<RoolSpace['getObject']>): Promise<RoolObject | undefined>;
18
48
  stat(...args: Parameters<RoolSpace['stat']>): Promise<import("@rool-dev/sdk").RoolObjectStat | undefined>;
19
49
  findObjects(...args: Parameters<RoolSpace['findObjects']>): Promise<{
20
- objects: import("@rool-dev/sdk").RoolObject[];
50
+ objects: RoolObject[];
21
51
  message: string;
22
52
  }>;
23
53
  getObjectIds(...args: Parameters<RoolSpace['getObjectIds']>): string[];
24
54
  createObject(...args: Parameters<RoolSpace['createObject']>): Promise<{
25
- object: import("@rool-dev/sdk").RoolObject;
55
+ object: RoolObject;
26
56
  message: string;
27
57
  }>;
28
58
  updateObject(...args: Parameters<RoolSpace['updateObject']>): Promise<{
29
- object: import("@rool-dev/sdk").RoolObject;
59
+ object: RoolObject;
30
60
  message: string;
31
61
  }>;
32
62
  deleteObjects(...args: Parameters<RoolSpace['deleteObjects']>): Promise<void>;
33
63
  link(...args: Parameters<RoolSpace['link']>): Promise<void>;
34
64
  unlink(...args: Parameters<RoolSpace['unlink']>): Promise<boolean>;
35
- getParents(...args: Parameters<RoolSpace['getParents']>): Promise<import("@rool-dev/sdk").RoolObject[]>;
36
- getChildren(...args: Parameters<RoolSpace['getChildren']>): Promise<import("@rool-dev/sdk").RoolObject[]>;
65
+ getParents(...args: Parameters<RoolSpace['getParents']>): Promise<RoolObject[]>;
66
+ getChildren(...args: Parameters<RoolSpace['getChildren']>): Promise<RoolObject[]>;
37
67
  prompt(...args: Parameters<RoolSpace['prompt']>): Promise<{
38
68
  message: string;
39
- objects: import("@rool-dev/sdk").RoolObject[];
69
+ objects: RoolObject[];
40
70
  }>;
41
71
  checkpoint(...args: Parameters<RoolSpace['checkpoint']>): Promise<string>;
42
72
  canUndo(): Promise<boolean>;
@@ -62,6 +92,17 @@ declare class ReactiveSpaceImpl {
62
92
  exportArchive(): Promise<Blob>;
63
93
  on(...args: Parameters<RoolSpace['on']>): () => void;
64
94
  off(...args: Parameters<RoolSpace['off']>): void;
95
+ /**
96
+ * Create a reactive collection that auto-updates when matching objects change.
97
+ *
98
+ * @example
99
+ * const articles = space.collection({ where: { type: 'article' } });
100
+ * // articles.objects is reactive
101
+ * // articles.loading indicates fetch status
102
+ * // articles.refresh() to manually re-fetch
103
+ * // articles.close() to stop listening
104
+ */
105
+ collection(options: CollectionOptions): ReactiveCollection;
65
106
  rename(...args: Parameters<RoolSpace['rename']>): Promise<void>;
66
107
  getData(): import("@rool-dev/sdk").RoolSpaceData;
67
108
  get isReadOnly(): boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"space.svelte.d.ts","sourceRoot":"","sources":["../src/space.svelte.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"space.svelte.d.ts","sourceRoot":"","sources":["../src/space.svelte.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,92 @@
1
+ /**
2
+ * A reactive collection of objects that auto-updates when matching objects change.
3
+ */
4
+ class ReactiveCollectionImpl {
5
+ #space;
6
+ #options;
7
+ #unsubscribers = [];
8
+ #currentIds = new Set();
9
+ // Reactive state
10
+ objects = $state([]);
11
+ loading = $state(true);
12
+ constructor(space, options) {
13
+ this.#space = space;
14
+ this.#options = options;
15
+ this.#setup();
16
+ }
17
+ #setup() {
18
+ // Initial fetch
19
+ this.refresh();
20
+ // Subscribe to object events
21
+ const onObjectCreated = ({ object }) => {
22
+ if (this.#matches(object)) {
23
+ this.refresh();
24
+ }
25
+ };
26
+ this.#space.on('objectCreated', onObjectCreated);
27
+ this.#unsubscribers.push(() => this.#space.off('objectCreated', onObjectCreated));
28
+ const onObjectUpdated = ({ objectId, object }) => {
29
+ // Re-fetch if object was in collection OR now matches the filter
30
+ if (this.#currentIds.has(objectId) || this.#matches(object)) {
31
+ this.refresh();
32
+ }
33
+ };
34
+ this.#space.on('objectUpdated', onObjectUpdated);
35
+ this.#unsubscribers.push(() => this.#space.off('objectUpdated', onObjectUpdated));
36
+ const onObjectDeleted = ({ objectId }) => {
37
+ if (this.#currentIds.has(objectId)) {
38
+ this.refresh();
39
+ }
40
+ };
41
+ this.#space.on('objectDeleted', onObjectDeleted);
42
+ this.#unsubscribers.push(() => this.#space.off('objectDeleted', onObjectDeleted));
43
+ // Handle full resets
44
+ const onReset = () => this.refresh();
45
+ this.#space.on('reset', onReset);
46
+ this.#unsubscribers.push(() => this.#space.off('reset', onReset));
47
+ }
48
+ /**
49
+ * Check if an object matches the `where` filter.
50
+ */
51
+ #matches(object) {
52
+ const where = this.#options.where;
53
+ if (!where)
54
+ return true;
55
+ for (const [key, value] of Object.entries(where)) {
56
+ if (object[key] !== value)
57
+ return false;
58
+ }
59
+ return true;
60
+ }
61
+ /**
62
+ * Re-fetch the collection from the space.
63
+ */
64
+ async refresh() {
65
+ this.loading = true;
66
+ try {
67
+ const findOptions = {
68
+ where: this.#options.where,
69
+ limit: this.#options.limit,
70
+ order: this.#options.order,
71
+ ephemeral: true, // Don't pollute conversation history
72
+ };
73
+ const { objects } = await this.#space.findObjects(findOptions);
74
+ this.objects = objects;
75
+ this.#currentIds = new Set(objects.map((o) => o.id));
76
+ }
77
+ finally {
78
+ this.loading = false;
79
+ }
80
+ }
81
+ /**
82
+ * Stop listening for updates and clean up.
83
+ */
84
+ close() {
85
+ for (const unsub of this.#unsubscribers)
86
+ unsub();
87
+ this.#unsubscribers.length = 0;
88
+ }
89
+ }
1
90
  /**
2
91
  * Minimal wrapper that adds reactive `interactions` to RoolSpace.
3
92
  * All other properties and methods are proxied to the underlying space.
@@ -87,6 +176,20 @@ class ReactiveSpaceImpl {
87
176
  // Events
88
177
  on(...args) { return this.#space.on(...args); }
89
178
  off(...args) { return this.#space.off(...args); }
179
+ // Reactive collections
180
+ /**
181
+ * Create a reactive collection that auto-updates when matching objects change.
182
+ *
183
+ * @example
184
+ * const articles = space.collection({ where: { type: 'article' } });
185
+ * // articles.objects is reactive
186
+ * // articles.loading indicates fetch status
187
+ * // articles.refresh() to manually re-fetch
188
+ * // articles.close() to stop listening
189
+ */
190
+ collection(options) {
191
+ return new ReactiveCollectionImpl(this.#space, options);
192
+ }
90
193
  // Advanced
91
194
  rename(...args) { return this.#space.rename(...args); }
92
195
  getData() { return this.#space.getData(); }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rool-dev/svelte",
3
- "version": "0.1.11-dev.1dedc51",
3
+ "version": "0.1.12-dev.f0f1757",
4
4
  "description": "Svelte 5 runes for Rool Spaces",
5
5
  "type": "module",
6
6
  "svelte": "./dist/index.js",