@agentshouse/mdruntime 0.1.0-ce131cb435f8b → 0.1.0-ce9f29a01a271
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/dist/adapter.d.ts +12 -0
- package/dist/adapter.d.ts.map +1 -1
- package/dist/change-set.d.ts +5 -2
- package/dist/change-set.d.ts.map +1 -1
- package/dist/change-set.js +6 -1
- package/dist/chat/list.d.ts +2 -1
- package/dist/chat/list.d.ts.map +1 -1
- package/dist/chat/list.js +2 -2
- package/dist/chat/markdown.d.ts +1 -0
- package/dist/chat/markdown.d.ts.map +1 -1
- package/dist/chat/markdown.js +78 -20
- package/dist/chat/message.d.ts.map +1 -1
- package/dist/chat/message.js +9 -2
- package/dist/chat/messages.d.ts.map +1 -1
- package/dist/chat/messages.js +36 -16
- package/dist/chat/overlay.d.ts +1 -0
- package/dist/chat/overlay.d.ts.map +1 -1
- package/dist/chat/overlay.js +10 -0
- package/dist/chat/pieces.d.ts +62 -0
- package/dist/chat/pieces.d.ts.map +1 -0
- package/dist/chat/pieces.js +1110 -0
- package/dist/chat/provider.d.ts +1 -0
- package/dist/chat/provider.d.ts.map +1 -1
- package/dist/chat/provider.js +12 -3
- package/dist/chat/ready.d.ts +1 -1
- package/dist/chat/ready.d.ts.map +1 -1
- package/dist/chat/ready.js +1 -1
- package/dist/chat/steady.d.ts +3 -0
- package/dist/chat/steady.d.ts.map +1 -0
- package/dist/chat/steady.js +26 -0
- package/dist/chat.d.ts +2 -2
- package/dist/chat.d.ts.map +1 -1
- package/dist/chat.js +2 -2
- package/dist/connection.d.ts.map +1 -1
- package/dist/connection.js +45 -30
- package/dist/conversation.d.ts +5 -0
- package/dist/conversation.d.ts.map +1 -1
- package/dist/conversation.js +35 -1
- package/dist/host.d.ts +1 -1
- package/dist/host.d.ts.map +1 -1
- package/dist/host.js +1 -1
- package/dist/overlay.d.ts +3 -4
- package/dist/overlay.d.ts.map +1 -1
- package/dist/overlay.js +178 -141
- package/dist/read-side.d.ts.map +1 -1
- package/dist/read-side.js +4 -2
- package/dist/refresh.d.ts.map +1 -1
- package/dist/refresh.js +34 -15
- package/dist/replica.d.ts +2 -1
- package/dist/replica.d.ts.map +1 -1
- package/dist/replica.js +18 -15
- package/dist/room-draft.d.ts.map +1 -1
- package/dist/room-draft.js +8 -9
- package/dist/save.d.ts +1 -1
- package/dist/save.d.ts.map +1 -1
- package/dist/save.js +154 -92
- package/dist/shared.d.ts +1 -0
- package/dist/shared.d.ts.map +1 -1
- package/dist/shared.js +5 -1
- package/dist/store.d.ts +2 -0
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +387 -339
- package/dist/turn.d.ts +1 -1
- package/dist/turn.d.ts.map +1 -1
- package/dist/turn.js +4 -4
- package/package.json +2 -2
package/dist/store.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { sameBinary, sameChange } from './overlay.js';
|
|
2
|
-
import {
|
|
2
|
+
import { differences } from './shared.js';
|
|
3
|
+
import { inUnits, ROW_WEIGHT, stepped } from './turn.js';
|
|
3
4
|
import { precedes } from './windows.js';
|
|
4
5
|
const DATABASE = 'mdruntime';
|
|
5
6
|
const AUTHORED = 'mdruntime-authored';
|
|
@@ -62,11 +63,52 @@ function settled(request) {
|
|
|
62
63
|
request.onerror = () => reject(request.error);
|
|
63
64
|
});
|
|
64
65
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
66
|
+
const turns = new Map();
|
|
67
|
+
function idle(database) {
|
|
68
|
+
return turns.get(database.name) ?? Promise.resolve();
|
|
69
|
+
}
|
|
70
|
+
export function transacted(database, stores, mode, work) {
|
|
71
|
+
let release = () => { };
|
|
72
|
+
const turn = new Promise((resolve) => {
|
|
73
|
+
release = resolve;
|
|
74
|
+
});
|
|
75
|
+
const before = idle(database);
|
|
76
|
+
const queued = before.then(() => turn);
|
|
77
|
+
turns.set(database.name, queued);
|
|
78
|
+
void queued.then(() => {
|
|
79
|
+
if (turns.get(database.name) === queued)
|
|
80
|
+
turns.delete(database.name);
|
|
81
|
+
});
|
|
82
|
+
return before.then(() => {
|
|
83
|
+
let transaction;
|
|
84
|
+
try {
|
|
85
|
+
transaction = database.transaction(stores, mode);
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
release();
|
|
89
|
+
throw error;
|
|
90
|
+
}
|
|
91
|
+
const committed = new Promise((resolve, reject) => {
|
|
92
|
+
transaction.oncomplete = () => {
|
|
93
|
+
release();
|
|
94
|
+
resolve();
|
|
95
|
+
};
|
|
96
|
+
transaction.onabort = () => {
|
|
97
|
+
release();
|
|
98
|
+
reject(transaction.error);
|
|
99
|
+
};
|
|
100
|
+
transaction.onerror = () => reject(transaction.error);
|
|
101
|
+
});
|
|
102
|
+
let value;
|
|
103
|
+
try {
|
|
104
|
+
value = work(transaction);
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
void committed.catch(() => { });
|
|
108
|
+
transaction.abort();
|
|
109
|
+
throw error;
|
|
110
|
+
}
|
|
111
|
+
return Promise.all([value, committed]).then(([held]) => held);
|
|
70
112
|
});
|
|
71
113
|
}
|
|
72
114
|
const EMPTY_DECLARATIONS = {
|
|
@@ -75,28 +117,27 @@ const EMPTY_DECLARATIONS = {
|
|
|
75
117
|
capabilities: [],
|
|
76
118
|
};
|
|
77
119
|
function declaration(database) {
|
|
78
|
-
|
|
79
|
-
return settled(transaction.objectStore(DECLARATIONS).get(CURRENT)).then((record) => record ?? EMPTY_DECLARATIONS);
|
|
120
|
+
return transacted(database, DECLARATIONS, 'readonly', (transaction) => settled(transaction.objectStore(DECLARATIONS).get(CURRENT))).then((record) => record ?? EMPTY_DECLARATIONS);
|
|
80
121
|
}
|
|
81
122
|
function updateDeclaration(database, update) {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
123
|
+
return transacted(database, DECLARATIONS, 'readwrite', (transaction) => {
|
|
124
|
+
const store = transaction.objectStore(DECLARATIONS);
|
|
125
|
+
const prior = store.get(CURRENT);
|
|
126
|
+
prior.onsuccess = () => {
|
|
127
|
+
store.put(update(prior.result ?? EMPTY_DECLARATIONS), CURRENT);
|
|
128
|
+
};
|
|
129
|
+
});
|
|
89
130
|
}
|
|
90
131
|
function amendPending(database, locator, id, amendment) {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
132
|
+
return transacted(database, PENDING_CHANGES, 'readwrite', (transaction) => {
|
|
133
|
+
const pending = transaction.objectStore(PENDING_CHANGES);
|
|
134
|
+
const request = pending.get([locator, id]);
|
|
135
|
+
request.onsuccess = () => {
|
|
136
|
+
const record = request.result;
|
|
137
|
+
if (record !== undefined)
|
|
138
|
+
pending.put({ ...record, ...amendment });
|
|
139
|
+
};
|
|
140
|
+
});
|
|
100
141
|
}
|
|
101
142
|
function accepted({ conversation: _held, ...message }) {
|
|
102
143
|
return message;
|
|
@@ -175,33 +216,44 @@ function binaryFileRecord(locator, transfer, layer, path) {
|
|
|
175
216
|
binary: layer.binaries[path],
|
|
176
217
|
};
|
|
177
218
|
}
|
|
178
|
-
function
|
|
219
|
+
function* changedIn(next, base) {
|
|
220
|
+
if (base === null)
|
|
221
|
+
return new Set([...Object.keys(next.documents), ...Object.keys(next.binaries)]);
|
|
222
|
+
return new Set([
|
|
223
|
+
...(yield* differences(base.documents, next.documents)),
|
|
224
|
+
...(yield* differences(base.revisions, next.revisions)),
|
|
225
|
+
...(yield* differences(base.fileIds, next.fileIds)),
|
|
226
|
+
...(yield* differences(base.written, next.written)),
|
|
227
|
+
...(yield* differences(base.changes, next.changes, sameChange)),
|
|
228
|
+
...(yield* differences(base.binaries, next.binaries, sameBinary)),
|
|
229
|
+
]);
|
|
230
|
+
}
|
|
231
|
+
function writeLayer(transaction, locator, transfer, layer) {
|
|
232
|
+
const { next, base, paths } = layer;
|
|
179
233
|
const documents = transaction.objectStore(DOCUMENTS);
|
|
180
234
|
const files = transaction.objectStore(BINARY_FILES);
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
: new Set([
|
|
184
|
-
...differing(base.documents, next.documents),
|
|
185
|
-
...differing(base.revisions, next.revisions),
|
|
186
|
-
...differing(base.fileIds, next.fileIds),
|
|
187
|
-
...differing(base.written, next.written),
|
|
188
|
-
...differing(base.changes, next.changes, sameChange),
|
|
189
|
-
...differing(base.binaries, next.binaries, sameBinary),
|
|
190
|
-
]);
|
|
191
|
-
for (const path of paths) {
|
|
235
|
+
let last = null;
|
|
236
|
+
return inUnits(paths, (path) => {
|
|
192
237
|
if (next.documents[path] !== undefined) {
|
|
193
|
-
documents.put(documentRecord(locator, transfer, next, path));
|
|
238
|
+
last = documents.put(documentRecord(locator, transfer, next, path));
|
|
194
239
|
}
|
|
195
240
|
else if (base?.documents[path] !== undefined) {
|
|
196
|
-
documents.delete([locator, transfer, path]);
|
|
241
|
+
last = documents.delete([locator, transfer, path]);
|
|
197
242
|
}
|
|
198
243
|
if (next.binaries[path] !== undefined) {
|
|
199
|
-
files.put(binaryFileRecord(locator, transfer, next, path));
|
|
244
|
+
last = files.put(binaryFileRecord(locator, transfer, next, path));
|
|
200
245
|
}
|
|
201
246
|
else if (base?.binaries[path] !== undefined) {
|
|
202
|
-
files.delete([locator, transfer, path]);
|
|
247
|
+
last = files.delete([locator, transfer, path]);
|
|
203
248
|
}
|
|
204
|
-
|
|
249
|
+
return ROW_WEIGHT + (next.documents[path]?.length ?? 0);
|
|
250
|
+
}, () => { }, () => {
|
|
251
|
+
const request = last;
|
|
252
|
+
last = null;
|
|
253
|
+
return request === null
|
|
254
|
+
? Promise.resolve()
|
|
255
|
+
: new Promise((resolve) => request.addEventListener('success', () => resolve()));
|
|
256
|
+
});
|
|
205
257
|
}
|
|
206
258
|
function removeRoomEntries(store, locator) {
|
|
207
259
|
const keys = store.getAllKeys();
|
|
@@ -222,10 +274,8 @@ function removeDatabase(name) {
|
|
|
222
274
|
export async function authoredHolder() {
|
|
223
275
|
const authored = await openAuthored();
|
|
224
276
|
try {
|
|
225
|
-
const
|
|
226
|
-
|
|
227
|
-
await completed(transaction);
|
|
228
|
-
return typeof held.result === 'string' ? held.result : null;
|
|
277
|
+
const held = await transacted(authored, FACTS, 'readonly', (transaction) => settled(transaction.objectStore(FACTS).get(HOLDER)));
|
|
278
|
+
return typeof held === 'string' ? held : null;
|
|
229
279
|
}
|
|
230
280
|
finally {
|
|
231
281
|
authored.close();
|
|
@@ -234,17 +284,17 @@ export async function authoredHolder() {
|
|
|
234
284
|
export async function authoredBy(holder) {
|
|
235
285
|
const authored = await openAuthored();
|
|
236
286
|
try {
|
|
237
|
-
const transaction = authored.transaction(FACTS, 'readwrite');
|
|
238
|
-
const facts = transaction.objectStore(FACTS);
|
|
239
|
-
const held = facts.get(HOLDER);
|
|
240
287
|
let owned = true;
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
288
|
+
await transacted(authored, FACTS, 'readwrite', (transaction) => {
|
|
289
|
+
const facts = transaction.objectStore(FACTS);
|
|
290
|
+
const held = facts.get(HOLDER);
|
|
291
|
+
held.onsuccess = () => {
|
|
292
|
+
if (held.result === undefined)
|
|
293
|
+
facts.put(holder, HOLDER);
|
|
294
|
+
else
|
|
295
|
+
owned = held.result === holder;
|
|
296
|
+
};
|
|
297
|
+
});
|
|
248
298
|
return owned;
|
|
249
299
|
}
|
|
250
300
|
finally {
|
|
@@ -254,10 +304,8 @@ export async function authoredBy(holder) {
|
|
|
254
304
|
export async function authoredBinding() {
|
|
255
305
|
const authored = await openAuthored();
|
|
256
306
|
try {
|
|
257
|
-
const
|
|
258
|
-
|
|
259
|
-
await completed(transaction);
|
|
260
|
-
return typeof held.result === 'string' ? held.result : null;
|
|
307
|
+
const held = await transacted(authored, FACTS, 'readonly', (transaction) => settled(transaction.objectStore(FACTS).get(BINDING)));
|
|
308
|
+
return typeof held === 'string' ? held : null;
|
|
261
309
|
}
|
|
262
310
|
finally {
|
|
263
311
|
authored.close();
|
|
@@ -266,9 +314,9 @@ export async function authoredBinding() {
|
|
|
266
314
|
export async function bindAuthored(binding) {
|
|
267
315
|
const authored = await openAuthored();
|
|
268
316
|
try {
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
317
|
+
await transacted(authored, FACTS, 'readwrite', (transaction) => {
|
|
318
|
+
transaction.objectStore(FACTS).put(binding, BINDING);
|
|
319
|
+
});
|
|
272
320
|
}
|
|
273
321
|
finally {
|
|
274
322
|
authored.close();
|
|
@@ -332,89 +380,97 @@ export async function openRuntimeStore(fenced) {
|
|
|
332
380
|
throw error;
|
|
333
381
|
});
|
|
334
382
|
return {
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
383
|
+
all() {
|
|
384
|
+
return transacted(database, [ROOMS, DOCUMENTS, BINARY_FILES], 'readonly', async (transaction) => {
|
|
385
|
+
const rooms = await settled(transaction.objectStore(ROOMS).getAll());
|
|
386
|
+
const records = [];
|
|
387
|
+
for (const room of rooms.filter((held) => !fenced(held.locator))) {
|
|
388
|
+
records.push({
|
|
389
|
+
...room,
|
|
390
|
+
...(await readLayer(transaction, room.locator, room.transfer)),
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
return records;
|
|
394
|
+
});
|
|
343
395
|
},
|
|
344
396
|
async keepAuthored({ locator, queue, founded, saved, roomDrafts, consumedRoomDrafts }) {
|
|
345
397
|
if (fenced(locator))
|
|
346
398
|
return;
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
}
|
|
362
|
-
for (const batch of queue) {
|
|
363
|
-
if (!before.has(batch.id)) {
|
|
364
|
-
pending.put({
|
|
365
|
-
locator,
|
|
366
|
-
id: batch.id,
|
|
367
|
-
batch,
|
|
368
|
-
drafts: saved?.get(batch.id) ?? [],
|
|
369
|
-
submission: { state: 'waiting' },
|
|
370
|
-
lost: false,
|
|
371
|
-
});
|
|
399
|
+
await transacted(authored, [QUEUES, PENDING_CHANGES, ROOM_DRAFTS], 'readwrite', (transaction) => {
|
|
400
|
+
const order = transaction.objectStore(QUEUES);
|
|
401
|
+
const pending = transaction.objectStore(PENDING_CHANGES);
|
|
402
|
+
const held = order.get(locator);
|
|
403
|
+
held.onsuccess = () => {
|
|
404
|
+
const before = new Set(held.result?.order ?? []);
|
|
405
|
+
const after = new Set(queue.map((batch) => batch.id));
|
|
406
|
+
if (queue.length === 0)
|
|
407
|
+
order.delete(locator);
|
|
408
|
+
else
|
|
409
|
+
order.put({ locator, order: [...after] });
|
|
410
|
+
for (const id of before) {
|
|
411
|
+
if (!after.has(id))
|
|
412
|
+
pending.delete([locator, id]);
|
|
372
413
|
}
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
414
|
+
for (const batch of queue) {
|
|
415
|
+
if (!before.has(batch.id)) {
|
|
416
|
+
pending.put({
|
|
417
|
+
locator,
|
|
418
|
+
id: batch.id,
|
|
419
|
+
batch,
|
|
420
|
+
drafts: saved?.get(batch.id) ?? [],
|
|
421
|
+
submission: { state: 'waiting' },
|
|
422
|
+
lost: false,
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
for (const batch of founded ?? []) {
|
|
427
|
+
if (!before.has(batch.id))
|
|
428
|
+
continue;
|
|
429
|
+
const stored = pending.get([locator, batch.id]);
|
|
430
|
+
stored.onsuccess = () => {
|
|
431
|
+
const record = stored.result;
|
|
432
|
+
if (record !== undefined)
|
|
433
|
+
pending.put({ ...record, batch });
|
|
434
|
+
};
|
|
435
|
+
}
|
|
436
|
+
};
|
|
437
|
+
const draftStore = transaction.objectStore(ROOM_DRAFTS);
|
|
438
|
+
for (const path of consumedRoomDrafts ?? [])
|
|
439
|
+
draftStore.delete([locator, path]);
|
|
440
|
+
for (const record of roomDrafts ?? [])
|
|
441
|
+
draftStore.put(record);
|
|
442
|
+
});
|
|
391
443
|
},
|
|
392
444
|
async write({ next, previous, stored }) {
|
|
393
445
|
if (next === previous || fenced(next.locator))
|
|
394
446
|
return;
|
|
395
|
-
const transaction = database.transaction([ROOMS, DOCUMENTS, BINARY_FILES, TRANSFERS], 'readwrite');
|
|
396
|
-
transaction.objectStore(ROOMS).put(roomRecord(next));
|
|
397
447
|
const moved = previous?.transfer !== next.transfer;
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
448
|
+
const base = moved ? (stored ?? null) : previous;
|
|
449
|
+
const paths = await stepped(changedIn(next, base));
|
|
450
|
+
if (fenced(next.locator))
|
|
451
|
+
return;
|
|
452
|
+
await transacted(database, [ROOMS, DOCUMENTS, BINARY_FILES, TRANSFERS], 'readwrite', (transaction) => {
|
|
453
|
+
transaction.objectStore(ROOMS).put(roomRecord(next));
|
|
454
|
+
if (moved && previous !== null) {
|
|
455
|
+
const range = underTransfer(previous.locator, previous.transfer);
|
|
456
|
+
transaction.objectStore(DOCUMENTS).delete(range);
|
|
457
|
+
transaction.objectStore(BINARY_FILES).delete(range);
|
|
458
|
+
}
|
|
459
|
+
if (moved)
|
|
460
|
+
transaction.objectStore(TRANSFERS).delete(next.locator);
|
|
461
|
+
return writeLayer(transaction, next.locator, next.transfer, { next, base, paths });
|
|
462
|
+
});
|
|
407
463
|
},
|
|
408
464
|
async revokeModels(records) {
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
465
|
+
await transacted(database, ROOMS, 'readwrite', (transaction) => {
|
|
466
|
+
const rooms = transaction.objectStore(ROOMS);
|
|
467
|
+
const revoked = { status: 'unavailable', reason: 'revoked' };
|
|
468
|
+
for (const record of records) {
|
|
469
|
+
if (fenced(record.locator))
|
|
470
|
+
continue;
|
|
471
|
+
rooms.put(roomRecord({ ...record, model: revoked, selectionModel: revoked }));
|
|
472
|
+
}
|
|
473
|
+
});
|
|
418
474
|
},
|
|
419
475
|
async lastCompleted() {
|
|
420
476
|
return (await declaration(database)).lastCompleted;
|
|
@@ -436,31 +492,28 @@ export async function openRuntimeStore(fenced) {
|
|
|
436
492
|
}));
|
|
437
493
|
},
|
|
438
494
|
async member() {
|
|
439
|
-
const
|
|
440
|
-
const held = await settled(transaction.objectStore(DECLARATIONS).get(MEMBER));
|
|
495
|
+
const held = await transacted(database, DECLARATIONS, 'readonly', (transaction) => settled(transaction.objectStore(DECLARATIONS).get(MEMBER)));
|
|
441
496
|
return held ?? null;
|
|
442
497
|
},
|
|
443
498
|
async keepMember(member) {
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
499
|
+
await transacted(database, DECLARATIONS, 'readwrite', (transaction) => {
|
|
500
|
+
transaction.objectStore(DECLARATIONS).put(member, MEMBER);
|
|
501
|
+
});
|
|
447
502
|
},
|
|
448
503
|
async targets() {
|
|
449
|
-
const
|
|
450
|
-
const held = await settled(transaction.objectStore(DECLARATIONS).get(TARGETS));
|
|
504
|
+
const held = await transacted(database, DECLARATIONS, 'readonly', (transaction) => settled(transaction.objectStore(DECLARATIONS).get(TARGETS)));
|
|
451
505
|
return held ?? {};
|
|
452
506
|
},
|
|
453
507
|
async keepTargets(targets) {
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
508
|
+
await transacted(database, DECLARATIONS, 'readwrite', (transaction) => {
|
|
509
|
+
transaction.objectStore(DECLARATIONS).put(targets, TARGETS);
|
|
510
|
+
});
|
|
457
511
|
},
|
|
458
512
|
async queues() {
|
|
459
|
-
const
|
|
460
|
-
const [queues, pending] = await Promise.all([
|
|
513
|
+
const [queues, pending] = await transacted(authored, [QUEUES, PENDING_CHANGES], 'readonly', (transaction) => Promise.all([
|
|
461
514
|
settled(transaction.objectStore(QUEUES).getAll()),
|
|
462
515
|
settled(transaction.objectStore(PENDING_CHANGES).getAll()),
|
|
463
|
-
]);
|
|
516
|
+
]));
|
|
464
517
|
const byId = new Map(pending.map((record) => [`${record.locator}\0${record.id}`, record]));
|
|
465
518
|
return queues
|
|
466
519
|
.filter((queue) => !fenced(queue.locator))
|
|
@@ -488,281 +541,276 @@ export async function openRuntimeStore(fenced) {
|
|
|
488
541
|
await amendPending(authored, locator, id, { upload });
|
|
489
542
|
},
|
|
490
543
|
async roomDrafts() {
|
|
491
|
-
const
|
|
492
|
-
const held = await settled(transaction.objectStore(ROOM_DRAFTS).getAll());
|
|
544
|
+
const held = await transacted(authored, ROOM_DRAFTS, 'readonly', (transaction) => settled(transaction.objectStore(ROOM_DRAFTS).getAll()));
|
|
493
545
|
return held.filter((record) => !fenced(record.locator));
|
|
494
546
|
},
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
return settled(transaction.objectStore(PRESENTATION).getAll());
|
|
547
|
+
presentation() {
|
|
548
|
+
return transacted(database, PRESENTATION, 'readonly', (transaction) => settled(transaction.objectStore(PRESENTATION).getAll()));
|
|
498
549
|
},
|
|
499
550
|
async present(record) {
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
await completed(transaction);
|
|
503
|
-
},
|
|
504
|
-
async conversations() {
|
|
505
|
-
const transaction = database.transaction([CONVERSATIONS, MESSAGES], 'readonly');
|
|
506
|
-
const records = await settled(transaction.objectStore(CONVERSATIONS).getAll());
|
|
507
|
-
const held = new Map(records.map(({ conversation, read, partial }) => [
|
|
508
|
-
conversation,
|
|
509
|
-
{ conversation, read, partial: partial === true },
|
|
510
|
-
]));
|
|
511
|
-
const keys = transaction.objectStore(MESSAGES).index('conversation');
|
|
512
|
-
await new Promise((resolve, reject) => {
|
|
513
|
-
const cursor = keys.openKeyCursor(null, 'nextunique');
|
|
514
|
-
cursor.onerror = () => reject(cursor.error);
|
|
515
|
-
cursor.onsuccess = () => {
|
|
516
|
-
const at = cursor.result;
|
|
517
|
-
if (at === null) {
|
|
518
|
-
resolve();
|
|
519
|
-
return;
|
|
520
|
-
}
|
|
521
|
-
const conversation = at.key;
|
|
522
|
-
if (!held.has(conversation)) {
|
|
523
|
-
held.set(conversation, { conversation, read: undefined, partial: true });
|
|
524
|
-
}
|
|
525
|
-
at.continue();
|
|
526
|
-
};
|
|
551
|
+
await transacted(database, PRESENTATION, 'readwrite', (transaction) => {
|
|
552
|
+
transaction.objectStore(PRESENTATION).put(record);
|
|
527
553
|
});
|
|
528
|
-
return [...held.values()];
|
|
529
554
|
},
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
stored.put({ ...message, conversation });
|
|
535
|
-
}
|
|
536
|
-
if (read !== undefined) {
|
|
537
|
-
transaction.objectStore(CONVERSATIONS).put({
|
|
555
|
+
conversations() {
|
|
556
|
+
return transacted(database, [CONVERSATIONS, MESSAGES], 'readonly', async (transaction) => {
|
|
557
|
+
const records = await settled(transaction.objectStore(CONVERSATIONS).getAll());
|
|
558
|
+
const held = new Map(records.map(({ conversation, read, partial }) => [
|
|
538
559
|
conversation,
|
|
539
|
-
read:
|
|
540
|
-
|
|
560
|
+
{ conversation, read, partial: partial === true },
|
|
561
|
+
]));
|
|
562
|
+
const keys = transaction.objectStore(MESSAGES).index('conversation');
|
|
563
|
+
await new Promise((resolve, reject) => {
|
|
564
|
+
const cursor = keys.openKeyCursor(null, 'nextunique');
|
|
565
|
+
cursor.onerror = () => reject(cursor.error);
|
|
566
|
+
cursor.onsuccess = () => {
|
|
567
|
+
const at = cursor.result;
|
|
568
|
+
if (at === null) {
|
|
569
|
+
resolve();
|
|
570
|
+
return;
|
|
571
|
+
}
|
|
572
|
+
const conversation = at.key;
|
|
573
|
+
if (!held.has(conversation)) {
|
|
574
|
+
held.set(conversation, { conversation, read: undefined, partial: true });
|
|
575
|
+
}
|
|
576
|
+
at.continue();
|
|
577
|
+
};
|
|
541
578
|
});
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
},
|
|
545
|
-
async
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
579
|
+
return [...held.values()];
|
|
580
|
+
});
|
|
581
|
+
},
|
|
582
|
+
async keepMessages({ conversation, messages, read }) {
|
|
583
|
+
await transacted(database, [CONVERSATIONS, MESSAGES], 'readwrite', (transaction) => {
|
|
584
|
+
const stored = transaction.objectStore(MESSAGES);
|
|
585
|
+
for (const message of messages) {
|
|
586
|
+
stored.put({ ...message, conversation });
|
|
587
|
+
}
|
|
588
|
+
if (read !== undefined) {
|
|
589
|
+
transaction.objectStore(CONVERSATIONS).put({
|
|
590
|
+
conversation,
|
|
591
|
+
read: read.at,
|
|
592
|
+
...(read.partial ? { partial: true } : {}),
|
|
593
|
+
});
|
|
594
|
+
}
|
|
595
|
+
});
|
|
596
|
+
},
|
|
597
|
+
messageWindow(conversation, limit, before) {
|
|
598
|
+
return transacted(database, MESSAGES, 'readonly', async (transaction) => {
|
|
599
|
+
const index = transaction.objectStore(MESSAGES).index('position');
|
|
600
|
+
const range = IDBKeyRange.bound([conversation], [conversation, before?.[0] ?? []]);
|
|
601
|
+
const latest = [];
|
|
602
|
+
let more = false;
|
|
603
|
+
await new Promise((resolve, reject) => {
|
|
604
|
+
const cursor = index.openCursor(range, 'prev');
|
|
605
|
+
cursor.onerror = () => reject(cursor.error);
|
|
606
|
+
cursor.onsuccess = () => {
|
|
607
|
+
const at = cursor.result;
|
|
608
|
+
if (at === null) {
|
|
609
|
+
resolve();
|
|
610
|
+
return;
|
|
611
|
+
}
|
|
612
|
+
const record = at.value;
|
|
613
|
+
if (!precedes(record, before)) {
|
|
614
|
+
at.continue();
|
|
615
|
+
return;
|
|
616
|
+
}
|
|
617
|
+
if (latest.length === limit) {
|
|
618
|
+
more = true;
|
|
619
|
+
resolve();
|
|
620
|
+
return;
|
|
621
|
+
}
|
|
622
|
+
latest.push(accepted(record));
|
|
562
623
|
at.continue();
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
more = true;
|
|
567
|
-
resolve();
|
|
568
|
-
return;
|
|
569
|
-
}
|
|
570
|
-
latest.push(accepted(record));
|
|
571
|
-
at.continue();
|
|
572
|
-
};
|
|
624
|
+
};
|
|
625
|
+
});
|
|
626
|
+
return { messages: latest.reverse(), more };
|
|
573
627
|
});
|
|
574
|
-
return { messages: latest.reverse(), more };
|
|
575
628
|
},
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
return settled(transaction.objectStore(MESSAGES).index('conversation').count(conversation));
|
|
629
|
+
messageCount(conversation) {
|
|
630
|
+
return transacted(database, MESSAGES, 'readonly', (transaction) => settled(transaction.objectStore(MESSAGES).index('conversation').count(conversation)));
|
|
579
631
|
},
|
|
580
632
|
async messagesAfter(conversation, identity) {
|
|
581
|
-
const transaction = database.transaction(MESSAGES, 'readonly');
|
|
582
633
|
const range = identity === null
|
|
583
634
|
? IDBKeyRange.bound([conversation], [conversation, []])
|
|
584
635
|
: IDBKeyRange.bound([conversation, identity], [conversation, []], true);
|
|
585
|
-
const held = await settled(transaction.objectStore(MESSAGES).getAll(range, READ_BATCH));
|
|
636
|
+
const held = await transacted(database, MESSAGES, 'readonly', (transaction) => settled(transaction.objectStore(MESSAGES).getAll(range, READ_BATCH)));
|
|
586
637
|
return held.map(accepted);
|
|
587
638
|
},
|
|
588
639
|
async messageIdentities(conversation) {
|
|
589
|
-
const
|
|
590
|
-
const keys = await settled(transaction.objectStore(MESSAGES).index('conversation').getAllKeys(conversation));
|
|
640
|
+
const keys = await transacted(database, MESSAGES, 'readonly', (transaction) => settled(transaction.objectStore(MESSAGES).index('conversation').getAllKeys(conversation)));
|
|
591
641
|
return keys.map((key) => key[1]);
|
|
592
642
|
},
|
|
593
643
|
async turnArrived(conversation, turn) {
|
|
594
|
-
const
|
|
595
|
-
const held = await settled(transaction.objectStore(MESSAGES).index('turn').count([conversation, turn]));
|
|
644
|
+
const held = await transacted(database, MESSAGES, 'readonly', (transaction) => settled(transaction.objectStore(MESSAGES).index('turn').count([conversation, turn])));
|
|
596
645
|
return held > 0;
|
|
597
646
|
},
|
|
598
647
|
async dropConversations(conversations) {
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
648
|
+
await transacted(authored, CHAT_DRAFTS, 'readwrite', (drafts) => {
|
|
649
|
+
for (const conversation of conversations)
|
|
650
|
+
drafts.objectStore(CHAT_DRAFTS).delete(conversation);
|
|
651
|
+
});
|
|
652
|
+
await transacted(database, [CONVERSATIONS, MESSAGES], 'readwrite', (transaction) => {
|
|
653
|
+
const messages = transaction.objectStore(MESSAGES);
|
|
654
|
+
for (const conversation of conversations) {
|
|
655
|
+
transaction.objectStore(CONVERSATIONS).delete(conversation);
|
|
656
|
+
const keys = messages.index('conversation').getAllKeys(conversation);
|
|
657
|
+
keys.onsuccess = () => {
|
|
658
|
+
for (const key of keys.result)
|
|
659
|
+
messages.delete(key);
|
|
660
|
+
};
|
|
661
|
+
}
|
|
662
|
+
});
|
|
614
663
|
},
|
|
615
664
|
async chatDrafts() {
|
|
616
|
-
const
|
|
617
|
-
const held = await settled(transaction.objectStore(CHAT_DRAFTS).getAll());
|
|
665
|
+
const held = await transacted(authored, CHAT_DRAFTS, 'readonly', (transaction) => settled(transaction.objectStore(CHAT_DRAFTS).getAll()));
|
|
618
666
|
return held.map(chatDraftRecord);
|
|
619
667
|
},
|
|
620
668
|
async keepChatDrafts(records) {
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
669
|
+
await transacted(authored, CHAT_DRAFTS, 'readwrite', (transaction) => {
|
|
670
|
+
for (const record of records)
|
|
671
|
+
transaction.objectStore(CHAT_DRAFTS).put(record);
|
|
672
|
+
});
|
|
625
673
|
},
|
|
626
674
|
async dropChatDraft(conversation) {
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
675
|
+
await transacted(authored, CHAT_DRAFTS, 'readwrite', (transaction) => {
|
|
676
|
+
transaction.objectStore(CHAT_DRAFTS).delete(conversation);
|
|
677
|
+
});
|
|
630
678
|
},
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
return settled(transaction.objectStore(CALLS).getAll());
|
|
679
|
+
calls() {
|
|
680
|
+
return transacted(authored, CALLS, 'readonly', (transaction) => settled(transaction.objectStore(CALLS).getAll()));
|
|
634
681
|
},
|
|
635
682
|
async keepCall(record) {
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
683
|
+
await transacted(authored, CALLS, 'readwrite', (transaction) => {
|
|
684
|
+
transaction.objectStore(CALLS).put(record);
|
|
685
|
+
});
|
|
639
686
|
},
|
|
640
687
|
async dropCall(operation) {
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
688
|
+
await transacted(authored, CALLS, 'readwrite', (transaction) => {
|
|
689
|
+
transaction.objectStore(CALLS).delete(operation);
|
|
690
|
+
});
|
|
644
691
|
},
|
|
645
692
|
async keepRoomDraft(record) {
|
|
646
693
|
if (fenced(record.locator))
|
|
647
694
|
return;
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
695
|
+
await transacted(authored, ROOM_DRAFTS, 'readwrite', (transaction) => {
|
|
696
|
+
transaction.objectStore(ROOM_DRAFTS).put(record);
|
|
697
|
+
});
|
|
651
698
|
},
|
|
652
699
|
async discardRoomDraft(locator, path) {
|
|
653
700
|
if (fenced(locator))
|
|
654
701
|
return;
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
702
|
+
await transacted(authored, ROOM_DRAFTS, 'readwrite', (transaction) => {
|
|
703
|
+
transaction.objectStore(ROOM_DRAFTS).delete([locator, path]);
|
|
704
|
+
});
|
|
658
705
|
},
|
|
659
706
|
async fences() {
|
|
660
|
-
const
|
|
661
|
-
const held = await settled(transaction.objectStore(FENCES).getAll());
|
|
707
|
+
const held = await transacted(authored, FENCES, 'readonly', (transaction) => settled(transaction.objectStore(FENCES).getAll()));
|
|
662
708
|
return held.map((fence) => fence.locator);
|
|
663
709
|
},
|
|
664
710
|
async erase(locators) {
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
711
|
+
await transacted(authored, [FENCES, QUEUES, PENDING_CHANGES, ROOM_DRAFTS], 'readwrite', (work) => {
|
|
712
|
+
for (const locator of locators) {
|
|
713
|
+
work.objectStore(FENCES).put({ locator });
|
|
714
|
+
work.objectStore(QUEUES).delete(locator);
|
|
715
|
+
for (const name of [PENDING_CHANGES, ROOM_DRAFTS]) {
|
|
716
|
+
removeRoomEntries(work.objectStore(name), locator);
|
|
717
|
+
}
|
|
671
718
|
}
|
|
672
|
-
}
|
|
673
|
-
await
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
}
|
|
681
|
-
await
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
await completed(fences);
|
|
719
|
+
});
|
|
720
|
+
await transacted(database, [ROOMS, DOCUMENTS, BINARY_FILES, TRANSFERS], 'readwrite', (transaction) => {
|
|
721
|
+
for (const locator of locators) {
|
|
722
|
+
transaction.objectStore(ROOMS).delete(locator);
|
|
723
|
+
transaction.objectStore(TRANSFERS).delete(locator);
|
|
724
|
+
transaction.objectStore(DOCUMENTS).delete(underRoom(locator));
|
|
725
|
+
transaction.objectStore(BINARY_FILES).delete(underRoom(locator));
|
|
726
|
+
}
|
|
727
|
+
});
|
|
728
|
+
await transacted(authored, FENCES, 'readwrite', (fences) => {
|
|
729
|
+
for (const locator of locators)
|
|
730
|
+
fences.objectStore(FENCES).delete(locator);
|
|
731
|
+
});
|
|
686
732
|
},
|
|
687
733
|
async discard(locator) {
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
734
|
+
await transacted(authored, [QUEUES, PENDING_CHANGES], 'readwrite', (transaction) => {
|
|
735
|
+
transaction.objectStore(QUEUES).delete(locator);
|
|
736
|
+
removeRoomEntries(transaction.objectStore(PENDING_CHANGES), locator);
|
|
737
|
+
});
|
|
692
738
|
},
|
|
693
739
|
async transfers() {
|
|
694
|
-
const
|
|
695
|
-
const held = await settled(transaction.objectStore(TRANSFERS).getAll());
|
|
740
|
+
const held = await transacted(database, TRANSFERS, 'readonly', (transaction) => settled(transaction.objectStore(TRANSFERS).getAll()));
|
|
696
741
|
return held.filter((record) => !fenced(record.locator));
|
|
697
742
|
},
|
|
698
743
|
staged(record) {
|
|
699
|
-
|
|
700
|
-
return readLayer(transaction, record.locator, record.transfer);
|
|
744
|
+
return transacted(database, [DOCUMENTS, BINARY_FILES], 'readonly', (transaction) => readLayer(transaction, record.locator, record.transfer));
|
|
701
745
|
},
|
|
702
746
|
async stage(record, page) {
|
|
703
747
|
if (fenced(record.locator))
|
|
704
748
|
return;
|
|
705
|
-
const
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
await
|
|
749
|
+
const paths = await stepped(changedIn(page, null));
|
|
750
|
+
if (fenced(record.locator))
|
|
751
|
+
return;
|
|
752
|
+
await transacted(database, [TRANSFERS, DOCUMENTS, BINARY_FILES], 'readwrite', (transaction) => {
|
|
753
|
+
transaction.objectStore(TRANSFERS).put(record);
|
|
754
|
+
return writeLayer(transaction, record.locator, record.transfer, {
|
|
755
|
+
next: page,
|
|
756
|
+
base: null,
|
|
757
|
+
paths,
|
|
758
|
+
});
|
|
759
|
+
});
|
|
709
760
|
},
|
|
710
761
|
async abandon(locator) {
|
|
711
762
|
if (fenced(locator))
|
|
712
763
|
return;
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
764
|
+
await transacted(database, [TRANSFERS, DOCUMENTS, BINARY_FILES], 'readwrite', (transaction) => {
|
|
765
|
+
const transfers = transaction.objectStore(TRANSFERS);
|
|
766
|
+
const held = transfers.get(locator);
|
|
767
|
+
held.onsuccess = () => {
|
|
768
|
+
const record = held.result;
|
|
769
|
+
if (record === undefined)
|
|
770
|
+
return;
|
|
771
|
+
transfers.delete(locator);
|
|
772
|
+
const range = underTransfer(locator, record.transfer);
|
|
773
|
+
transaction.objectStore(DOCUMENTS).delete(range);
|
|
774
|
+
transaction.objectStore(BINARY_FILES).delete(range);
|
|
775
|
+
};
|
|
776
|
+
});
|
|
726
777
|
},
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
return settled(transaction.objectStore(RECEIVED).getAll());
|
|
778
|
+
receivedHeads() {
|
|
779
|
+
return transacted(database, RECEIVED, 'readonly', (transaction) => settled(transaction.objectStore(RECEIVED).getAll()));
|
|
730
780
|
},
|
|
731
781
|
async receivedParts(key, count) {
|
|
732
|
-
const
|
|
733
|
-
const kept = await settled(transaction
|
|
782
|
+
const kept = await transacted(database, RECEIVED_PARTS, 'readonly', (transaction) => settled(transaction
|
|
734
783
|
.objectStore(RECEIVED_PARTS)
|
|
735
|
-
.getAll(IDBKeyRange.bound([key, 0], [key, count], false, true)));
|
|
784
|
+
.getAll(IDBKeyRange.bound([key, 0], [key, count], false, true))));
|
|
736
785
|
return kept.map((part) => part.value);
|
|
737
786
|
},
|
|
738
787
|
async keepReceived(key, head, part) {
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
788
|
+
await transacted(database, [RECEIVED, RECEIVED_PARTS], 'readwrite', (transaction) => {
|
|
789
|
+
transaction.objectStore(RECEIVED).put({ key, head });
|
|
790
|
+
if (part !== undefined)
|
|
791
|
+
transaction.objectStore(RECEIVED_PARTS).put({ key, ...part });
|
|
792
|
+
});
|
|
744
793
|
},
|
|
745
794
|
async dropReceived(keys) {
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
795
|
+
await transacted(database, [RECEIVED, RECEIVED_PARTS], 'readwrite', (transaction) => {
|
|
796
|
+
for (const key of keys) {
|
|
797
|
+
transaction.objectStore(RECEIVED).delete(key);
|
|
798
|
+
transaction.objectStore(RECEIVED_PARTS).delete(IDBKeyRange.bound([key], [key, []]));
|
|
799
|
+
}
|
|
800
|
+
});
|
|
752
801
|
},
|
|
753
802
|
async generation() {
|
|
754
|
-
const
|
|
755
|
-
const held = await settled(transaction.objectStore(FACTS).get(GENERATION));
|
|
803
|
+
const held = await transacted(authored, FACTS, 'readonly', (transaction) => settled(transaction.objectStore(FACTS).get(GENERATION)));
|
|
756
804
|
return held ?? null;
|
|
757
805
|
},
|
|
758
806
|
async rememberGeneration(value) {
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
807
|
+
await transacted(authored, FACTS, 'readwrite', (transaction) => {
|
|
808
|
+
transaction.objectStore(FACTS).put(value, GENERATION);
|
|
809
|
+
});
|
|
762
810
|
},
|
|
763
811
|
close() {
|
|
764
|
-
authored
|
|
765
|
-
|
|
812
|
+
for (const held of [authored, database])
|
|
813
|
+
void idle(held).then(() => held.close());
|
|
766
814
|
},
|
|
767
815
|
};
|
|
768
816
|
}
|