@agentshouse/mdruntime 0.1.0-alpha.20 → 0.1.0-alpha.22
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/AGENTS.md +9 -1
- package/dist/adapter.d.ts +20 -3
- package/dist/adapter.d.ts.map +1 -1
- package/dist/adapter.js.map +1 -1
- package/dist/change-set.d.ts +40 -0
- package/dist/change-set.d.ts.map +1 -0
- package/dist/change-set.js +94 -0
- package/dist/change-set.js.map +1 -0
- package/dist/client.d.ts +7 -6
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +19 -13
- package/dist/client.js.map +1 -1
- package/dist/collection.d.ts +8 -2
- package/dist/collection.d.ts.map +1 -1
- package/dist/collection.js +8 -3
- package/dist/collection.js.map +1 -1
- package/dist/connection.d.ts +4 -2
- package/dist/connection.d.ts.map +1 -1
- package/dist/connection.js +308 -168
- package/dist/connection.js.map +1 -1
- package/dist/conversation.d.ts +28 -16
- package/dist/conversation.d.ts.map +1 -1
- package/dist/conversation.js +371 -269
- package/dist/conversation.js.map +1 -1
- package/dist/file.d.ts +2 -2
- package/dist/file.d.ts.map +1 -1
- package/dist/file.js.map +1 -1
- package/dist/host.d.ts.map +1 -1
- package/dist/host.js +7 -8
- package/dist/host.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/memory.d.ts +3 -2
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +24 -20
- package/dist/memory.js.map +1 -1
- package/dist/overlay.d.ts +2 -0
- package/dist/overlay.d.ts.map +1 -1
- package/dist/overlay.js +106 -0
- package/dist/overlay.js.map +1 -1
- package/dist/refresh.d.ts.map +1 -1
- package/dist/refresh.js +1 -1
- package/dist/refresh.js.map +1 -1
- package/dist/replica.d.ts +12 -3
- package/dist/replica.d.ts.map +1 -1
- package/dist/replica.js +61 -26
- package/dist/replica.js.map +1 -1
- package/dist/store.d.ts +43 -19
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +371 -106
- package/dist/store.js.map +1 -1
- package/dist/wire.d.ts +2 -2
- package/dist/wire.d.ts.map +1 -1
- package/dist/wire.js +4 -5
- package/dist/wire.js.map +1 -1
- package/package.json +1 -1
package/dist/connection.js
CHANGED
|
@@ -2,6 +2,7 @@ import { rawQuery } from './query.js';
|
|
|
2
2
|
import { cached, modelTypes, NO_MODEL, sameModel } from './model.js';
|
|
3
3
|
import { ROOM_CONTRACT_VERSION, VERSION_1_CAPABILITIES } from './adapter.js';
|
|
4
4
|
import { bootstrapRoom } from './bootstrap.js';
|
|
5
|
+
import { changeSet, mergeChangeSets } from './change-set.js';
|
|
5
6
|
import { createConversationStore } from './conversation.js';
|
|
6
7
|
import { MD_MODEL, PRESENTED, validRoot } from './collection.js';
|
|
7
8
|
import { createLog } from './log.js';
|
|
@@ -78,6 +79,7 @@ export function createMdRuntime(options) {
|
|
|
78
79
|
let refusal = null;
|
|
79
80
|
let storageLoss = null;
|
|
80
81
|
let status = STARTING;
|
|
82
|
+
let shown = STARTING;
|
|
81
83
|
let discoveryPaused = false;
|
|
82
84
|
let timer;
|
|
83
85
|
let closed = false;
|
|
@@ -97,12 +99,14 @@ export function createMdRuntime(options) {
|
|
|
97
99
|
const draftListeners = new Set();
|
|
98
100
|
const presentationListeners = new Set();
|
|
99
101
|
let withdrawConversations;
|
|
102
|
+
let currencyQueued = false;
|
|
100
103
|
const conversations = createConversationStore({
|
|
101
104
|
cards: declaredCards,
|
|
102
|
-
documents: ()=>visible({}),
|
|
105
|
+
documents: ()=>visible({}).documents,
|
|
103
106
|
call: (name, input)=>invokeAction(name, input),
|
|
104
107
|
durably,
|
|
105
|
-
|
|
108
|
+
stream: ()=>options.adapter.conversations,
|
|
109
|
+
publish: publishChangeSet,
|
|
106
110
|
closed: ()=>closed
|
|
107
111
|
});
|
|
108
112
|
const journal = createLog();
|
|
@@ -142,10 +146,6 @@ export function createMdRuntime(options) {
|
|
|
142
146
|
});
|
|
143
147
|
return entries;
|
|
144
148
|
}
|
|
145
|
-
async function readDrafts(opened) {
|
|
146
|
-
await hydrate(opened);
|
|
147
|
-
return snapshotDrafts();
|
|
148
|
-
}
|
|
149
149
|
function publishDrafts(waitingOnly) {
|
|
150
150
|
if (closed) return;
|
|
151
151
|
const value = snapshotDrafts();
|
|
@@ -171,13 +171,15 @@ export function createMdRuntime(options) {
|
|
|
171
171
|
if (listener.app === app && listener.ready) listener.notify(presentationOf(app));
|
|
172
172
|
}
|
|
173
173
|
}
|
|
174
|
-
function commitDraft(work) {
|
|
174
|
+
function commitDraft(locator, path, work) {
|
|
175
175
|
return exclusive(async ()=>{
|
|
176
176
|
const local = await openLocal();
|
|
177
|
-
await hydrate(local);
|
|
178
177
|
await work(local);
|
|
179
|
-
|
|
180
|
-
|
|
178
|
+
publishChangeSet(changeSet(locator, null, null, {
|
|
179
|
+
drafts: [
|
|
180
|
+
path
|
|
181
|
+
]
|
|
182
|
+
}));
|
|
181
183
|
});
|
|
182
184
|
}
|
|
183
185
|
function pending() {
|
|
@@ -214,19 +216,13 @@ export function createMdRuntime(options) {
|
|
|
214
216
|
reset
|
|
215
217
|
};
|
|
216
218
|
}
|
|
217
|
-
function
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
}
|
|
225
|
-
async function persistQueue(local, locator, batches) {
|
|
226
|
-
await local.writeQueue({
|
|
227
|
-
locator,
|
|
228
|
-
batches,
|
|
229
|
-
outcomes: storedOutcomes(batches)
|
|
219
|
+
async function persistQueue(local, replica, batches, changedOutcomes = []) {
|
|
220
|
+
await local.write({
|
|
221
|
+
next: replica.confirmed.record,
|
|
222
|
+
previous: replica.confirmed.record,
|
|
223
|
+
queue: batches,
|
|
224
|
+
previousQueue: replica.queue,
|
|
225
|
+
outcomes: changedOutcomes
|
|
230
226
|
});
|
|
231
227
|
}
|
|
232
228
|
function listed() {
|
|
@@ -270,9 +266,19 @@ export function createMdRuntime(options) {
|
|
|
270
266
|
for (const listener of storageLossListeners)listener(storageLoss);
|
|
271
267
|
}
|
|
272
268
|
function moveTo(next) {
|
|
273
|
-
if (closed
|
|
269
|
+
if (closed) return;
|
|
274
270
|
status = next;
|
|
275
|
-
|
|
271
|
+
show();
|
|
272
|
+
}
|
|
273
|
+
function show() {
|
|
274
|
+
if (closed) return;
|
|
275
|
+
const next = status.state === 'synced' && !conversations.current() ? {
|
|
276
|
+
...status,
|
|
277
|
+
state: 'syncing'
|
|
278
|
+
} : status;
|
|
279
|
+
if (same(shown, next)) return;
|
|
280
|
+
shown = next;
|
|
281
|
+
for (const listener of statusListeners)listener(shown);
|
|
276
282
|
}
|
|
277
283
|
function visible(request) {
|
|
278
284
|
if (options.queryBinding === null) {
|
|
@@ -308,6 +314,18 @@ export function createMdRuntime(options) {
|
|
|
308
314
|
if (subscription.locator === locator) subscription.notify(entries);
|
|
309
315
|
}
|
|
310
316
|
}
|
|
317
|
+
function publishChangeSet(set) {
|
|
318
|
+
if (set.rooms.length > 0) emitRooms();
|
|
319
|
+
if (set.documents.length > 0 || set.query) emitVisible();
|
|
320
|
+
for (const locator of set.queues)emitQueue(locator);
|
|
321
|
+
if (set.drafts.length > 0) emitDrafts();
|
|
322
|
+
for (const app of set.presentations)emitPresentation(app);
|
|
323
|
+
conversations.changed(set);
|
|
324
|
+
const cards = declaredCards();
|
|
325
|
+
if (cards !== undefined && set.documents.some((change)=>change.locator === cards.locator)) {
|
|
326
|
+
scheduleCurrency();
|
|
327
|
+
}
|
|
328
|
+
}
|
|
311
329
|
function stopTimer() {
|
|
312
330
|
if (timer === undefined) return;
|
|
313
331
|
clearInterval(timer);
|
|
@@ -319,55 +337,76 @@ export function createMdRuntime(options) {
|
|
|
319
337
|
void enqueue();
|
|
320
338
|
}, period);
|
|
321
339
|
}
|
|
322
|
-
function refuse(reason, provider = null) {
|
|
323
|
-
if (reason === 'revoked-authorization') {
|
|
324
|
-
const revoked = {
|
|
325
|
-
status: 'unavailable',
|
|
326
|
-
reason: 'revoked'
|
|
327
|
-
};
|
|
328
|
-
const attachments = [
|
|
329
|
-
'collection',
|
|
330
|
-
'typed-selection'
|
|
331
|
-
];
|
|
332
|
-
const keys = new Set(models.keys());
|
|
333
|
-
for (const locator of rooms.keys()){
|
|
334
|
-
for (const attached of attachments)keys.add(modelKey(locator, attached));
|
|
335
|
-
}
|
|
336
|
-
for (const key of keys){
|
|
337
|
-
invalidModels.add(key);
|
|
338
|
-
modelEpoch.set(key, (modelEpoch.get(key) ?? 0) + 1);
|
|
339
|
-
models.set(key, revoked);
|
|
340
|
-
liveModels.delete(key);
|
|
341
|
-
}
|
|
342
|
-
for (const [locator, room] of rooms)rooms.set(locator, {
|
|
343
|
-
...room,
|
|
344
|
-
model: modelTypes(revoked),
|
|
345
|
-
typedSelection: room.typedSelection === null ? null : {
|
|
346
|
-
...room.typedSelection,
|
|
347
|
-
model: modelTypes(revoked)
|
|
348
|
-
}
|
|
349
|
-
});
|
|
350
|
-
emitRooms();
|
|
351
|
-
void exclusive(async ()=>{
|
|
352
|
-
const local = await openLocal();
|
|
353
|
-
for (const record of (await local.all()))await local.publish({
|
|
354
|
-
...record,
|
|
355
|
-
model: revoked,
|
|
356
|
-
selectionModel: revoked
|
|
357
|
-
});
|
|
358
|
-
}).catch(()=>{
|
|
359
|
-
journal.record('model invalidation durable-write failure');
|
|
360
|
-
});
|
|
361
|
-
}
|
|
340
|
+
async function refuse(reason, provider = null) {
|
|
362
341
|
stopTimer();
|
|
363
342
|
discoveryPaused = true;
|
|
364
|
-
|
|
365
|
-
reason
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
343
|
+
try {
|
|
344
|
+
if (reason === 'revoked-authorization') {
|
|
345
|
+
await exclusive(async ()=>{
|
|
346
|
+
const revoked = {
|
|
347
|
+
status: 'unavailable',
|
|
348
|
+
reason: 'revoked'
|
|
349
|
+
};
|
|
350
|
+
try {
|
|
351
|
+
const local = await openLocal();
|
|
352
|
+
await local.revokeModels([
|
|
353
|
+
...replicas.values()
|
|
354
|
+
].map((replica)=>({
|
|
355
|
+
record: replica.confirmed.record,
|
|
356
|
+
queue: replica.queue
|
|
357
|
+
})));
|
|
358
|
+
} catch {
|
|
359
|
+
journal.record('model revocation persistence failed');
|
|
360
|
+
}
|
|
361
|
+
const keys = new Set(models.keys());
|
|
362
|
+
for (const locator of rooms.keys()){
|
|
363
|
+
keys.add(modelKey(locator, 'collection'));
|
|
364
|
+
keys.add(modelKey(locator, 'typed-selection'));
|
|
365
|
+
}
|
|
366
|
+
for (const key of keys){
|
|
367
|
+
invalidModels.add(key);
|
|
368
|
+
modelEpoch.set(key, (modelEpoch.get(key) ?? 0) + 1);
|
|
369
|
+
models.set(key, revoked);
|
|
370
|
+
liveModels.delete(key);
|
|
371
|
+
}
|
|
372
|
+
const changed = [];
|
|
373
|
+
for (const [locator, room] of rooms){
|
|
374
|
+
const before = replicas.get(locator) ?? null;
|
|
375
|
+
if (before !== null) {
|
|
376
|
+
const record = {
|
|
377
|
+
...before.confirmed.record,
|
|
378
|
+
model: revoked,
|
|
379
|
+
selectionModel: revoked
|
|
380
|
+
};
|
|
381
|
+
const confirmed = readConfirmed(record, before.confirmed);
|
|
382
|
+
if (confirmed === null) throw new Error(`Cannot retype revoked Room ${locator}`);
|
|
383
|
+
replicas.set(locator, replicaOf(confirmed, before.queue, rewriting(), before));
|
|
384
|
+
}
|
|
385
|
+
rooms.set(locator, {
|
|
386
|
+
...room,
|
|
387
|
+
model: modelTypes(revoked),
|
|
388
|
+
typedSelection: room.typedSelection === null ? null : {
|
|
389
|
+
...room.typedSelection,
|
|
390
|
+
model: modelTypes(revoked)
|
|
391
|
+
}
|
|
392
|
+
});
|
|
393
|
+
changed.push(changeSet(locator, before, replicas.get(locator) ?? null, {
|
|
394
|
+
room: true,
|
|
395
|
+
query: true
|
|
396
|
+
}));
|
|
397
|
+
}
|
|
398
|
+
publishChangeSet(mergeChangeSets(changed));
|
|
399
|
+
});
|
|
400
|
+
}
|
|
401
|
+
} finally{
|
|
402
|
+
refusal = {
|
|
403
|
+
reason,
|
|
404
|
+
reauthorizationOffered: reason === 'revoked-authorization',
|
|
405
|
+
refusal: provider
|
|
406
|
+
};
|
|
407
|
+
journal.record(`connection refused ${reason}`);
|
|
408
|
+
emitRefusal();
|
|
409
|
+
}
|
|
371
410
|
}
|
|
372
411
|
function list(room, synchronizationAvailable) {
|
|
373
412
|
const selection = room.typedSelection ?? null;
|
|
@@ -417,7 +456,6 @@ export function createMdRuntime(options) {
|
|
|
417
456
|
async function dropUnlisted(listed, local) {
|
|
418
457
|
if (unlistedHeld(listed).length === 0) return;
|
|
419
458
|
await exclusive(async ()=>{
|
|
420
|
-
await hydrate(local);
|
|
421
459
|
const unlisted = unlistedHeld(listed);
|
|
422
460
|
await local.dropRooms(unlisted);
|
|
423
461
|
for (const [batch, locator] of acceptedIn){
|
|
@@ -425,6 +463,14 @@ export function createMdRuntime(options) {
|
|
|
425
463
|
acceptedIn.delete(batch);
|
|
426
464
|
outcomes.delete(batch);
|
|
427
465
|
}
|
|
466
|
+
const removed = unlisted.map((locator)=>changeSet(locator, replicas.get(locator) ?? null, null, {
|
|
467
|
+
room: true,
|
|
468
|
+
queue: true,
|
|
469
|
+
query: true,
|
|
470
|
+
drafts: [
|
|
471
|
+
...drafts.get(locator)?.keys() ?? []
|
|
472
|
+
]
|
|
473
|
+
}));
|
|
428
474
|
for (const locator of unlisted){
|
|
429
475
|
for (const batch of replicas.get(locator)?.queue ?? [])outcomes.delete(batch.id);
|
|
430
476
|
replicas.delete(locator);
|
|
@@ -444,9 +490,7 @@ export function createMdRuntime(options) {
|
|
|
444
490
|
}
|
|
445
491
|
journal.record(`room unlisted ${locator}`);
|
|
446
492
|
}
|
|
447
|
-
|
|
448
|
-
for (const locator of unlisted)emitQueue(locator);
|
|
449
|
-
emitDrafts();
|
|
493
|
+
publishChangeSet(mergeChangeSets(removed));
|
|
450
494
|
moveTo({
|
|
451
495
|
...status,
|
|
452
496
|
...attention()
|
|
@@ -468,13 +512,14 @@ export function createMdRuntime(options) {
|
|
|
468
512
|
return model;
|
|
469
513
|
}
|
|
470
514
|
async function hydrate(opened) {
|
|
471
|
-
const [records, queues, kept, presented,
|
|
515
|
+
const [records, queues, recordedOutcomes, kept, presented, held, chatDrafts, lastCompleted, declared, named, listedSlots] = await Promise.all([
|
|
472
516
|
opened.all(),
|
|
473
517
|
opened.queues(),
|
|
518
|
+
opened.outcomes(),
|
|
474
519
|
opened.drafts(),
|
|
475
520
|
opened.presentation(),
|
|
476
521
|
opened.conversations(),
|
|
477
|
-
opened.
|
|
522
|
+
opened.chatDrafts(),
|
|
478
523
|
opened.lastCompleted(),
|
|
479
524
|
opened.providerLimits(),
|
|
480
525
|
opened.capabilities(),
|
|
@@ -487,27 +532,30 @@ export function createMdRuntime(options) {
|
|
|
487
532
|
for (const draft of kept)rememberDraft(draft.locator, draft.path, draft.content);
|
|
488
533
|
presentations.clear();
|
|
489
534
|
for (const record of presented)presentations.set(record.app, record.value);
|
|
490
|
-
conversations.hydrate(
|
|
535
|
+
conversations.hydrate(held, chatDrafts);
|
|
491
536
|
const queuedBatches = new Map(queues.map((queue)=>[
|
|
492
537
|
queue.locator,
|
|
493
538
|
queue.batches
|
|
494
539
|
]));
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
540
|
+
outcomes.clear();
|
|
541
|
+
acceptedIn.clear();
|
|
542
|
+
for (const record of recordedOutcomes){
|
|
543
|
+
outcomes.set(record.id, record.outcome);
|
|
544
|
+
if (record.outcome.kind === 'accepted') acceptedIn.set(record.id, record.locator);
|
|
499
545
|
}
|
|
546
|
+
const previousReplicas = new Map(replicas);
|
|
500
547
|
replicas.clear();
|
|
501
548
|
for (const record of records){
|
|
502
549
|
const model = restored(modelKey(record.locator, 'collection'), record.model);
|
|
503
550
|
const selectionModel = restored(modelKey(record.locator, 'typed-selection'), record.selectionModel);
|
|
551
|
+
const prior = previousReplicas.get(record.locator);
|
|
504
552
|
const confirmed = readConfirmed({
|
|
505
553
|
...record,
|
|
506
554
|
model,
|
|
507
555
|
selectionModel
|
|
508
|
-
});
|
|
556
|
+
}, prior?.confirmed);
|
|
509
557
|
if (confirmed === null) continue;
|
|
510
|
-
replicas.set(record.locator, replicaOf(confirmed, queuedBatches.get(record.locator) ?? [], rewriting()));
|
|
558
|
+
replicas.set(record.locator, replicaOf(confirmed, queuedBatches.get(record.locator) ?? [], rewriting(), prior));
|
|
511
559
|
const existing = rooms.get(record.locator);
|
|
512
560
|
if (existing === undefined) list(record, false);
|
|
513
561
|
else {
|
|
@@ -568,7 +616,6 @@ export function createMdRuntime(options) {
|
|
|
568
616
|
function durably(work) {
|
|
569
617
|
return exclusive(async ()=>{
|
|
570
618
|
const local = await openLocal();
|
|
571
|
-
await hydrate(local);
|
|
572
619
|
return work(local);
|
|
573
620
|
});
|
|
574
621
|
}
|
|
@@ -586,25 +633,30 @@ export function createMdRuntime(options) {
|
|
|
586
633
|
}
|
|
587
634
|
function publish(local, room, confirmed) {
|
|
588
635
|
return exclusive(async ()=>{
|
|
589
|
-
|
|
636
|
+
const prior = replicas.get(room.locator);
|
|
590
637
|
const retained = readConfirmed({
|
|
591
638
|
...confirmed.record,
|
|
592
639
|
model: modelOf(room.locator),
|
|
593
640
|
selectionModel: modelOf(room.locator, 'typed-selection')
|
|
594
|
-
});
|
|
641
|
+
}, prior?.confirmed);
|
|
595
642
|
if (retained !== null) {
|
|
596
|
-
await local.
|
|
643
|
+
await local.write({
|
|
644
|
+
next: retained.record,
|
|
645
|
+
previous: prior?.confirmed.record ?? null,
|
|
646
|
+
queue: prior?.queue ?? []
|
|
647
|
+
});
|
|
597
648
|
unreadable.delete(room.locator);
|
|
598
|
-
replicas.set(room.locator, replicaOf(retained,
|
|
649
|
+
replicas.set(room.locator, replicaOf(retained, prior?.queue ?? [], rewriting(), prior));
|
|
599
650
|
}
|
|
600
651
|
list(room, true);
|
|
601
|
-
|
|
602
|
-
|
|
652
|
+
publishChangeSet(changeSet(room.locator, prior ?? null, replicas.get(room.locator) ?? null, {
|
|
653
|
+
room: true,
|
|
654
|
+
query: true
|
|
655
|
+
}));
|
|
603
656
|
});
|
|
604
657
|
}
|
|
605
658
|
async function write(locator, changes, replacing, writtenBy) {
|
|
606
659
|
const local = await openLocal();
|
|
607
|
-
await hydrate(local);
|
|
608
660
|
const replica = replicas.get(locator);
|
|
609
661
|
const room = rooms.get(locator);
|
|
610
662
|
if (replica === undefined || room === undefined) {
|
|
@@ -650,11 +702,19 @@ export function createMdRuntime(options) {
|
|
|
650
702
|
...new Set(changes.map((change)=>change.path))
|
|
651
703
|
];
|
|
652
704
|
try {
|
|
653
|
-
await local.
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
705
|
+
await local.write({
|
|
706
|
+
next: replica.confirmed.record,
|
|
707
|
+
previous: replica.confirmed.record,
|
|
708
|
+
queue: batches,
|
|
709
|
+
previousQueue: replica.queue,
|
|
710
|
+
outcomes: replacing === undefined ? [] : [
|
|
711
|
+
{
|
|
712
|
+
id: replacing,
|
|
713
|
+
outcome: null
|
|
714
|
+
}
|
|
715
|
+
],
|
|
716
|
+
consumedDrafts: consumed
|
|
717
|
+
});
|
|
658
718
|
} catch {
|
|
659
719
|
return {
|
|
660
720
|
outcome: 'refused',
|
|
@@ -663,10 +723,11 @@ export function createMdRuntime(options) {
|
|
|
663
723
|
}
|
|
664
724
|
if (replacing !== undefined) outcomes.delete(replacing);
|
|
665
725
|
for (const path of consumed)forgetDraft(locator, path);
|
|
666
|
-
replicas.set(locator, replicaOf(replica.confirmed, batches, rewriting()));
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
726
|
+
replicas.set(locator, replicaOf(replica.confirmed, batches, rewriting(), replica));
|
|
727
|
+
publishChangeSet(changeSet(locator, replica, replicas.get(locator) ?? null, {
|
|
728
|
+
queue: true,
|
|
729
|
+
drafts: consumed
|
|
730
|
+
}));
|
|
670
731
|
moveTo({
|
|
671
732
|
...saving(status),
|
|
672
733
|
...attention()
|
|
@@ -679,18 +740,23 @@ export function createMdRuntime(options) {
|
|
|
679
740
|
}
|
|
680
741
|
async function discardHead(locator, identifier) {
|
|
681
742
|
const local = await openLocal();
|
|
682
|
-
await hydrate(local);
|
|
683
743
|
const replica = replicas.get(locator);
|
|
684
744
|
const head = replica?.queue[0];
|
|
685
745
|
if (replica === undefined || head === undefined || head.id !== identifier || !refused(outcomes.get(head.id))) {
|
|
686
746
|
return;
|
|
687
747
|
}
|
|
688
748
|
const batches = replica.queue.slice(1);
|
|
749
|
+
await persistQueue(local, replica, batches, [
|
|
750
|
+
{
|
|
751
|
+
id: identifier,
|
|
752
|
+
outcome: null
|
|
753
|
+
}
|
|
754
|
+
]);
|
|
689
755
|
outcomes.delete(identifier);
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
756
|
+
replicas.set(locator, replicaOf(replica.confirmed, batches, rewriting(), replica));
|
|
757
|
+
publishChangeSet(changeSet(locator, replica, replicas.get(locator) ?? null, {
|
|
758
|
+
queue: true
|
|
759
|
+
}));
|
|
694
760
|
moveTo({
|
|
695
761
|
...status,
|
|
696
762
|
state: pending() ? 'pending' : status.state,
|
|
@@ -739,7 +805,7 @@ export function createMdRuntime(options) {
|
|
|
739
805
|
const room = replicas.get(result.locator)?.confirmed.record;
|
|
740
806
|
if (room !== undefined) await scoped(result, room, await openLocal());
|
|
741
807
|
}
|
|
742
|
-
if (result.kind === 'revoked-authorization') refuse('revoked-authorization');
|
|
808
|
+
if (result.kind === 'revoked-authorization') await refuse('revoked-authorization');
|
|
743
809
|
return result;
|
|
744
810
|
} catch {
|
|
745
811
|
journal.record('outcome history transport-uncertainty');
|
|
@@ -792,7 +858,7 @@ export function createMdRuntime(options) {
|
|
|
792
858
|
const room = replicas.get(result.locator)?.confirmed.record;
|
|
793
859
|
if (room !== undefined) await scoped(result, room, await openLocal());
|
|
794
860
|
}
|
|
795
|
-
if (result.kind === 'revoked-authorization') refuse('revoked-authorization');
|
|
861
|
+
if (result.kind === 'revoked-authorization') await refuse('revoked-authorization');
|
|
796
862
|
journal.record(`outcome action ${result.kind}`);
|
|
797
863
|
if (result.kind === 'rejected') journal.record(`refusal rejected ${result.code}`);
|
|
798
864
|
return result;
|
|
@@ -885,7 +951,6 @@ export function createMdRuntime(options) {
|
|
|
885
951
|
};
|
|
886
952
|
}
|
|
887
953
|
async function commitAccept(room, local, submitted, accepted, base, overlay) {
|
|
888
|
-
await hydrate(local);
|
|
889
954
|
const current = replicas.get(room.locator);
|
|
890
955
|
if (current === undefined || !current.queue.some((batch)=>batch.id === submitted.id)) {
|
|
891
956
|
return true;
|
|
@@ -895,14 +960,11 @@ export function createMdRuntime(options) {
|
|
|
895
960
|
...base.record,
|
|
896
961
|
model: modelOf(room.locator),
|
|
897
962
|
selectionModel: modelOf(room.locator, 'typed-selection')
|
|
898
|
-
});
|
|
963
|
+
}, base);
|
|
899
964
|
if (retainedBase === null) return false;
|
|
900
965
|
const applied = overlay ? applyReturned(retainedBase, accepted.documents, accepted.revisions, accepted.removals, accepted.roomVersion, options.modelBinding) : retainedBase;
|
|
901
966
|
if (applied === null) return false;
|
|
902
|
-
|
|
903
|
-
await persistQueue(local, room.locator, remaining);
|
|
904
|
-
acceptedIn.set(submitted.id, room.locator);
|
|
905
|
-
outcomes.set(submitted.id, {
|
|
967
|
+
const acceptedOutcome = {
|
|
906
968
|
kind: 'accepted',
|
|
907
969
|
roomVersion: accepted.roomVersion,
|
|
908
970
|
...accepted.author === undefined ? {} : {
|
|
@@ -911,13 +973,29 @@ export function createMdRuntime(options) {
|
|
|
911
973
|
...accepted.time === undefined ? {} : {
|
|
912
974
|
time: accepted.time
|
|
913
975
|
}
|
|
976
|
+
};
|
|
977
|
+
await local.write({
|
|
978
|
+
next: applied.record,
|
|
979
|
+
previous: current.confirmed.record,
|
|
980
|
+
queue: remaining,
|
|
981
|
+
previousQueue: current.queue,
|
|
982
|
+
outcomes: [
|
|
983
|
+
{
|
|
984
|
+
id: submitted.id,
|
|
985
|
+
outcome: acceptedOutcome
|
|
986
|
+
}
|
|
987
|
+
]
|
|
914
988
|
});
|
|
989
|
+
acceptedIn.set(submitted.id, room.locator);
|
|
990
|
+
outcomes.set(submitted.id, acceptedOutcome);
|
|
915
991
|
unreadable.delete(room.locator);
|
|
916
|
-
replicas.set(room.locator, replicaOf(applied, remaining, rewriting()));
|
|
992
|
+
replicas.set(room.locator, replicaOf(applied, remaining, rewriting(), current));
|
|
917
993
|
list(room, true);
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
994
|
+
publishChangeSet(changeSet(room.locator, current, replicas.get(room.locator) ?? null, {
|
|
995
|
+
room: true,
|
|
996
|
+
queue: true,
|
|
997
|
+
query: true
|
|
998
|
+
}));
|
|
921
999
|
journal.record(`outcome ${room.locator} ${submitted.id} accepted ${accepted.roomVersion}` + (accepted.author === undefined ? '' : ` author ${accepted.author}`) + (accepted.time === undefined ? '' : ` time ${accepted.time}`));
|
|
922
1000
|
return true;
|
|
923
1001
|
}
|
|
@@ -934,12 +1012,18 @@ export function createMdRuntime(options) {
|
|
|
934
1012
|
return null;
|
|
935
1013
|
}
|
|
936
1014
|
await exclusive(async ()=>{
|
|
937
|
-
await hydrate(local);
|
|
938
1015
|
const current = replicas.get(room.locator);
|
|
939
1016
|
if (current === undefined || current.queue[0]?.id !== head.id) return;
|
|
1017
|
+
await persistQueue(local, current, current.queue, [
|
|
1018
|
+
{
|
|
1019
|
+
id: head.id,
|
|
1020
|
+
outcome: null
|
|
1021
|
+
}
|
|
1022
|
+
]);
|
|
940
1023
|
outcomes.delete(head.id);
|
|
941
|
-
|
|
942
|
-
|
|
1024
|
+
publishChangeSet(changeSet(room.locator, current, current, {
|
|
1025
|
+
queue: true
|
|
1026
|
+
}));
|
|
943
1027
|
moveTo({
|
|
944
1028
|
...status,
|
|
945
1029
|
...attention()
|
|
@@ -948,6 +1032,11 @@ export function createMdRuntime(options) {
|
|
|
948
1032
|
}
|
|
949
1033
|
let result;
|
|
950
1034
|
journal.record(`submission ${room.locator} ${head.id}`);
|
|
1035
|
+
if (await local.markSubmitted(room.locator, head.id)) {
|
|
1036
|
+
publishChangeSet(changeSet(room.locator, replica, replica, {
|
|
1037
|
+
queue: true
|
|
1038
|
+
}));
|
|
1039
|
+
}
|
|
951
1040
|
try {
|
|
952
1041
|
result = await options.adapter.mutate(authorized, {
|
|
953
1042
|
locator: room.locator,
|
|
@@ -972,7 +1061,7 @@ export function createMdRuntime(options) {
|
|
|
972
1061
|
return null;
|
|
973
1062
|
}
|
|
974
1063
|
if (result.kind === 'revoked-authorization') {
|
|
975
|
-
refuse('revoked-authorization');
|
|
1064
|
+
await refuse('revoked-authorization');
|
|
976
1065
|
return 'stop';
|
|
977
1066
|
}
|
|
978
1067
|
if (result.kind === 'scoped-refusal') {
|
|
@@ -985,14 +1074,21 @@ export function createMdRuntime(options) {
|
|
|
985
1074
|
if (result.kind !== 'expired') journal.record(`refusal ${result.kind} ${result.code}`);
|
|
986
1075
|
if (result.kind === 'retryable-refusal') progress.complete = false;
|
|
987
1076
|
await exclusive(async ()=>{
|
|
988
|
-
await hydrate(local);
|
|
989
1077
|
const current = replicas.get(room.locator);
|
|
990
1078
|
if (current === undefined || !current.queue.some((batch)=>batch.id === head.id)) {
|
|
991
1079
|
return;
|
|
992
1080
|
}
|
|
993
|
-
|
|
994
|
-
await persistQueue(local,
|
|
995
|
-
|
|
1081
|
+
const recorded = recordRefusal(result);
|
|
1082
|
+
await persistQueue(local, current, current.queue, [
|
|
1083
|
+
{
|
|
1084
|
+
id: head.id,
|
|
1085
|
+
outcome: recorded
|
|
1086
|
+
}
|
|
1087
|
+
]);
|
|
1088
|
+
outcomes.set(head.id, recorded);
|
|
1089
|
+
publishChangeSet(changeSet(room.locator, current, current, {
|
|
1090
|
+
queue: true
|
|
1091
|
+
}));
|
|
996
1092
|
moveTo({
|
|
997
1093
|
...status,
|
|
998
1094
|
...attention()
|
|
@@ -1004,7 +1100,7 @@ export function createMdRuntime(options) {
|
|
|
1004
1100
|
if (from === undefined) return null;
|
|
1005
1101
|
const pulled = await pullRefresh(authorized, from);
|
|
1006
1102
|
if (pulled.kind === 'revoked-authorization') {
|
|
1007
|
-
refuse('revoked-authorization');
|
|
1103
|
+
await refuse('revoked-authorization');
|
|
1008
1104
|
return 'stop';
|
|
1009
1105
|
}
|
|
1010
1106
|
if (pulled.kind === 'scoped-refusal') {
|
|
@@ -1032,7 +1128,7 @@ export function createMdRuntime(options) {
|
|
|
1032
1128
|
if (pulled.kind === 'beyond-horizon') {
|
|
1033
1129
|
const bootstrapped = await pullBootstrap(authorized, room);
|
|
1034
1130
|
if (bootstrapped.kind === 'revoked-authorization') {
|
|
1035
|
-
refuse('revoked-authorization');
|
|
1131
|
+
await refuse('revoked-authorization');
|
|
1036
1132
|
return 'stop';
|
|
1037
1133
|
}
|
|
1038
1134
|
if (bootstrapped.kind === 'scoped-refusal') {
|
|
@@ -1084,7 +1180,6 @@ export function createMdRuntime(options) {
|
|
|
1084
1180
|
liveModels.delete(key);
|
|
1085
1181
|
}
|
|
1086
1182
|
await exclusive(async ()=>{
|
|
1087
|
-
await hydrate(local);
|
|
1088
1183
|
if (next.status !== 'unavailable' && epoch !== (modelEpoch.get(key) ?? 0)) return;
|
|
1089
1184
|
const held = replicas.get(room.locator);
|
|
1090
1185
|
if (held !== undefined) {
|
|
@@ -1100,9 +1195,15 @@ export function createMdRuntime(options) {
|
|
|
1100
1195
|
selectionModel: next
|
|
1101
1196
|
}
|
|
1102
1197
|
};
|
|
1103
|
-
await local.
|
|
1104
|
-
|
|
1105
|
-
|
|
1198
|
+
await local.write({
|
|
1199
|
+
next: record,
|
|
1200
|
+
previous: held.confirmed.record,
|
|
1201
|
+
queue: held.queue
|
|
1202
|
+
});
|
|
1203
|
+
const confirmed = readConfirmed(record, held.confirmed);
|
|
1204
|
+
if (confirmed !== null) {
|
|
1205
|
+
replicas.set(room.locator, replicaOf(confirmed, held.queue, rewriting(), held));
|
|
1206
|
+
}
|
|
1106
1207
|
}
|
|
1107
1208
|
models.set(key, next);
|
|
1108
1209
|
if (next.status === 'current') {
|
|
@@ -1110,8 +1211,11 @@ export function createMdRuntime(options) {
|
|
|
1110
1211
|
invalidModels.delete(key);
|
|
1111
1212
|
}
|
|
1112
1213
|
list(room, room.replica.admission === 'admitted' && !unreadable.has(room.locator));
|
|
1113
|
-
emitRooms();
|
|
1114
|
-
|
|
1214
|
+
if (held === undefined) emitRooms();
|
|
1215
|
+
else publishChangeSet(changeSet(room.locator, held, replicas.get(room.locator) ?? null, {
|
|
1216
|
+
room: true,
|
|
1217
|
+
query: queryChanged
|
|
1218
|
+
}));
|
|
1115
1219
|
});
|
|
1116
1220
|
}
|
|
1117
1221
|
async function acquireModel(local, room, authorized, selection) {
|
|
@@ -1147,11 +1251,7 @@ export function createMdRuntime(options) {
|
|
|
1147
1251
|
}
|
|
1148
1252
|
if (epoch !== (modelEpoch.get(key) ?? 0)) return;
|
|
1149
1253
|
if (answer.kind === 'revoked-authorization') {
|
|
1150
|
-
await
|
|
1151
|
-
status: 'unavailable',
|
|
1152
|
-
reason: 'revoked'
|
|
1153
|
-
});
|
|
1154
|
-
refuse('revoked-authorization');
|
|
1254
|
+
await refuse('revoked-authorization');
|
|
1155
1255
|
return;
|
|
1156
1256
|
}
|
|
1157
1257
|
if (answer.kind === 'transport-uncertainty') {
|
|
@@ -1271,7 +1371,7 @@ export function createMdRuntime(options) {
|
|
|
1271
1371
|
continue;
|
|
1272
1372
|
}
|
|
1273
1373
|
if (withheld.kind === 'revoked-authorization') {
|
|
1274
|
-
refuse('revoked-authorization');
|
|
1374
|
+
await refuse('revoked-authorization');
|
|
1275
1375
|
return;
|
|
1276
1376
|
}
|
|
1277
1377
|
continue;
|
|
@@ -1311,7 +1411,7 @@ export function createMdRuntime(options) {
|
|
|
1311
1411
|
}
|
|
1312
1412
|
if (result.kind === 'contract-unavailable') {
|
|
1313
1413
|
journal.record(`connection contract unavailable ${result.code}`);
|
|
1314
|
-
refuse('missing-required-guarantee', {
|
|
1414
|
+
await refuse('missing-required-guarantee', {
|
|
1315
1415
|
code: result.code,
|
|
1316
1416
|
fields: result.fields
|
|
1317
1417
|
});
|
|
@@ -1319,17 +1419,17 @@ export function createMdRuntime(options) {
|
|
|
1319
1419
|
return;
|
|
1320
1420
|
}
|
|
1321
1421
|
if (result.kind === 'revoked-authorization') {
|
|
1322
|
-
refuse('revoked-authorization');
|
|
1422
|
+
await refuse('revoked-authorization');
|
|
1323
1423
|
notifyReady();
|
|
1324
1424
|
return;
|
|
1325
1425
|
}
|
|
1326
1426
|
if (!result.supportedVersions.includes(ROOM_CONTRACT_VERSION)) {
|
|
1327
|
-
refuse('no-matching-version');
|
|
1427
|
+
await refuse('no-matching-version');
|
|
1328
1428
|
notifyReady();
|
|
1329
1429
|
return;
|
|
1330
1430
|
}
|
|
1331
1431
|
if (result.mdModel.identity !== MD_MODEL.identity || result.mdModel.version !== MD_MODEL.version) {
|
|
1332
|
-
refuse('md-model-version-mismatch');
|
|
1432
|
+
await refuse('md-model-version-mismatch');
|
|
1333
1433
|
notifyReady();
|
|
1334
1434
|
return;
|
|
1335
1435
|
}
|
|
@@ -1347,13 +1447,13 @@ export function createMdRuntime(options) {
|
|
|
1347
1447
|
'unavailable'
|
|
1348
1448
|
].includes(room.replica.admission) || !declaredIdentity(room.attachedModel)) {
|
|
1349
1449
|
journal.record(`invalid model or replica declaration ${room.locator}`);
|
|
1350
|
-
refuse('missing-required-guarantee');
|
|
1450
|
+
await refuse('missing-required-guarantee');
|
|
1351
1451
|
notifyReady();
|
|
1352
1452
|
return;
|
|
1353
1453
|
}
|
|
1354
1454
|
if (!declaredSelection(room)) {
|
|
1355
1455
|
journal.record(`invalid typed selection declaration ${room.locator}`);
|
|
1356
|
-
refuse('missing-required-guarantee');
|
|
1456
|
+
await refuse('missing-required-guarantee');
|
|
1357
1457
|
notifyReady();
|
|
1358
1458
|
return;
|
|
1359
1459
|
}
|
|
@@ -1363,14 +1463,14 @@ export function createMdRuntime(options) {
|
|
|
1363
1463
|
}
|
|
1364
1464
|
}
|
|
1365
1465
|
if (mismatchedRoots.size > 0) {
|
|
1366
|
-
refuse('missing-required-guarantee');
|
|
1466
|
+
await refuse('missing-required-guarantee');
|
|
1367
1467
|
notifyReady();
|
|
1368
1468
|
return;
|
|
1369
1469
|
}
|
|
1370
1470
|
const declared = new Set(result.capabilities.map((capability)=>capability.name));
|
|
1371
1471
|
for (const required of options.requiredGuarantees){
|
|
1372
1472
|
if (!knownCapabilities.has(required) || !declared.has(required)) {
|
|
1373
|
-
refuse('missing-required-guarantee');
|
|
1473
|
+
await refuse('missing-required-guarantee');
|
|
1374
1474
|
notifyReady();
|
|
1375
1475
|
return;
|
|
1376
1476
|
}
|
|
@@ -1394,6 +1494,10 @@ export function createMdRuntime(options) {
|
|
|
1394
1494
|
handSelected(result.rooms.filter((room)=>room.replica.admission === 'admitted').map((room)=>room.locator).sort());
|
|
1395
1495
|
progress.complete = true;
|
|
1396
1496
|
await synchronize(result.rooms, local, progress);
|
|
1497
|
+
if (closed || discoveryPaused) return;
|
|
1498
|
+
await conversations.reconcile();
|
|
1499
|
+
if (status.providerUnreachable) conversations.reconnected();
|
|
1500
|
+
await conversations.catchUp(progress);
|
|
1397
1501
|
}
|
|
1398
1502
|
async function ensureAuthorization() {
|
|
1399
1503
|
if (authorization !== undefined) return;
|
|
@@ -1457,12 +1561,44 @@ export function createMdRuntime(options) {
|
|
|
1457
1561
|
});
|
|
1458
1562
|
}
|
|
1459
1563
|
function observeConversations() {
|
|
1460
|
-
const
|
|
1461
|
-
if (
|
|
1462
|
-
withdrawConversations =
|
|
1564
|
+
const stream = options.adapter.conversations;
|
|
1565
|
+
if (stream === undefined || withdrawConversations !== undefined) return;
|
|
1566
|
+
withdrawConversations = stream.observe((event)=>{
|
|
1463
1567
|
conversations.receive(event);
|
|
1568
|
+
if (event.kind !== 'gap' || conversations.current()) return;
|
|
1569
|
+
show();
|
|
1570
|
+
scheduleCurrency();
|
|
1464
1571
|
});
|
|
1465
1572
|
}
|
|
1573
|
+
function scheduleCurrency() {
|
|
1574
|
+
if (currencyQueued || closed) return;
|
|
1575
|
+
currencyQueued = true;
|
|
1576
|
+
chain = chain.then(runCurrency, runCurrency);
|
|
1577
|
+
}
|
|
1578
|
+
async function runCurrency() {
|
|
1579
|
+
currencyQueued = false;
|
|
1580
|
+
if (closed || discoveryPaused) return;
|
|
1581
|
+
await conversations.reconcile();
|
|
1582
|
+
if (conversations.current()) {
|
|
1583
|
+
show();
|
|
1584
|
+
return;
|
|
1585
|
+
}
|
|
1586
|
+
const resting = status;
|
|
1587
|
+
const progress = {
|
|
1588
|
+
complete: false,
|
|
1589
|
+
reachable: !resting.providerUnreachable
|
|
1590
|
+
};
|
|
1591
|
+
moveTo(transferring(resting));
|
|
1592
|
+
try {
|
|
1593
|
+
await conversations.catchUp(progress);
|
|
1594
|
+
} catch {
|
|
1595
|
+
progress.reachable = false;
|
|
1596
|
+
} finally{
|
|
1597
|
+
if (!closed) {
|
|
1598
|
+
moveTo(settled(resting, progress, resting.lastCompleted, pending(), attention()));
|
|
1599
|
+
}
|
|
1600
|
+
}
|
|
1601
|
+
}
|
|
1466
1602
|
function handSelected(locators) {
|
|
1467
1603
|
const path = options.adapter.roomVersions;
|
|
1468
1604
|
if (path === undefined || withdrawNotifications === undefined) return;
|
|
@@ -1508,7 +1644,7 @@ export function createMdRuntime(options) {
|
|
|
1508
1644
|
continue;
|
|
1509
1645
|
}
|
|
1510
1646
|
if (withheld.kind === 'revoked-authorization') {
|
|
1511
|
-
refuse('revoked-authorization');
|
|
1647
|
+
await refuse('revoked-authorization');
|
|
1512
1648
|
return;
|
|
1513
1649
|
}
|
|
1514
1650
|
}
|
|
@@ -1559,6 +1695,9 @@ export function createMdRuntime(options) {
|
|
|
1559
1695
|
});
|
|
1560
1696
|
void enqueue();
|
|
1561
1697
|
return {
|
|
1698
|
+
loaded () {
|
|
1699
|
+
return openLocal().then(()=>undefined);
|
|
1700
|
+
},
|
|
1562
1701
|
rooms () {
|
|
1563
1702
|
return listed();
|
|
1564
1703
|
},
|
|
@@ -1575,13 +1714,13 @@ export function createMdRuntime(options) {
|
|
|
1575
1714
|
};
|
|
1576
1715
|
},
|
|
1577
1716
|
syncStatus () {
|
|
1578
|
-
return
|
|
1717
|
+
return shown;
|
|
1579
1718
|
},
|
|
1580
1719
|
draft: {
|
|
1581
1720
|
list () {
|
|
1582
1721
|
return exclusive(async ()=>{
|
|
1583
|
-
|
|
1584
|
-
return
|
|
1722
|
+
await openLocal();
|
|
1723
|
+
return snapshotDrafts();
|
|
1585
1724
|
}).then((entries)=>{
|
|
1586
1725
|
releaseWaitingDrafts();
|
|
1587
1726
|
return entries;
|
|
@@ -1592,7 +1731,7 @@ export function createMdRuntime(options) {
|
|
|
1592
1731
|
return content === undefined ? null : structuredClone(content);
|
|
1593
1732
|
},
|
|
1594
1733
|
replace (locator, path, content) {
|
|
1595
|
-
return commitDraft(async (local)=>{
|
|
1734
|
+
return commitDraft(locator, path, async (local)=>{
|
|
1596
1735
|
const stored = structuredClone(content);
|
|
1597
1736
|
await local.keep({
|
|
1598
1737
|
locator,
|
|
@@ -1603,32 +1742,33 @@ export function createMdRuntime(options) {
|
|
|
1603
1742
|
});
|
|
1604
1743
|
},
|
|
1605
1744
|
discard (locator, path) {
|
|
1606
|
-
return commitDraft(async (local)=>{
|
|
1745
|
+
return commitDraft(locator, path, async (local)=>{
|
|
1607
1746
|
await local.discard(locator, path);
|
|
1608
1747
|
forgetDraft(locator, path);
|
|
1609
1748
|
});
|
|
1610
1749
|
}
|
|
1611
1750
|
},
|
|
1612
1751
|
conversation: conversations.surface,
|
|
1752
|
+
chatDraft: conversations.chatDraft,
|
|
1613
1753
|
presentation: {
|
|
1614
1754
|
read (app) {
|
|
1615
1755
|
return exclusive(async ()=>{
|
|
1616
|
-
await
|
|
1756
|
+
await openLocal();
|
|
1617
1757
|
return presentationOf(app);
|
|
1618
1758
|
});
|
|
1619
1759
|
},
|
|
1620
1760
|
write (app, value) {
|
|
1621
1761
|
return exclusive(async ()=>{
|
|
1622
1762
|
const local = await openLocal();
|
|
1623
|
-
await hydrate(local);
|
|
1624
1763
|
const stored = structuredClone(value);
|
|
1625
1764
|
await local.present({
|
|
1626
1765
|
app,
|
|
1627
1766
|
value: stored
|
|
1628
1767
|
});
|
|
1629
1768
|
presentations.set(app, stored);
|
|
1630
|
-
|
|
1631
|
-
|
|
1769
|
+
publishChangeSet(changeSet('', null, null, {
|
|
1770
|
+
presentation: app
|
|
1771
|
+
}));
|
|
1632
1772
|
});
|
|
1633
1773
|
}
|
|
1634
1774
|
},
|
|
@@ -1665,7 +1805,7 @@ export function createMdRuntime(options) {
|
|
|
1665
1805
|
persistence () {
|
|
1666
1806
|
return options.shell.persistentStorage;
|
|
1667
1807
|
},
|
|
1668
|
-
observe (topic, second, third) {
|
|
1808
|
+
observe (topic, second, third, fourth) {
|
|
1669
1809
|
if (topic === 'drafts') {
|
|
1670
1810
|
const notify = second;
|
|
1671
1811
|
const listener = {
|
|
@@ -1674,8 +1814,7 @@ export function createMdRuntime(options) {
|
|
|
1674
1814
|
};
|
|
1675
1815
|
draftListeners.add(listener);
|
|
1676
1816
|
void exclusive(async ()=>{
|
|
1677
|
-
|
|
1678
|
-
await readDrafts(local);
|
|
1817
|
+
await openLocal();
|
|
1679
1818
|
if (closed || !draftListeners.has(listener)) return;
|
|
1680
1819
|
listener.ready = true;
|
|
1681
1820
|
}).then(()=>{
|
|
@@ -1687,7 +1826,7 @@ export function createMdRuntime(options) {
|
|
|
1687
1826
|
};
|
|
1688
1827
|
}
|
|
1689
1828
|
if (topic === 'conversation') {
|
|
1690
|
-
return conversations.observe(second, third);
|
|
1829
|
+
return conversations.observe(second, third, fourth);
|
|
1691
1830
|
}
|
|
1692
1831
|
if (topic === 'presentation') {
|
|
1693
1832
|
const listener = {
|
|
@@ -1697,7 +1836,7 @@ export function createMdRuntime(options) {
|
|
|
1697
1836
|
};
|
|
1698
1837
|
presentationListeners.add(listener);
|
|
1699
1838
|
void exclusive(async ()=>{
|
|
1700
|
-
await
|
|
1839
|
+
await openLocal();
|
|
1701
1840
|
}).then(()=>{
|
|
1702
1841
|
if (closed || !presentationListeners.has(listener)) return;
|
|
1703
1842
|
listener.ready = true;
|
|
@@ -1734,7 +1873,7 @@ export function createMdRuntime(options) {
|
|
|
1734
1873
|
if (topic === 'sync-status') {
|
|
1735
1874
|
const notify = second;
|
|
1736
1875
|
statusListeners.add(notify);
|
|
1737
|
-
notify(
|
|
1876
|
+
notify(shown);
|
|
1738
1877
|
return ()=>{
|
|
1739
1878
|
statusListeners.delete(notify);
|
|
1740
1879
|
};
|
|
@@ -1764,6 +1903,7 @@ export function createMdRuntime(options) {
|
|
|
1764
1903
|
async reauthorize () {
|
|
1765
1904
|
if (refusal === null || !refusal.reauthorizationOffered) return;
|
|
1766
1905
|
journal.record('connection reauthorize');
|
|
1906
|
+
await mutations;
|
|
1767
1907
|
authorization = undefined;
|
|
1768
1908
|
discoveryPaused = false;
|
|
1769
1909
|
await enqueue();
|