@agentshouse/mdruntime-adapter 0.1.0-cb6436097e8a2 → 0.1.0-cb8fc491b1a92

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 (64) hide show
  1. package/README.md +2 -2
  2. package/dist/actions.d.ts +122 -23
  3. package/dist/actions.d.ts.map +1 -1
  4. package/dist/actions.js +27 -141
  5. package/dist/adapter.d.ts.map +1 -1
  6. package/dist/adapter.js +220 -337
  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 +6 -10
  14. package/dist/discovery.d.ts.map +1 -1
  15. package/dist/discovery.js +36 -40
  16. package/dist/house-model.d.ts +2983 -0
  17. package/dist/house-model.d.ts.map +1 -0
  18. package/dist/house-model.js +1643 -0
  19. package/dist/index.d.ts +9 -2
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +8 -1
  22. package/dist/model.d.ts +5 -2
  23. package/dist/model.d.ts.map +1 -1
  24. package/dist/model.js +10 -29
  25. package/dist/part.d.ts +14 -0
  26. package/dist/part.d.ts.map +1 -0
  27. package/dist/part.js +90 -0
  28. package/dist/read.d.ts +46 -63
  29. package/dist/read.d.ts.map +1 -1
  30. package/dist/read.js +216 -283
  31. package/dist/refusal.d.ts +0 -3
  32. package/dist/refusal.d.ts.map +1 -1
  33. package/dist/refusal.js +0 -5
  34. package/dist/room-stream.d.ts +19 -0
  35. package/dist/room-stream.d.ts.map +1 -0
  36. package/dist/room-stream.js +57 -0
  37. package/dist/room-types.d.ts +7 -0
  38. package/dist/room-types.d.ts.map +1 -0
  39. package/dist/room-types.js +126 -0
  40. package/dist/site.d.ts.map +1 -1
  41. package/dist/site.js +80 -179
  42. package/dist/stream.d.ts +4 -14
  43. package/dist/stream.d.ts.map +1 -1
  44. package/dist/stream.js +125 -413
  45. package/dist/transport.d.ts +53 -43
  46. package/dist/transport.d.ts.map +1 -1
  47. package/dist/transport.js +49 -11
  48. package/dist/upload.d.ts +12 -0
  49. package/dist/upload.d.ts.map +1 -0
  50. package/dist/upload.js +63 -0
  51. package/dist/write.d.ts +16 -1
  52. package/dist/write.d.ts.map +1 -1
  53. package/dist/write.js +101 -56
  54. package/package.json +8 -4
  55. package/AGENTS.md +0 -299
  56. package/dist/gather.d.ts +0 -4
  57. package/dist/gather.d.ts.map +0 -1
  58. package/dist/gather.js +0 -45
  59. package/dist/handed.d.ts +0 -15
  60. package/dist/handed.d.ts.map +0 -1
  61. package/dist/handed.js +0 -38
  62. package/dist/referrer.d.ts +0 -7
  63. package/dist/referrer.d.ts.map +0 -1
  64. package/dist/referrer.js +0 -35
package/dist/stream.js CHANGED
@@ -1,100 +1,84 @@
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 } from './actions.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,
33
+ waiting: listed.waiting,
34
+ newest: listed.newest === null ? null : cursorPosition(listed.newest),
18
35
  };
19
36
  }
20
37
  function position(value) {
21
- if (!/^(?:0|[1-9][0-9]*)$/.test(value))
38
+ if (!DECIMAL.test(value))
22
39
  return null;
23
40
  return BigInt(value);
24
41
  }
25
- function assembled(entries) {
26
- const whole = [];
27
- let open = null;
42
+ function* changed(tracked, entries, version, schemas) {
43
+ const answer = answering();
28
44
  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] };
45
+ yield ROW_WEIGHT + (entry.text?.length ?? 0);
46
+ if (entry.kind === 'folder') {
47
+ folded(answer, entry.path, entry.removed === true);
48
+ continue;
44
49
  }
45
- 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);
46
55
  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
56
  }
61
- return true;
62
- }
63
- catch {
64
- 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);
65
68
  }
