@rool-dev/svelte 0.10.2 → 0.11.0-dev.7c05180
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 +131 -88
- package/dist/channel.svelte.d.ts +20 -27
- package/dist/channel.svelte.d.ts.map +1 -1
- package/dist/channel.svelte.js +103 -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
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
import { isObjectPath, machinePath, } from '@rool-dev/sdk';
|
|
2
|
+
const ROOT = '/';
|
|
3
|
+
const DEFAULT_PROPS = [
|
|
4
|
+
'displayname',
|
|
5
|
+
'getcontentlength',
|
|
6
|
+
'getcontenttype',
|
|
7
|
+
'getetag',
|
|
8
|
+
'getlastmodified',
|
|
9
|
+
'resourcetype',
|
|
10
|
+
];
|
|
11
|
+
function normalizePath(path) {
|
|
12
|
+
return machinePath(path);
|
|
13
|
+
}
|
|
14
|
+
function parentPath(path) {
|
|
15
|
+
if (path === ROOT)
|
|
16
|
+
return null;
|
|
17
|
+
const parts = path.split('/').filter(Boolean);
|
|
18
|
+
parts.pop();
|
|
19
|
+
return parts.length === 0 ? ROOT : `/${parts.join('/')}`;
|
|
20
|
+
}
|
|
21
|
+
function leafName(path) {
|
|
22
|
+
if (path === ROOT)
|
|
23
|
+
return 'Space';
|
|
24
|
+
const leaf = path.split('/').filter(Boolean).pop() ?? '';
|
|
25
|
+
try {
|
|
26
|
+
return decodeURIComponent(leaf);
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return leaf;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
function rootOf(path) {
|
|
33
|
+
if (path === ROOT)
|
|
34
|
+
return '';
|
|
35
|
+
if (path === '/space' || path.startsWith('/space/'))
|
|
36
|
+
return 'space';
|
|
37
|
+
if (path === '/rool-drive' || path.startsWith('/rool-drive/'))
|
|
38
|
+
return 'rool-drive';
|
|
39
|
+
return '';
|
|
40
|
+
}
|
|
41
|
+
function modifiedAt(props) {
|
|
42
|
+
const raw = props.getlastmodified;
|
|
43
|
+
if (typeof raw !== 'string')
|
|
44
|
+
return null;
|
|
45
|
+
const parsed = Date.parse(raw);
|
|
46
|
+
return Number.isNaN(parsed) ? null : parsed;
|
|
47
|
+
}
|
|
48
|
+
function nodeFromResponse(response) {
|
|
49
|
+
const path = normalizePath(response.path);
|
|
50
|
+
return {
|
|
51
|
+
id: path,
|
|
52
|
+
path,
|
|
53
|
+
parent: parentPath(path),
|
|
54
|
+
name: typeof response.props.displayname === 'string' && response.props.displayname
|
|
55
|
+
? response.props.displayname
|
|
56
|
+
: leafName(path),
|
|
57
|
+
root: rootOf(path),
|
|
58
|
+
isCollection: response.isCollection,
|
|
59
|
+
size: typeof response.props.getcontentlength === 'number' ? response.props.getcontentlength : null,
|
|
60
|
+
contentType: typeof response.props.getcontenttype === 'string' ? response.props.getcontenttype : null,
|
|
61
|
+
etag: typeof response.props.getetag === 'string' ? response.props.getetag : null,
|
|
62
|
+
modifiedAt: modifiedAt(response.props),
|
|
63
|
+
href: response.href || null,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
function isDeletedResponse(response) {
|
|
67
|
+
if (response.status === 404 || response.status === 410)
|
|
68
|
+
return true;
|
|
69
|
+
return response.propstats.length > 0 && response.propstats.every((p) => p.status === 404 || p.status === 410);
|
|
70
|
+
}
|
|
71
|
+
function sameNode(a, b) {
|
|
72
|
+
return a.id === b.id
|
|
73
|
+
&& a.path === b.path
|
|
74
|
+
&& a.parent === b.parent
|
|
75
|
+
&& a.name === b.name
|
|
76
|
+
&& a.root === b.root
|
|
77
|
+
&& a.isCollection === b.isCollection
|
|
78
|
+
&& a.size === b.size
|
|
79
|
+
&& a.contentType === b.contentType
|
|
80
|
+
&& a.etag === b.etag
|
|
81
|
+
&& a.modifiedAt === b.modifiedAt
|
|
82
|
+
&& a.href === b.href;
|
|
83
|
+
}
|
|
84
|
+
function sortNodes(a, b) {
|
|
85
|
+
return Number(b.isCollection) - Number(a.isCollection) || a.name.localeCompare(b.name);
|
|
86
|
+
}
|
|
87
|
+
function emptyEvent(token, reset = false) {
|
|
88
|
+
return { reset, changedPaths: new Set(), deletedPaths: new Set(), token };
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Canonical Svelte-owned tree for the whole per-space WebDAV filesystem.
|
|
92
|
+
*
|
|
93
|
+
* It watches the SDK's coarse `filesChanged` / `filesReset` events and
|
|
94
|
+
* reconciles with WebDAV `sync-collection`. Consumers that care about both
|
|
95
|
+
* object files (`/space/...`) and user files (`/rool-drive/...`) should depend
|
|
96
|
+
* on this tree.
|
|
97
|
+
*/
|
|
98
|
+
export class ReactiveFileTree {
|
|
99
|
+
#space;
|
|
100
|
+
#nodes = new Map();
|
|
101
|
+
#children = new Map();
|
|
102
|
+
#listeners = new Set();
|
|
103
|
+
#unsubscribers = [];
|
|
104
|
+
#syncing = null;
|
|
105
|
+
#initialLoad = null;
|
|
106
|
+
#syncAgain = false;
|
|
107
|
+
#closed = false;
|
|
108
|
+
nodes = $state([]);
|
|
109
|
+
byPath = $state({});
|
|
110
|
+
token = $state(null);
|
|
111
|
+
version = $state(0);
|
|
112
|
+
loading = $state(true);
|
|
113
|
+
syncing = $state(false);
|
|
114
|
+
error = $state(null);
|
|
115
|
+
constructor(space) {
|
|
116
|
+
this.#space = space;
|
|
117
|
+
this.#setNode(rootNode());
|
|
118
|
+
this.#publishState();
|
|
119
|
+
this.#setupSpaceListeners();
|
|
120
|
+
this.#initialLoad = this.loadSnapshot().then(() => undefined, () => undefined);
|
|
121
|
+
}
|
|
122
|
+
get isClosed() { return this.#closed; }
|
|
123
|
+
get root() { return ROOT; }
|
|
124
|
+
subscribe(listener) {
|
|
125
|
+
this.#listeners.add(listener);
|
|
126
|
+
return () => this.#listeners.delete(listener);
|
|
127
|
+
}
|
|
128
|
+
ready() {
|
|
129
|
+
return this.#initialLoad ?? Promise.resolve();
|
|
130
|
+
}
|
|
131
|
+
get(path) {
|
|
132
|
+
return this.#nodes.get(normalizePath(path));
|
|
133
|
+
}
|
|
134
|
+
has(path) {
|
|
135
|
+
return this.#nodes.has(normalizePath(path));
|
|
136
|
+
}
|
|
137
|
+
childrenOf(path) {
|
|
138
|
+
return (this.#children.get(normalizePath(path)) ?? [])
|
|
139
|
+
.map((child) => this.#nodes.get(child))
|
|
140
|
+
.filter((node) => !!node);
|
|
141
|
+
}
|
|
142
|
+
descendantsOf(path) {
|
|
143
|
+
const root = normalizePath(path);
|
|
144
|
+
return this.nodes.filter((node) => node.path !== root && isDescendant(node.path, root));
|
|
145
|
+
}
|
|
146
|
+
/** Object file paths sorted by modified time descending. */
|
|
147
|
+
objectPaths(options = {}) {
|
|
148
|
+
const paths = this.nodes
|
|
149
|
+
.filter((node) => !node.isCollection && isObjectPath(node.path))
|
|
150
|
+
.filter((node) => !options.collection || safeCollection(node.path) === options.collection)
|
|
151
|
+
.sort((a, b) => (b.modifiedAt ?? 0) - (a.modifiedAt ?? 0))
|
|
152
|
+
.map((node) => node.path);
|
|
153
|
+
if (options.order === 'asc')
|
|
154
|
+
paths.reverse();
|
|
155
|
+
return options.limit === undefined ? paths : paths.slice(0, options.limit);
|
|
156
|
+
}
|
|
157
|
+
collections() {
|
|
158
|
+
return this.childrenOf('/space')
|
|
159
|
+
.filter((node) => node.isCollection)
|
|
160
|
+
.map((node) => node.name)
|
|
161
|
+
.sort((a, b) => a.localeCompare(b));
|
|
162
|
+
}
|
|
163
|
+
async loadSnapshot() {
|
|
164
|
+
if (this.#closed)
|
|
165
|
+
return { changed: false, ...emptyEvent(this.token, true) };
|
|
166
|
+
this.loading = true;
|
|
167
|
+
this.error = null;
|
|
168
|
+
try {
|
|
169
|
+
let snapshot;
|
|
170
|
+
try {
|
|
171
|
+
snapshot = await this.#space.webdav.syncCollection('/', { token: null, level: 'infinite', props: [...DEFAULT_PROPS] });
|
|
172
|
+
}
|
|
173
|
+
catch {
|
|
174
|
+
const [listing, tokenListing] = await Promise.all([
|
|
175
|
+
this.#space.webdav.propfind('/', { depth: 'infinity', props: [...DEFAULT_PROPS] }),
|
|
176
|
+
this.#space.webdav.propfind('/', { depth: '0', props: ['sync-token'] }),
|
|
177
|
+
]);
|
|
178
|
+
snapshot = {
|
|
179
|
+
token: tokenListing.responses[0]?.props.syncToken ?? null,
|
|
180
|
+
responses: listing.responses,
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
this.token = snapshot.token;
|
|
184
|
+
const result = this.#replaceSnapshot(snapshot.responses);
|
|
185
|
+
const event = { reset: true, changedPaths: result.changedPaths, deletedPaths: result.deletedPaths, token: this.token };
|
|
186
|
+
this.#emit(event);
|
|
187
|
+
return { changed: result.changed, ...event };
|
|
188
|
+
}
|
|
189
|
+
catch (error) {
|
|
190
|
+
this.error = error instanceof Error ? error : new Error(String(error));
|
|
191
|
+
throw error;
|
|
192
|
+
}
|
|
193
|
+
finally {
|
|
194
|
+
this.loading = false;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
async sync() {
|
|
198
|
+
if (this.#closed)
|
|
199
|
+
return { changed: false, ...emptyEvent(this.token) };
|
|
200
|
+
if (this.#syncing) {
|
|
201
|
+
this.#syncAgain = true;
|
|
202
|
+
return this.#syncing;
|
|
203
|
+
}
|
|
204
|
+
this.syncing = true;
|
|
205
|
+
this.error = null;
|
|
206
|
+
this.#syncing = this.#syncOnce();
|
|
207
|
+
try {
|
|
208
|
+
const result = await this.#syncing;
|
|
209
|
+
return result;
|
|
210
|
+
}
|
|
211
|
+
finally {
|
|
212
|
+
this.#syncing = null;
|
|
213
|
+
this.syncing = false;
|
|
214
|
+
if (this.#syncAgain && !this.#closed) {
|
|
215
|
+
this.#syncAgain = false;
|
|
216
|
+
void this.sync();
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
refresh() {
|
|
221
|
+
return this.loadSnapshot();
|
|
222
|
+
}
|
|
223
|
+
close() {
|
|
224
|
+
if (this.#closed)
|
|
225
|
+
return;
|
|
226
|
+
this.#closed = true;
|
|
227
|
+
for (const unsub of this.#unsubscribers)
|
|
228
|
+
unsub();
|
|
229
|
+
this.#unsubscribers.length = 0;
|
|
230
|
+
this.#listeners.clear();
|
|
231
|
+
}
|
|
232
|
+
#setupSpaceListeners() {
|
|
233
|
+
const onFilesChanged = () => { void this.sync(); };
|
|
234
|
+
const onFilesReset = () => { void this.loadSnapshot(); };
|
|
235
|
+
const onConnectionStateChanged = (state) => {
|
|
236
|
+
if (state === 'connected' && !this.loading)
|
|
237
|
+
void this.sync();
|
|
238
|
+
};
|
|
239
|
+
this.#space.on('filesChanged', onFilesChanged);
|
|
240
|
+
this.#space.on('filesReset', onFilesReset);
|
|
241
|
+
this.#space.on('connectionStateChanged', onConnectionStateChanged);
|
|
242
|
+
this.#unsubscribers.push(() => this.#space.off('filesChanged', onFilesChanged));
|
|
243
|
+
this.#unsubscribers.push(() => this.#space.off('filesReset', onFilesReset));
|
|
244
|
+
this.#unsubscribers.push(() => this.#space.off('connectionStateChanged', onConnectionStateChanged));
|
|
245
|
+
}
|
|
246
|
+
async #syncOnce() {
|
|
247
|
+
try {
|
|
248
|
+
const delta = await this.#space.webdav.syncCollection('/', { token: this.token, level: 'infinite', props: [...DEFAULT_PROPS] });
|
|
249
|
+
this.token = delta.token;
|
|
250
|
+
const result = this.#applyResponses(delta.responses);
|
|
251
|
+
const event = { reset: false, changedPaths: result.changedPaths, deletedPaths: result.deletedPaths, token: this.token };
|
|
252
|
+
if (result.changed || event.deletedPaths.size > 0)
|
|
253
|
+
this.#emit(event);
|
|
254
|
+
return { changed: result.changed, ...event };
|
|
255
|
+
}
|
|
256
|
+
catch {
|
|
257
|
+
return this.loadSnapshot();
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
#replaceSnapshot(responses) {
|
|
261
|
+
const next = new Map();
|
|
262
|
+
next.set(ROOT, rootNode());
|
|
263
|
+
for (const response of responses) {
|
|
264
|
+
if (isDeletedResponse(response))
|
|
265
|
+
continue;
|
|
266
|
+
const node = nodeFromResponse(response);
|
|
267
|
+
next.set(node.path, node);
|
|
268
|
+
}
|
|
269
|
+
// Ensure aggregate roots exist even if a server/proxy omits them.
|
|
270
|
+
if (!next.has('/space'))
|
|
271
|
+
next.set('/space', syntheticRootChild('/space', 'space'));
|
|
272
|
+
if (!next.has('/rool-drive'))
|
|
273
|
+
next.set('/rool-drive', syntheticRootChild('/rool-drive', 'rool-drive'));
|
|
274
|
+
const changedPaths = new Set();
|
|
275
|
+
const deletedPaths = new Set();
|
|
276
|
+
for (const [path, node] of next) {
|
|
277
|
+
const old = this.#nodes.get(path);
|
|
278
|
+
if (!old || !sameNode(old, node))
|
|
279
|
+
changedPaths.add(path);
|
|
280
|
+
}
|
|
281
|
+
for (const path of this.#nodes.keys()) {
|
|
282
|
+
if (!next.has(path))
|
|
283
|
+
deletedPaths.add(path);
|
|
284
|
+
}
|
|
285
|
+
this.#nodes = next;
|
|
286
|
+
this.#rebuildChildren();
|
|
287
|
+
const changed = changedPaths.size > 0 || deletedPaths.size > 0;
|
|
288
|
+
if (changed)
|
|
289
|
+
this.#publishState();
|
|
290
|
+
return { changed, changedPaths, deletedPaths };
|
|
291
|
+
}
|
|
292
|
+
#applyResponses(responses) {
|
|
293
|
+
let changed = false;
|
|
294
|
+
const changedPaths = new Set();
|
|
295
|
+
const deletedPaths = new Set();
|
|
296
|
+
for (const response of responses) {
|
|
297
|
+
const path = normalizePath(response.path);
|
|
298
|
+
if (path === ROOT)
|
|
299
|
+
continue;
|
|
300
|
+
if (isDeletedResponse(response)) {
|
|
301
|
+
if (this.#deleteSubtree(path, deletedPaths))
|
|
302
|
+
changed = true;
|
|
303
|
+
else
|
|
304
|
+
deletedPaths.add(path);
|
|
305
|
+
continue;
|
|
306
|
+
}
|
|
307
|
+
const node = nodeFromResponse(response);
|
|
308
|
+
const old = this.#nodes.get(node.path);
|
|
309
|
+
if (!old || !sameNode(old, node)) {
|
|
310
|
+
this.#setNode(node);
|
|
311
|
+
changed = true;
|
|
312
|
+
changedPaths.add(node.path);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
if (changed) {
|
|
316
|
+
this.#rebuildChildren();
|
|
317
|
+
this.#publishState();
|
|
318
|
+
}
|
|
319
|
+
return { changed, changedPaths, deletedPaths };
|
|
320
|
+
}
|
|
321
|
+
#setNode(node) {
|
|
322
|
+
this.#nodes.set(node.path, node);
|
|
323
|
+
}
|
|
324
|
+
#deleteSubtree(path, deletedPaths) {
|
|
325
|
+
let deleted = false;
|
|
326
|
+
for (const nodePath of [...this.#nodes.keys()].sort((a, b) => b.length - a.length)) {
|
|
327
|
+
if (nodePath === path || isDescendant(nodePath, path)) {
|
|
328
|
+
this.#nodes.delete(nodePath);
|
|
329
|
+
deletedPaths.add(nodePath);
|
|
330
|
+
deleted = true;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
return deleted;
|
|
334
|
+
}
|
|
335
|
+
#rebuildChildren() {
|
|
336
|
+
this.#children = new Map();
|
|
337
|
+
for (const node of this.#nodes.values()) {
|
|
338
|
+
if (!node.parent)
|
|
339
|
+
continue;
|
|
340
|
+
const bucket = this.#children.get(node.parent) ?? [];
|
|
341
|
+
bucket.push(node.path);
|
|
342
|
+
this.#children.set(node.parent, bucket);
|
|
343
|
+
}
|
|
344
|
+
for (const [parent, children] of this.#children) {
|
|
345
|
+
children.sort((a, b) => sortNodes(this.#nodes.get(a), this.#nodes.get(b)));
|
|
346
|
+
this.#children.set(parent, children);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
#publishState() {
|
|
350
|
+
const nodes = [...this.#nodes.values()].sort((a, b) => a.path === ROOT ? -1 : b.path === ROOT ? 1 : a.path.localeCompare(b.path));
|
|
351
|
+
this.nodes = nodes;
|
|
352
|
+
this.byPath = Object.fromEntries(nodes.map((node) => [node.path, node]));
|
|
353
|
+
this.version += 1;
|
|
354
|
+
}
|
|
355
|
+
#emit(event) {
|
|
356
|
+
for (const listener of this.#listeners)
|
|
357
|
+
listener(event);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
function rootNode() {
|
|
361
|
+
return {
|
|
362
|
+
id: ROOT,
|
|
363
|
+
path: ROOT,
|
|
364
|
+
parent: null,
|
|
365
|
+
name: 'Space',
|
|
366
|
+
root: '',
|
|
367
|
+
isCollection: true,
|
|
368
|
+
size: null,
|
|
369
|
+
contentType: null,
|
|
370
|
+
etag: null,
|
|
371
|
+
modifiedAt: null,
|
|
372
|
+
href: null,
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
function syntheticRootChild(path, name) {
|
|
376
|
+
return {
|
|
377
|
+
id: path,
|
|
378
|
+
path,
|
|
379
|
+
parent: ROOT,
|
|
380
|
+
name,
|
|
381
|
+
root: name,
|
|
382
|
+
isCollection: true,
|
|
383
|
+
size: null,
|
|
384
|
+
contentType: null,
|
|
385
|
+
etag: null,
|
|
386
|
+
modifiedAt: null,
|
|
387
|
+
href: null,
|
|
388
|
+
};
|
|
389
|
+
}
|
|
390
|
+
function isDescendant(path, ancestor) {
|
|
391
|
+
if (ancestor === ROOT)
|
|
392
|
+
return path !== ROOT;
|
|
393
|
+
return path.startsWith(`${ancestor}/`);
|
|
394
|
+
}
|
|
395
|
+
function safeCollection(path) {
|
|
396
|
+
if (!isObjectPath(path))
|
|
397
|
+
return undefined;
|
|
398
|
+
return path.split('/')[2];
|
|
399
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
export { createRool, generateId } from './rool.svelte.js';
|
|
2
|
-
export {
|
|
3
|
-
export type { ParsedLocation, MachineResource } from '@rool-dev/sdk';
|
|
2
|
+
export { isObjectPath, machinePath, machineUri } from '@rool-dev/sdk';
|
|
4
3
|
export { wrapChannel } from './channel.svelte.js';
|
|
5
4
|
export { wrapSpace } from './space.svelte.js';
|
|
5
|
+
export { ReactiveFileTree } from './file-tree.svelte.js';
|
|
6
6
|
export type { Rool } from './rool.svelte.js';
|
|
7
7
|
export type { ReactiveChannel, ReactiveConversationHandle, ReactiveObject, ReactiveWatch, ReactiveChannelList, WatchOptions } from './channel.svelte.js';
|
|
8
8
|
export type { ReactiveSpace } from './space.svelte.js';
|
|
9
|
-
export type {
|
|
9
|
+
export type { ReactiveFileNode, ReactiveFilePath, ReactiveFileRoot, ReactiveFileTreeEvent, ReactiveFileTreeSyncResult } from './file-tree.svelte.js';
|
|
10
|
+
export type { RoolClientConfig, RoolChannel, RoolSpace, RoolSpaceInfo, RoolObject, GetObjectsResult, RoolObjectStat, RoolUserRole, ConnectionState, ChannelInfo, Conversation, ConversationInfo, CurrentUser, Interaction, PromptOptions, PromptAttachment, UpdateObjectOptions, MoveObjectOptions, CollectionOptions, FieldType, FieldDef, CollectionDef, SpaceSchema, SpaceMember, UserResult, RoolClient, RoolSpaceEvents, SpaceFileStorageUsage, WebDAVDepth, WebDAVSyncLevel, WebDAVPropName, WebDAVResponse, WebDAVProps, } from '@rool-dev/sdk';
|
|
10
11
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -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,
|
|
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,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAGtE,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAGzD,YAAY,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC7C,YAAY,EAAE,eAAe,EAAE,0BAA0B,EAAE,cAAc,EAAE,aAAa,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACzJ,YAAY,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACvD,YAAY,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,0BAA0B,EAAE,MAAM,uBAAuB,CAAC;AAGrJ,YAAY,EACV,gBAAgB,EAChB,WAAW,EACX,SAAS,EACT,aAAa,EACb,UAAU,EACV,gBAAgB,EAChB,cAAc,EACd,YAAY,EACZ,eAAe,EACf,WAAW,EACX,YAAY,EACZ,gBAAgB,EAChB,WAAW,EACX,WAAW,EACX,aAAa,EACb,gBAAgB,EAChB,mBAAmB,EACnB,iBAAiB,EACjB,iBAAiB,EACjB,SAAS,EACT,QAAQ,EACR,aAAa,EACb,WAAW,EACX,WAAW,EACX,UAAU,EACV,UAAU,EACV,eAAe,EACf,qBAAqB,EACrB,WAAW,EACX,eAAe,EACf,cAAc,EACd,cAAc,EACd,WAAW,GACZ,MAAM,eAAe,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
// Main export
|
|
2
2
|
export { createRool, generateId } from './rool.svelte.js';
|
|
3
|
-
//
|
|
4
|
-
export {
|
|
3
|
+
// Machine path helpers — re-exported from the SDK for convenience
|
|
4
|
+
export { isObjectPath, machinePath, machineUri } from '@rool-dev/sdk';
|
|
5
5
|
// Reactive wrappers
|
|
6
6
|
export { wrapChannel } from './channel.svelte.js';
|
|
7
7
|
export { wrapSpace } from './space.svelte.js';
|
|
8
|
+
export { ReactiveFileTree } from './file-tree.svelte.js';
|
package/dist/rool.svelte.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { RoolClient, type RoolSpaceInfo, type ConnectionState, type RoolClientConfig, type CurrentUser
|
|
1
|
+
import { RoolClient, type RoolSpaceInfo, type ConnectionState, type RoolClientConfig, type CurrentUser } from '@rool-dev/sdk';
|
|
2
2
|
import { type ReactiveChannelList } from './channel.svelte.js';
|
|
3
3
|
import { type ReactiveSpace } from './space.svelte.js';
|
|
4
4
|
/**
|
|
@@ -58,6 +58,10 @@ declare class RoolImpl {
|
|
|
58
58
|
* Create a new space. Returns a ReactiveSpace.
|
|
59
59
|
*/
|
|
60
60
|
createSpace(name: string): Promise<ReactiveSpace>;
|
|
61
|
+
/**
|
|
62
|
+
* Duplicate an existing space. Returns a ReactiveSpace.
|
|
63
|
+
*/
|
|
64
|
+
duplicateSpace(sourceSpaceId: string, name: string): Promise<ReactiveSpace>;
|
|
61
65
|
/**
|
|
62
66
|
* Manually refresh the spaces list.
|
|
63
67
|
*/
|
|
@@ -66,6 +70,22 @@ declare class RoolImpl {
|
|
|
66
70
|
* Delete a space.
|
|
67
71
|
*/
|
|
68
72
|
deleteSpace(spaceId: string): Promise<void>;
|
|
73
|
+
/**
|
|
74
|
+
* Mark the current user for deletion, then log out locally.
|
|
75
|
+
*/
|
|
76
|
+
deleteCurrentUser(): Promise<void>;
|
|
77
|
+
/**
|
|
78
|
+
* Set or change the current user's password.
|
|
79
|
+
*/
|
|
80
|
+
setPassword(password: string): Promise<void>;
|
|
81
|
+
/**
|
|
82
|
+
* Get a value from user storage.
|
|
83
|
+
*/
|
|
84
|
+
getUserStorage<T = unknown>(key: string): T | undefined;
|
|
85
|
+
/**
|
|
86
|
+
* Get all user storage data.
|
|
87
|
+
*/
|
|
88
|
+
getAllUserStorage(): Record<string, unknown>;
|
|
69
89
|
/**
|
|
70
90
|
* Set a value in user storage.
|
|
71
91
|
* Updates reactive state immediately, then syncs to server.
|
|
@@ -98,28 +118,8 @@ declare class RoolImpl {
|
|
|
98
118
|
updateCurrentUser(input: {
|
|
99
119
|
name?: string;
|
|
100
120
|
slug?: string;
|
|
121
|
+
marketingOptIn?: boolean;
|
|
101
122
|
}): Promise<CurrentUser>;
|
|
102
|
-
/**
|
|
103
|
-
* Install an extension into a space.
|
|
104
|
-
* Creates/updates a channel with the extension's manifest settings.
|
|
105
|
-
* Returns the channel ID.
|
|
106
|
-
*/
|
|
107
|
-
/** Upload or update a user extension bundle. */
|
|
108
|
-
uploadExtension(extensionId: string, options: UploadExtensionOptions): Promise<ExtensionInfo>;
|
|
109
|
-
/** Delete a user extension permanently. */
|
|
110
|
-
deleteExtension(extensionId: string): Promise<void>;
|
|
111
|
-
/** List the current user's extensions. */
|
|
112
|
-
listExtensions(): Promise<ExtensionInfo[]>;
|
|
113
|
-
/** Get info for a specific user extension. */
|
|
114
|
-
getExtensionInfo(extensionId: string): Promise<ExtensionInfo | null>;
|
|
115
|
-
/** Search published extensions. */
|
|
116
|
-
findExtensions(options?: FindExtensionsOptions): Promise<PublishedExtensionInfo[]>;
|
|
117
|
-
/** Respond to a server-initiated probe with a method-specific result or error. */
|
|
118
|
-
probeResponse(requestId: string, result?: unknown, error?: string): Promise<boolean>;
|
|
119
|
-
/** Publish a user extension (make it publicly discoverable). */
|
|
120
|
-
publishToPublic(extensionId: string): Promise<void>;
|
|
121
|
-
/** Unpublish an extension (remove from public listing). */
|
|
122
|
-
unpublishFromPublic(extensionId: string): Promise<void>;
|
|
123
123
|
/**
|
|
124
124
|
* Create a reactive channel list for a space.
|
|
125
125
|
* Auto-updates when channels are created, updated, or deleted.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rool.svelte.d.ts","sourceRoot":"","sources":["../src/rool.svelte.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,KAAK,aAAa,EAAE,KAAK,eAAe,EAAE,KAAK,gBAAgB,EAAE,KAAK,WAAW,EAAE,
|
|
1
|
+
{"version":3,"file":"rool.svelte.d.ts","sourceRoot":"","sources":["../src/rool.svelte.ts"],"names":[],"mappings":"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"}
|
package/dist/rool.svelte.js
CHANGED
|
@@ -163,6 +163,15 @@ class RoolImpl {
|
|
|
163
163
|
this.#openSpaces.add(reactive);
|
|
164
164
|
return reactive;
|
|
165
165
|
}
|
|
166
|
+
/**
|
|
167
|
+
* Duplicate an existing space. Returns a ReactiveSpace.
|
|
168
|
+
*/
|
|
169
|
+
async duplicateSpace(sourceSpaceId, name) {
|
|
170
|
+
const raw = await this.#client.duplicateSpace(sourceSpaceId, name);
|
|
171
|
+
const reactive = wrapSpace(raw);
|
|
172
|
+
this.#openSpaces.add(reactive);
|
|
173
|
+
return reactive;
|
|
174
|
+
}
|
|
166
175
|
/**
|
|
167
176
|
* Manually refresh the spaces list.
|
|
168
177
|
*/
|
|
@@ -175,6 +184,30 @@ class RoolImpl {
|
|
|
175
184
|
deleteSpace(spaceId) {
|
|
176
185
|
return this.#client.deleteSpace(spaceId);
|
|
177
186
|
}
|
|
187
|
+
/**
|
|
188
|
+
* Mark the current user for deletion, then log out locally.
|
|
189
|
+
*/
|
|
190
|
+
deleteCurrentUser() {
|
|
191
|
+
return this.#client.deleteCurrentUser();
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Set or change the current user's password.
|
|
195
|
+
*/
|
|
196
|
+
setPassword(password) {
|
|
197
|
+
return this.#client.setPassword(password);
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Get a value from user storage.
|
|
201
|
+
*/
|
|
202
|
+
getUserStorage(key) {
|
|
203
|
+
return this.#client.getUserStorage(key);
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Get all user storage data.
|
|
207
|
+
*/
|
|
208
|
+
getAllUserStorage() {
|
|
209
|
+
return this.#client.getAllUserStorage();
|
|
210
|
+
}
|
|
178
211
|
/**
|
|
179
212
|
* Set a value in user storage.
|
|
180
213
|
* Updates reactive state immediately, then syncs to server.
|
|
@@ -227,45 +260,6 @@ class RoolImpl {
|
|
|
227
260
|
this.currentUser = user;
|
|
228
261
|
return user;
|
|
229
262
|
}
|
|
230
|
-
/**
|
|
231
|
-
* Install an extension into a space.
|
|
232
|
-
* Creates/updates a channel with the extension's manifest settings.
|
|
233
|
-
* Returns the channel ID.
|
|
234
|
-
*/
|
|
235
|
-
// --- User Extensions (your personal library) ---
|
|
236
|
-
/** Upload or update a user extension bundle. */
|
|
237
|
-
uploadExtension(extensionId, options) {
|
|
238
|
-
return this.#client.uploadExtension(extensionId, options);
|
|
239
|
-
}
|
|
240
|
-
/** Delete a user extension permanently. */
|
|
241
|
-
deleteExtension(extensionId) {
|
|
242
|
-
return this.#client.deleteExtension(extensionId);
|
|
243
|
-
}
|
|
244
|
-
/** List the current user's extensions. */
|
|
245
|
-
listExtensions() {
|
|
246
|
-
return this.#client.listExtensions();
|
|
247
|
-
}
|
|
248
|
-
/** Get info for a specific user extension. */
|
|
249
|
-
getExtensionInfo(extensionId) {
|
|
250
|
-
return this.#client.getExtensionInfo(extensionId);
|
|
251
|
-
}
|
|
252
|
-
// --- Published Extensions (public discovery & install) ---
|
|
253
|
-
/** Search published extensions. */
|
|
254
|
-
findExtensions(options) {
|
|
255
|
-
return this.#client.findExtensions(options);
|
|
256
|
-
}
|
|
257
|
-
/** Respond to a server-initiated probe with a method-specific result or error. */
|
|
258
|
-
probeResponse(requestId, result, error) {
|
|
259
|
-
return this.#client.probeResponse(requestId, result, error);
|
|
260
|
-
}
|
|
261
|
-
/** Publish a user extension (make it publicly discoverable). */
|
|
262
|
-
publishToPublic(extensionId) {
|
|
263
|
-
return this.#client.publishToPublic(extensionId);
|
|
264
|
-
}
|
|
265
|
-
/** Unpublish an extension (remove from public listing). */
|
|
266
|
-
unpublishFromPublic(extensionId) {
|
|
267
|
-
return this.#client.unpublishFromPublic(extensionId);
|
|
268
|
-
}
|
|
269
263
|
/**
|
|
270
264
|
* Create a reactive channel list for a space.
|
|
271
265
|
* Auto-updates when channels are created, updated, or deleted.
|
package/dist/space.svelte.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { RoolSpace, ChannelInfo, ConnectionState, RoolUserRole, LinkAccess, SpaceMember } from '@rool-dev/sdk';
|
|
2
2
|
import { type ReactiveChannel } from './channel.svelte.js';
|
|
3
|
+
import { ReactiveFileTree } from './file-tree.svelte.js';
|
|
3
4
|
/**
|
|
4
5
|
* A reactive wrapper around a RoolSpace. Exposes reactive `channels` and
|
|
5
6
|
* `connectionState`, and provides `openChannel()` that returns a ReactiveChannel.
|
|
@@ -29,8 +30,9 @@ declare class ReactiveSpaceImpl {
|
|
|
29
30
|
get linkAccess(): LinkAccess;
|
|
30
31
|
get memberCount(): number;
|
|
31
32
|
get webdav(): import("@rool-dev/sdk").RoolWebDAV;
|
|
33
|
+
get fileTree(): ReactiveFileTree;
|
|
32
34
|
getStorageUsage(...args: Parameters<RoolSpace['getStorageUsage']>): Promise<import("@rool-dev/sdk").SpaceFileStorageUsage>;
|
|
33
|
-
|
|
35
|
+
fetchPath(...args: Parameters<RoolSpace['fetchPath']>): Promise<Response>;
|
|
34
36
|
rename(newName: string): Promise<void>;
|
|
35
37
|
delete(): Promise<void>;
|
|
36
38
|
listUsers(): Promise<SpaceMember[]>;
|
|
@@ -39,7 +41,6 @@ declare class ReactiveSpaceImpl {
|
|
|
39
41
|
setLinkAccess(...args: Parameters<RoolSpace['setLinkAccess']>): Promise<void>;
|
|
40
42
|
renameChannel(channelId: string, name: string): Promise<void>;
|
|
41
43
|
deleteChannel(channelId: string): Promise<void>;
|
|
42
|
-
installExtension(extensionId: string, channelId: string): Promise<string>;
|
|
43
44
|
exportArchive(): Promise<Blob>;
|
|
44
45
|
refresh(): Promise<void>;
|
|
45
46
|
on(...args: Parameters<RoolSpace['on']>): () => void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"space.svelte.d.ts","sourceRoot":"","sources":["../src/space.svelte.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,eAAe,EAAE,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACpH,OAAO,EAAe,KAAK,eAAe,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"space.svelte.d.ts","sourceRoot":"","sources":["../src/space.svelte.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,eAAe,EAAE,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACpH,OAAO,EAAe,KAAK,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACxE,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAEzD;;;;;;GAMG;AACH,cAAM,iBAAiB;;IASrB,eAAe,kBAA2C;gBAE9C,KAAK,EAAE,SAAS;IAoB5B,IAAI,QAAQ,YAA2B;IAEvC;;;OAGG;IACG,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;IAY9D;;;OAGG;IACH,KAAK,IAAI,IAAI;IAiBb,IAAI,QAAQ,IAAI,WAAW,EAAE,CAA8B;IAG3D,IAAI,EAAE,IAAI,MAAM,CAA2B;IAC3C,IAAI,IAAI,IAAI,MAAM,CAA6B;IAC/C,IAAI,IAAI,IAAI,YAAY,CAA6B;IACrD,IAAI,UAAU,IAAI,UAAU,CAAmC;IAC/D,IAAI,WAAW,IAAI,MAAM,CAAoC;IAC7D,IAAI,MAAM,uCAAiC;IAC3C,IAAI,QAAQ,IAAI,gBAAgB,CAA2B;IAG3D,eAAe,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC;IACjE,SAAS,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;IAGrD,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IACtC,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IACvB,SAAS,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;IACnC,OAAO,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;IACjD,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IACzC,aAAa,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC;IAC7D,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAC7D,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAC/C,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAC9B,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAGxB,EAAE,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IACvC,GAAG,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;CAC1C;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,SAAS,GAAG,aAAa,CAEzD;AAED,MAAM,MAAM,aAAa,GAAG,iBAAiB,CAAC"}
|