@rool-dev/svelte 0.10.2 → 0.11.0-dev.59f195f
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 +134 -88
- package/dist/channel.svelte.d.ts +23 -27
- package/dist/channel.svelte.d.ts.map +1 -1
- package/dist/channel.svelte.js +106 -171
- package/dist/file-tree.svelte.d.ts +91 -0
- package/dist/file-tree.svelte.d.ts.map +1 -0
- package/dist/file-tree.svelte.js +399 -0
- package/dist/index.d.ts +4 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/rool.svelte.d.ts +22 -22
- package/dist/rool.svelte.d.ts.map +1 -1
- package/dist/rool.svelte.js +33 -39
- package/dist/space.svelte.d.ts +3 -2
- package/dist/space.svelte.d.ts.map +1 -1
- package/dist/space.svelte.js +7 -3
- package/package.json +2 -2
package/dist/channel.svelte.js
CHANGED
|
@@ -1,122 +1,81 @@
|
|
|
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
|
+
}
|
|
1
49
|
/**
|
|
2
|
-
* A reactive watch of objects that auto-updates when matching
|
|
50
|
+
* A reactive watch of objects that auto-updates when matching object files change.
|
|
3
51
|
*/
|
|
4
52
|
class ReactiveWatchImpl {
|
|
5
53
|
#channel;
|
|
54
|
+
#fileTree;
|
|
6
55
|
#options;
|
|
7
56
|
#unsubscribers = [];
|
|
8
|
-
#currentLocations = new Set();
|
|
9
57
|
// Reactive state
|
|
10
58
|
objects = $state([]);
|
|
11
59
|
loading = $state(true);
|
|
12
|
-
constructor(channel, options) {
|
|
60
|
+
constructor(channel, fileTree, options) {
|
|
13
61
|
this.#channel = channel;
|
|
62
|
+
this.#fileTree = fileTree;
|
|
14
63
|
this.#options = options;
|
|
15
64
|
this.#setup();
|
|
16
65
|
}
|
|
17
66
|
#setup() {
|
|
18
|
-
// Initial fetch
|
|
19
67
|
this.refresh();
|
|
20
|
-
const
|
|
21
|
-
if (this.#
|
|
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));
|
|
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);
|
|
88
73
|
}
|
|
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
|
-
*/
|
|
74
|
+
/** Re-fetch matching objects using the canonical file tree for paths. */
|
|
107
75
|
async refresh() {
|
|
108
76
|
this.loading = true;
|
|
109
77
|
try {
|
|
110
|
-
|
|
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));
|
|
78
|
+
this.objects = await watchObjectsFromTree(this.#channel, this.#fileTree, this.#options);
|
|
120
79
|
}
|
|
121
80
|
finally {
|
|
122
81
|
this.loading = false;
|
|
@@ -133,58 +92,34 @@ class ReactiveWatchImpl {
|
|
|
133
92
|
*/
|
|
134
93
|
class ReactiveObjectImpl {
|
|
135
94
|
#channel;
|
|
136
|
-
#
|
|
95
|
+
#fileTree;
|
|
96
|
+
#path;
|
|
137
97
|
#unsubscribers = [];
|
|
138
98
|
// Reactive state
|
|
139
99
|
data = $state(undefined);
|
|
140
100
|
loading = $state(true);
|
|
141
|
-
constructor(channel,
|
|
101
|
+
constructor(channel, fileTree, path) {
|
|
142
102
|
this.#channel = channel;
|
|
143
|
-
this.#
|
|
103
|
+
this.#fileTree = fileTree;
|
|
104
|
+
this.#path = machinePath(path);
|
|
144
105
|
this.#setup();
|
|
145
106
|
}
|
|
146
107
|
#setup() {
|
|
147
108
|
this.refresh();
|
|
148
|
-
const
|
|
149
|
-
if (
|
|
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.
|
|
109
|
+
const unsubscribe = this.#fileTree.subscribe((event) => {
|
|
110
|
+
if (event.deletedPaths.has(this.#path)) {
|
|
172
111
|
this.data = undefined;
|
|
112
|
+
return;
|
|
173
113
|
}
|
|
174
|
-
|
|
175
|
-
this.
|
|
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));
|
|
114
|
+
if (eventTouchesObject(event, this.#path))
|
|
115
|
+
void this.refresh();
|
|
116
|
+
});
|
|
117
|
+
this.#unsubscribers.push(unsubscribe);
|
|
183
118
|
}
|
|
184
119
|
async refresh() {
|
|
185
120
|
this.loading = true;
|
|
186
121
|
try {
|
|
187
|
-
this.data = await this.#channel.getObject(this.#
|
|
122
|
+
this.data = await this.#channel.getObject(this.#path);
|
|
188
123
|
}
|
|
189
124
|
finally {
|
|
190
125
|
this.loading = false;
|
|
@@ -232,13 +167,15 @@ class ReactiveConversationHandleImpl {
|
|
|
232
167
|
setSystemInstruction(...args) { return this.#handle.setSystemInstruction(...args); }
|
|
233
168
|
rename(...args) { return this.#handle.rename(...args); }
|
|
234
169
|
// Object operations
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
updateObject(...args) { return this.#handle.updateObject(...args); }
|
|
170
|
+
putObject(...args) { return this.#handle.putObject(...args); }
|
|
171
|
+
patchObject(...args) { return this.#handle.patchObject(...args); }
|
|
238
172
|
moveObject(...args) { return this.#handle.moveObject(...args); }
|
|
239
173
|
deleteObjects(...args) { return this.#handle.deleteObjects(...args); }
|
|
174
|
+
/** @deprecated Use deleteObjects instead. */
|
|
175
|
+
deletePaths(...args) { return this.#handle.deletePaths(...args); }
|
|
240
176
|
// AI
|
|
241
177
|
prompt(...args) { return this.#handle.prompt(...args); }
|
|
178
|
+
stop() { return this.#handle.stop(); }
|
|
242
179
|
// Schema
|
|
243
180
|
createCollection(...args) { return this.#handle.createCollection(...args); }
|
|
244
181
|
alterCollection(...args) { return this.#handle.alterCollection(...args); }
|
|
@@ -257,21 +194,24 @@ class ReactiveConversationHandleImpl {
|
|
|
257
194
|
*/
|
|
258
195
|
class ReactiveChannelImpl {
|
|
259
196
|
#channel;
|
|
197
|
+
#fileTree;
|
|
260
198
|
#unsubscribers = [];
|
|
261
199
|
#closed = false;
|
|
262
200
|
// Reactive state
|
|
263
201
|
interactions = $state([]);
|
|
264
|
-
|
|
202
|
+
objectPaths = $state([]);
|
|
265
203
|
collections = $state([]);
|
|
266
204
|
conversations = $state([]);
|
|
267
|
-
constructor(channel) {
|
|
205
|
+
constructor(channel, fileTree) {
|
|
268
206
|
this.#channel = channel;
|
|
207
|
+
this.#fileTree = fileTree;
|
|
269
208
|
this.interactions = channel.getInteractions();
|
|
270
|
-
this.
|
|
271
|
-
this.collections =
|
|
209
|
+
this.objectPaths = fileTree.objectPaths();
|
|
210
|
+
this.collections = fileTree.collections();
|
|
272
211
|
this.conversations = channel.getConversations();
|
|
273
212
|
const onChannelUpdated = () => {
|
|
274
213
|
this.interactions = channel.getInteractions();
|
|
214
|
+
this.conversations = channel.getConversations();
|
|
275
215
|
};
|
|
276
216
|
channel.on('channelUpdated', onChannelUpdated);
|
|
277
217
|
this.#unsubscribers.push(() => channel.off('channelUpdated', onChannelUpdated));
|
|
@@ -280,24 +220,18 @@ class ReactiveChannelImpl {
|
|
|
280
220
|
};
|
|
281
221
|
channel.on('conversationUpdated', onConversationUpdated);
|
|
282
222
|
this.#unsubscribers.push(() => channel.off('conversationUpdated', onConversationUpdated));
|
|
283
|
-
const
|
|
284
|
-
this.
|
|
223
|
+
const refreshFromFileTree = () => {
|
|
224
|
+
this.objectPaths = fileTree.objectPaths();
|
|
225
|
+
this.collections = fileTree.collections();
|
|
285
226
|
};
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
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));
|
|
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
|
+
}));
|
|
297
232
|
const onReset = () => {
|
|
298
233
|
this.interactions = channel.getInteractions();
|
|
299
|
-
|
|
300
|
-
this.collections = Object.keys(channel.getSchema());
|
|
234
|
+
refreshFromFileTree();
|
|
301
235
|
this.conversations = channel.getConversations();
|
|
302
236
|
};
|
|
303
237
|
channel.on('reset', onReset);
|
|
@@ -312,8 +246,6 @@ class ReactiveChannelImpl {
|
|
|
312
246
|
get channelName() { return this.#channel.channelName; }
|
|
313
247
|
get isReadOnly() { return this.#channel.isReadOnly; }
|
|
314
248
|
get linkAccess() { return this.#channel.linkAccess; }
|
|
315
|
-
get extensionUrl() { return this.#channel.extensionUrl; }
|
|
316
|
-
get manifest() { return this.#channel.manifest; }
|
|
317
249
|
get isClosed() { return this.#closed; }
|
|
318
250
|
close() {
|
|
319
251
|
if (this.#closed)
|
|
@@ -326,15 +258,18 @@ class ReactiveChannelImpl {
|
|
|
326
258
|
}
|
|
327
259
|
// Object operations
|
|
328
260
|
getObject(...args) { return this.#channel.getObject(...args); }
|
|
261
|
+
getObjects(...args) { return this.#channel.getObjects(...args); }
|
|
329
262
|
stat(...args) { return this.#channel.stat(...args); }
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
createObject(...args) { return this.#channel.createObject(...args); }
|
|
333
|
-
updateObject(...args) { return this.#channel.updateObject(...args); }
|
|
263
|
+
putObject(...args) { return this.#channel.putObject(...args); }
|
|
264
|
+
patchObject(...args) { return this.#channel.patchObject(...args); }
|
|
334
265
|
moveObject(...args) { return this.#channel.moveObject(...args); }
|
|
335
266
|
deleteObjects(...args) { return this.#channel.deleteObjects(...args); }
|
|
267
|
+
/** @deprecated Use deleteObjects instead. */
|
|
268
|
+
deletePaths(...args) { return this.#channel.deletePaths(...args); }
|
|
336
269
|
// AI
|
|
337
270
|
prompt(...args) { return this.#channel.prompt(...args); }
|
|
271
|
+
stop() { return this.#channel.stop(); }
|
|
272
|
+
stopInteraction(...args) { return this.#channel.stopInteraction(...args); }
|
|
338
273
|
// Undo/redo
|
|
339
274
|
checkpoint(...args) { return this.#channel.checkpoint(...args); }
|
|
340
275
|
canUndo() { return this.#channel.canUndo(); }
|
|
@@ -376,12 +311,12 @@ class ReactiveChannelImpl {
|
|
|
376
311
|
off(...args) { return this.#channel.off(...args); }
|
|
377
312
|
// Reactive primitives
|
|
378
313
|
/**
|
|
379
|
-
* Create a reactive object that auto-updates when the object at this
|
|
314
|
+
* Create a reactive object that auto-updates when the object at this path changes.
|
|
380
315
|
*/
|
|
381
|
-
object(
|
|
316
|
+
object(path) {
|
|
382
317
|
if (this.#closed)
|
|
383
318
|
throw new Error('Cannot create reactive object: channel is closed');
|
|
384
|
-
return new ReactiveObjectImpl(this.#channel,
|
|
319
|
+
return new ReactiveObjectImpl(this.#channel, this.#fileTree, path);
|
|
385
320
|
}
|
|
386
321
|
/**
|
|
387
322
|
* Create a reactive watch that auto-updates when matching objects change.
|
|
@@ -389,11 +324,11 @@ class ReactiveChannelImpl {
|
|
|
389
324
|
watch(options) {
|
|
390
325
|
if (this.#closed)
|
|
391
326
|
throw new Error('Cannot create reactive watch: channel is closed');
|
|
392
|
-
return new ReactiveWatchImpl(this.#channel, options);
|
|
327
|
+
return new ReactiveWatchImpl(this.#channel, this.#fileTree, options);
|
|
393
328
|
}
|
|
394
329
|
}
|
|
395
|
-
export function wrapChannel(channel) {
|
|
396
|
-
return new ReactiveChannelImpl(channel);
|
|
330
|
+
export function wrapChannel(channel, fileTree) {
|
|
331
|
+
return new ReactiveChannelImpl(channel, fileTree);
|
|
397
332
|
}
|
|
398
333
|
/**
|
|
399
334
|
* A reactive list of channels for a space that auto-updates via SSE events.
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { type RoolSpace, type WebDAVDepth, type WebDAVPropName, type WebDAVResponse, type WebDAVSyncLevel } from '@rool-dev/sdk';
|
|
2
|
+
export type ReactiveFilePath = 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 paths sorted by modified time descending. */
|
|
79
|
+
objectPaths(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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"}
|