@rool-dev/svelte 0.1.0-dev.9257360

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 ADDED
@@ -0,0 +1,233 @@
1
+ # Rool Svelte
2
+
3
+ Svelte 5 runes for Rool Spaces. Transforms the event-based SDK into reactive state using `$state`.
4
+
5
+ **Requires Svelte 5.**
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install @rool-dev/svelte
11
+ ```
12
+
13
+ ## Quick Start
14
+
15
+ ```svelte
16
+ <script>
17
+ import { createRool } from '@rool-dev/svelte';
18
+
19
+ const rool = createRool();
20
+ rool.init();
21
+ </script>
22
+
23
+ {#if !rool.authenticated}
24
+ <button onclick={() => rool.login('My App')}>Login</button>
25
+ {:else}
26
+ <h1>My Spaces</h1>
27
+ {#each rool.spaces ?? [] as space}
28
+ <button onclick={() => rool.openSpace(space.id)}>
29
+ {space.name}
30
+ </button>
31
+ {/each}
32
+ {/if}
33
+ ```
34
+
35
+ ## API
36
+
37
+ ### Lifecycle
38
+
39
+ ```typescript
40
+ const rool = createRool();
41
+
42
+ rool.init(); // Process auth callbacks (call on app startup)
43
+ rool.login('My App'); // Redirect to login page
44
+ rool.logout(); // Clear auth state
45
+ rool.destroy(); // Clean up all resources
46
+ ```
47
+
48
+ ### Client State (Always Available)
49
+
50
+ ```svelte
51
+ <script>
52
+ // Direct property access - automatically reactive
53
+ // rool.authenticated → boolean
54
+ // rool.spaces → RoolSpaceInfo[] | undefined
55
+ // rool.spacesLoading → boolean
56
+ // rool.spacesError → Error | null
57
+ // rool.connectionState → 'connected' | 'disconnected' | 'reconnecting'
58
+ </script>
59
+
60
+ {#if rool.spacesLoading}
61
+ <p>Loading spaces...</p>
62
+ {:else if rool.spacesError}
63
+ <p>Error: {rool.spacesError.message}</p>
64
+ {:else}
65
+ {#each rool.spaces ?? [] as space}
66
+ <div>{space.name}</div>
67
+ {/each}
68
+ {/if}
69
+ ```
70
+
71
+ ### Space Lifecycle
72
+
73
+ Opening a space returns a `SpaceHandle` with reactive state and methods:
74
+
75
+ ```typescript
76
+ const space = await rool.openSpace('space-id');
77
+ const space = await rool.openSpace('space-id', { conversationId: 'my-convo' });
78
+ const space = await rool.createSpace('My New Space');
79
+
80
+ // Multiple spaces can be open at once
81
+ const spaceA = await rool.openSpace('space-a');
82
+ const spaceB = await rool.openSpace('space-b');
83
+
84
+ // Clean up
85
+ space.close();
86
+ ```
87
+
88
+ ### Space State
89
+
90
+ ```svelte
91
+ <script>
92
+ // space.info → { id, name, role }
93
+ // space.conversationId → string
94
+ // space.conversations → ConversationInfo[] | undefined
95
+ // space.conversationsLoading → boolean
96
+ // space.interactions → Interaction[]
97
+ // space.systemInstruction → string | undefined
98
+ </script>
99
+
100
+ <h1>{space.info.name}</h1>
101
+ <p>Role: {space.info.role}</p>
102
+
103
+ <!-- Conversation picker -->
104
+ <select onchange={(e) => space.setConversationId(e.target.value)}>
105
+ {#each space.conversations ?? [] as conv}
106
+ <option value={conv.id} selected={conv.id === space.conversationId}>
107
+ {conv.name ?? 'Untitled'}
108
+ </option>
109
+ {/each}
110
+ </select>
111
+
112
+ <!-- Chat messages -->
113
+ {#each space.interactions as interaction}
114
+ <div class="message">
115
+ <strong>{interaction.operation}</strong>
116
+ <p>{interaction.output}</p>
117
+ </div>
118
+ {/each}
119
+ ```
120
+
121
+ ### Object Factories
122
+
123
+ Object state is created via factory functions and cached by arguments. Each returns an `AsyncValue` with reactive `value`, `loading`, and `error` properties.
124
+
125
+ ```svelte
126
+ <script>
127
+ // Single object
128
+ const sun = space.object('sun-id');
129
+ // sun.value → RoolObject | undefined
130
+ // sun.loading → boolean
131
+ // sun.error → Error | null
132
+
133
+ // Children (objects this object links TO)
134
+ const planets = space.children('sun-id', 'hasPlanet');
135
+
136
+ // Parents (objects that link TO this object)
137
+ const stars = space.parents('earth-id', 'orbits');
138
+
139
+ // Query (manual refresh only)
140
+ const articles = space.query({ where: { type: 'article' } });
141
+ </script>
142
+
143
+ {#if sun.loading}
144
+ <p>Loading...</p>
145
+ {:else if sun.error}
146
+ <p>Error: {sun.error.message}</p>
147
+ {:else if sun.value}
148
+ <h1>{sun.value.name}</h1>
149
+ {/if}
150
+
151
+ <!-- Manual refresh -->
152
+ <button onclick={() => articles.refresh()}>Refresh</button>
153
+ ```
154
+
155
+ ### Mutations
156
+
157
+ All mutations are async and pass through to the underlying SDK.
158
+
159
+ ```typescript
160
+ // Create objects
161
+ const { object, message } = await space.createObject({
162
+ data: { type: 'article', title: 'Hello World' }
163
+ });
164
+
165
+ // Update objects
166
+ await space.updateObject(object.id, {
167
+ data: { status: 'published' }
168
+ });
169
+
170
+ // Delete objects
171
+ await space.deleteObjects([object.id]);
172
+
173
+ // Links
174
+ await space.link(sourceId, 'references', targetId);
175
+ await space.unlink(sourceId, 'references', targetId);
176
+
177
+ // AI prompt
178
+ const { message, objects } = await space.prompt(
179
+ 'Create a summary of all articles'
180
+ );
181
+
182
+ // Undo/Redo
183
+ await space.checkpoint('Before edit');
184
+ await space.updateObject(id, { data: { title: 'New title' } });
185
+ await space.undo(); // Reverts the update
186
+ await space.redo(); // Reapplies the update
187
+ ```
188
+
189
+ ### Conversation Management
190
+
191
+ ```typescript
192
+ space.setConversationId('new-convo-id');
193
+ await space.setSystemInstruction('You are a helpful assistant');
194
+ await space.renameConversation('convo-id', 'Research Thread');
195
+ await space.deleteConversation('convo-id');
196
+ ```
197
+
198
+ ## Auto-Refresh Behavior
199
+
200
+ | State | Auto-refreshes on |
201
+ |-------|-------------------|
202
+ | `object(id)` | `objectUpdated`/`objectDeleted` for that ID |
203
+ | `children(id, rel)` | `linked`/`unlinked` events + member object updates |
204
+ | `parents(id, rel)` | `linked`/`unlinked` events + member object updates |
205
+ | `query(options)` | Never (call `refresh()` manually) |
206
+ | `rool.spaces` | `spaceCreated`/`spaceDeleted`/`spaceRenamed` |
207
+ | `space.conversations` | `conversationsChanged` |
208
+ | `space.interactions` | `conversationUpdated` + `conversationIdChanged` |
209
+
210
+ ## AsyncValue Interface
211
+
212
+ Object factories return `AsyncValue` instances:
213
+
214
+ ```typescript
215
+ class AsyncValue<T> {
216
+ value: T | undefined; // The data (reactive)
217
+ loading: boolean; // Loading state (reactive)
218
+ error: Error | null; // Last error (reactive)
219
+ refresh(): Promise<void>; // Manually refresh
220
+ }
221
+ ```
222
+
223
+ ## Design Principles
224
+
225
+ 1. **Svelte 5 runes** — Uses `$state` for reactivity, no legacy stores
226
+ 2. **Direct property access** — No `$` prefix needed, just access properties
227
+ 3. **Go through the API** — Never exposes raw space data, all access via SDK methods
228
+ 4. **Auto-refresh where safe** — Object/relation state auto-refreshes; queries are manual
229
+ 5. **Caching** — Factory functions return cached instances by arguments
230
+
231
+ ## License
232
+
233
+ MIT - see [LICENSE](../../LICENSE) for details.
@@ -0,0 +1,3 @@
1
+ export { createRool, generateId } from './rool.svelte.js';
2
+ export type { Rool, SpaceHandle, SpaceInfo, AsyncValue, CreateObjectOptions, UpdateObjectOptions, RoolSpaceInfo, RoolObject, RoolUserRole, ConnectionState, ConversationInfo, Interaction, FindObjectsOptions, PromptOptions, } from './types.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +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,YAAY,EAEV,IAAI,EACJ,WAAW,EACX,SAAS,EACT,UAAU,EACV,mBAAmB,EACnB,mBAAmB,EAEnB,aAAa,EACb,UAAU,EACV,YAAY,EACZ,eAAe,EACf,gBAAgB,EAChB,WAAW,EACX,kBAAkB,EAClB,aAAa,GACd,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ // Main export
2
+ export { createRool, generateId } from './rool.svelte.js';
@@ -0,0 +1,36 @@
1
+ import { type RoolSpaceInfo, type ConnectionState } from '@rool-dev/sdk';
2
+ import { type SpaceHandle } from './space.svelte.js';
3
+ /**
4
+ * Rool client with reactive state using Svelte 5 runes.
5
+ */
6
+ declare class RoolImpl {
7
+ #private;
8
+ authenticated: boolean;
9
+ spaces: RoolSpaceInfo[] | undefined;
10
+ spacesLoading: boolean;
11
+ spacesError: Error | null;
12
+ connectionState: ConnectionState;
13
+ constructor();
14
+ init(): boolean;
15
+ login(appName: string): void;
16
+ logout(): void;
17
+ openSpace(id: string, options?: {
18
+ conversationId?: string;
19
+ }): Promise<SpaceHandle>;
20
+ createSpace(name?: string, options?: {
21
+ conversationId?: string;
22
+ }): Promise<SpaceHandle>;
23
+ refreshSpaces(): Promise<void>;
24
+ destroy(): void;
25
+ }
26
+ /**
27
+ * Create a new Rool instance.
28
+ */
29
+ export declare function createRool(): RoolImpl;
30
+ /**
31
+ * Generate a unique 6-character alphanumeric ID.
32
+ */
33
+ export declare function generateId(): string;
34
+ export type Rool = RoolImpl;
35
+ export {};
36
+ //# sourceMappingURL=rool.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rool.svelte.d.ts","sourceRoot":"","sources":["../src/rool.svelte.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,aAAa,EAAE,KAAK,eAAe,EAAE,MAAM,eAAe,CAAC;AACrF,OAAO,EAAqB,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAExE;;GAEG;AACH,cAAM,QAAQ;;IAMZ,aAAa,UAAiB;IAC9B,MAAM,8BAAkD;IACxD,aAAa,UAAiB;IAC9B,WAAW,eAA8B;IACzC,eAAe,kBAA2C;;IAsD1D,IAAI,IAAI,OAAO;IAIf,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAI5B,MAAM,IAAI,IAAI;IAYR,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,cAAc,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,WAAW,CAAC;IAelF,WAAW,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,cAAc,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,WAAW,CAAC;IAmB7F,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ9B,OAAO,IAAI,IAAI;CAahB;AAED;;GAEG;AACH,wBAAgB,UAAU,IAAI,QAAQ,CAErC;AAED;;GAEG;AACH,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAED,MAAM,MAAM,IAAI,GAAG,QAAQ,CAAC"}
@@ -0,0 +1,135 @@
1
+ import { RoolClient } from '@rool-dev/sdk';
2
+ import { createSpaceHandle } from './space.svelte.js';
3
+ /**
4
+ * Rool client with reactive state using Svelte 5 runes.
5
+ */
6
+ class RoolImpl {
7
+ #client;
8
+ #unsubscribers = [];
9
+ #openSpaces = new Set();
10
+ // Reactive state
11
+ authenticated = $state(false);
12
+ spaces = $state(undefined);
13
+ spacesLoading = $state(false);
14
+ spacesError = $state(null);
15
+ connectionState = $state('disconnected');
16
+ constructor() {
17
+ this.#client = new RoolClient();
18
+ this.#setupEventListeners();
19
+ }
20
+ #setupEventListeners() {
21
+ const onAuthStateChanged = (auth) => {
22
+ this.authenticated = auth;
23
+ if (auth) {
24
+ this.#refreshSpaces();
25
+ }
26
+ else {
27
+ this.spaces = undefined;
28
+ }
29
+ };
30
+ this.#client.on('authStateChanged', onAuthStateChanged);
31
+ this.#unsubscribers.push(() => this.#client.off('authStateChanged', onAuthStateChanged));
32
+ const onConnectionStateChanged = (state) => {
33
+ this.connectionState = state;
34
+ };
35
+ this.#client.on('connectionStateChanged', onConnectionStateChanged);
36
+ this.#unsubscribers.push(() => this.#client.off('connectionStateChanged', onConnectionStateChanged));
37
+ const onSpaceCreated = () => this.#refreshSpaces();
38
+ this.#client.on('spaceCreated', onSpaceCreated);
39
+ this.#unsubscribers.push(() => this.#client.off('spaceCreated', onSpaceCreated));
40
+ const onSpaceDeleted = () => this.#refreshSpaces();
41
+ this.#client.on('spaceDeleted', onSpaceDeleted);
42
+ this.#unsubscribers.push(() => this.#client.off('spaceDeleted', onSpaceDeleted));
43
+ const onSpaceRenamed = () => this.#refreshSpaces();
44
+ this.#client.on('spaceRenamed', onSpaceRenamed);
45
+ this.#unsubscribers.push(() => this.#client.off('spaceRenamed', onSpaceRenamed));
46
+ }
47
+ async #refreshSpaces() {
48
+ this.spacesLoading = true;
49
+ this.spacesError = null;
50
+ try {
51
+ this.spaces = await this.#client.listSpaces();
52
+ }
53
+ catch (e) {
54
+ this.spacesError = e;
55
+ }
56
+ finally {
57
+ this.spacesLoading = false;
58
+ }
59
+ }
60
+ // ===========================================================================
61
+ // Lifecycle
62
+ // ===========================================================================
63
+ init() {
64
+ return this.#client.initialize();
65
+ }
66
+ login(appName) {
67
+ this.#client.login(appName);
68
+ }
69
+ logout() {
70
+ for (const space of this.#openSpaces) {
71
+ space.close();
72
+ }
73
+ this.#openSpaces.clear();
74
+ this.#client.logout();
75
+ }
76
+ // ===========================================================================
77
+ // Space Lifecycle
78
+ // ===========================================================================
79
+ async openSpace(id, options) {
80
+ const sdkSpace = await this.#client.openSpace(id, options);
81
+ const handle = createSpaceHandle(sdkSpace);
82
+ this.#openSpaces.add(handle);
83
+ // Track when closed
84
+ const originalClose = handle.close.bind(handle);
85
+ handle.close = () => {
86
+ this.#openSpaces.delete(handle);
87
+ originalClose();
88
+ };
89
+ return handle;
90
+ }
91
+ async createSpace(name, options) {
92
+ const sdkSpace = await this.#client.createSpace(name, options);
93
+ const handle = createSpaceHandle(sdkSpace);
94
+ this.#openSpaces.add(handle);
95
+ // Track when closed
96
+ const originalClose = handle.close.bind(handle);
97
+ handle.close = () => {
98
+ this.#openSpaces.delete(handle);
99
+ originalClose();
100
+ };
101
+ return handle;
102
+ }
103
+ // ===========================================================================
104
+ // Spaces management
105
+ // ===========================================================================
106
+ refreshSpaces() {
107
+ return this.#refreshSpaces();
108
+ }
109
+ // ===========================================================================
110
+ // Cleanup
111
+ // ===========================================================================
112
+ destroy() {
113
+ for (const space of this.#openSpaces) {
114
+ space.close();
115
+ }
116
+ this.#openSpaces.clear();
117
+ for (const unsub of this.#unsubscribers) {
118
+ unsub();
119
+ }
120
+ this.#unsubscribers.length = 0;
121
+ this.#client.destroy();
122
+ }
123
+ }
124
+ /**
125
+ * Create a new Rool instance.
126
+ */
127
+ export function createRool() {
128
+ return new RoolImpl();
129
+ }
130
+ /**
131
+ * Generate a unique 6-character alphanumeric ID.
132
+ */
133
+ export function generateId() {
134
+ return RoolClient.generateId();
135
+ }
@@ -0,0 +1,72 @@
1
+ import type { RoolSpace, RoolObject, ConversationInfo, Interaction, FindObjectsOptions, PromptOptions, RoolUserRole } from '@rool-dev/sdk';
2
+ export interface SpaceInfo {
3
+ id: string;
4
+ name: string;
5
+ role: RoolUserRole;
6
+ }
7
+ export interface CreateObjectOptions {
8
+ data: Record<string, unknown>;
9
+ prompt?: string;
10
+ ephemeral?: boolean;
11
+ }
12
+ export interface UpdateObjectOptions {
13
+ data?: Record<string, unknown>;
14
+ prompt?: string;
15
+ ephemeral?: boolean;
16
+ }
17
+ export declare class AsyncValue<T> {
18
+ #private;
19
+ value: T | undefined;
20
+ loading: boolean;
21
+ error: Error | null;
22
+ constructor(fetcher: () => Promise<T>, fetchOnCreate?: boolean);
23
+ refresh(): Promise<void>;
24
+ set(value: T | undefined): void;
25
+ clear(): void;
26
+ }
27
+ declare class SpaceHandleImpl {
28
+ #private;
29
+ info: SpaceInfo;
30
+ conversationId: string;
31
+ conversations: ConversationInfo[] | undefined;
32
+ conversationsLoading: boolean;
33
+ conversationsError: Error | null;
34
+ interactions: Interaction[];
35
+ systemInstruction: string | undefined;
36
+ constructor(space: RoolSpace);
37
+ setConversationId(id: string): void;
38
+ setSystemInstruction(instruction: string | null): Promise<void>;
39
+ refreshConversations(): Promise<void>;
40
+ object(id: string): AsyncValue<RoolObject>;
41
+ children(id: string, relation: string): AsyncValue<RoolObject[]>;
42
+ parents(id: string, relation: string): AsyncValue<RoolObject[]>;
43
+ query(options: FindObjectsOptions): AsyncValue<RoolObject[]>;
44
+ createObject(options: CreateObjectOptions): Promise<{
45
+ object: RoolObject;
46
+ message: string;
47
+ }>;
48
+ updateObject(objectId: string, options: UpdateObjectOptions): Promise<{
49
+ object: RoolObject;
50
+ message: string;
51
+ }>;
52
+ deleteObjects(objectIds: string[]): Promise<void>;
53
+ link(sourceId: string, relation: string, targetId: string): Promise<void>;
54
+ unlink(sourceId: string, relation?: string, targetId?: string): Promise<boolean>;
55
+ prompt(text: string, options?: PromptOptions): Promise<{
56
+ message: string;
57
+ objects: RoolObject[];
58
+ }>;
59
+ checkpoint(label?: string): Promise<string>;
60
+ undo(): Promise<boolean>;
61
+ redo(): Promise<boolean>;
62
+ deleteConversation(conversationId?: string): Promise<void>;
63
+ renameConversation(conversationId: string, name: string): Promise<void>;
64
+ close(): void;
65
+ }
66
+ /**
67
+ * Create a SpaceHandle from a RoolSpace instance.
68
+ */
69
+ export declare function createSpaceHandle(space: RoolSpace): SpaceHandle;
70
+ export type SpaceHandle = SpaceHandleImpl;
71
+ export {};
72
+ //# sourceMappingURL=space.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"space.svelte.d.ts","sourceRoot":"","sources":["../src/space.svelte.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,SAAS,EACT,UAAU,EACV,gBAAgB,EAChB,WAAW,EACX,kBAAkB,EAClB,aAAa,EACb,YAAY,EACb,MAAM,eAAe,CAAC;AAMvB,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,YAAY,CAAC;CACpB;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAMD,qBAAa,UAAU,CAAC,CAAC;;IACvB,KAAK,gBAAoC;IACzC,OAAO,UAAiB;IACxB,KAAK,eAA8B;gBAIvB,OAAO,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAAE,aAAa,UAAO;IAOrD,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAY9B,GAAG,CAAC,KAAK,EAAE,CAAC,GAAG,SAAS,GAAG,IAAI;IAK/B,KAAK,IAAI,IAAI;CAKd;AAMD,cAAM,eAAe;;IAWnB,IAAI,YAA2D;IAC/D,cAAc,SAAc;IAC5B,aAAa,iCAAqD;IAClE,oBAAoB,UAAiB;IACrC,kBAAkB,eAA8B;IAChD,YAAY,gBAA6B;IACzC,iBAAiB,qBAAyC;gBAE9C,KAAK,EAAE,SAAS;IAiJ5B,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAO7B,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAKrE,oBAAoB,IAAI,OAAO,CAAC,IAAI,CAAC;IAQrC,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,UAAU,CAAC,UAAU,CAAC;IAc1C,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,UAAU,CAAC,UAAU,EAAE,CAAC;IAWhE,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,UAAU,CAAC,UAAU,EAAE,CAAC;IAW/D,KAAK,CAAC,OAAO,EAAE,kBAAkB,GAAG,UAAU,CAAC,UAAU,EAAE,CAAC;IAkB5D,YAAY,CAAC,OAAO,EAAE,mBAAmB;;;;IAIzC,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,mBAAmB;;;;IAI3D,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE;IAIjC,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;IAIzD,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM;IAI7D,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa;;;;IAI5C,UAAU,CAAC,KAAK,CAAC,EAAE,MAAM;IAIzB,IAAI;IAIJ,IAAI;IAQJ,kBAAkB,CAAC,cAAc,CAAC,EAAE,MAAM;IAI1C,kBAAkB,CAAC,cAAc,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;IAQvD,KAAK,IAAI,IAAI;CA4Bd;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,SAAS,GAAG,WAAW,CAE/D;AAED,MAAM,MAAM,WAAW,GAAG,eAAe,CAAC"}
@@ -0,0 +1,318 @@
1
+ // ===========================================================================
2
+ // AsyncValue - reactive async data wrapper
3
+ // ===========================================================================
4
+ export class AsyncValue {
5
+ value = $state(undefined);
6
+ loading = $state(false);
7
+ error = $state(null);
8
+ #fetcher;
9
+ constructor(fetcher, fetchOnCreate = true) {
10
+ this.#fetcher = fetcher;
11
+ if (fetchOnCreate) {
12
+ this.refresh();
13
+ }
14
+ }
15
+ async refresh() {
16
+ this.loading = true;
17
+ this.error = null;
18
+ try {
19
+ this.value = await this.#fetcher();
20
+ }
21
+ catch (e) {
22
+ this.error = e;
23
+ }
24
+ finally {
25
+ this.loading = false;
26
+ }
27
+ }
28
+ set(value) {
29
+ this.value = value;
30
+ this.error = null;
31
+ }
32
+ clear() {
33
+ this.value = undefined;
34
+ this.loading = false;
35
+ this.error = null;
36
+ }
37
+ }
38
+ // ===========================================================================
39
+ // SpaceHandle - reactive space wrapper
40
+ // ===========================================================================
41
+ class SpaceHandleImpl {
42
+ #space;
43
+ #unsubscribers = [];
44
+ // Store caches
45
+ #objectCache = new Map();
46
+ #childrenCache = new Map();
47
+ #parentsCache = new Map();
48
+ #queryCache = new Map();
49
+ // Reactive state
50
+ info = $state({ id: '', name: '', role: 'viewer' });
51
+ conversationId = $state('');
52
+ conversations = $state(undefined);
53
+ conversationsLoading = $state(false);
54
+ conversationsError = $state(null);
55
+ interactions = $state([]);
56
+ systemInstruction = $state(undefined);
57
+ constructor(space) {
58
+ this.#space = space;
59
+ // Initialize state
60
+ this.info = {
61
+ id: space.id,
62
+ name: space.name,
63
+ role: space.role,
64
+ };
65
+ this.conversationId = space.conversationId;
66
+ this.interactions = space.getInteractions();
67
+ this.systemInstruction = space.getSystemInstruction();
68
+ // Initial fetches
69
+ this.#refreshConversations();
70
+ // Setup event listeners
71
+ this.#setupEventListeners();
72
+ }
73
+ #setupEventListeners() {
74
+ // Object events
75
+ const onObjectCreated = (event) => {
76
+ const store = this.#objectCache.get(event.objectId);
77
+ if (store) {
78
+ store.set(event.object);
79
+ }
80
+ };
81
+ this.#space.on('objectCreated', onObjectCreated);
82
+ this.#unsubscribers.push(() => this.#space.off('objectCreated', onObjectCreated));
83
+ const onObjectUpdated = (event) => {
84
+ const store = this.#objectCache.get(event.objectId);
85
+ if (store) {
86
+ store.set(event.object);
87
+ }
88
+ this.#refreshRelationStoresForObject(event.objectId);
89
+ };
90
+ this.#space.on('objectUpdated', onObjectUpdated);
91
+ this.#unsubscribers.push(() => this.#space.off('objectUpdated', onObjectUpdated));
92
+ const onObjectDeleted = (event) => {
93
+ const store = this.#objectCache.get(event.objectId);
94
+ if (store) {
95
+ store.set(undefined);
96
+ }
97
+ this.#refreshRelationStoresForObject(event.objectId);
98
+ };
99
+ this.#space.on('objectDeleted', onObjectDeleted);
100
+ this.#unsubscribers.push(() => this.#space.off('objectDeleted', onObjectDeleted));
101
+ // Link events
102
+ const onLinked = (event) => {
103
+ const childrenKey = JSON.stringify([event.sourceId, event.relation]);
104
+ this.#childrenCache.get(childrenKey)?.refresh();
105
+ const parentsKey = JSON.stringify([event.targetId, event.relation]);
106
+ this.#parentsCache.get(parentsKey)?.refresh();
107
+ };
108
+ this.#space.on('linked', onLinked);
109
+ this.#unsubscribers.push(() => this.#space.off('linked', onLinked));
110
+ const onUnlinked = (event) => {
111
+ const childrenKey = JSON.stringify([event.sourceId, event.relation]);
112
+ this.#childrenCache.get(childrenKey)?.refresh();
113
+ const parentsKey = JSON.stringify([event.targetId, event.relation]);
114
+ this.#parentsCache.get(parentsKey)?.refresh();
115
+ };
116
+ this.#space.on('unlinked', onUnlinked);
117
+ this.#unsubscribers.push(() => this.#space.off('unlinked', onUnlinked));
118
+ // Conversation events
119
+ const onConversationUpdated = (event) => {
120
+ if (event.conversationId === this.conversationId) {
121
+ this.interactions = this.#space.getInteractions();
122
+ this.systemInstruction = this.#space.getSystemInstruction();
123
+ }
124
+ };
125
+ this.#space.on('conversationUpdated', onConversationUpdated);
126
+ this.#unsubscribers.push(() => this.#space.off('conversationUpdated', onConversationUpdated));
127
+ const onConversationsChanged = () => {
128
+ this.#refreshConversations();
129
+ };
130
+ this.#space.on('conversationsChanged', onConversationsChanged);
131
+ this.#unsubscribers.push(() => this.#space.off('conversationsChanged', onConversationsChanged));
132
+ const onConversationIdChanged = (event) => {
133
+ this.conversationId = event.newConversationId;
134
+ this.interactions = this.#space.getInteractions();
135
+ this.systemInstruction = this.#space.getSystemInstruction();
136
+ };
137
+ this.#space.on('conversationIdChanged', onConversationIdChanged);
138
+ this.#unsubscribers.push(() => this.#space.off('conversationIdChanged', onConversationIdChanged));
139
+ // Reset event (undo/redo, resync)
140
+ const onReset = () => {
141
+ for (const store of this.#objectCache.values()) {
142
+ store.refresh();
143
+ }
144
+ for (const store of this.#childrenCache.values()) {
145
+ store.refresh();
146
+ }
147
+ for (const store of this.#parentsCache.values()) {
148
+ store.refresh();
149
+ }
150
+ for (const store of this.#queryCache.values()) {
151
+ store.refresh();
152
+ }
153
+ this.#refreshConversations();
154
+ this.interactions = this.#space.getInteractions();
155
+ this.systemInstruction = this.#space.getSystemInstruction();
156
+ };
157
+ this.#space.on('reset', onReset);
158
+ this.#unsubscribers.push(() => this.#space.off('reset', onReset));
159
+ }
160
+ async #refreshConversations() {
161
+ this.conversationsLoading = true;
162
+ this.conversationsError = null;
163
+ try {
164
+ this.conversations = await this.#space.listConversations();
165
+ }
166
+ catch (e) {
167
+ this.conversationsError = e;
168
+ }
169
+ finally {
170
+ this.conversationsLoading = false;
171
+ }
172
+ }
173
+ #refreshRelationStoresForObject(objectId) {
174
+ for (const store of this.#childrenCache.values()) {
175
+ if (store.value?.some((obj) => obj.id === objectId)) {
176
+ store.refresh();
177
+ }
178
+ }
179
+ for (const store of this.#parentsCache.values()) {
180
+ if (store.value?.some((obj) => obj.id === objectId)) {
181
+ store.refresh();
182
+ }
183
+ }
184
+ }
185
+ // ===========================================================================
186
+ // Conversation management
187
+ // ===========================================================================
188
+ setConversationId(id) {
189
+ if (id !== this.conversationId) {
190
+ this.#space.conversationId = id;
191
+ // Note: conversationIdChanged event will update our state
192
+ }
193
+ }
194
+ async setSystemInstruction(instruction) {
195
+ await this.#space.setSystemInstruction(instruction);
196
+ this.systemInstruction = instruction ?? undefined;
197
+ }
198
+ refreshConversations() {
199
+ return this.#refreshConversations();
200
+ }
201
+ // ===========================================================================
202
+ // Object store factories
203
+ // ===========================================================================
204
+ object(id) {
205
+ const cached = this.#objectCache.get(id);
206
+ if (cached)
207
+ return cached;
208
+ const store = new AsyncValue(async () => {
209
+ const obj = await this.#space.getObject(id);
210
+ if (!obj)
211
+ throw new Error(`Object not found: ${id}`);
212
+ return obj;
213
+ });
214
+ this.#objectCache.set(id, store);
215
+ return store;
216
+ }
217
+ children(id, relation) {
218
+ const key = JSON.stringify([id, relation]);
219
+ const cached = this.#childrenCache.get(key);
220
+ if (cached)
221
+ return cached;
222
+ const store = new AsyncValue(() => this.#space.getChildren(id, relation));
223
+ this.#childrenCache.set(key, store);
224
+ return store;
225
+ }
226
+ parents(id, relation) {
227
+ const key = JSON.stringify([id, relation]);
228
+ const cached = this.#parentsCache.get(key);
229
+ if (cached)
230
+ return cached;
231
+ const store = new AsyncValue(() => this.#space.getParents(id, relation));
232
+ this.#parentsCache.set(key, store);
233
+ return store;
234
+ }
235
+ query(options) {
236
+ const key = JSON.stringify(options);
237
+ const cached = this.#queryCache.get(key);
238
+ if (cached)
239
+ return cached;
240
+ const store = new AsyncValue(async () => {
241
+ const result = await this.#space.findObjects(options);
242
+ return result.objects;
243
+ });
244
+ this.#queryCache.set(key, store);
245
+ return store;
246
+ }
247
+ // ===========================================================================
248
+ // Mutations (passthrough to SDK)
249
+ // ===========================================================================
250
+ createObject(options) {
251
+ return this.#space.createObject(options);
252
+ }
253
+ updateObject(objectId, options) {
254
+ return this.#space.updateObject(objectId, options);
255
+ }
256
+ deleteObjects(objectIds) {
257
+ return this.#space.deleteObjects(objectIds);
258
+ }
259
+ link(sourceId, relation, targetId) {
260
+ return this.#space.link(sourceId, relation, targetId);
261
+ }
262
+ unlink(sourceId, relation, targetId) {
263
+ return this.#space.unlink(sourceId, relation, targetId);
264
+ }
265
+ prompt(text, options) {
266
+ return this.#space.prompt(text, options);
267
+ }
268
+ checkpoint(label) {
269
+ return this.#space.checkpoint(label);
270
+ }
271
+ undo() {
272
+ return this.#space.undo();
273
+ }
274
+ redo() {
275
+ return this.#space.redo();
276
+ }
277
+ // ===========================================================================
278
+ // Conversation management (passthrough)
279
+ // ===========================================================================
280
+ deleteConversation(conversationId) {
281
+ return this.#space.deleteConversation(conversationId);
282
+ }
283
+ renameConversation(conversationId, name) {
284
+ return this.#space.renameConversation(conversationId, name);
285
+ }
286
+ // ===========================================================================
287
+ // Cleanup
288
+ // ===========================================================================
289
+ close() {
290
+ for (const unsub of this.#unsubscribers) {
291
+ unsub();
292
+ }
293
+ this.#unsubscribers.length = 0;
294
+ for (const store of this.#objectCache.values()) {
295
+ store.clear();
296
+ }
297
+ this.#objectCache.clear();
298
+ for (const store of this.#childrenCache.values()) {
299
+ store.clear();
300
+ }
301
+ this.#childrenCache.clear();
302
+ for (const store of this.#parentsCache.values()) {
303
+ store.clear();
304
+ }
305
+ this.#parentsCache.clear();
306
+ for (const store of this.#queryCache.values()) {
307
+ store.clear();
308
+ }
309
+ this.#queryCache.clear();
310
+ this.#space.close();
311
+ }
312
+ }
313
+ /**
314
+ * Create a SpaceHandle from a RoolSpace instance.
315
+ */
316
+ export function createSpaceHandle(space) {
317
+ return new SpaceHandleImpl(space);
318
+ }
@@ -0,0 +1,4 @@
1
+ export type { RoolSpaceInfo, RoolObject, RoolUserRole, ConnectionState, ConversationInfo, Interaction, FindObjectsOptions, PromptOptions, } from '@rool-dev/sdk';
2
+ export type { Rool } from './rool.svelte.js';
3
+ export type { SpaceHandle, SpaceInfo, AsyncValue, CreateObjectOptions, UpdateObjectOptions } from './space.svelte.js';
4
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AACA,YAAY,EACV,aAAa,EACb,UAAU,EACV,YAAY,EACZ,eAAe,EACf,gBAAgB,EAChB,WAAW,EACX,kBAAkB,EAClB,aAAa,GACd,MAAM,eAAe,CAAC;AAGvB,YAAY,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC7C,YAAY,EAAE,WAAW,EAAE,SAAS,EAAE,UAAU,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC"}
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
package/package.json ADDED
@@ -0,0 +1,62 @@
1
+ {
2
+ "name": "@rool-dev/svelte",
3
+ "version": "0.1.0-dev.9257360",
4
+ "description": "Svelte 5 runes for Rool Spaces",
5
+ "packageManager": "pnpm@10.17.1",
6
+ "type": "module",
7
+ "svelte": "./dist/index.js",
8
+ "main": "./dist/index.js",
9
+ "module": "./dist/index.js",
10
+ "types": "./dist/index.d.ts",
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "svelte": "./dist/index.js",
15
+ "default": "./dist/index.js"
16
+ }
17
+ },
18
+ "files": [
19
+ "dist"
20
+ ],
21
+ "scripts": {
22
+ "build": "svelte-package -i src -o dist",
23
+ "dev": "svelte-package -i src -o dist --watch",
24
+ "typecheck": "svelte-check --tsconfig ./tsconfig.json",
25
+ "clean": "rm -rf dist"
26
+ },
27
+ "publishConfig": {
28
+ "access": "public"
29
+ },
30
+ "homepage": "https://docs.rool.dev/svelte",
31
+ "repository": {
32
+ "type": "git",
33
+ "url": "git+https://github.com/rool-dev/rool-js.git",
34
+ "directory": "packages/svelte"
35
+ },
36
+ "keywords": [
37
+ "rool",
38
+ "svelte",
39
+ "svelte5",
40
+ "runes",
41
+ "reactive",
42
+ "real-time"
43
+ ],
44
+ "author": {
45
+ "name": "Rool Limited",
46
+ "email": "info@rool.dev",
47
+ "url": "https://rool.dev"
48
+ },
49
+ "license": "MIT",
50
+ "dependencies": {
51
+ "@rool-dev/sdk": "workspace:*"
52
+ },
53
+ "peerDependencies": {
54
+ "svelte": "^5.0.0"
55
+ },
56
+ "devDependencies": {
57
+ "@sveltejs/package": "^2.0.0",
58
+ "svelte": "^5.0.0",
59
+ "svelte-check": "^4.0.0",
60
+ "typescript": "^5.9.3"
61
+ }
62
+ }