@agentshouse/mdruntime 0.1.0-cd507e16e5fc0 → 0.1.0-cd574a610e9c8

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 (269) hide show
  1. package/README.md +21 -19
  2. package/dist/acceptance.d.ts +0 -3
  3. package/dist/acceptance.d.ts.map +1 -1
  4. package/dist/acceptance.js +75 -165
  5. package/dist/act-lanes.d.ts +30 -0
  6. package/dist/act-lanes.d.ts.map +1 -0
  7. package/dist/act-lanes.js +225 -0
  8. package/dist/actions.d.ts +8 -2
  9. package/dist/actions.d.ts.map +1 -1
  10. package/dist/actions.js +118 -67
  11. package/dist/adapter.d.ts +90 -58
  12. package/dist/adapter.d.ts.map +1 -1
  13. package/dist/attached-model.d.ts +0 -1
  14. package/dist/attached-model.d.ts.map +1 -1
  15. package/dist/attached-model.js +0 -5
  16. package/dist/authored.d.ts +88 -0
  17. package/dist/authored.d.ts.map +1 -0
  18. package/dist/authored.js +345 -0
  19. package/dist/bootstrap.d.ts +1 -1
  20. package/dist/bootstrap.d.ts.map +1 -1
  21. package/dist/bootstrap.js +6 -19
  22. package/dist/change-set.d.ts +4 -0
  23. package/dist/change-set.d.ts.map +1 -1
  24. package/dist/change-set.js +6 -0
  25. package/dist/change.d.ts +4 -0
  26. package/dist/change.d.ts.map +1 -1
  27. package/dist/change.js +7 -2
  28. package/dist/chat-types.d.ts +0 -2
  29. package/dist/chat-types.d.ts.map +1 -1
  30. package/dist/chat-types.js +0 -2
  31. package/dist/client.d.ts +13 -20
  32. package/dist/client.d.ts.map +1 -1
  33. package/dist/client.js +36 -20
  34. package/dist/collection.d.ts +25 -4
  35. package/dist/collection.d.ts.map +1 -1
  36. package/dist/collection.js +19 -2
  37. package/dist/column.d.ts +5 -0
  38. package/dist/column.d.ts.map +1 -0
  39. package/dist/column.js +9 -0
  40. package/dist/compile.d.ts +2 -0
  41. package/dist/compile.d.ts.map +1 -1
  42. package/dist/compile.js +31 -25
  43. package/dist/connection.d.ts.map +1 -1
  44. package/dist/connection.js +31 -24
  45. package/dist/context.d.ts.map +1 -1
  46. package/dist/context.js +1 -1
  47. package/dist/conversation-live.d.ts +26 -12
  48. package/dist/conversation-live.d.ts.map +1 -1
  49. package/dist/conversation-live.js +23 -12
  50. package/dist/conversation-row.d.ts +8 -1
  51. package/dist/conversation-row.d.ts.map +1 -1
  52. package/dist/conversation-row.js +20 -7
  53. package/dist/conversation.d.ts +37 -12
  54. package/dist/conversation.d.ts.map +1 -1
  55. package/dist/conversation.js +320 -234
  56. package/dist/declaration.d.ts +10 -0
  57. package/dist/declaration.d.ts.map +1 -0
  58. package/dist/declaration.js +24 -0
  59. package/dist/discovery.d.ts.map +1 -1
  60. package/dist/discovery.js +19 -44
  61. package/dist/durability.d.ts +4 -0
  62. package/dist/durability.d.ts.map +1 -1
  63. package/dist/durability.js +4 -0
  64. package/dist/entry.js +1 -1
  65. package/dist/expectation.d.ts +26 -13
  66. package/dist/expectation.d.ts.map +1 -1
  67. package/dist/expectation.js +72 -19
  68. package/dist/failure.d.ts +3 -0
  69. package/dist/failure.d.ts.map +1 -1
  70. package/dist/failure.js +6 -0
  71. package/dist/figures.d.ts.map +1 -1
  72. package/dist/figures.js +4 -2
  73. package/dist/file.d.ts +1 -1
  74. package/dist/file.d.ts.map +1 -1
  75. package/dist/file.js +3 -2
  76. package/dist/host.d.ts +18 -2
  77. package/dist/host.d.ts.map +1 -1
  78. package/dist/host.js +59 -15
  79. package/dist/index.d.ts +16 -11
  80. package/dist/index.d.ts.map +1 -1
  81. package/dist/index.js +12 -7
  82. package/dist/install.d.ts +10 -6
  83. package/dist/install.d.ts.map +1 -1
  84. package/dist/install.js +92 -111
  85. package/dist/lifecycle.d.ts +1 -1
  86. package/dist/lifecycle.d.ts.map +1 -1
  87. package/dist/lifecycle.js +54 -40
  88. package/dist/listing.d.ts +11 -12
  89. package/dist/listing.d.ts.map +1 -1
  90. package/dist/listing.js +48 -72
  91. package/dist/live.d.ts +5 -3
  92. package/dist/live.d.ts.map +1 -1
  93. package/dist/live.js +74 -33
  94. package/dist/loaded.d.ts +5 -0
  95. package/dist/loaded.d.ts.map +1 -0
  96. package/dist/loaded.js +40 -0
  97. package/dist/locks.d.ts +2 -4
  98. package/dist/locks.d.ts.map +1 -1
  99. package/dist/locks.js +10 -39
  100. package/dist/lost.d.ts.map +1 -1
  101. package/dist/lost.js +11 -23
  102. package/dist/media.d.ts +6 -1
  103. package/dist/media.d.ts.map +1 -1
  104. package/dist/media.js +68 -17
  105. package/dist/memory.d.ts +8 -3
  106. package/dist/memory.d.ts.map +1 -1
  107. package/dist/memory.js +92 -33
  108. package/dist/messages.d.ts +12 -6
  109. package/dist/messages.d.ts.map +1 -1
  110. package/dist/messages.js +30 -38
  111. package/dist/model.d.ts +0 -1
  112. package/dist/model.d.ts.map +1 -1
  113. package/dist/model.js +0 -5
  114. package/dist/models.d.ts +4 -8
  115. package/dist/models.d.ts.map +1 -1
  116. package/dist/models.js +97 -139
  117. package/dist/observation.d.ts +27 -12
  118. package/dist/observation.d.ts.map +1 -1
  119. package/dist/observation.js +184 -85
  120. package/dist/opened.d.ts +1 -1
  121. package/dist/opened.d.ts.map +1 -1
  122. package/dist/opened.js +5 -5
  123. package/dist/opening.d.ts.map +1 -1
  124. package/dist/opening.js +5 -9
  125. package/dist/outcome.d.ts +13 -1
  126. package/dist/outcome.d.ts.map +1 -1
  127. package/dist/outcome.js +32 -2
  128. package/dist/overlay.d.ts +6 -2
  129. package/dist/overlay.d.ts.map +1 -1
  130. package/dist/overlay.js +37 -24
  131. package/dist/page-metadata.d.ts +8 -0
  132. package/dist/page-metadata.d.ts.map +1 -0
  133. package/dist/page-metadata.js +19 -0
  134. package/dist/parts.d.ts +3 -58
  135. package/dist/parts.d.ts.map +1 -1
  136. package/dist/parts.js +10 -115
  137. package/dist/preparation.d.ts +27 -6
  138. package/dist/preparation.d.ts.map +1 -1
  139. package/dist/preparation.js +156 -68
  140. package/dist/presence.d.ts +58 -0
  141. package/dist/presence.d.ts.map +1 -0
  142. package/dist/presence.js +231 -0
  143. package/dist/queries.d.ts +2 -2
  144. package/dist/queries.d.ts.map +1 -1
  145. package/dist/queries.js +67 -31
  146. package/dist/query.d.ts +0 -1
  147. package/dist/query.d.ts.map +1 -1
  148. package/dist/questions.d.ts +1 -5
  149. package/dist/questions.d.ts.map +1 -1
  150. package/dist/questions.js +1 -7
  151. package/dist/queue.d.ts +40 -0
  152. package/dist/queue.d.ts.map +1 -0
  153. package/dist/queue.js +480 -0
  154. package/dist/reach.d.ts +2 -3
  155. package/dist/reach.d.ts.map +1 -1
  156. package/dist/reach.js +88 -26
  157. package/dist/react.d.ts +8 -1
  158. package/dist/react.d.ts.map +1 -1
  159. package/dist/react.js +33 -1
  160. package/dist/readiness.d.ts +9 -3
  161. package/dist/readiness.d.ts.map +1 -1
  162. package/dist/readiness.js +3 -5
  163. package/dist/reads.d.ts +4 -2
  164. package/dist/reads.d.ts.map +1 -1
  165. package/dist/reads.js +11 -4
  166. package/dist/recovery.d.ts +3 -1
  167. package/dist/recovery.d.ts.map +1 -1
  168. package/dist/recovery.js +29 -7
  169. package/dist/refresh.js +2 -2
  170. package/dist/refusal.d.ts.map +1 -1
  171. package/dist/refusal.js +5 -6
  172. package/dist/replica.d.ts +5 -11
  173. package/dist/replica.d.ts.map +1 -1
  174. package/dist/replica.js +15 -17
  175. package/dist/retried.d.ts +30 -0
  176. package/dist/retried.d.ts.map +1 -0
  177. package/dist/retried.js +72 -0
  178. package/dist/room-draft.d.ts +31 -8
  179. package/dist/room-draft.d.ts.map +1 -1
  180. package/dist/room-draft.js +273 -66
  181. package/dist/room-drafts.d.ts.map +1 -1
  182. package/dist/room-drafts.js +22 -18
  183. package/dist/room-list.d.ts +10 -0
  184. package/dist/room-list.d.ts.map +1 -0
  185. package/dist/room-list.js +45 -0
  186. package/dist/rows.d.ts +2 -1
  187. package/dist/rows.d.ts.map +1 -1
  188. package/dist/rows.js +9 -10
  189. package/dist/runtime.d.ts +9 -18
  190. package/dist/runtime.d.ts.map +1 -1
  191. package/dist/save.d.ts +42 -90
  192. package/dist/save.d.ts.map +1 -1
  193. package/dist/save.js +327 -229
  194. package/dist/saves.d.ts +4 -40
  195. package/dist/saves.d.ts.map +1 -1
  196. package/dist/saves.js +143 -714
  197. package/dist/seed.d.ts.map +1 -1
  198. package/dist/seed.js +4 -5
  199. package/dist/shared.d.ts +0 -5
  200. package/dist/shared.d.ts.map +1 -1
  201. package/dist/shared.js +4 -90
  202. package/dist/shown.d.ts +7 -5
  203. package/dist/shown.d.ts.map +1 -1
  204. package/dist/shown.js +77 -63
  205. package/dist/socket/lanes.d.ts +12 -4
  206. package/dist/socket/lanes.d.ts.map +1 -1
  207. package/dist/socket/lanes.js +34 -8
  208. package/dist/socket/session.d.ts +0 -1
  209. package/dist/socket/session.d.ts.map +1 -1
  210. package/dist/socket.d.ts +3 -6
  211. package/dist/socket.d.ts.map +1 -1
  212. package/dist/socket.js +5 -16
  213. package/dist/source.d.ts +5 -7
  214. package/dist/source.d.ts.map +1 -1
  215. package/dist/source.js +18 -6
  216. package/dist/store/installs.d.ts +2 -2
  217. package/dist/store/installs.d.ts.map +1 -1
  218. package/dist/store/installs.js +10 -4
  219. package/dist/store/readiness.d.ts +5 -4
  220. package/dist/store/readiness.d.ts.map +1 -1
  221. package/dist/store/readiness.js +28 -12
  222. package/dist/store/records.d.ts +18 -7
  223. package/dist/store/records.d.ts.map +1 -1
  224. package/dist/store/records.js +58 -24
  225. package/dist/store/rooms-shown.d.ts +8 -0
  226. package/dist/store/rooms-shown.d.ts.map +1 -0
  227. package/dist/store/rooms-shown.js +13 -0
  228. package/dist/store/space.d.ts +1 -1
  229. package/dist/store/space.d.ts.map +1 -1
  230. package/dist/store/space.js +0 -2
  231. package/dist/store/watchers.js +1 -2
  232. package/dist/store.d.ts +23 -14
  233. package/dist/store.d.ts.map +1 -1
  234. package/dist/store.js +46 -17
  235. package/dist/stored.d.ts +25 -14
  236. package/dist/stored.d.ts.map +1 -1
  237. package/dist/stored.js +83 -32
  238. package/dist/surface.d.ts +5 -3
  239. package/dist/surface.d.ts.map +1 -1
  240. package/dist/surface.js +25 -23
  241. package/dist/sync.d.ts +1 -1
  242. package/dist/sync.d.ts.map +1 -1
  243. package/dist/sync.js +96 -92
  244. package/dist/tables.d.ts +16 -57
  245. package/dist/tables.d.ts.map +1 -1
  246. package/dist/tables.js +91 -332
  247. package/dist/tallies.d.ts.map +1 -1
  248. package/dist/tallies.js +6 -7
  249. package/dist/validation.d.ts.map +1 -1
  250. package/dist/validation.js +4 -10
  251. package/dist/wire.d.ts +53 -7
  252. package/dist/wire.d.ts.map +1 -1
  253. package/dist/wire.js +17 -4
  254. package/package.json +3 -2
  255. package/dist/attempt.d.ts +0 -16
  256. package/dist/attempt.d.ts.map +0 -1
  257. package/dist/attempt.js +0 -70
  258. package/dist/job.d.ts +0 -33
  259. package/dist/job.d.ts.map +0 -1
  260. package/dist/job.js +0 -54
  261. package/dist/log.d.ts +0 -6
  262. package/dist/log.d.ts.map +0 -1
  263. package/dist/log.js +0 -14
  264. package/dist/socket/rooms.d.ts +0 -44
  265. package/dist/socket/rooms.d.ts.map +0 -1
  266. package/dist/socket/rooms.js +0 -90
  267. package/dist/store/fences.d.ts +0 -16
  268. package/dist/store/fences.d.ts.map +0 -1
  269. package/dist/store/fences.js +0 -26
