@agentshouse/mdruntime-adapter 0.1.0-cd61dfca5d699 → 0.1.0-cd7e4bb187177

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