@agentshouse/mdruntime-adapter 0.1.0-cc63dd043d0e2 → 0.1.0-cc710a8825617
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 +270 -183
- package/README.md +3 -3
- package/dist/actions.d.ts +63 -2
- package/dist/actions.d.ts.map +1 -1
- package/dist/actions.js +154 -138
- package/dist/adapter.d.ts +1 -0
- package/dist/adapter.d.ts.map +1 -1
- package/dist/adapter.js +325 -166
- package/dist/discovery.d.ts +6 -12
- package/dist/discovery.d.ts.map +1 -1
- package/dist/discovery.js +32 -36
- package/dist/gather.d.ts +1 -0
- package/dist/gather.d.ts.map +1 -1
- package/dist/gather.js +11 -6
- package/dist/handed.d.ts +15 -0
- package/dist/handed.d.ts.map +1 -0
- package/dist/handed.js +38 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/model.d.ts +7 -18
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js +60 -39
- package/dist/read.d.ts +35 -7
- package/dist/read.d.ts.map +1 -1
- package/dist/read.js +164 -86
- package/dist/referrer.d.ts +7 -0
- package/dist/referrer.d.ts.map +1 -0
- package/dist/referrer.js +35 -0
- package/dist/refusal.d.ts +5 -9
- package/dist/refusal.d.ts.map +1 -1
- package/dist/refusal.js +31 -17
- package/dist/site.d.ts +1 -1
- package/dist/site.d.ts.map +1 -1
- package/dist/site.js +191 -107
- package/dist/stream.d.ts +10 -4
- package/dist/stream.d.ts.map +1 -1
- package/dist/stream.js +391 -47
- package/dist/transport.d.ts +79 -11
- package/dist/transport.d.ts.map +1 -1
- package/dist/transport.js +3 -1
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +10 -1
- package/dist/write.d.ts +2 -1
- package/dist/write.d.ts.map +1 -1
- package/dist/write.js +96 -14
- package/package.json +3 -4
- package/dist/links.d.ts +0 -12
- package/dist/links.d.ts.map +0 -1
- package/dist/links.js +0 -66
package/dist/stream.js
CHANGED
|
@@ -1,45 +1,130 @@
|
|
|
1
1
|
import { acceptedMessage } from './actions.js';
|
|
2
|
-
import {
|
|
2
|
+
import { sha256Hex } from './digest.js';
|
|
3
|
+
import { binaryFileOf, headChange, identities } from './read.js';
|
|
3
4
|
import { roomVersion } from './version.js';
|
|
4
5
|
const HELD_FRAMES_MAX = 256;
|
|
5
6
|
function turnOperation(frame) {
|
|
6
7
|
const { type: _type, conversation_id: _conversation, turn_id: _turn, ...operation } = frame;
|
|
7
8
|
return structuredClone(operation);
|
|
8
9
|
}
|
|
10
|
+
function listedConversation(listed) {
|
|
11
|
+
return {
|
|
12
|
+
conversation: listed.conversation_id,
|
|
13
|
+
agent: listed.agent_id,
|
|
14
|
+
name: listed.name,
|
|
15
|
+
created: listed.created_at,
|
|
16
|
+
finished: listed.finished_at,
|
|
17
|
+
outcome: listed.outcome,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
9
20
|
function position(value) {
|
|
10
21
|
if (!/^(?:0|[1-9][0-9]*)$/.test(value))
|
|
11
22
|
return null;
|
|
12
23
|
return BigInt(value);
|
|
13
24
|
}
|
|
25
|
+
function assembled(entries) {
|
|
26
|
+
const whole = [];
|
|
27
|
+
let open = null;
|
|
28
|
+
for (const entry of entries) {
|
|
29
|
+
if (entry.kind === 'piece') {
|
|
30
|
+
if (open === null || open.entry.path !== entry.path || entry.text === undefined)
|
|
31
|
+
return null;
|
|
32
|
+
open.texts.push(entry.text);
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
if (open !== null)
|
|
36
|
+
return null;
|
|
37
|
+
if (entry.continued !== true) {
|
|
38
|
+
whole.push(entry);
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
if (entry.text === undefined)
|
|
42
|
+
return null;
|
|
43
|
+
open = { entry, texts: [entry.text] };
|
|
44
|
+
}
|
|
45
|
+
if (entry.continued === true)
|
|
46
|
+
continue;
|
|
47
|
+
const { continued: _continued, ...head } = open.entry;
|
|
48
|
+
whole.push({ ...head, text: open.texts.join('') });
|
|
49
|
+
open = null;
|
|
50
|
+
}
|
|
51
|
+
return open === null ? whole : null;
|
|
52
|
+
}
|
|
53
|
+
async function verified(entries) {
|
|
54
|
+
try {
|
|
55
|
+
for (const entry of entries) {
|
|
56
|
+
if (entry.text === undefined || entry.sha256 === undefined)
|
|
57
|
+
continue;
|
|
58
|
+
if ((await sha256Hex(entry.text)) !== entry.sha256)
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
function resumed(kept, frame) {
|
|
68
|
+
const last = frame.entries.at(-1);
|
|
69
|
+
const point = { parts: frame.index + 1, from: frame.from, target: frame.target };
|
|
70
|
+
if (last?.continued !== true)
|
|
71
|
+
return { ...point, handled: frame.handled, piece: null };
|
|
72
|
+
const text = last.text?.length ?? 0;
|
|
73
|
+
if (last.kind !== 'piece') {
|
|
74
|
+
return last.sha256 === undefined
|
|
75
|
+
? kept.resume
|
|
76
|
+
: { ...point, handled: frame.handled, piece: { sha256: last.sha256, offset: text } };
|
|
77
|
+
}
|
|
78
|
+
const piece = kept.resume?.piece ?? null;
|
|
79
|
+
if (piece === null)
|
|
80
|
+
return kept.resume;
|
|
81
|
+
const pieces = frame.entries.reduce((sum, entry) => sum + (entry.kind === 'piece' ? (entry.text?.length ?? 0) : 0), 0);
|
|
82
|
+
return {
|
|
83
|
+
...point,
|
|
84
|
+
handled: frame.handled,
|
|
85
|
+
piece: { sha256: piece.sha256, offset: piece.offset + pieces },
|
|
86
|
+
};
|
|
87
|
+
}
|
|
14
88
|
export function houseNotifications(transport, mode) {
|
|
15
89
|
const stream = transport.stream;
|
|
16
90
|
const lines = new Map();
|
|
91
|
+
const kept = new Map();
|
|
92
|
+
let receipts = null;
|
|
93
|
+
let loaded = Promise.resolve();
|
|
94
|
+
let acknowledging = null;
|
|
95
|
+
let receiving = Promise.resolve();
|
|
96
|
+
let verifying = 0;
|
|
17
97
|
const locators = new Map();
|
|
18
|
-
const schemas = new Map();
|
|
19
98
|
const observers = new Set();
|
|
20
99
|
const conversationObservers = new Set();
|
|
21
100
|
const modeObservers = new Set();
|
|
22
101
|
let replicated = [];
|
|
23
102
|
const live = new Set();
|
|
24
|
-
let
|
|
25
|
-
|
|
26
|
-
function
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
listening = true;
|
|
30
|
-
stream.observe(receive);
|
|
103
|
+
let opening = null;
|
|
104
|
+
const runtime = crypto.randomUUID();
|
|
105
|
+
function emit(event) {
|
|
106
|
+
for (const observer of observers)
|
|
107
|
+
observer(event);
|
|
31
108
|
}
|
|
32
109
|
function emitConversation(event) {
|
|
33
|
-
if (event.kind
|
|
110
|
+
if (event.kind === 'turn' ||
|
|
111
|
+
event.kind === 'questions' ||
|
|
112
|
+
event.kind === 'process' ||
|
|
113
|
+
event.kind === 'commands' ||
|
|
114
|
+
event.kind === 'options') {
|
|
34
115
|
live.add(event.conversation);
|
|
116
|
+
}
|
|
35
117
|
for (const observer of conversationObservers)
|
|
36
118
|
observer(event);
|
|
37
119
|
}
|
|
38
|
-
function reopened() {
|
|
120
|
+
function reopened(next) {
|
|
121
|
+
opening = next;
|
|
122
|
+
acknowledging = next;
|
|
39
123
|
const gapped = new Set([...replicated, ...live]);
|
|
40
124
|
live.clear();
|
|
41
125
|
for (const conversation of gapped)
|
|
42
126
|
emitConversation({ kind: 'gap', conversation });
|
|
127
|
+
emit({ kind: 'opened' });
|
|
43
128
|
}
|
|
44
129
|
function converse(frame) {
|
|
45
130
|
const conversation = frame.conversation_id;
|
|
@@ -85,14 +170,10 @@ export function houseNotifications(transport, mode) {
|
|
|
85
170
|
return;
|
|
86
171
|
emitConversation({ kind: 'accepted-message', conversation, message });
|
|
87
172
|
}
|
|
88
|
-
function announce(authority, at
|
|
173
|
+
function announce(authority, at) {
|
|
89
174
|
const version = roomVersion(at);
|
|
90
175
|
for (const locator of locators.get(authority) ?? []) {
|
|
91
|
-
|
|
92
|
-
observer(modelChanged
|
|
93
|
-
? { locator, roomVersion: version, modelChanged: true }
|
|
94
|
-
: { locator, roomVersion: version });
|
|
95
|
-
}
|
|
176
|
+
emit({ kind: 'room-version', locator, roomVersion: version });
|
|
96
177
|
}
|
|
97
178
|
}
|
|
98
179
|
function interrupt(authority) {
|
|
@@ -100,7 +181,162 @@ export function houseNotifications(transport, mode) {
|
|
|
100
181
|
if (line !== undefined)
|
|
101
182
|
lines.set(authority, { ...line, frames: [] });
|
|
102
183
|
}
|
|
103
|
-
function
|
|
184
|
+
async function forget(carries) {
|
|
185
|
+
const held = carries.filter((carry) => kept.delete(carry));
|
|
186
|
+
if (held.length > 0)
|
|
187
|
+
await receipts?.drop(held).catch(() => { });
|
|
188
|
+
}
|
|
189
|
+
async function lost(authority, carry) {
|
|
190
|
+
interrupt(authority);
|
|
191
|
+
await forget([carry]);
|
|
192
|
+
}
|
|
193
|
+
async function stage(frame, via) {
|
|
194
|
+
await loaded;
|
|
195
|
+
const port = receipts;
|
|
196
|
+
if (port === null)
|
|
197
|
+
return;
|
|
198
|
+
const held = kept.get(frame.carry);
|
|
199
|
+
if (held === undefined && frame.index !== 0) {
|
|
200
|
+
interrupt(frame.authority);
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
if (held !== undefined &&
|
|
204
|
+
(held.fenced !== null || frame.index > held.parts || frame.index < (held.resume?.parts ?? 0))) {
|
|
205
|
+
await lost(frame.authority, frame.carry);
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
if (held === undefined) {
|
|
209
|
+
await forget([...kept.values()]
|
|
210
|
+
.filter((other) => other.authority === frame.authority && other.fenced === null)
|
|
211
|
+
.map((other) => other.carry));
|
|
212
|
+
}
|
|
213
|
+
const start = held ?? {
|
|
214
|
+
authority: frame.authority,
|
|
215
|
+
carry: frame.carry,
|
|
216
|
+
logEpoch: lines.get(frame.authority)?.logEpoch ?? null,
|
|
217
|
+
after: frame.after,
|
|
218
|
+
parts: 0,
|
|
219
|
+
resume: null,
|
|
220
|
+
fenced: null,
|
|
221
|
+
};
|
|
222
|
+
const next = { ...start, parts: frame.index + 1, resume: resumed(start, frame) };
|
|
223
|
+
const part = { entries: frame.entries };
|
|
224
|
+
try {
|
|
225
|
+
await port.keep(frame.carry, next, { index: frame.index, value: part });
|
|
226
|
+
}
|
|
227
|
+
catch {
|
|
228
|
+
await lost(frame.authority, frame.carry);
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
kept.set(frame.carry, next);
|
|
232
|
+
via?.received(frame.authority, frame.carry, frame.index);
|
|
233
|
+
}
|
|
234
|
+
async function keptEntries(carry, parts) {
|
|
235
|
+
if (parts === 0)
|
|
236
|
+
return [];
|
|
237
|
+
if (receipts === null)
|
|
238
|
+
return null;
|
|
239
|
+
const read = (await receipts.parts(carry, parts));
|
|
240
|
+
if (read.length !== parts)
|
|
241
|
+
return null;
|
|
242
|
+
const entries = assembled(read.flatMap((part) => part.entries));
|
|
243
|
+
return entries !== null && (await verified(entries)) ? entries : null;
|
|
244
|
+
}
|
|
245
|
+
async function carried(frame) {
|
|
246
|
+
await loaded;
|
|
247
|
+
const held = kept.get(frame.carry);
|
|
248
|
+
if (frame.parts > 0 && held?.parts !== frame.parts) {
|
|
249
|
+
await lost(frame.authority, frame.carry);
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
const entries = await keptEntries(frame.carry, frame.parts).catch(() => null);
|
|
253
|
+
if (entries === null) {
|
|
254
|
+
await lost(frame.authority, frame.carry);
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
const fenced = {
|
|
258
|
+
...(held ?? {
|
|
259
|
+
authority: frame.authority,
|
|
260
|
+
carry: frame.carry,
|
|
261
|
+
logEpoch: frame.log_epoch,
|
|
262
|
+
after: frame.after,
|
|
263
|
+
parts: 0,
|
|
264
|
+
resume: null,
|
|
265
|
+
}),
|
|
266
|
+
after: frame.after,
|
|
267
|
+
fenced: { position: frame.position, logEpoch: frame.log_epoch },
|
|
268
|
+
};
|
|
269
|
+
try {
|
|
270
|
+
await receipts?.keep(frame.carry, fenced);
|
|
271
|
+
}
|
|
272
|
+
catch {
|
|
273
|
+
await lost(frame.authority, frame.carry);
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
kept.set(frame.carry, fenced);
|
|
277
|
+
publish(frame, entries);
|
|
278
|
+
}
|
|
279
|
+
async function load(port) {
|
|
280
|
+
try {
|
|
281
|
+
for (const { key, head } of await port.heads())
|
|
282
|
+
kept.set(key, head);
|
|
283
|
+
}
|
|
284
|
+
catch {
|
|
285
|
+
kept.clear();
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
async function restored(room) {
|
|
289
|
+
const line = lines.get(room.authority);
|
|
290
|
+
let at = room.position;
|
|
291
|
+
const chain = [];
|
|
292
|
+
for (;;) {
|
|
293
|
+
const next = [...kept.values()].find((carry) => carry.authority === room.authority &&
|
|
294
|
+
carry.after === at &&
|
|
295
|
+
carry.fenced?.logEpoch === room.log_epoch);
|
|
296
|
+
if (next?.fenced == null)
|
|
297
|
+
break;
|
|
298
|
+
const entries = await keptEntries(next.carry, next.parts).catch(() => null);
|
|
299
|
+
if (entries === null)
|
|
300
|
+
break;
|
|
301
|
+
chain.push({ carry: next, entries });
|
|
302
|
+
at = next.fenced.position;
|
|
303
|
+
}
|
|
304
|
+
const partial = [...kept.values()].find((carry) => carry.authority === room.authority &&
|
|
305
|
+
carry.fenced === null &&
|
|
306
|
+
carry.logEpoch === room.log_epoch &&
|
|
307
|
+
carry.after === at &&
|
|
308
|
+
carry.resume !== null &&
|
|
309
|
+
carry.resume.parts > 0);
|
|
310
|
+
const stale = [...kept.values()].filter((carry) => carry.authority === room.authority &&
|
|
311
|
+
carry !== partial &&
|
|
312
|
+
!chain.some((link) => link.carry === carry));
|
|
313
|
+
await forget(stale.map((carry) => carry.carry));
|
|
314
|
+
if (line !== undefined && line.logEpoch === room.log_epoch && chain.length > 0) {
|
|
315
|
+
const frames = chain.map(({ carry, entries }) => ({
|
|
316
|
+
after: BigInt(carry.after),
|
|
317
|
+
position: BigInt(carry.fenced.position),
|
|
318
|
+
entries,
|
|
319
|
+
}));
|
|
320
|
+
lines.set(room.authority, { ...line, frames: [...line.frames, ...frames] });
|
|
321
|
+
}
|
|
322
|
+
return {
|
|
323
|
+
...room,
|
|
324
|
+
position: at,
|
|
325
|
+
...(partial?.resume == null
|
|
326
|
+
? {}
|
|
327
|
+
: {
|
|
328
|
+
carry: {
|
|
329
|
+
id: partial.carry,
|
|
330
|
+
parts: partial.resume.parts,
|
|
331
|
+
from: partial.resume.from,
|
|
332
|
+
target: partial.resume.target,
|
|
333
|
+
handled: partial.resume.handled,
|
|
334
|
+
...(partial.resume.piece === null ? {} : { piece: partial.resume.piece }),
|
|
335
|
+
},
|
|
336
|
+
}),
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
function handle(frame, via) {
|
|
104
340
|
if (frame.type === 'signal') {
|
|
105
341
|
const mode = frame.service_mode;
|
|
106
342
|
if (mode !== 'open' && mode !== 'write-halted')
|
|
@@ -109,6 +345,25 @@ export function houseNotifications(transport, mode) {
|
|
|
109
345
|
observer(mode);
|
|
110
346
|
return;
|
|
111
347
|
}
|
|
348
|
+
if (frame.type === 'opening') {
|
|
349
|
+
emit({
|
|
350
|
+
kind: 'opening',
|
|
351
|
+
expired: frame.expired.flatMap((authority) => locators.get(authority) ?? []),
|
|
352
|
+
});
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
if (frame.type === 'conversations') {
|
|
356
|
+
emitConversation({ kind: 'list', entries: frame.conversations.map(listedConversation) });
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
359
|
+
if (frame.type === 'conversation') {
|
|
360
|
+
emitConversation({ kind: 'listed', entry: listedConversation(frame.conversation) });
|
|
361
|
+
return;
|
|
362
|
+
}
|
|
363
|
+
if (frame.type === 'conversation_deleted') {
|
|
364
|
+
emitConversation({ kind: 'unlisted', conversation: frame.conversation_id });
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
112
367
|
if (frame.type === 'turn' ||
|
|
113
368
|
frame.type === 'process' ||
|
|
114
369
|
frame.type === 'commands' ||
|
|
@@ -118,8 +373,12 @@ export function houseNotifications(transport, mode) {
|
|
|
118
373
|
converse(frame);
|
|
119
374
|
return;
|
|
120
375
|
}
|
|
121
|
-
if (frame.type
|
|
122
|
-
return;
|
|
376
|
+
if (frame.type === 'part')
|
|
377
|
+
return stage(frame, via);
|
|
378
|
+
if (frame.type === 'carried')
|
|
379
|
+
return carried(frame);
|
|
380
|
+
}
|
|
381
|
+
function publish(frame, entries) {
|
|
123
382
|
const at = position(frame.position);
|
|
124
383
|
const after = position(frame.after);
|
|
125
384
|
if (at === null || after === null || after >= at) {
|
|
@@ -133,21 +392,45 @@ export function houseNotifications(transport, mode) {
|
|
|
133
392
|
const last = line.frames.at(-1);
|
|
134
393
|
if (last !== undefined && at <= last.position)
|
|
135
394
|
return;
|
|
136
|
-
const held = { after, position: at, entries
|
|
395
|
+
const held = { after, position: at, entries };
|
|
137
396
|
const next = last !== undefined && after <= last.position ? [...line.frames, held] : [held];
|
|
138
397
|
lines.set(frame.authority, { ...line, frames: next.length > HELD_FRAMES_MAX ? [] : next });
|
|
139
398
|
}
|
|
140
399
|
else {
|
|
141
400
|
interrupt(frame.authority);
|
|
142
401
|
}
|
|
143
|
-
|
|
144
|
-
announce(frame.authority, { position: frame.position, logEpoch: frame.log_epoch }, frame.entries.some((entry) => addresses.includes(entry.path)));
|
|
402
|
+
announce(frame.authority, { position: frame.position, logEpoch: frame.log_epoch });
|
|
145
403
|
}
|
|
404
|
+
stream.observe((frame) => {
|
|
405
|
+
const via = acknowledging;
|
|
406
|
+
if (verifying === 0) {
|
|
407
|
+
const handled = handle(frame, via);
|
|
408
|
+
if (handled === undefined)
|
|
409
|
+
return;
|
|
410
|
+
verifying += 1;
|
|
411
|
+
receiving = handled.finally(() => {
|
|
412
|
+
verifying -= 1;
|
|
413
|
+
});
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
416
|
+
verifying += 1;
|
|
417
|
+
receiving = receiving
|
|
418
|
+
.then(() => handle(frame, via))
|
|
419
|
+
.finally(() => {
|
|
420
|
+
verifying -= 1;
|
|
421
|
+
});
|
|
422
|
+
});
|
|
423
|
+
stream.opened(reopened);
|
|
424
|
+
stream.closed((revoked) => {
|
|
425
|
+
opening = null;
|
|
426
|
+
acknowledging = null;
|
|
427
|
+
emit({ kind: 'closed', revoked });
|
|
428
|
+
});
|
|
146
429
|
return {
|
|
430
|
+
runtime,
|
|
147
431
|
serviceMode: {
|
|
148
432
|
observe(notify) {
|
|
149
433
|
modeObservers.add(notify);
|
|
150
|
-
listen();
|
|
151
434
|
return () => {
|
|
152
435
|
modeObservers.delete(notify);
|
|
153
436
|
};
|
|
@@ -159,22 +442,71 @@ export function houseNotifications(transport, mode) {
|
|
|
159
442
|
},
|
|
160
443
|
observe(notify) {
|
|
161
444
|
conversationObservers.add(notify);
|
|
162
|
-
listen();
|
|
163
|
-
if (!catching) {
|
|
164
|
-
catching = true;
|
|
165
|
-
stream.opened(reopened);
|
|
166
|
-
}
|
|
167
445
|
return () => {
|
|
168
446
|
conversationObservers.delete(notify);
|
|
169
447
|
};
|
|
170
448
|
},
|
|
171
449
|
},
|
|
450
|
+
observe(notify, port) {
|
|
451
|
+
observers.add(notify);
|
|
452
|
+
if (receipts === null) {
|
|
453
|
+
receipts = port;
|
|
454
|
+
loaded = load(port);
|
|
455
|
+
}
|
|
456
|
+
if (opening !== null) {
|
|
457
|
+
queueMicrotask(() => {
|
|
458
|
+
if (observers.has(notify))
|
|
459
|
+
notify({ kind: 'opened' });
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
return () => {
|
|
463
|
+
observers.delete(notify);
|
|
464
|
+
};
|
|
465
|
+
},
|
|
466
|
+
send(rooms, demand) {
|
|
467
|
+
for (const room of rooms) {
|
|
468
|
+
const line = lines.get(room.authority);
|
|
469
|
+
const held = position(room.position);
|
|
470
|
+
if (line === undefined || held === null || line.logEpoch !== room.log_epoch)
|
|
471
|
+
continue;
|
|
472
|
+
lines.set(room.authority, { ...line, frames: [], held });
|
|
473
|
+
}
|
|
474
|
+
const current = opening;
|
|
475
|
+
opening = null;
|
|
476
|
+
if (current === null)
|
|
477
|
+
return;
|
|
478
|
+
void loaded
|
|
479
|
+
.then(() => Promise.all(rooms.map(restored)))
|
|
480
|
+
.then((presented) => {
|
|
481
|
+
current.hold(presented, runtime, demand);
|
|
482
|
+
for (const [index, room] of presented.entries()) {
|
|
483
|
+
if (room.position === rooms[index].position)
|
|
484
|
+
continue;
|
|
485
|
+
announce(room.authority, { position: room.position, logEpoch: room.log_epoch });
|
|
486
|
+
}
|
|
487
|
+
});
|
|
488
|
+
},
|
|
489
|
+
published(locator, at) {
|
|
490
|
+
const authority = [...locators].find(([, held]) => held.includes(locator))?.[0];
|
|
491
|
+
const reached = position(at.position);
|
|
492
|
+
if (authority === undefined || reached === null)
|
|
493
|
+
return;
|
|
494
|
+
void forget([...kept.values()]
|
|
495
|
+
.filter((carry) => carry.authority === authority &&
|
|
496
|
+
carry.fenced !== null &&
|
|
497
|
+
carry.fenced.logEpoch === at.logEpoch &&
|
|
498
|
+
BigInt(carry.fenced.position) <= reached)
|
|
499
|
+
.map((carry) => carry.carry));
|
|
500
|
+
},
|
|
501
|
+
reopen() {
|
|
502
|
+
const current = opening;
|
|
503
|
+
opening = null;
|
|
504
|
+
current?.close();
|
|
505
|
+
},
|
|
172
506
|
track(entries) {
|
|
173
507
|
locators.clear();
|
|
174
|
-
schemas.clear();
|
|
175
508
|
for (const entry of entries) {
|
|
176
509
|
locators.set(entry.authority, [...(locators.get(entry.authority) ?? []), entry.locator]);
|
|
177
|
-
schemas.set(entry.authority, entry.schemas);
|
|
178
510
|
if (lines.get(entry.authority)?.logEpoch !== entry.logEpoch) {
|
|
179
511
|
lines.set(entry.authority, { logEpoch: entry.logEpoch, frames: [], held: null });
|
|
180
512
|
}
|
|
@@ -183,21 +515,22 @@ export function houseNotifications(transport, mode) {
|
|
|
183
515
|
if (!locators.has(authority))
|
|
184
516
|
lines.delete(authority);
|
|
185
517
|
}
|
|
518
|
+
void loaded.then(() => forget([...kept.values()]
|
|
519
|
+
.filter((carry) => !locators.has(carry.authority))
|
|
520
|
+
.map((carry) => carry.carry)));
|
|
186
521
|
},
|
|
187
|
-
|
|
188
|
-
observe(notify) {
|
|
189
|
-
observers.add(notify);
|
|
190
|
-
listen();
|
|
191
|
-
return () => {
|
|
192
|
-
observers.delete(notify);
|
|
193
|
-
};
|
|
194
|
-
},
|
|
195
|
-
hold(authority, at) {
|
|
522
|
+
reach(authority, at) {
|
|
196
523
|
const line = lines.get(authority);
|
|
197
524
|
const held = position(at.position);
|
|
198
525
|
if (line === undefined || held === null || line.logEpoch !== at.logEpoch)
|
|
199
526
|
return;
|
|
200
|
-
|
|
527
|
+
if (line.held !== null && held <= line.held)
|
|
528
|
+
return;
|
|
529
|
+
lines.set(authority, {
|
|
530
|
+
...line,
|
|
531
|
+
frames: line.frames.filter((frame) => frame.position > held),
|
|
532
|
+
held,
|
|
533
|
+
});
|
|
201
534
|
},
|
|
202
535
|
advance(tracked, from, holds) {
|
|
203
536
|
const line = lines.get(tracked.authority);
|
|
@@ -211,12 +544,15 @@ export function houseNotifications(transport, mode) {
|
|
|
211
544
|
const documents = {};
|
|
212
545
|
const revisions = {};
|
|
213
546
|
const changes = {};
|
|
547
|
+
const binaryFiles = {};
|
|
214
548
|
const removals = [];
|
|
215
549
|
const applied = [];
|
|
550
|
+
const schemas = new Map();
|
|
216
551
|
const forget = (path) => {
|
|
217
552
|
delete documents[path];
|
|
218
553
|
delete revisions[path];
|
|
219
554
|
delete changes[path];
|
|
555
|
+
delete binaryFiles[path];
|
|
220
556
|
const removed = removals.indexOf(path);
|
|
221
557
|
if (removed !== -1)
|
|
222
558
|
removals.splice(removed, 1);
|
|
@@ -224,19 +560,21 @@ export function houseNotifications(transport, mode) {
|
|
|
224
560
|
for (const frame of pending) {
|
|
225
561
|
for (const entry of frame.entries) {
|
|
226
562
|
if (entry.kind === 'edited' &&
|
|
227
|
-
entry.text === undefined &&
|
|
228
563
|
entry.revision !== undefined &&
|
|
229
564
|
holds?.(entry.path, entry.revision) === true) {
|
|
230
565
|
forget(entry.path);
|
|
231
566
|
continue;
|
|
232
567
|
}
|
|
233
568
|
applied.push(entry);
|
|
569
|
+
if (tracked.schemas.includes(entry.path))
|
|
570
|
+
schemas.set(entry.path, entry);
|
|
234
571
|
if (entry.kind === 'removed') {
|
|
235
572
|
forget(entry.path);
|
|
236
573
|
removals.push(entry.path);
|
|
237
574
|
continue;
|
|
238
575
|
}
|
|
239
|
-
|
|
576
|
+
const binary = binaryFileOf(entry);
|
|
577
|
+
if (binary === null || (binary === undefined && entry.text === undefined))
|
|
240
578
|
return null;
|
|
241
579
|
if (mode === 'credential' && entry.revision === undefined)
|
|
242
580
|
return null;
|
|
@@ -244,9 +582,13 @@ export function houseNotifications(transport, mode) {
|
|
|
244
582
|
if (head === null)
|
|
245
583
|
return null;
|
|
246
584
|
forget(entry.path);
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
585
|
+
if (binary === undefined)
|
|
586
|
+
documents[entry.path] = entry.text;
|
|
587
|
+
else
|
|
588
|
+
binaryFiles[entry.path] = binary;
|
|
589
|
+
const revision = entry.revision ?? binary?.sha256;
|
|
590
|
+
if (revision !== undefined)
|
|
591
|
+
revisions[entry.path] = revision;
|
|
250
592
|
if (head !== undefined)
|
|
251
593
|
changes[entry.path] = head;
|
|
252
594
|
}
|
|
@@ -259,11 +601,13 @@ export function houseNotifications(transport, mode) {
|
|
|
259
601
|
roomVersion: roomVersion({ position: last.position.toString(), logEpoch: line.logEpoch }),
|
|
260
602
|
documents,
|
|
261
603
|
revisions,
|
|
604
|
+
...identities(revisions),
|
|
262
605
|
changes,
|
|
263
|
-
|
|
606
|
+
binaryFiles,
|
|
264
607
|
removals: removals.sort(),
|
|
265
608
|
},
|
|
266
609
|
entries: applied,
|
|
610
|
+
schemas,
|
|
267
611
|
};
|
|
268
612
|
},
|
|
269
613
|
};
|