69
+ return { kind: 'net-advancement', roomVersion: version, ...(yield* answered(answer)) };
66
70
  }
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
- };
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 };
87
76
  }
88
77
  export function houseNotifications(transport, mode) {
89
78
  const stream = transport.stream;
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;
97
- const locators = new Map();
79
+ const staged = new Map();
80
+ let socket = null;
81
+ const tracking = new Map();
98
82
  const observers = new Set();
99
83
  const conversationObservers = new Set();
100
84
  const modeObservers = new Set();
@@ -111,7 +95,10 @@ export function houseNotifications(transport, mode) {
111
95
  event.kind === 'questions' ||
112
96
  event.kind === 'process' ||
113
97
  event.kind === 'commands' ||
114
- event.kind === 'options') {
98
+ event.kind === 'options' ||
99
+ event.kind === 'starting' ||
100
+ event.kind === 'link' ||
101
+ event.kind === 'deliveries') {
115
102
  live.add(event.conversation);
116
103
  }
117
104
  for (const observer of conversationObservers)
@@ -119,7 +106,8 @@ export function houseNotifications(transport, mode) {
119
106
  }
120
107
  function reopened(next) {
121
108
  opening = next;
122
- acknowledging = next;
109
+ socket = next;
110
+ staged.clear();
123
111
  const gapped = new Set([...replicated, ...live]);
124
112
  live.clear();
125
113
  for (const conversation of gapped)
@@ -157,6 +145,18 @@ export function houseNotifications(transport, mode) {
157
145
  emitConversation({ kind: 'options', conversation, options: structuredClone(frame.options) });
158
146
  return;
159
147
  }
148
+ if (frame.type === 'starting') {
149
+ emitConversation({ kind: 'starting', conversation, step: frame.step });
150
+ return;
151
+ }
152
+ if (frame.type === 'link') {
153
+ emitConversation({ kind: 'link', conversation, connected: frame.connected });
154
+ return;
155
+ }
156
+ if (frame.type === 'deliveries') {
157
+ emitConversation({ kind: 'deliveries', conversation, unknown: [...frame.unknown] });
158
+ return;
159
+ }
160
160
  if (frame.type === 'interactions') {
161
161
  emitConversation({
162
162
  kind: 'questions',
@@ -170,171 +170,30 @@ export function houseNotifications(transport, mode) {
170
170
  return;
171
171
  emitConversation({ kind: 'accepted-message', conversation, message });
172
172
  }
173
- function announce(authority, at) {
174
- const version = roomVersion(at);
175
- for (const locator of locators.get(authority) ?? []) {
176
- emit({ kind: 'room-version', locator, roomVersion: version });
177
- }
178
- }
179
- function interrupt(authority) {
180
- const line = lines.get(authority);
181
- if (line !== undefined)
182
- lines.set(authority, { ...line, frames: [] });
183
- }
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);
173
+ function stage(frame, via) {
174
+ const held = staged.get(frame.carry);
175
+ if (frame.index !== (held?.parts ?? 0)) {
176
+ staged.delete(frame.carry);
206
177
  return;
207
178
  }
208
179
  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;
180
+ for (const [carry, other] of staged) {
181
+ if (other.authority === frame.authority)
182
+ staged.delete(carry);
183
+ }
230
184
  }
231
- kept.set(frame.carry, next);
185
+ const next = held ?? { authority: frame.authority, parts: 0, entries: [] };
186
+ next.entries.push(...frame.entries);
187
+ next.parts += 1;
188
+ staged.set(frame.carry, next);
232
189
  via?.received(frame.authority, frame.carry, frame.index);
233
190
  }
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);
191
+ function carried(frame) {
192
+ const held = staged.get(frame.carry);
193
+ staged.delete(frame.carry);
194
+ if ((held?.parts ?? 0) !== frame.parts)
274
195
  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
- };
196
+ publish(frame, held?.entries ?? []);
338
197
  }
339
198
  function handle(frame, via) {
340
199
  if (frame.type === 'signal') {
@@ -348,10 +207,14 @@ export function houseNotifications(transport, mode) {
348
207
  if (frame.type === 'opening') {
349
208
  emit({
350
209
  kind: 'opening',
351
- expired: frame.expired.flatMap((authority) => locators.get(authority) ?? []),
210
+ expired: frame.expired.flatMap((authority) => (tracking.get(authority) ?? []).map((tracked) => tracked.locator)),
352
211
  });
353
212
  return;
354
213
  }
214
+ if (frame.type === 'authority_changed') {
215
+ emit({ kind: 'authority-changed', scope: { authorities: frame.rooms } });
216
+ return;
217
+ }
355
218
  if (frame.type === 'conversations') {
356
219
  emitConversation({ kind: 'list', entries: frame.conversations.map(listedConversation) });
357
220
  return;
@@ -368,63 +231,43 @@ export function houseNotifications(transport, mode) {
368
231
  frame.type === 'process' ||
369
232
  frame.type === 'commands' ||
370
233
  frame.type === 'options' ||
234
+ frame.type === 'starting' ||
235
+ frame.type === 'link' ||
236
+ frame.type === 'deliveries' ||
371
237
  frame.type === 'interactions' ||
372
238
  frame.type === 'message') {
373
239
  converse(frame);
374
240
  return;
375
241
  }
376
242
  if (frame.type === 'part')
377
- return stage(frame, via);
378
- if (frame.type === 'carried')
379
- return carried(frame);
243
+ stage(frame, via);
244
+ else if (frame.type === 'carried')
245
+ carried(frame);
380
246
  }
381
247
  function publish(frame, entries) {
382
248
  const at = position(frame.position);
383
249
  const after = position(frame.after);
384
- if (at === null || after === null || after >= at) {
385
- interrupt(frame.authority);
250
+ if (at === null || after === null || after >= at)
386
251
  return;
387
- }
388
- const line = lines.get(frame.authority);
389
- if (line?.logEpoch === frame.log_epoch) {
390
- if (line.held !== null && at <= line.held)
391
- return;
392
- const last = line.frames.at(-1);
393
- if (last !== undefined && at <= last.position)
394
- return;
395
- const held = { after, position: at, entries };
396
- const next = last !== undefined && after <= last.position ? [...line.frames, held] : [held];
397
- lines.set(frame.authority, { ...line, frames: next.length > HELD_FRAMES_MAX ? [] : next });
398
- }
399
- else {
400
- interrupt(frame.authority);
401
- }
402
- announce(frame.authority, { position: frame.position, logEpoch: frame.log_epoch });
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;
252
+ const from = roomVersion({ position: frame.after, logEpoch: frame.log_epoch });
253
+ const version = roomVersion({ position: frame.position, logEpoch: frame.log_epoch });
254
+ for (const tracked of tracking.get(frame.authority) ?? []) {
255
+ emit({
256
+ kind: 'room-change',
257
+ locator: tracked.locator,
258
+ from,
259
+ roomVersion: version,
260
+ read: () => changePage(tracked, entries, version, mode),
413
261
  });
414
- return;
415
262
  }
416
- verifying += 1;
417
- receiving = receiving
418
- .then(() => handle(frame, via))
419
- .finally(() => {
420
- verifying -= 1;
421
- });
422
- });
263
+ }
264
+ stream.observe((frame) => handle(frame, socket));
423
265
  stream.opened(reopened);
424
- stream.closed((revoked) => {
266
+ stream.closed(({ revoked, lost }) => {
425
267
  opening = null;
426
- acknowledging = null;
427
- emit({ kind: 'closed', revoked });
268
+ socket = null;
269
+ staged.clear();
270
+ emit({ kind: 'closed', revoked, lost });
428
271
  });
429
272
  return {
430
273
  runtime,
@@ -446,13 +289,10 @@ export function houseNotifications(transport, mode) {
446
289
  conversationObservers.delete(notify);
447
290
  };
448
291
  },
292
+ ...(mode === 'credential' ? { agents: () => houseAgents(transport) } : {}),
449
293
  },
450
- observe(notify, port) {
294
+ observe(notify) {
451
295
  observers.add(notify);
452
- if (receipts === null) {
453
- receipts = port;
454
- loaded = load(port);
455
- }
456
296
  if (opening !== null) {
457
297
  queueMicrotask(() => {
458
298
  if (observers.has(notify))
@@ -463,40 +303,9 @@ export function houseNotifications(transport, mode) {
463
303
  observers.delete(notify);
464
304
  };
465
305
  },
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;
306
+ send(rooms) {
475
307
  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));
308
+ socket?.hold(rooms, runtime);
500
309
  },
501
310
  reopen() {
502
311
  const current = opening;
@@ -504,111 +313,14 @@ export function houseNotifications(transport, mode) {
504
313
  current?.close();
505
314
  },
506
315
  track(entries) {
507
- locators.clear();
316
+ tracking.clear();
508
317
  for (const entry of entries) {
509
- locators.set(entry.authority, [...(locators.get(entry.authority) ?? []), entry.locator]);
510
- if (lines.get(entry.authority)?.logEpoch !== entry.logEpoch) {
511
- lines.set(entry.authority, { logEpoch: entry.logEpoch, frames: [], held: null });
512
- }
318
+ tracking.set(entry.authority, [...(tracking.get(entry.authority) ?? []), entry]);
513
319
  }
514
- for (const authority of lines.keys()) {
515
- if (!locators.has(authority))
516
- lines.delete(authority);
320
+ for (const [carry, held] of staged) {
321
+ if (!tracking.has(held.authority))
322
+ staged.delete(carry);
517
323
  }
518
- void loaded.then(() => forget([...kept.values()]
519
- .filter((carry) => !locators.has(carry.authority))
520
- .map((carry) => carry.carry)));
521
- },
522
- reach(authority, at) {
523
- const line = lines.get(authority);
524
- const held = position(at.position);
525
- if (line === undefined || held === null || line.logEpoch !== at.logEpoch)
526
- return;
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
- });
534
- },
535
- advance(tracked, from, holds) {
536
- const line = lines.get(tracked.authority);
537
- const start = position(from.position);
538
- if (line === undefined || start === null || line.logEpoch !== from.logEpoch)
539
- return null;
540
- const pending = line.frames.filter((frame) => frame.position > start);
541
- const first = pending[0];
542
- if (first === undefined || first.after > start)
543
- return null;
544
- const documents = {};
545
- const revisions = {};
546
- const changes = {};
547
- const binaryFiles = {};
548
- const removals = [];
549
- const applied = [];
550
- const schemas = new Map();
551
- const forget = (path) => {
552
- delete documents[path];
553
- delete revisions[path];
554
- delete changes[path];
555
- delete binaryFiles[path];
556
- const removed = removals.indexOf(path);
557
- if (removed !== -1)
558
- removals.splice(removed, 1);
559
- };
560
- for (const frame of pending) {
561
- for (const entry of frame.entries) {
562
- if (entry.kind === 'edited' &&
563
- entry.revision !== undefined &&
564
- holds?.(entry.path, entry.revision) === true) {
565
- forget(entry.path);
566
- continue;
567
- }
568
- applied.push(entry);
569
- if (tracked.schemas.includes(entry.path))
570
- schemas.set(entry.path, entry);
571
- if (entry.kind === 'removed') {
572
- forget(entry.path);
573
- removals.push(entry.path);
574
- continue;
575
- }
576
- const binary = binaryFileOf(entry);
577
- if (binary === null || (binary === undefined && entry.text === undefined))
578
- return null;
579
- if (mode === 'credential' && entry.revision === undefined)
580
- return null;
581
- const head = headChange(entry);
582
- if (head === null)
583
- return null;
584
- forget(entry.path);
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;
592
- if (head !== undefined)
593
- changes[entry.path] = head;
594
- }
595
- }
596
- const last = pending.at(-1);
597
- lines.set(tracked.authority, { ...line, frames: pending, held: last.position });
598
- return {
599
- page: {
600
- kind: 'net-advancement',
601
- roomVersion: roomVersion({ position: last.position.toString(), logEpoch: line.logEpoch }),
602
- documents,
603
- revisions,
604
- ...identities(revisions),
605
- changes,
606
- binaryFiles,
607
- removals: removals.sort(),
608
- },
609
- entries: applied,
610
- schemas,
611
- };
612
324
  },
613
325
  };
614
326
  }