@rool-dev/svelte 0.11.3 → 0.11.4
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 +91 -122
- package/dist/index.d.ts +2 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -1
- package/dist/rool.svelte.d.ts +1 -10
- package/dist/rool.svelte.d.ts.map +1 -1
- package/dist/rool.svelte.js +1 -12
- package/dist/space-session.svelte.d.ts +82 -0
- package/dist/space-session.svelte.d.ts.map +1 -0
- package/dist/space-session.svelte.js +191 -0
- package/dist/space.svelte.d.ts +27 -16
- package/dist/space.svelte.d.ts.map +1 -1
- package/dist/space.svelte.js +36 -39
- package/package.json +2 -2
- package/dist/channel.svelte.d.ts +0 -177
- package/dist/channel.svelte.d.ts.map +0 -1
- package/dist/channel.svelte.js +0 -391
package/dist/channel.svelte.js
DELETED
|
@@ -1,391 +0,0 @@
|
|
|
1
|
-
import { isObjectPath, machinePath } from '@rool-dev/sdk';
|
|
2
|
-
function objectCollection(path) {
|
|
3
|
-
if (!isObjectPath(path))
|
|
4
|
-
return undefined;
|
|
5
|
-
return path.split('/')[2];
|
|
6
|
-
}
|
|
7
|
-
function eventTouchesObject(event, objectPath, collection) {
|
|
8
|
-
if (event.reset)
|
|
9
|
-
return true;
|
|
10
|
-
for (const path of [...event.changedPaths, ...event.deletedPaths]) {
|
|
11
|
-
if (objectPath && path === objectPath)
|
|
12
|
-
return true;
|
|
13
|
-
if (!objectPath && isObjectPath(path)) {
|
|
14
|
-
if (!collection || objectCollection(path) === collection)
|
|
15
|
-
return true;
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
return false;
|
|
19
|
-
}
|
|
20
|
-
function sameJsonValue(a, b) {
|
|
21
|
-
return JSON.stringify(a) === JSON.stringify(b);
|
|
22
|
-
}
|
|
23
|
-
async function watchObjectsFromTree(channel, fileTree, options) {
|
|
24
|
-
if (fileTree.loading)
|
|
25
|
-
await fileTree.ready();
|
|
26
|
-
const paths = fileTree.objectPaths({ collection: options.collection, order: options.order });
|
|
27
|
-
const objects = [];
|
|
28
|
-
for (const path of paths) {
|
|
29
|
-
const object = await channel.getObject(path);
|
|
30
|
-
if (!object)
|
|
31
|
-
continue;
|
|
32
|
-
if (options.where) {
|
|
33
|
-
let matches = true;
|
|
34
|
-
for (const [key, value] of Object.entries(options.where)) {
|
|
35
|
-
if (!sameJsonValue(object.body[key], value)) {
|
|
36
|
-
matches = false;
|
|
37
|
-
break;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
if (!matches)
|
|
41
|
-
continue;
|
|
42
|
-
}
|
|
43
|
-
objects.push(object);
|
|
44
|
-
if (options.limit !== undefined && objects.length >= options.limit)
|
|
45
|
-
break;
|
|
46
|
-
}
|
|
47
|
-
return objects;
|
|
48
|
-
}
|
|
49
|
-
/**
|
|
50
|
-
* A reactive watch of objects that auto-updates when matching object files change.
|
|
51
|
-
*/
|
|
52
|
-
class ReactiveWatchImpl {
|
|
53
|
-
#channel;
|
|
54
|
-
#fileTree;
|
|
55
|
-
#options;
|
|
56
|
-
#unsubscribers = [];
|
|
57
|
-
// Reactive state
|
|
58
|
-
objects = $state([]);
|
|
59
|
-
loading = $state(true);
|
|
60
|
-
constructor(channel, fileTree, options) {
|
|
61
|
-
this.#channel = channel;
|
|
62
|
-
this.#fileTree = fileTree;
|
|
63
|
-
this.#options = options;
|
|
64
|
-
this.#setup();
|
|
65
|
-
}
|
|
66
|
-
#setup() {
|
|
67
|
-
this.refresh();
|
|
68
|
-
const unsubscribe = this.#fileTree.subscribe((event) => {
|
|
69
|
-
if (eventTouchesObject(event, undefined, this.#options.collection))
|
|
70
|
-
void this.refresh();
|
|
71
|
-
});
|
|
72
|
-
this.#unsubscribers.push(unsubscribe);
|
|
73
|
-
}
|
|
74
|
-
/** Re-fetch matching objects using the canonical file tree for paths. */
|
|
75
|
-
async refresh() {
|
|
76
|
-
this.loading = true;
|
|
77
|
-
try {
|
|
78
|
-
this.objects = await watchObjectsFromTree(this.#channel, this.#fileTree, this.#options);
|
|
79
|
-
}
|
|
80
|
-
finally {
|
|
81
|
-
this.loading = false;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
close() {
|
|
85
|
-
for (const unsub of this.#unsubscribers)
|
|
86
|
-
unsub();
|
|
87
|
-
this.#unsubscribers.length = 0;
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
/**
|
|
91
|
-
* A reactive single object that auto-updates when the object changes.
|
|
92
|
-
*/
|
|
93
|
-
class ReactiveObjectImpl {
|
|
94
|
-
#channel;
|
|
95
|
-
#fileTree;
|
|
96
|
-
#path;
|
|
97
|
-
#unsubscribers = [];
|
|
98
|
-
// Reactive state
|
|
99
|
-
data = $state(undefined);
|
|
100
|
-
loading = $state(true);
|
|
101
|
-
constructor(channel, fileTree, path) {
|
|
102
|
-
this.#channel = channel;
|
|
103
|
-
this.#fileTree = fileTree;
|
|
104
|
-
this.#path = machinePath(path);
|
|
105
|
-
this.#setup();
|
|
106
|
-
}
|
|
107
|
-
#setup() {
|
|
108
|
-
this.refresh();
|
|
109
|
-
const unsubscribe = this.#fileTree.subscribe((event) => {
|
|
110
|
-
if (event.deletedPaths.has(this.#path)) {
|
|
111
|
-
this.data = undefined;
|
|
112
|
-
return;
|
|
113
|
-
}
|
|
114
|
-
if (eventTouchesObject(event, this.#path))
|
|
115
|
-
void this.refresh();
|
|
116
|
-
});
|
|
117
|
-
this.#unsubscribers.push(unsubscribe);
|
|
118
|
-
}
|
|
119
|
-
async refresh() {
|
|
120
|
-
this.loading = true;
|
|
121
|
-
try {
|
|
122
|
-
this.data = await this.#channel.getObject(this.#path);
|
|
123
|
-
}
|
|
124
|
-
finally {
|
|
125
|
-
this.loading = false;
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
close() {
|
|
129
|
-
for (const unsub of this.#unsubscribers)
|
|
130
|
-
unsub();
|
|
131
|
-
this.#unsubscribers.length = 0;
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
// ---------------------------------------------------------------------------
|
|
135
|
-
// ReactiveConversationHandle
|
|
136
|
-
// ---------------------------------------------------------------------------
|
|
137
|
-
class ReactiveConversationHandleImpl {
|
|
138
|
-
#handle;
|
|
139
|
-
#conversationId;
|
|
140
|
-
#unsubscribers = [];
|
|
141
|
-
// Reactive state
|
|
142
|
-
interactions = $state([]);
|
|
143
|
-
constructor(channel, conversationId) {
|
|
144
|
-
this.#conversationId = conversationId;
|
|
145
|
-
this.#handle = channel.conversation(conversationId);
|
|
146
|
-
this.interactions = this.#handle.getInteractions();
|
|
147
|
-
const onConversationUpdated = (event) => {
|
|
148
|
-
if (event.conversationId === this.#conversationId) {
|
|
149
|
-
this.interactions = this.#handle.getInteractions();
|
|
150
|
-
}
|
|
151
|
-
};
|
|
152
|
-
channel.on('conversationUpdated', onConversationUpdated);
|
|
153
|
-
this.#unsubscribers.push(() => channel.off('conversationUpdated', onConversationUpdated));
|
|
154
|
-
const onReset = () => {
|
|
155
|
-
this.interactions = this.#handle.getInteractions();
|
|
156
|
-
};
|
|
157
|
-
channel.on('reset', onReset);
|
|
158
|
-
this.#unsubscribers.push(() => channel.off('reset', onReset));
|
|
159
|
-
}
|
|
160
|
-
get conversationId() { return this.#conversationId; }
|
|
161
|
-
// Conversation history
|
|
162
|
-
getInteractions() { return this.#handle.getInteractions(); }
|
|
163
|
-
getTree() { return this.#handle.getTree(); }
|
|
164
|
-
get activeLeafId() { return this.#handle.activeLeafId; }
|
|
165
|
-
setActiveLeaf(interactionId) { this.#handle.setActiveLeaf(interactionId); }
|
|
166
|
-
getSystemInstruction() { return this.#handle.getSystemInstruction(); }
|
|
167
|
-
setSystemInstruction(...args) { return this.#handle.setSystemInstruction(...args); }
|
|
168
|
-
rename(...args) { return this.#handle.rename(...args); }
|
|
169
|
-
// Object operations
|
|
170
|
-
putObject(...args) { return this.#handle.putObject(...args); }
|
|
171
|
-
patchObject(...args) { return this.#handle.patchObject(...args); }
|
|
172
|
-
moveObject(...args) { return this.#handle.moveObject(...args); }
|
|
173
|
-
deleteObjects(...args) { return this.#handle.deleteObjects(...args); }
|
|
174
|
-
/** @deprecated Use deleteObjects instead. */
|
|
175
|
-
deletePaths(...args) { return this.#handle.deletePaths(...args); }
|
|
176
|
-
// AI
|
|
177
|
-
prompt(...args) { return this.#handle.prompt(...args); }
|
|
178
|
-
stop() { return this.#handle.stop(); }
|
|
179
|
-
// Schema
|
|
180
|
-
createCollection(...args) { return this.#handle.createCollection(...args); }
|
|
181
|
-
alterCollection(...args) { return this.#handle.alterCollection(...args); }
|
|
182
|
-
dropCollection(...args) { return this.#handle.dropCollection(...args); }
|
|
183
|
-
// Metadata
|
|
184
|
-
setMetadata(...args) { return this.#handle.setMetadata(...args); }
|
|
185
|
-
close() {
|
|
186
|
-
for (const unsub of this.#unsubscribers)
|
|
187
|
-
unsub();
|
|
188
|
-
this.#unsubscribers.length = 0;
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
/**
|
|
192
|
-
* Minimal wrapper that adds reactive `interactions` to RoolChannel.
|
|
193
|
-
* All other properties and methods are proxied to the underlying channel.
|
|
194
|
-
*/
|
|
195
|
-
class ReactiveChannelImpl {
|
|
196
|
-
#channel;
|
|
197
|
-
#fileTree;
|
|
198
|
-
#unsubscribers = [];
|
|
199
|
-
#closed = false;
|
|
200
|
-
// Reactive state
|
|
201
|
-
interactions = $state([]);
|
|
202
|
-
objectPaths = $state([]);
|
|
203
|
-
collections = $state([]);
|
|
204
|
-
conversations = $state([]);
|
|
205
|
-
constructor(channel, fileTree) {
|
|
206
|
-
this.#channel = channel;
|
|
207
|
-
this.#fileTree = fileTree;
|
|
208
|
-
this.interactions = channel.getInteractions();
|
|
209
|
-
this.objectPaths = fileTree.objectPaths();
|
|
210
|
-
this.collections = fileTree.collections();
|
|
211
|
-
this.conversations = channel.getConversations();
|
|
212
|
-
const onChannelUpdated = () => {
|
|
213
|
-
this.interactions = channel.getInteractions();
|
|
214
|
-
this.conversations = channel.getConversations();
|
|
215
|
-
};
|
|
216
|
-
channel.on('channelUpdated', onChannelUpdated);
|
|
217
|
-
this.#unsubscribers.push(() => channel.off('channelUpdated', onChannelUpdated));
|
|
218
|
-
const onConversationUpdated = () => {
|
|
219
|
-
this.conversations = channel.getConversations();
|
|
220
|
-
};
|
|
221
|
-
channel.on('conversationUpdated', onConversationUpdated);
|
|
222
|
-
this.#unsubscribers.push(() => channel.off('conversationUpdated', onConversationUpdated));
|
|
223
|
-
const refreshFromFileTree = () => {
|
|
224
|
-
this.objectPaths = fileTree.objectPaths();
|
|
225
|
-
this.collections = fileTree.collections();
|
|
226
|
-
};
|
|
227
|
-
this.#unsubscribers.push(fileTree.subscribe((event) => {
|
|
228
|
-
if (event.reset || eventTouchesObject(event) || [...event.changedPaths, ...event.deletedPaths].some((path) => path === '/space' || path.startsWith('/space/'))) {
|
|
229
|
-
refreshFromFileTree();
|
|
230
|
-
}
|
|
231
|
-
}));
|
|
232
|
-
const onReset = () => {
|
|
233
|
-
this.interactions = channel.getInteractions();
|
|
234
|
-
refreshFromFileTree();
|
|
235
|
-
this.conversations = channel.getConversations();
|
|
236
|
-
};
|
|
237
|
-
channel.on('reset', onReset);
|
|
238
|
-
this.#unsubscribers.push(() => channel.off('reset', onReset));
|
|
239
|
-
}
|
|
240
|
-
// Proxy read-only properties
|
|
241
|
-
get id() { return this.#channel.id; }
|
|
242
|
-
get name() { return this.#channel.name; }
|
|
243
|
-
get role() { return this.#channel.role; }
|
|
244
|
-
get userId() { return this.#channel.userId; }
|
|
245
|
-
get channelId() { return this.#channel.channelId; }
|
|
246
|
-
get channelName() { return this.#channel.channelName; }
|
|
247
|
-
get isReadOnly() { return this.#channel.isReadOnly; }
|
|
248
|
-
get isClosed() { return this.#closed; }
|
|
249
|
-
close() {
|
|
250
|
-
if (this.#closed)
|
|
251
|
-
return;
|
|
252
|
-
this.#closed = true;
|
|
253
|
-
for (const unsub of this.#unsubscribers)
|
|
254
|
-
unsub();
|
|
255
|
-
this.#unsubscribers.length = 0;
|
|
256
|
-
this.#channel.close();
|
|
257
|
-
}
|
|
258
|
-
// Object operations
|
|
259
|
-
getObject(...args) { return this.#channel.getObject(...args); }
|
|
260
|
-
getObjects(...args) { return this.#channel.getObjects(...args); }
|
|
261
|
-
stat(...args) { return this.#channel.stat(...args); }
|
|
262
|
-
putObject(...args) { return this.#channel.putObject(...args); }
|
|
263
|
-
patchObject(...args) { return this.#channel.patchObject(...args); }
|
|
264
|
-
moveObject(...args) { return this.#channel.moveObject(...args); }
|
|
265
|
-
deleteObjects(...args) { return this.#channel.deleteObjects(...args); }
|
|
266
|
-
/** @deprecated Use deleteObjects instead. */
|
|
267
|
-
deletePaths(...args) { return this.#channel.deletePaths(...args); }
|
|
268
|
-
// AI
|
|
269
|
-
prompt(...args) { return this.#channel.prompt(...args); }
|
|
270
|
-
stop() { return this.#channel.stop(); }
|
|
271
|
-
stopInteraction(...args) { return this.#channel.stopInteraction(...args); }
|
|
272
|
-
// Undo/redo
|
|
273
|
-
checkpoint(...args) { return this.#channel.checkpoint(...args); }
|
|
274
|
-
canUndo() { return this.#channel.canUndo(); }
|
|
275
|
-
canRedo() { return this.#channel.canRedo(); }
|
|
276
|
-
undo() { return this.#channel.undo(); }
|
|
277
|
-
redo() { return this.#channel.redo(); }
|
|
278
|
-
clearHistory() { return this.#channel.clearHistory(); }
|
|
279
|
-
// Metadata
|
|
280
|
-
setMetadata(...args) { return this.#channel.setMetadata(...args); }
|
|
281
|
-
getMetadata(...args) { return this.#channel.getMetadata(...args); }
|
|
282
|
-
getAllMetadata() { return this.#channel.getAllMetadata(); }
|
|
283
|
-
// Channel history
|
|
284
|
-
getInteractions() { return this.#channel.getInteractions(); }
|
|
285
|
-
getTree() { return this.#channel.getTree(); }
|
|
286
|
-
get activeLeafId() { return this.#channel.activeLeafId; }
|
|
287
|
-
setActiveLeaf(interactionId) { this.#channel.setActiveLeaf(interactionId); }
|
|
288
|
-
getSystemInstruction() { return this.#channel.getSystemInstruction(); }
|
|
289
|
-
setSystemInstruction(...args) { return this.#channel.setSystemInstruction(...args); }
|
|
290
|
-
getConversations() { return this.#channel.getConversations(); }
|
|
291
|
-
deleteConversation(...args) { return this.#channel.deleteConversation(...args); }
|
|
292
|
-
renameConversation(...args) { return this.#channel.renameConversation(...args); }
|
|
293
|
-
// Schema
|
|
294
|
-
getSchema() { return this.#channel.getSchema(); }
|
|
295
|
-
createCollection(...args) { return this.#channel.createCollection(...args); }
|
|
296
|
-
alterCollection(...args) { return this.#channel.alterCollection(...args); }
|
|
297
|
-
dropCollection(...args) { return this.#channel.dropCollection(...args); }
|
|
298
|
-
// Proxied fetch
|
|
299
|
-
fetch(...args) { return this.#channel.fetch(...args); }
|
|
300
|
-
// Channel admin
|
|
301
|
-
rename(...args) { return this.#channel.rename(...args); }
|
|
302
|
-
// Conversations
|
|
303
|
-
conversation(conversationId) {
|
|
304
|
-
if (this.#closed)
|
|
305
|
-
throw new Error('Cannot create reactive conversation: channel is closed');
|
|
306
|
-
return new ReactiveConversationHandleImpl(this.#channel, conversationId);
|
|
307
|
-
}
|
|
308
|
-
// Events
|
|
309
|
-
on(...args) { return this.#channel.on(...args); }
|
|
310
|
-
off(...args) { return this.#channel.off(...args); }
|
|
311
|
-
// Reactive primitives
|
|
312
|
-
/**
|
|
313
|
-
* Create a reactive object that auto-updates when the object at this path changes.
|
|
314
|
-
*/
|
|
315
|
-
object(path) {
|
|
316
|
-
if (this.#closed)
|
|
317
|
-
throw new Error('Cannot create reactive object: channel is closed');
|
|
318
|
-
return new ReactiveObjectImpl(this.#channel, this.#fileTree, path);
|
|
319
|
-
}
|
|
320
|
-
/**
|
|
321
|
-
* Create a reactive watch that auto-updates when matching objects change.
|
|
322
|
-
*/
|
|
323
|
-
watch(options) {
|
|
324
|
-
if (this.#closed)
|
|
325
|
-
throw new Error('Cannot create reactive watch: channel is closed');
|
|
326
|
-
return new ReactiveWatchImpl(this.#channel, this.#fileTree, options);
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
export function wrapChannel(channel, fileTree) {
|
|
330
|
-
return new ReactiveChannelImpl(channel, fileTree);
|
|
331
|
-
}
|
|
332
|
-
/**
|
|
333
|
-
* A reactive list of channels for a space that auto-updates via SSE events.
|
|
334
|
-
*/
|
|
335
|
-
class ReactiveChannelListImpl {
|
|
336
|
-
#space = null;
|
|
337
|
-
#unsubscribers = [];
|
|
338
|
-
// Reactive state
|
|
339
|
-
list = $state([]);
|
|
340
|
-
loading = $state(true);
|
|
341
|
-
constructor(spaceOrPromise) {
|
|
342
|
-
if (spaceOrPromise instanceof Promise) {
|
|
343
|
-
spaceOrPromise.then((space) => this.#attach(space)).catch(() => {
|
|
344
|
-
this.loading = false;
|
|
345
|
-
});
|
|
346
|
-
}
|
|
347
|
-
else {
|
|
348
|
-
this.#attach(spaceOrPromise);
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
#attach(space) {
|
|
352
|
-
this.#space = space;
|
|
353
|
-
this.list = space.channels;
|
|
354
|
-
this.loading = false;
|
|
355
|
-
const onChannelCreated = (channel) => {
|
|
356
|
-
this.list = [...this.list, channel];
|
|
357
|
-
};
|
|
358
|
-
space.on('channelCreated', onChannelCreated);
|
|
359
|
-
this.#unsubscribers.push(() => space.off('channelCreated', onChannelCreated));
|
|
360
|
-
const onChannelUpdated = (channel) => {
|
|
361
|
-
this.list = this.list.map(ch => ch.id === channel.id ? channel : ch);
|
|
362
|
-
};
|
|
363
|
-
space.on('channelUpdated', onChannelUpdated);
|
|
364
|
-
this.#unsubscribers.push(() => space.off('channelUpdated', onChannelUpdated));
|
|
365
|
-
const onChannelDeleted = (channelId) => {
|
|
366
|
-
this.list = this.list.filter(ch => ch.id !== channelId);
|
|
367
|
-
};
|
|
368
|
-
space.on('channelDeleted', onChannelDeleted);
|
|
369
|
-
this.#unsubscribers.push(() => space.off('channelDeleted', onChannelDeleted));
|
|
370
|
-
}
|
|
371
|
-
async refresh() {
|
|
372
|
-
if (!this.#space)
|
|
373
|
-
return;
|
|
374
|
-
this.loading = true;
|
|
375
|
-
try {
|
|
376
|
-
await this.#space.refresh();
|
|
377
|
-
this.list = this.#space.channels;
|
|
378
|
-
}
|
|
379
|
-
finally {
|
|
380
|
-
this.loading = false;
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
close() {
|
|
384
|
-
for (const unsub of this.#unsubscribers)
|
|
385
|
-
unsub();
|
|
386
|
-
this.#unsubscribers.length = 0;
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
export function createChannelList(spaceOrPromise) {
|
|
390
|
-
return new ReactiveChannelListImpl(spaceOrPromise);
|
|
391
|
-
}
|