@agentshouse/mdruntime-adapter 0.1.0-cc1bdabaf4e28 → 0.1.0-cc34762b70bb0

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