@rool-dev/svelte 0.11.3-dev.a6a4bb1 → 0.11.4-dev.10ce346

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.
@@ -1,177 +0,0 @@
1
- import type { RoolChannel, RoolSpace, Interaction, RoolObject, ChannelInfo, ConversationInfo, ConversationHandle } from '@rool-dev/sdk';
2
- import { ReactiveFileTree } from './file-tree.svelte.js';
3
- /**
4
- * Options for creating a reactive watch.
5
- * Structured object filter for reactive updates.
6
- */
7
- export interface WatchOptions {
8
- /** Field requirements for exact matching */
9
- where?: Record<string, unknown>;
10
- /** Filter by collection name. */
11
- collection?: string;
12
- /** Maximum number of objects */
13
- limit?: number;
14
- /** Sort order by modifiedAt: 'asc' or 'desc' (default: 'desc') */
15
- order?: 'asc' | 'desc';
16
- }
17
- /**
18
- * A reactive watch of objects that auto-updates when matching object files change.
19
- */
20
- declare class ReactiveWatchImpl {
21
- #private;
22
- objects: RoolObject[];
23
- loading: boolean;
24
- constructor(channel: RoolChannel, fileTree: ReactiveFileTree, options: WatchOptions);
25
- /** Re-fetch matching objects using the canonical file tree for paths. */
26
- refresh(): Promise<void>;
27
- close(): void;
28
- }
29
- export type ReactiveWatch = ReactiveWatchImpl;
30
- /**
31
- * A reactive single object that auto-updates when the object changes.
32
- */
33
- declare class ReactiveObjectImpl {
34
- #private;
35
- data: RoolObject | undefined;
36
- loading: boolean;
37
- constructor(channel: RoolChannel, fileTree: ReactiveFileTree, path: string);
38
- refresh(): Promise<void>;
39
- close(): void;
40
- }
41
- export type ReactiveObject = ReactiveObjectImpl;
42
- declare class ReactiveConversationHandleImpl {
43
- #private;
44
- interactions: Interaction[];
45
- constructor(channel: RoolChannel, conversationId: string);
46
- get conversationId(): string;
47
- getInteractions(): Interaction[];
48
- getTree(): Record<string, Interaction>;
49
- get activeLeafId(): string | undefined;
50
- setActiveLeaf(interactionId: string): void;
51
- getSystemInstruction(): string | undefined;
52
- setSystemInstruction(...args: Parameters<ConversationHandle['setSystemInstruction']>): Promise<void>;
53
- rename(...args: Parameters<ConversationHandle['rename']>): Promise<void>;
54
- putObject(...args: Parameters<ConversationHandle['putObject']>): Promise<{
55
- object: RoolObject;
56
- message: string;
57
- }>;
58
- patchObject(...args: Parameters<ConversationHandle['patchObject']>): Promise<{
59
- object: RoolObject;
60
- message: string;
61
- }>;
62
- moveObject(...args: Parameters<ConversationHandle['moveObject']>): Promise<{
63
- object: RoolObject;
64
- message: string;
65
- }>;
66
- deleteObjects(...args: Parameters<ConversationHandle['deleteObjects']>): Promise<void>;
67
- /** @deprecated Use deleteObjects instead. */
68
- deletePaths(...args: Parameters<ConversationHandle['deletePaths']>): Promise<void>;
69
- prompt(...args: Parameters<ConversationHandle['prompt']>): Promise<{
70
- message: string;
71
- objects: RoolObject[];
72
- }>;
73
- stop(): Promise<boolean>;
74
- createCollection(...args: Parameters<ConversationHandle['createCollection']>): Promise<import("@rool-dev/sdk").CollectionDef>;
75
- alterCollection(...args: Parameters<ConversationHandle['alterCollection']>): Promise<import("@rool-dev/sdk").CollectionDef>;
76
- dropCollection(...args: Parameters<ConversationHandle['dropCollection']>): Promise<void>;
77
- setMetadata(...args: Parameters<ConversationHandle['setMetadata']>): void;
78
- close(): void;
79
- }
80
- export type ReactiveConversationHandle = ReactiveConversationHandleImpl;
81
- /**
82
- * Minimal wrapper that adds reactive `interactions` to RoolChannel.
83
- * All other properties and methods are proxied to the underlying channel.
84
- */
85
- declare class ReactiveChannelImpl {
86
- #private;
87
- interactions: Interaction[];
88
- objectPaths: string[];
89
- collections: string[];
90
- conversations: ConversationInfo[];
91
- constructor(channel: RoolChannel, fileTree: ReactiveFileTree);
92
- get id(): string;
93
- get name(): string;
94
- get role(): import("@rool-dev/sdk").RoolUserRole;
95
- get userId(): string;
96
- get channelId(): string;
97
- get channelName(): string | null;
98
- get isReadOnly(): boolean;
99
- get isClosed(): boolean;
100
- close(): void;
101
- getObject(...args: Parameters<RoolChannel['getObject']>): Promise<RoolObject | undefined>;
102
- getObjects(...args: Parameters<RoolChannel['getObjects']>): Promise<import("@rool-dev/sdk").GetObjectsResult>;
103
- stat(...args: Parameters<RoolChannel['stat']>): import("@rool-dev/sdk").RoolObjectStat | undefined;
104
- putObject(...args: Parameters<RoolChannel['putObject']>): Promise<{
105
- object: RoolObject;
106
- message: string;
107
- }>;
108
- patchObject(...args: Parameters<RoolChannel['patchObject']>): Promise<{
109
- object: RoolObject;
110
- message: string;
111
- }>;
112
- moveObject(...args: Parameters<RoolChannel['moveObject']>): Promise<{
113
- object: RoolObject;
114
- message: string;
115
- }>;
116
- deleteObjects(...args: Parameters<RoolChannel['deleteObjects']>): Promise<void>;
117
- /** @deprecated Use deleteObjects instead. */
118
- deletePaths(...args: Parameters<RoolChannel['deletePaths']>): Promise<void>;
119
- prompt(...args: Parameters<RoolChannel['prompt']>): Promise<{
120
- message: string;
121
- objects: RoolObject[];
122
- }>;
123
- stop(): Promise<boolean>;
124
- stopInteraction(...args: Parameters<RoolChannel['stopInteraction']>): Promise<boolean>;
125
- checkpoint(...args: Parameters<RoolChannel['checkpoint']>): Promise<string>;
126
- canUndo(): Promise<boolean>;
127
- canRedo(): Promise<boolean>;
128
- undo(): Promise<boolean>;
129
- redo(): Promise<boolean>;
130
- clearHistory(): Promise<void>;
131
- setMetadata(...args: Parameters<RoolChannel['setMetadata']>): void;
132
- getMetadata(...args: Parameters<RoolChannel['getMetadata']>): unknown;
133
- getAllMetadata(): Record<string, unknown>;
134
- getInteractions(): Interaction[];
135
- getTree(): Record<string, Interaction>;
136
- get activeLeafId(): string | undefined;
137
- setActiveLeaf(interactionId: string): void;
138
- getSystemInstruction(): string | undefined;
139
- setSystemInstruction(...args: Parameters<RoolChannel['setSystemInstruction']>): Promise<void>;
140
- getConversations(): ConversationInfo[];
141
- deleteConversation(...args: Parameters<RoolChannel['deleteConversation']>): Promise<void>;
142
- renameConversation(...args: Parameters<RoolChannel['renameConversation']>): Promise<void>;
143
- getSchema(): import("@rool-dev/sdk").SpaceSchema;
144
- createCollection(...args: Parameters<RoolChannel['createCollection']>): Promise<import("@rool-dev/sdk").CollectionDef>;
145
- alterCollection(...args: Parameters<RoolChannel['alterCollection']>): Promise<import("@rool-dev/sdk").CollectionDef>;
146
- dropCollection(...args: Parameters<RoolChannel['dropCollection']>): Promise<void>;
147
- fetch(...args: Parameters<RoolChannel['fetch']>): Promise<Response>;
148
- rename(...args: Parameters<RoolChannel['rename']>): Promise<void>;
149
- conversation(conversationId: string): ReactiveConversationHandle;
150
- on(...args: Parameters<RoolChannel['on']>): () => void;
151
- off(...args: Parameters<RoolChannel['off']>): void;
152
- /**
153
- * Create a reactive object that auto-updates when the object at this path changes.
154
- */
155
- object(path: string): ReactiveObject;
156
- /**
157
- * Create a reactive watch that auto-updates when matching objects change.
158
- */
159
- watch(options: WatchOptions): ReactiveWatch;
160
- }
161
- export declare function wrapChannel(channel: RoolChannel, fileTree: ReactiveFileTree): ReactiveChannel;
162
- export type ReactiveChannel = ReactiveChannelImpl;
163
- /**
164
- * A reactive list of channels for a space that auto-updates via SSE events.
165
- */
166
- declare class ReactiveChannelListImpl {
167
- #private;
168
- list: ChannelInfo[];
169
- loading: boolean;
170
- constructor(spaceOrPromise: RoolSpace | Promise<RoolSpace>);
171
- refresh(): Promise<void>;
172
- close(): void;
173
- }
174
- export declare function createChannelList(spaceOrPromise: RoolSpace | Promise<RoolSpace>): ReactiveChannelList;
175
- export type ReactiveChannelList = ReactiveChannelListImpl;
176
- export {};
177
- //# sourceMappingURL=channel.svelte.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"channel.svelte.d.ts","sourceRoot":"","sources":["../src/channel.svelte.ts"],"names":[],"mappings":"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"}
@@ -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
- }