@@ -1,13 +1,15 @@
1
- import { apply, equalValue, frontmatterValue, parse, serialize, } from '@agentshouse/mdmodel';
1
+ import { apply, create, documentValue, equalValue, parse, serialize, } from '@agentshouse/mdmodel';
2
+ import { definitionsAt, governing } from './collection.js';
2
3
  import { runtimeError } from './failure.js';
3
4
  import { sha256 } from './digest.js';
5
+ import { declaredType } from './outcome.js';
4
6
  import { binaryLocalId } from './identity.js';
5
7
  import { normalize } from './paths.js';
6
- export function returnedBy(kind) {
7
- return { kind, code: kind, fields: {}, retryable: false };
8
+ export function returnedBy() {
9
+ return { kind: 'withdrawn', code: 'withdrawn', fields: {}, retryable: false };
8
10
  }
9
11
  export function staleWrite(current) {
10
- return { outcome: 'stale', code: 'stale', retryable: false, current };
12
+ return { outcome: 'stale', current };
11
13
  }
12
14
  function malformed(at, needs) {
13
15
  throw runtimeError('room-draft-malformed', at === undefined ? 'room-draft-malformed' : `room-draft-malformed at ${at}: ${needs}`);
@@ -32,14 +34,14 @@ function entries(value, at, each) {
32
34
  read[name] = each(item, `${at}.${name}`);
33
35
  return read;
34
36
  }
35
- function frontmatter(item, at) {
36
- return frontmatterValue(item) ? item : malformed(at, 'a frontmatter value');
37
+ function documentValueAt(item, at) {
38
+ return documentValue(item) ? item : malformed(at, 'a document value');
37
39
  }
38
40
  function fieldValue(value, at) {
39
41
  if (value === null)
40
42
  return null;
41
- if (!plain(value) || !Object.hasOwn(value, 'value') || !frontmatterValue(value.value)) {
42
- malformed(at, '{ value } with a frontmatter value, or null where the document lacks it');
43
+ if (!plain(value) || !Object.hasOwn(value, 'value') || !documentValue(value.value)) {
44
+ malformed(at, '{ value } with a document value, or null where the document lacks it');
43
45
  }
44
46
  return { value: value.value };
45
47
  }
@@ -58,7 +60,7 @@ function creationOf(value, at) {
58
60
  malformed(`${at}.type`, 'a type name, or markdown in place of type, fields and sections');
59
61
  return {
60
62
  type: value.type,
61
- fields: entries(value.fields, `${at}.fields`, frontmatter),
63
+ fields: entries(value.fields, `${at}.fields`, documentValueAt),
62
64
  sections: entries(value.sections, `${at}.sections`, text),
63
65
  };
64
66
  }
@@ -72,7 +74,7 @@ const PART_NAMES = [
72
74
  'removal',
73
75
  'file',
74
76
  ];
75
- const NAMED_PARTS = `a part named ${PART_NAMES.slice(0, -1).join(', ')} or ${PART_NAMES.at(-1)}`;
77
+ const NAMED_PARTS = `a part named ${PART_NAMES.slice(0, -1).join(', ')} or ${PART_NAMES.slice(-1).join('')}`;
76
78
  export function readParts(value, path) {
77
79
  if (!plain(value))
78
80
  malformed(path, 'an object of parts');
@@ -82,8 +84,8 @@ export function readParts(value, path) {
82
84
  const parts = {};
83
85
  if (value.fields !== undefined) {
84
86
  parts.fields = entries(value.fields, `${path} fields`, (item, at) => {
85
- if (!plain(item) || !Object.hasOwn(item, 'value') || !frontmatterValue(item.value)) {
86
- malformed(at, '{ value, base } with a frontmatter value');
87
+ if (!plain(item) || !Object.hasOwn(item, 'value') || !documentValue(item.value)) {
88
+ malformed(at, '{ value, base } with a document value');
87
89
  }
88
90
  return item.base === undefined
89
91
  ? { value: item.value }
@@ -255,8 +257,10 @@ export function underneath(parts, path, visible) {
255
257
  const markdown = visible?.documents[path] ?? null;
256
258
  const document = visible?.collection.document(path);
257
259
  const report = {};
260
+ const unread = document?.type !== undefined &&
261
+ governing(visible.collection.composition, path).status === 'unavailable';
258
262
  const fields = {};
259
- for (const [name, part] of named(parts.fields)) {
263
+ for (const [name, part] of unread ? [] : named(parts.fields)) {
260
264
  const current = document !== undefined && Object.hasOwn(document.fields, name)
261
265
  ? { value: document.fields[name] }
262
266
  : null;
@@ -266,7 +270,7 @@ export function underneath(parts, path, visible) {
266
270
  if (Object.keys(fields).length > 0)
267
271
  report.fields = fields;
268
272
  const sections = {};
269
- for (const [name, part] of named(parts.sections)) {
273
+ for (const [name, part] of unread ? [] : named(parts.sections)) {
270
274
  const current = document !== undefined && Object.hasOwn(document.sections, name)
271
275
  ? document.sections[name]
272
276
  : null;
@@ -276,8 +280,9 @@ export function underneath(parts, path, visible) {
276
280
  if (Object.keys(sections).length > 0)
277
281
  report.sections = sections;
278
282
  const preamble = document?.preamble ?? null;
279
- if (parts.preamble !== undefined && preamble !== parts.preamble.base)
283
+ if (!unread && parts.preamble !== undefined && preamble !== parts.preamble.base) {
280
284
  report.preamble = preamble;
285
+ }
281
286
  if (parts.markdown !== undefined && markdown !== parts.markdown.base)
282
287
  report.markdown = markdown;
283
288
  if (parts.creation !== undefined && markdown !== null)
@@ -293,13 +298,12 @@ export function underneath(parts, path, visible) {
293
298
  }
294
299
  return report;
295
300
  }
296
- const UNTYPED_MEDIA_TYPE = 'application/octet-stream';
297
301
  export async function heldFile(blob, base) {
298
302
  return {
299
303
  localId: binaryLocalId(),
300
304
  ...(blob instanceof File ? { name: blob.name } : {}),
301
305
  byteLength: blob.size,
302
- mediaType: blob.type === '' ? UNTYPED_MEDIA_TYPE : blob.type,
306
+ mediaType: declaredType(blob),
303
307
  sha256: await sha256(blob),
304
308
  base,
305
309
  };
@@ -323,6 +327,224 @@ export function changedParts(path, parts, visible) {
323
327
  ...(report.file === undefined || made ? [] : [{ path, part: 'file' }]),
324
328
  ];
325
329
  }
330
+ function marksOf(fields, sections, rest) {
331
+ return {
332
+ ...(Object.keys(fields).length === 0 ? {} : { fields }),
333
+ ...(Object.keys(sections).length === 0 ? {} : { sections }),
334
+ ...(rest.preamble === undefined ? {} : { preamble: rest.preamble }),
335
+ ...(rest.markdown === undefined ? {} : { markdown: rest.markdown }),
336
+ ...(rest.file === undefined ? {} : { file: rest.file }),
337
+ };
338
+ }
339
+ export function marksOver(kept, under) {
340
+ return marksOf({ ...under.fields, ...kept.fields }, { ...under.sections, ...kept.sections }, {
341
+ preamble: kept.preamble ?? under.preamble,
342
+ markdown: kept.markdown ?? under.markdown,
343
+ file: kept.file ?? under.file,
344
+ });
345
+ }
346
+ export function heldMarks(marks, parts) {
347
+ const whole = parts.markdown !== undefined;
348
+ const heldIn = (record, part) => Object.fromEntries(named(record).filter(([name]) => whole || own(part, name) !== undefined));
349
+ return marksOf(heldIn(marks.fields, parts.fields), heldIn(marks.sections, parts.sections), {
350
+ preamble: whole || parts.preamble !== undefined ? marks.preamble : undefined,
351
+ markdown: whole ? marks.markdown : undefined,
352
+ file: parts.file === undefined ? undefined : marks.file,
353
+ });
354
+ }
355
+ function followedBy(first, then) {
356
+ const kept = first.replace(/(?:\r?\n)+$/u, '');
357
+ return kept.trim() === '' ? then : `${kept}\n\n${then.replace(/^(?:\r?\n)+/u, '')}`;
358
+ }
359
+ function bothSides(current, value) {
360
+ return lineEnded(current) === lineEnded(value) ? value : followedBy(current, value);
361
+ }
362
+ export function partsBetween(path, before, after) {
363
+ const changes = [];
364
+ for (const name of new Set([...Object.keys(before.fields), ...Object.keys(after.fields)])) {
365
+ const value = own(after.fields, name);
366
+ if (!equalValue(own(before.fields, name), value)) {
367
+ changes.push({ kind: 'field', path, name, value });
368
+ }
369
+ }
370
+ if (after.preamble !== before.preamble) {
371
+ changes.push({ kind: 'preamble', path, value: after.preamble });
372
+ }
373
+ for (const [name, value] of Object.entries(after.sections)) {
374
+ if (own(before.sections, name) !== value)
375
+ changes.push({ kind: 'section', path, name, value });
376
+ }
377
+ return changes;
378
+ }
379
+ export function applyParts(document, changes, definition) {
380
+ const parts = new Map();
381
+ for (const change of changes) {
382
+ if (change.kind === 'field')
383
+ parts.set(`field ${change.name}`, {
384
+ kind: 'field',
385
+ name: change.name,
386
+ value: change.value,
387
+ prior: own(document.fields, change.name),
388
+ });
389
+ if (change.kind === 'preamble')
390
+ parts.set('preamble', { kind: 'preamble', value: change.value, prior: document.preamble });
391
+ if (change.kind === 'section')
392
+ parts.set(`section ${change.name}`, {
393
+ kind: 'section',
394
+ name: change.name,
395
+ value: change.value,
396
+ prior: own(document.sections, change.name),
397
+ });
398
+ }
399
+ if (parts.size === 0)
400
+ return { outcome: 'applied', document };
401
+ return apply(document, [...parts.values()], definition);
402
+ }
403
+ function wholeJoined(part, current, path, composition, change) {
404
+ const definitions = definitionsAt(composition, path);
405
+ const read = (text) => {
406
+ const parsed = parse(text, path, definitions);
407
+ return parsed.ok ? parsed.document : undefined;
408
+ };
409
+ const base = read(part.base);
410
+ const mine = read(part.value);
411
+ const now = read(current);
412
+ if (base === undefined ||
413
+ mine === undefined ||
414
+ now === undefined ||
415
+ mine.type !== base.type ||
416
+ now.type !== base.type ||
417
+ Object.keys(base.sections).some((name) => !Object.hasOwn(mine.sections, name))) {
418
+ return null;
419
+ }
420
+ const definition = definitions(base.type);
421
+ const changes = partsBetween(path, base, mine);
422
+ const again = applyParts(base, changes, definition);
423
+ if (again.outcome !== 'applied' || serialize(again.document) !== part.value)
424
+ return null;
425
+ const fields = {};
426
+ const sections = {};
427
+ let preamble;
428
+ const over = [];
429
+ for (const one of changes) {
430
+ if (one.kind === 'field') {
431
+ const held = own(now.fields, one.name);
432
+ if (!equalValue(held, own(base.fields, one.name)) && !equalValue(held, one.value)) {
433
+ fields[one.name] = { current: held === undefined ? null : { value: held }, change };
434
+ }
435
+ over.push(one);
436
+ continue;
437
+ }
438
+ if (one.kind === 'preamble') {
439
+ const value = now.preamble === base.preamble ? one.value : bothSides(now.preamble, one.value);
440
+ if (value !== one.value)
441
+ preamble = { change };
442
+ over.push({ ...one, value });
443
+ continue;
444
+ }
445
+ const prior = own(base.sections, one.name);
446
+ const held = own(now.sections, one.name);
447
+ if (held === undefined && prior !== undefined)
448
+ return null;
449
+ const value = held === undefined || held === prior ? one.value : bothSides(held, one.value);
450
+ if (value !== one.value)
451
+ sections[one.name] = { change };
452
+ over.push({ ...one, value });
453
+ }
454
+ const joined = applyParts(now, over, definition);
455
+ if (joined.outcome !== 'applied')
456
+ return null;
457
+ return {
458
+ value: serialize(joined.document),
459
+ marks: marksOf(fields, sections, { preamble }),
460
+ };
461
+ }
462
+ export function joinedOver(parts, marks, path, visible) {
463
+ const report = underneath(parts, path, visible);
464
+ const change = visible.changes[path] ?? null;
465
+ const next = { ...parts };
466
+ const fields = {};
467
+ const sections = {};
468
+ const rest = {};
469
+ let rebased = false;
470
+ const text = (value, current, mark) => {
471
+ const joined = bothSides(current, value);
472
+ if (joined !== value)
473
+ mark();
474
+ return { value: joined, base: current };
475
+ };
476
+ const now = visible.collection.document(path);
477
+ if (now !== undefined) {
478
+ for (const [name, current] of named(report.fields)) {
479
+ const { value } = parts.fields[name];
480
+ next.fields = { ...next.fields, [name]: { value, base: current } };
481
+ if (!sameField(current, { value }))
482
+ fields[name] = { current, change };
483
+ rebased = true;
484
+ }
485
+ const removed = [];
486
+ for (const [name, current] of named(report.sections)) {
487
+ if (current === null) {
488
+ removed.push(name);
489
+ continue;
490
+ }
491
+ const joined = text(parts.sections[name].value, current, () => {
492
+ sections[name] = { change };
493
+ });
494
+ next.sections = { ...next.sections, [name]: joined };
495
+ rebased = true;
496
+ }
497
+ if (typeof report.preamble === 'string') {
498
+ next.preamble = text(parts.preamble.value, report.preamble, () => {
499
+ rest.preamble = { change };
500
+ });
501
+ rebased = true;
502
+ }
503
+ const whole = removed.length === 0
504
+ ? null
505
+ : applyParts(now, changesOf(path, next).changes, definitionsAt(visible.collection.composition, path)(now.type));
506
+ if (whole?.outcome === 'applied') {
507
+ delete next.fields;
508
+ delete next.sections;
509
+ delete next.preamble;
510
+ next.markdown = { value: serialize(whole.document), base: visible.documents[path] };
511
+ for (const name of removed)
512
+ sections[name] = { change };
513
+ rebased = true;
514
+ }
515
+ }
516
+ if (typeof report.markdown === 'string' && parts.markdown !== undefined) {
517
+ const current = report.markdown;
518
+ const whole = wholeJoined(parts.markdown, current, path, visible.collection.composition, change);
519
+ const value = whole?.value ?? bothSides(current, parts.markdown.value);
520
+ next.markdown = { value, base: current };
521
+ if (whole !== null) {
522
+ Object.assign(fields, whole.marks.fields);
523
+ Object.assign(sections, whole.marks.sections);
524
+ if (whole.marks.preamble !== undefined)
525
+ rest.preamble = whole.marks.preamble;
526
+ }
527
+ else if (value !== parts.markdown.value)
528
+ rest.markdown = { change };
529
+ rebased = true;
530
+ }
531
+ if (typeof report.move === 'string' && parts.move !== undefined) {
532
+ next.move = { ...parts.move, base: report.move };
533
+ rebased = true;
534
+ }
535
+ if (typeof report.removal === 'string' && parts.removal !== undefined) {
536
+ next.removal = { base: report.removal };
537
+ rebased = true;
538
+ }
539
+ if (typeof report.file === 'string' && parts.file !== undefined && parts.file.base !== null) {
540
+ next.file = { ...parts.file, base: report.file };
541
+ if (visible.binaries[path]?.sha256 !== parts.file.sha256) {
542
+ rest.file = { current: report.file, change };
543
+ }
544
+ rebased = true;
545
+ }
546
+ return rebased ? { parts: next, marks: marksOver(marksOf(fields, sections, rest), marks) } : null;
547
+ }
326
548
  function joined(existing, returned) {
327
549
  const merged = { ...existing };
328
550
  for (const [name, part] of named(returned))
@@ -333,30 +555,42 @@ function joined(existing, returned) {
333
555
  export function lineEnded(text) {
334
556
  return text === '' || text.endsWith('\n') ? text : `${text}\n`;
335
557
  }
336
- function frontmatterOf(fields) {
337
- const opened = parse('---\n---\n');
338
- if (!opened.ok)
339
- return malformed();
340
- const next = apply(opened.document, fields.map(([name, part]) => ({
341
- kind: 'field',
342
- name,
343
- value: part.value,
344
- prior: undefined,
345
- })));
346
- return next.outcome === 'applied' ? serialize(next.document) : malformed();
558
+ function written(start, changes, definition) {
559
+ const next = apply(start, changes, definition);
560
+ return next.outcome === 'applied' ? next.document : malformed();
561
+ }
562
+ function empty(definition) {
563
+ const parsed = parse('', '', definition);
564
+ return parsed.ok ? parsed.document : malformed();
347
565
  }
348
- export function partsAfter(markdown, parts) {
566
+ export function partsAfter(markdown, parts, definitions) {
349
567
  const fields = named(parts.fields);
568
+ const sections = named(parts.sections);
569
+ if (fields.length === 0 && sections.length === 0 && parts.preamble === undefined)
570
+ return markdown;
571
+ const whole = parse(markdown, '', definitions);
572
+ const type = whole.ok ? whole.document.type : undefined;
573
+ const definition = definitions?.(type);
574
+ if (type !== undefined && definition === undefined)
575
+ return null;
576
+ const valued = fields.length === 0
577
+ ? empty(definition)
578
+ : written(create(type, definition), fields.map(([name, part]) => ({
579
+ kind: 'field',
580
+ name,
581
+ value: part.value,
582
+ prior: undefined,
583
+ })), definition);
584
+ const head = parts.preamble === undefined
585
+ ? valued
586
+ : written(valued, [{ kind: 'preamble', value: lineEnded(parts.preamble.value), prior: valued.preamble }], definition);
350
587
  const pieces = [
351
- ...(fields.length === 0 ? [] : [frontmatterOf(fields)]),
352
- ...(parts.preamble === undefined ? [] : [parts.preamble.value]),
353
- ...named(parts.sections).map(([name, part]) => `## ${name}\n${part.value}`),
588
+ ...(fields.length === 0 && parts.preamble === undefined ? [] : [serialize(head)]),
589
+ ...sections.map(([name, part]) => serialize(written(empty(definition), [{ kind: 'section', name, value: lineEnded(part.value), prior: undefined }], definition))),
354
590
  ];
355
- if (pieces.length === 0)
356
- return markdown;
357
- return `${lineEnded(markdown)}\n${pieces.map(lineEnded).join('')}`;
591
+ return followedBy(markdown, pieces.join(''));
358
592
  }
359
- export function returnedInto(existing, returned) {
593
+ export function returnedInto(existing, returned, definitions) {
360
594
  if (existing === undefined)
361
595
  return returned;
362
596
  const next = { ...existing };
@@ -376,7 +610,9 @@ export function returnedInto(existing, returned) {
376
610
  delete next.fields;
377
611
  delete next.sections;
378
612
  delete next.preamble;
379
- const value = partsAfter(whole.value, existing.markdown === undefined ? existing : returned);
613
+ const value = partsAfter(whole.value, existing.markdown === undefined ? existing : returned, definitions);
614
+ if (value === null)
615
+ return null;
380
616
  next.markdown = { value, base: whole.base };
381
617
  }
382
618
  const creation = existing.creation ?? returned.creation;
@@ -474,35 +710,6 @@ export function changesOf(path, parts) {
474
710
  changes.push({ kind: 'remove', path });
475
711
  return { changes, bases };
476
712
  }
477
- function rebased(before, after) {
478
- return before === undefined ? after : { ...after, base: before.base };
479
- }
480
- function rebasedAll(before, after) {
481
- return {
482
- ...before,
483
- ...Object.fromEntries(Object.entries(after).map(([name, part]) => [name, rebased(before?.[name], part)])),
484
- };
485
- }
486
- export function joinedDraft(carried, saved) {
487
- const draft = saved.find((item) => item.path === carried.path);
488
- if (draft === undefined)
489
- return carried;
490
- const held = carried.parts;
491
- const next = draft.parts;
492
- return {
493
- path: carried.path,
494
- parts: {
495
- ...held,
496
- ...next,
497
- ...(next.fields === undefined ? {} : { fields: rebasedAll(held.fields, next.fields) }),
498
- ...(next.sections === undefined
499
- ? {}
500
- : { sections: rebasedAll(held.sections, next.sections) }),
501
- ...(next.preamble === undefined ? {} : { preamble: rebased(held.preamble, next.preamble) }),
502
- ...(next.markdown === undefined ? {} : { markdown: rebased(held.markdown, next.markdown) }),
503
- },
504
- };
505
- }
506
713
  export function withdrawnDrafts(drafts, changes) {
507
714
  return drafts.flatMap((draft) => {
508
715
  const file = draft.parts.file;
@@ -1 +1 @@
1
- {"version":3,"file":"room-drafts.d.ts","sourceRoot":"","sources":["../src/room-drafts.ts"],"names":[],"mappings":"AACA,OAAO,EAAa,KAAK,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAK5D,OAAO,EAAW,KAAK,YAAY,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,EAQL,KAAK,SAAS,EAEd,KAAK,cAAc,EACpB,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAGxC,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,IAAI,OAAO,CAAC,SAAS,SAAS,EAAE,CAAC,CAAC;IACtC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC;IAC5D,KAAK,CACH,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,GAAG,IAAI,EACvB,KAAK,EAAE,OAAO,EACd,IAAI,CAAC,EAAE,MAAM,GACZ,OAAO,CAAC,cAAc,CAAC,CAAC;IAC3B,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;CAChF,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACpC,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClD,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9E,CAAC;AAMF,wBAAsB,SAAS,CAC7B,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,SAAS,MAAM,EAAE,GACvB,OAAO,CAAC,YAAY,GAAG,SAAS,CAAC,CAMnC;AA0CD,wBAAgB,iBAAiB,CAC/B,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,OAAO,EAC1B,WAAW,EAAE,OAAO,EACpB,OAAO,GAAE,SAAS,CAAC,WAAW,CAAC,GAAG,IAAW,GAC5C,OAAO,CAAC,IAAI,CAAC,CAuBf;AAOD,wBAAgB,gBAAgB,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAUvF;AA4DD,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,gBAAgB,CAkDnE;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,mBAAmB,CA0BzE;AAED,wBAAgB,eAAe,CAC7B,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,OAAO,EAC1B,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,GAChC,MAAM,IAAI,CAiBZ;AAED,wBAAgB,iBAAiB,CAC/B,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,OAAO,EAC1B,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,GAChC,MAAM,IAAI,CASZ"}
1
+ {"version":3,"file":"room-drafts.d.ts","sourceRoot":"","sources":["../src/room-drafts.ts"],"names":[],"mappings":"AACA,OAAO,EAAa,KAAK,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAK5D,OAAO,EAAW,KAAK,YAAY,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,EASL,KAAK,SAAS,EAEd,KAAK,cAAc,EACpB,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAGxC,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,IAAI,OAAO,CAAC,SAAS,SAAS,EAAE,CAAC,CAAC;IACtC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC;IAC5D,KAAK,CACH,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,GAAG,IAAI,EACvB,KAAK,EAAE,OAAO,EACd,IAAI,CAAC,EAAE,MAAM,GACZ,OAAO,CAAC,cAAc,CAAC,CAAC;IAC3B,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;CAChF,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACpC,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClD,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9E,CAAC;AAMF,wBAAsB,SAAS,CAC7B,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,SAAS,MAAM,EAAE,GACvB,OAAO,CAAC,YAAY,GAAG,SAAS,CAAC,CAMnC;AA2CD,wBAAgB,iBAAiB,CAC/B,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,OAAO,EAC1B,WAAW,EAAE,OAAO,EACpB,OAAO,GAAE,SAAS,CAAC,WAAW,CAAC,GAAG,IAAW,GAC5C,OAAO,CAAC,IAAI,CAAC,CAuBf;AAOD,wBAAgB,gBAAgB,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAUvF;AAsDD,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,gBAAgB,CAkDnE;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,mBAAmB,CA8BzE;AAED,wBAAgB,eAAe,CAC7B,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,OAAO,EAC1B,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,GAChC,MAAM,IAAI,CAiBZ;AAED,wBAAgB,iBAAiB,CAC/B,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,OAAO,EAC1B,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,GAChC,MAAM,IAAI,CASZ"}
@@ -1,11 +1,11 @@
1
1
  import { plain } from '@agentshouse/mdmodel';
2
2
  import { changeSet } from './change-set.js';
3
3
  import { collectionOf } from './collection.js';
4
- import { runtimeError } from './failure.js';
4
+ import { runtimeError, uncaught } from './failure.js';
5
5
  import { roomDraftRevision } from './identity.js';
6
6
  import { normalize } from './paths.js';
7
7
  import { slicing } from './replica.js';
8
- import { binaryBase, gatheredParts, held, heldFile, readParts, staleWrite, underneath, } from './room-draft.js';
8
+ import { binaryBase, gatheredParts, held, heldFile, heldMarks, readParts, staleWrite, underneath, } from './room-draft.js';
9
9
  import { stepped } from './turn.js';
10
10
  const ROOM_DRAFTS = 'room-drafts';
11
11
  const presentationTopic = (app) => `presentation\u0000${app}`;
@@ -24,6 +24,7 @@ function roomDraftOf(record, visible) {
24
24
  revision: record.revision,
25
25
  parts: record.parts,
26
26
  changedUnderneath: underneath(record.parts, record.path, visible),
27
+ marks: record.marks,
27
28
  returned: record.returned,
28
29
  });
29
30
  }
@@ -100,30 +101,30 @@ async function writtenRoomDraft({ store }, room, path, revision, input, next) {
100
101
  const local = await store.open();
101
102
  const current = await store.draft(room, path);
102
103
  if ((current?.revision ?? null) !== revision) {
103
- return staleWrite(current === undefined ? null : ((await roomDraftsOf(store, [current]))[0] ?? null));
104
+ return staleWrite(current === undefined ? null : (await roomDraftsOf(store, [current]))[0]);
104
105
  }
105
106
  const file = parts.file === undefined
106
107
  ? undefined
107
108
  : await heldFile(parts.file.blob, parts.file.base === undefined
108
109
  ? binaryBase(await visibleOf(store, room, [path]), path)
109
110
  : parts.file.base);
111
+ const kept = held(current?.parts, parts, file);
110
112
  const record = {
111
113
  locator: room,
112
114
  path,
113
115
  revision: next,
114
- parts: held(current?.parts, parts, file),
116
+ parts: kept,
117
+ marks: heldMarks(current?.marks ?? {}, kept),
115
118
  returned: current?.returned ?? null,
116
119
  };
117
120
  await local.keepRoomDraft(record, parts.file === undefined || file === undefined
118
121
  ? []
119
122
  : [{ key: file.localId, blob: parts.file.blob }]);
120
123
  await store.changed(changeSet(room, { drafts: [path] }));
121
- return { outcome: 'written', roomDraft: (await roomDraftsOf(store, [record]))[0] ?? null };
124
+ return { outcome: 'written', roomDraft: (await roomDraftsOf(store, [record]))[0] };
122
125
  }
123
- async function keptPresentation({ store }, app, next) {
124
- const local = await store.open();
125
- const stored = next(await local.presentation(app));
126
- await local.present({ app, value: stored });
126
+ async function keptPresentation({ store }, app, value) {
127
+ await (await store.open()).present({ app, value });
127
128
  await store.changed(changeSet('', { presentation: app }));
128
129
  }
129
130
  export function roomDraftSurface(runtime) {
@@ -142,7 +143,7 @@ export function roomDraftSurface(runtime) {
142
143
  },
143
144
  async read(room, path) {
144
145
  const record = await store.draft(room, path);
145
- return record === undefined ? null : ((await roomDraftsOf(store, [record]))[0] ?? null);
146
+ return record === undefined ? null : (await roomDraftsOf(store, [record]))[0];
146
147
  },
147
148
  write(room, path, revision, input, next = roomDraftRevision()) {
148
149
  if (typeof next !== 'string' || next === '')
@@ -161,7 +162,7 @@ export function roomDraftSurface(runtime) {
161
162
  const local = await store.open();
162
163
  const current = await store.draft(room, path);
163
164
  if (current === undefined || current.revision !== revision) {
164
- return staleWrite(current === undefined ? null : ((await roomDraftsOf(store, [current]))[0] ?? null));
165
+ return staleWrite(current === undefined ? null : (await roomDraftsOf(store, [current]))[0]);
165
166
  }
166
167
  await local.discardRoomDraft(room, path);
167
168
  await store.changed(changeSet(room, { drafts: [path] }));
@@ -177,13 +178,16 @@ export function presentationSurface(runtime) {
177
178
  return store.exclusive(() => presentationOf(store, app));
178
179
  },
179
180
  write(app, value) {
180
- return store.exclusive(() => keptPresentation(runtime, app, () => structuredClone(value)));
181
+ return store.exclusive(() => keptPresentation(runtime, app, structuredClone(value)));
181
182
  },
182
183
  edit(app, members) {
183
- return store.gathered(`presentation\u0000${app}`, structuredClone(members), (earlier, later) => ({ ...earlier, ...later }), (edited) => keptPresentation(runtime, app, (kept) => Object.fromEntries([
184
- ...Object.entries(plain(kept) ? kept : {}).filter(([member]) => !Object.hasOwn(edited, member)),
185
- ...Object.entries(edited).filter(([, value]) => value !== null),
186
- ])));
184
+ return store.gathered(`presentation\u0000${app}`, structuredClone(members), (earlier, later) => ({ ...earlier, ...later }), async (edited) => {
185
+ const kept = await (await store.open()).presentation(app);
186
+ await keptPresentation(runtime, app, Object.fromEntries([
187
+ ...Object.entries(plain(kept) ? kept : {}).filter(([member]) => !Object.hasOwn(edited, member)),
188
+ ...Object.entries(edited).filter(([, value]) => value !== null),
189
+ ]));
190
+ });
187
191
  },
188
192
  };
189
193
  }
@@ -200,7 +204,7 @@ export function watchRoomDrafts({ store, socket }, deliver) {
200
204
  const value = await snapshotRoomDrafts(store);
201
205
  if (!unwatched())
202
206
  watcher.answer(value);
203
- }), () => { });
207
+ }), uncaught);
204
208
  return watcher.stop;
205
209
  }
206
210
  export function watchPresentation({ store, socket }, app, deliver) {
@@ -211,6 +215,6 @@ export function watchPresentation({ store, socket }, app, deliver) {
211
215
  if (!socket.closed() && watcher.held())
212
216
  watcher.answer(value);
213
217
  })
214
- .catch(() => { });
218
+ .catch(uncaught);
215
219
  return watcher.stop;
216
220
  }
@@ -0,0 +1,10 @@
1
+ import type { AuthorityChange, RoomList } from './adapter.js';
2
+ import type { Runtime } from './runtime.js';
3
+ import type { Deliver } from './reach.js';
4
+ export declare const ROOM_LIST_TOPIC = "room-list";
5
+ type RoomListChange = NonNullable<AuthorityChange['roomList']>;
6
+ export declare function roomsListed(runtime: Runtime, list: RoomList | undefined): Promise<void>;
7
+ export declare function roomListChanged(runtime: Runtime, change: RoomListChange | undefined): Promise<void>;
8
+ export declare function watchRoomList(runtime: Runtime, deliver: Deliver): () => void;
9
+ export {};
10
+ //# sourceMappingURL=room-list.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"room-list.d.ts","sourceRoot":"","sources":["../src/room-list.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAE9D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C,eAAO,MAAM,eAAe,cAAc,CAAC;AAE3C,KAAK,cAAc,GAAG,WAAW,CAAC,eAAe,CAAC,UAAU,CAAC,CAAC,CAAC;AA0B/D,wBAAgB,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,GAAG,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAGvF;AAED,wBAAgB,eAAe,CAC7B,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,cAAc,GAAG,SAAS,GACjC,OAAO,CAAC,IAAI,CAAC,CAGf;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,GAAG,MAAM,IAAI,CAU5E"}
@@ -0,0 +1,45 @@
1
+ import { uncaught } from './failure.js';
2
+ export const ROOM_LIST_TOPIC = 'room-list';
3
+ async function kept(runtime, next) {
4
+ const local = await runtime.store.open();
5
+ const { roomList } = await local.facts(['roomList']);
6
+ const listed = next(roomList);
7
+ if (listed === null || JSON.stringify(listed) === JSON.stringify(roomList))
8
+ return;
9
+ await local.fact('roomList', listed);
10
+ runtime.store.tell(ROOM_LIST_TOPIC, listed);
11
+ }
12
+ function changed(held, change) {
13
+ const named = new Map(change.rooms.map((room) => [room.room_ref, room]));
14
+ const left = new Set(change.left);
15
+ const known = new Set(held.rooms.map((room) => room.room_ref));
16
+ return {
17
+ rooms: [
18
+ ...held.rooms.flatMap((room) => left.has(room.room_ref) ? [] : [named.get(room.room_ref) ?? room]),
19
+ ...change.rooms.filter((room) => !known.has(room.room_ref)),
20
+ ],
21
+ spaces: change.spaces,
22
+ };
23
+ }
24
+ export function roomsListed(runtime, list) {
25
+ if (list === undefined)
26
+ return Promise.resolve();
27
+ return kept(runtime, () => list).catch(uncaught);
28
+ }
29
+ export function roomListChanged(runtime, change) {
30
+ if (change === undefined)
31
+ return Promise.resolve();
32
+ return kept(runtime, (held) => (held === null ? null : changed(held, change))).catch(uncaught);
33
+ }
34
+ export function watchRoomList(runtime, deliver) {
35
+ const { store } = runtime;
36
+ const watcher = store.watch(ROOM_LIST_TOPIC, deliver);
37
+ void store
38
+ .open()
39
+ .then((local) => local.facts(['roomList']))
40
+ .then(({ roomList }) => {
41
+ if (watcher.held())
42
+ deliver(roomList);
43
+ }, uncaught);
44
+ return watcher.stop;
45
+ }
package/dist/rows.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { type HeldValue } from '@agentshouse/mdmodel';
2
2
  import type { SavedFacts } from './adapter.js';
3
3
  import { type Composition } from './collection.js';
4
+ import type { PlanReach } from './query.js';
4
5
  type LinkKind = 'field' | 'link';
5
6
  type HeldLink = {
6
7
  readonly kind: LinkKind;
@@ -12,7 +13,6 @@ type HeldLink = {
12
13
  export type Described = {
13
14
  readonly type: string | null;
14
15
  readonly declared: string | null;
15
- readonly queried: boolean;
16
16
  readonly folder: string;
17
17
  readonly fields: string | null;
18
18
  readonly links: string | null;
@@ -28,6 +28,7 @@ export type Derived = {
28
28
  };
29
29
  export declare function documentKey(room: string, path: string): string;
30
30
  export declare function roomOfKey(key: string): string;
31
+ export declare function roomsOfReach(reach: PlanReach): ReadonlySet<string>;
31
32
  export declare function pathOfKey(key: string): string;
32
33
  export declare function markdownPath(path: string): boolean;
33
34
  export declare function folderOf(path: string): string;
@@ -1 +1 @@
1
- {"version":3,"file":"rows.d.ts","sourceRoot":"","sources":["../src/rows.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8C,KAAK,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAClG,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAa,KAAK,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAG9D,KAAK,QAAQ,GAAG,OAAO,GAAG,MAAM,CAAC;AAEjC,KAAK,QAAQ,GAAG;IACd,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B,CAAC;AAEF,MAAM,MAAM,IAAI,GAAG;IACjB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC;IAC1D,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;CACnC,CAAC;AAEF,MAAM,MAAM,OAAO,GAAG;IACpB,QAAQ,CAAC,MAAM,EAAE,SAAS,SAAS,EAAE,CAAC;IACtC,QAAQ,CAAC,KAAK,EAAE,SAAS,QAAQ,EAAE,CAAC;CACrC,CAAC;AAMF,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAE9D;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE7C;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE7C;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAElD;AAED,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE7C;AAaD,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,WAAW,GACvB,UAAU,GAAG,IAAI,CAQnB;AAED,wBAAgB,SAAS,CACvB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,GAAG,IAAI,EACtB,KAAK,EAAE,UAAU,GAAG,IAAI,GACvB,SAAS,CAeX;AAED,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,EAAE,KAAK,EAAE,UAAU,GAAG,IAAI,GAAG,IAAI,CAK3F;AAED,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,WAAW,GAAG,OAAO,CAYnF"}
1
+ {"version":3,"file":"rows.d.ts","sourceRoot":"","sources":["../src/rows.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8C,KAAK,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAClG,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAA4B,KAAK,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC7E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C,KAAK,QAAQ,GAAG,OAAO,GAAG,MAAM,CAAC;AAEjC,KAAK,QAAQ,GAAG;IACd,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B,CAAC;AAEF,MAAM,MAAM,IAAI,GAAG;IACjB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC;IAC1D,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;CACnC,CAAC;AAEF,MAAM,MAAM,OAAO,GAAG;IACpB,QAAQ,CAAC,MAAM,EAAE,SAAS,SAAS,EAAE,CAAC;IACtC,QAAQ,CAAC,KAAK,EAAE,SAAS,QAAQ,EAAE,CAAC;CACrC,CAAC;AAMF,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAE9D;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE7C;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,SAAS,GAAG,WAAW,CAAC,MAAM,CAAC,CAElE;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE7C;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAElD;AAED,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE7C;AAaD,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,WAAW,GACvB,UAAU,GAAG,IAAI,CAQnB;AAED,wBAAgB,SAAS,CACvB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,GAAG,IAAI,EACtB,KAAK,EAAE,UAAU,GAAG,IAAI,GACvB,SAAS,CAaX;AAED,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,EAAE,KAAK,EAAE,UAAU,GAAG,IAAI,GAAG,IAAI,CAK3F;AAED,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,WAAW,GAAG,OAAO,CAYnF"}