@agentshouse/mdruntime 0.1.0-cff8ba8fa2542 → 0.1.0-cffcba9cd9c2f

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 (327) hide show
  1. package/README.md +24 -11
  2. package/dist/acceptance.d.ts +3 -0
  3. package/dist/acceptance.d.ts.map +1 -0
  4. package/dist/acceptance.js +309 -0
  5. package/dist/actions.d.ts +20 -0
  6. package/dist/actions.d.ts.map +1 -0
  7. package/dist/actions.js +251 -0
  8. package/dist/adapter.d.ts +195 -88
  9. package/dist/adapter.d.ts.map +1 -1
  10. package/dist/attached-model.d.ts +7 -10
  11. package/dist/attached-model.d.ts.map +1 -1
  12. package/dist/attached-model.js +40 -28
  13. package/dist/attempt.d.ts +16 -0
  14. package/dist/attempt.d.ts.map +1 -0
  15. package/dist/attempt.js +70 -0
  16. package/dist/binary.d.ts +18 -0
  17. package/dist/binary.d.ts.map +1 -0
  18. package/dist/binary.js +8 -0
  19. package/dist/bootstrap.d.ts +37 -5
  20. package/dist/bootstrap.d.ts.map +1 -1
  21. package/dist/bootstrap.js +324 -51
  22. package/dist/cell.d.ts +6 -0
  23. package/dist/cell.d.ts.map +1 -0
  24. package/dist/cell.js +9 -0
  25. package/dist/chain.d.ts +12 -0
  26. package/dist/chain.d.ts.map +1 -0
  27. package/dist/chain.js +64 -0
  28. package/dist/change-set.d.ts +13 -14
  29. package/dist/change-set.d.ts.map +1 -1
  30. package/dist/change-set.js +17 -56
  31. package/dist/change.d.ts +46 -0
  32. package/dist/change.d.ts.map +1 -1
  33. package/dist/change.js +36 -0
  34. package/dist/chat-types.d.ts +5 -0
  35. package/dist/chat-types.d.ts.map +1 -0
  36. package/dist/chat-types.js +13 -0
  37. package/dist/client.d.ts +56 -18
  38. package/dist/client.d.ts.map +1 -1
  39. package/dist/client.js +164 -23
  40. package/dist/collection.d.ts +31 -14
  41. package/dist/collection.d.ts.map +1 -1
  42. package/dist/collection.js +61 -55
  43. package/dist/compile.d.ts +16 -0
  44. package/dist/compile.d.ts.map +1 -0
  45. package/dist/compile.js +711 -0
  46. package/dist/connection.d.ts +8 -103
  47. package/dist/connection.d.ts.map +1 -1
  48. package/dist/connection.js +103 -2076
  49. package/dist/context.d.ts +2 -0
  50. package/dist/context.d.ts.map +1 -0
  51. package/dist/context.js +7 -0
  52. package/dist/conversation-live.d.ts +135 -0
  53. package/dist/conversation-live.d.ts.map +1 -0
  54. package/dist/conversation-live.js +247 -0
  55. package/dist/conversation-row.d.ts +33 -0
  56. package/dist/conversation-row.d.ts.map +1 -0
  57. package/dist/conversation-row.js +53 -0
  58. package/dist/conversation.d.ts +67 -44
  59. package/dist/conversation.d.ts.map +1 -1
  60. package/dist/conversation.js +1010 -549
  61. package/dist/declaration.d.ts +10 -0
  62. package/dist/declaration.d.ts.map +1 -0
  63. package/dist/declaration.js +24 -0
  64. package/dist/digest.d.ts +7 -0
  65. package/dist/digest.d.ts.map +1 -0
  66. package/dist/digest.js +113 -0
  67. package/dist/discovery.d.ts +10 -0
  68. package/dist/discovery.d.ts.map +1 -0
  69. package/dist/discovery.js +177 -0
  70. package/dist/durability.d.ts +19 -1
  71. package/dist/durability.d.ts.map +1 -1
  72. package/dist/durability.js +5 -0
  73. package/dist/entry.d.ts +20 -0
  74. package/dist/entry.d.ts.map +1 -0
  75. package/dist/entry.js +161 -0
  76. package/dist/expectation.d.ts +23 -0
  77. package/dist/expectation.d.ts.map +1 -0
  78. package/dist/expectation.js +92 -0
  79. package/dist/failure.d.ts +14 -0
  80. package/dist/failure.d.ts.map +1 -0
  81. package/dist/failure.js +22 -0
  82. package/dist/figures.d.ts +49 -0
  83. package/dist/figures.d.ts.map +1 -0
  84. package/dist/figures.js +197 -0
  85. package/dist/file.d.ts +2 -19
  86. package/dist/file.d.ts.map +1 -1
  87. package/dist/file.js +7 -122
  88. package/dist/holdings.d.ts +29 -0
  89. package/dist/holdings.d.ts.map +1 -0
  90. package/dist/holdings.js +95 -0
  91. package/dist/host.d.ts +28 -3
  92. package/dist/host.d.ts.map +1 -1
  93. package/dist/host.js +149 -26
  94. package/dist/identity.d.ts +3 -0
  95. package/dist/identity.d.ts.map +1 -1
  96. package/dist/identity.js +13 -1
  97. package/dist/index.d.ts +39 -10
  98. package/dist/index.d.ts.map +1 -1
  99. package/dist/index.js +16 -0
  100. package/dist/install.d.ts +55 -0
  101. package/dist/install.d.ts.map +1 -0
  102. package/dist/install.js +543 -0
  103. package/dist/job.d.ts +5 -0
  104. package/dist/job.d.ts.map +1 -0
  105. package/dist/job.js +7 -0
  106. package/dist/lifecycle.d.ts +7 -0
  107. package/dist/lifecycle.d.ts.map +1 -0
  108. package/dist/lifecycle.js +271 -0
  109. package/dist/listing.d.ts +52 -0
  110. package/dist/listing.d.ts.map +1 -0
  111. package/dist/listing.js +168 -0
  112. package/dist/live.d.ts +23 -0
  113. package/dist/live.d.ts.map +1 -0
  114. package/dist/live.js +165 -0
  115. package/dist/locks.d.ts +9 -0
  116. package/dist/locks.d.ts.map +1 -0
  117. package/dist/locks.js +62 -0
  118. package/dist/log.d.ts +1 -0
  119. package/dist/log.d.ts.map +1 -1
  120. package/dist/lost.d.ts +5 -0
  121. package/dist/lost.d.ts.map +1 -0
  122. package/dist/lost.js +61 -0
  123. package/dist/media.d.ts +8 -0
  124. package/dist/media.d.ts.map +1 -0
  125. package/dist/media.js +218 -0
  126. package/dist/memory.d.ts +25 -8
  127. package/dist/memory.d.ts.map +1 -1
  128. package/dist/memory.js +296 -93
  129. package/dist/messages.d.ts +49 -0
  130. package/dist/messages.d.ts.map +1 -0
  131. package/dist/messages.js +148 -0
  132. package/dist/model.d.ts +16 -9
  133. package/dist/model.d.ts.map +1 -1
  134. package/dist/model.js +9 -15
  135. package/dist/models.d.ts +10 -0
  136. package/dist/models.d.ts.map +1 -0
  137. package/dist/models.js +170 -0
  138. package/dist/name.d.ts +4 -0
  139. package/dist/name.d.ts.map +1 -0
  140. package/dist/name.js +122 -0
  141. package/dist/observation.d.ts +22 -4
  142. package/dist/observation.d.ts.map +1 -1
  143. package/dist/observation.js +127 -26
  144. package/dist/open.d.ts +2 -0
  145. package/dist/open.d.ts.map +1 -0
  146. package/dist/open.js +1 -0
  147. package/dist/opened.d.ts +22 -0
  148. package/dist/opened.d.ts.map +1 -0
  149. package/dist/opened.js +107 -0
  150. package/dist/opening.d.ts +4 -0
  151. package/dist/opening.d.ts.map +1 -0
  152. package/dist/opening.js +59 -0
  153. package/dist/outcome.d.ts +75 -5
  154. package/dist/outcome.d.ts.map +1 -1
  155. package/dist/outcome.js +84 -1
  156. package/dist/overlay.d.ts +17 -5
  157. package/dist/overlay.d.ts.map +1 -1
  158. package/dist/overlay.js +168 -190
  159. package/dist/parts.d.ts +11 -0
  160. package/dist/parts.d.ts.map +1 -0
  161. package/dist/parts.js +21 -0
  162. package/dist/paths.d.ts +2 -1
  163. package/dist/paths.d.ts.map +1 -1
  164. package/dist/paths.js +26 -16
  165. package/dist/preparation.d.ts +20 -0
  166. package/dist/preparation.d.ts.map +1 -0
  167. package/dist/preparation.js +233 -0
  168. package/dist/queries.d.ts +16 -0
  169. package/dist/queries.d.ts.map +1 -0
  170. package/dist/queries.js +272 -0
  171. package/dist/query.d.ts +51 -181
  172. package/dist/query.d.ts.map +1 -1
  173. package/dist/query.js +3 -431
  174. package/dist/questions.d.ts +34 -0
  175. package/dist/questions.d.ts.map +1 -0
  176. package/dist/questions.js +122 -0
  177. package/dist/queue.d.ts +32 -0
  178. package/dist/queue.d.ts.map +1 -0
  179. package/dist/queue.js +402 -0
  180. package/dist/reach.d.ts +21 -5
  181. package/dist/reach.d.ts.map +1 -1
  182. package/dist/reach.js +306 -96
  183. package/dist/react.d.ts +43 -19
  184. package/dist/react.d.ts.map +1 -1
  185. package/dist/react.js +22 -21
  186. package/dist/read.d.ts +7 -0
  187. package/dist/read.d.ts.map +1 -0
  188. package/dist/read.js +17 -0
  189. package/dist/readiness.d.ts +49 -0
  190. package/dist/readiness.d.ts.map +1 -0
  191. package/dist/readiness.js +27 -0
  192. package/dist/reads.d.ts +37 -0
  193. package/dist/reads.d.ts.map +1 -0
  194. package/dist/reads.js +174 -0
  195. package/dist/recovery.d.ts +26 -0
  196. package/dist/recovery.d.ts.map +1 -0
  197. package/dist/recovery.js +232 -0
  198. package/dist/refresh.d.ts +20 -7
  199. package/dist/refresh.d.ts.map +1 -1
  200. package/dist/refresh.js +155 -59
  201. package/dist/refusal.d.ts +5 -0
  202. package/dist/refusal.d.ts.map +1 -0
  203. package/dist/refusal.js +57 -0
  204. package/dist/replica.d.ts +53 -33
  205. package/dist/replica.d.ts.map +1 -1
  206. package/dist/replica.js +361 -164
  207. package/dist/room-draft.d.ts +59 -12
  208. package/dist/room-draft.d.ts.map +1 -1
  209. package/dist/room-draft.js +299 -90
  210. package/dist/room-drafts.d.ts +24 -0
  211. package/dist/room-drafts.d.ts.map +1 -0
  212. package/dist/room-drafts.js +217 -0
  213. package/dist/rows.d.ts +32 -34
  214. package/dist/rows.d.ts.map +1 -1
  215. package/dist/rows.js +67 -87
  216. package/dist/runtime.d.ts +32 -0
  217. package/dist/runtime.d.ts.map +1 -0
  218. package/dist/runtime.js +1 -0
  219. package/dist/save.d.ts +74 -5
  220. package/dist/save.d.ts.map +1 -1
  221. package/dist/save.js +914 -188
  222. package/dist/saves.d.ts +32 -0
  223. package/dist/saves.d.ts.map +1 -0
  224. package/dist/saves.js +679 -0
  225. package/dist/search.d.ts +15 -54
  226. package/dist/search.d.ts.map +1 -1
  227. package/dist/search.js +10 -121
  228. package/dist/seed.d.ts +25 -0
  229. package/dist/seed.d.ts.map +1 -0
  230. package/dist/seed.js +145 -0
  231. package/dist/shared.d.ts +10 -0
  232. package/dist/shared.d.ts.map +1 -0
  233. package/dist/shared.js +339 -0
  234. package/dist/shown.d.ts +32 -0
  235. package/dist/shown.d.ts.map +1 -0
  236. package/dist/shown.js +299 -0
  237. package/dist/socket/admission.d.ts +7 -0
  238. package/dist/socket/admission.d.ts.map +1 -0
  239. package/dist/socket/admission.js +39 -0
  240. package/dist/socket/answers.d.ts +6 -0
  241. package/dist/socket/answers.d.ts.map +1 -0
  242. package/dist/socket/answers.js +20 -0
  243. package/dist/socket/lanes.d.ts +20 -0
  244. package/dist/socket/lanes.d.ts.map +1 -0
  245. package/dist/socket/lanes.js +77 -0
  246. package/dist/socket/reads.d.ts +10 -0
  247. package/dist/socket/reads.d.ts.map +1 -0
  248. package/dist/socket/reads.js +31 -0
  249. package/dist/socket/rooms.d.ts +41 -0
  250. package/dist/socket/rooms.d.ts.map +1 -0
  251. package/dist/socket/rooms.js +90 -0
  252. package/dist/socket/session.d.ts +38 -0
  253. package/dist/socket/session.d.ts.map +1 -0
  254. package/dist/socket/session.js +23 -0
  255. package/dist/socket.d.ts +69 -0
  256. package/dist/socket.d.ts.map +1 -0
  257. package/dist/socket.js +175 -0
  258. package/dist/source.d.ts +61 -0
  259. package/dist/source.d.ts.map +1 -0
  260. package/dist/source.js +82 -0
  261. package/dist/status.d.ts +7 -4
  262. package/dist/status.d.ts.map +1 -1
  263. package/dist/status.js +3 -15
  264. package/dist/store/fences.d.ts +16 -0
  265. package/dist/store/fences.d.ts.map +1 -0
  266. package/dist/store/fences.js +26 -0
  267. package/dist/store/installs.d.ts +30 -0
  268. package/dist/store/installs.d.ts.map +1 -0
  269. package/dist/store/installs.js +34 -0
  270. package/dist/store/readiness.d.ts +10 -0
  271. package/dist/store/readiness.d.ts.map +1 -0
  272. package/dist/store/readiness.js +52 -0
  273. package/dist/store/records.d.ts +210 -0
  274. package/dist/store/records.d.ts.map +1 -0
  275. package/dist/store/records.js +428 -0
  276. package/dist/store/room-held.d.ts +8 -0
  277. package/dist/store/room-held.d.ts.map +1 -0
  278. package/dist/store/room-held.js +17 -0
  279. package/dist/store/space.d.ts +11 -0
  280. package/dist/store/space.d.ts.map +1 -0
  281. package/dist/store/space.js +41 -0
  282. package/dist/store/watchers.d.ts +17 -0
  283. package/dist/store/watchers.d.ts.map +1 -0
  284. package/dist/store/watchers.js +56 -0
  285. package/dist/store/writes.d.ts +24 -0
  286. package/dist/store/writes.d.ts.map +1 -0
  287. package/dist/store/writes.js +125 -0
  288. package/dist/store.d.ts +106 -92
  289. package/dist/store.d.ts.map +1 -1
  290. package/dist/store.js +142 -385
  291. package/dist/stored.d.ts +156 -0
  292. package/dist/stored.d.ts.map +1 -0
  293. package/dist/stored.js +649 -0
  294. package/dist/surface.d.ts +88 -0
  295. package/dist/surface.d.ts.map +1 -0
  296. package/dist/surface.js +224 -0
  297. package/dist/sync.d.ts +19 -0
  298. package/dist/sync.d.ts.map +1 -0
  299. package/dist/sync.js +530 -0
  300. package/dist/tables.d.ts +412 -0
  301. package/dist/tables.d.ts.map +1 -0
  302. package/dist/tables.js +737 -0
  303. package/dist/tallies.d.ts +18 -0
  304. package/dist/tallies.d.ts.map +1 -0
  305. package/dist/tallies.js +129 -0
  306. package/dist/transfer.d.ts +0 -5
  307. package/dist/transfer.d.ts.map +1 -1
  308. package/dist/turn.d.ts +9 -0
  309. package/dist/turn.d.ts.map +1 -0
  310. package/dist/turn.js +75 -0
  311. package/dist/validation.d.ts +29 -0
  312. package/dist/validation.d.ts.map +1 -0
  313. package/dist/validation.js +104 -0
  314. package/dist/windows.d.ts +11 -0
  315. package/dist/windows.d.ts.map +1 -0
  316. package/dist/windows.js +16 -0
  317. package/dist/wire.d.ts +189 -37
  318. package/dist/wire.d.ts.map +1 -1
  319. package/dist/wire.js +77 -33
  320. package/package.json +27 -15
  321. package/AGENTS.md +0 -231
  322. package/dist/attachment.d.ts +0 -3
  323. package/dist/attachment.d.ts.map +0 -1
  324. package/dist/attachment.js +0 -8
  325. package/dist/read-side.d.ts +0 -18
  326. package/dist/read-side.d.ts.map +0 -1
  327. package/dist/read-side.js +0 -377
@@ -1,59 +1,68 @@
1
- import { apply, parse, serialize } from '@agentshouse/mdmodel';
1
+ import { apply, create, equalValue, frontmatterValue, parse, serialize, } from '@agentshouse/mdmodel';
2
+ import { runtimeError } from './failure.js';
3
+ import { sha256 } from './digest.js';
4
+ import { binaryLocalId } from './identity.js';
2
5
  import { normalize } from './paths.js';
3
- function malformed() {
4
- throw new Error('room-draft-malformed');
6
+ export function returnedBy() {
7
+ return { kind: 'withdrawn', code: 'withdrawn', fields: {}, retryable: false };
8
+ }
9
+ export function staleWrite(current) {
10
+ return { outcome: 'stale', current };
11
+ }
12
+ function malformed(at, needs) {
13
+ throw runtimeError('room-draft-malformed', at === undefined ? 'room-draft-malformed' : `room-draft-malformed at ${at}: ${needs}`);
5
14
  }
6
15
  function plain(value) {
7
16
  return typeof value === 'object' && value !== null && !Array.isArray(value);
8
17
  }
9
- function frontmatterValue(value) {
10
- if (Array.isArray(value))
11
- return value.every(frontmatterValue);
12
- return (value === null ||
13
- typeof value === 'string' ||
14
- typeof value === 'boolean' ||
15
- (typeof value === 'number' && Number.isFinite(value)));
16
- }
17
- function text(value) {
18
- return typeof value === 'string' ? value : malformed();
18
+ function text(value, at) {
19
+ return typeof value === 'string' ? value : malformed(at, 'text');
19
20
  }
20
- function optionalText(value) {
21
- return value === undefined ? undefined : text(value);
21
+ function optionalText(value, at) {
22
+ return value === undefined ? undefined : text(value, at);
22
23
  }
23
- function markdownBase(value) {
24
- return value === null ? null : optionalText(value);
24
+ function markdownBase(value, at) {
25
+ return value === null ? null : optionalText(value, at);
25
26
  }
26
- function entries(value, each) {
27
+ function entries(value, at, each) {
27
28
  if (!plain(value))
28
- malformed();
29
+ malformed(at, 'an object of named values');
29
30
  const read = {};
30
31
  for (const [name, item] of Object.entries(value))
31
- read[name] = each(item);
32
+ read[name] = each(item, `${at}.${name}`);
32
33
  return read;
33
34
  }
34
- function fieldValue(value) {
35
+ function frontmatter(item, at) {
36
+ return frontmatterValue(item) ? item : malformed(at, 'a frontmatter value');
37
+ }
38
+ function fieldValue(value, at) {
35
39
  if (value === null)
36
40
  return null;
37
41
  if (!plain(value) || !Object.hasOwn(value, 'value') || !frontmatterValue(value.value)) {
38
- malformed();
42
+ malformed(at, '{ value } with a frontmatter value, or null where the document lacks it');
39
43
  }
40
44
  return { value: value.value };
41
45
  }
42
- function textPart(value) {
46
+ function textPart(value, at) {
43
47
  if (!plain(value))
44
- malformed();
45
- const base = optionalText(value.base);
46
- return { value: text(value.value), ...(base === undefined ? {} : { base }) };
48
+ malformed(at, '{ value, base }');
49
+ const base = optionalText(value.base, `${at}.base`);
50
+ return { value: text(value.value, `${at}.value`), ...(base === undefined ? {} : { base }) };
47
51
  }
48
- function creationOf(value) {
52
+ function creationOf(value, at) {
49
53
  if (!plain(value))
50
- malformed();
54
+ malformed(at, '{ type, fields, sections }, or { markdown }');
51
55
  if (Object.hasOwn(value, 'markdown'))
52
- return { markdown: text(value.markdown) };
53
- const fields = entries(value.fields, (item) => (frontmatterValue(item) ? item : malformed()));
54
- return { type: text(value.type), fields, sections: entries(value.sections, text) };
56
+ return { markdown: text(value.markdown, `${at}.markdown`) };
57
+ if (typeof value.type !== 'string')
58
+ malformed(`${at}.type`, 'a type name, or markdown in place of type, fields and sections');
59
+ return {
60
+ type: value.type,
61
+ fields: entries(value.fields, `${at}.fields`, frontmatter),
62
+ sections: entries(value.sections, `${at}.sections`, text),
63
+ };
55
64
  }
56
- const PART_NAMES = new Set([
65
+ const PART_NAMES = [
57
66
  'fields',
58
67
  'sections',
59
68
  'preamble',
@@ -61,41 +70,59 @@ const PART_NAMES = new Set([
61
70
  'creation',
62
71
  'move',
63
72
  'removal',
64
- ]);
65
- export function readParts(value) {
66
- if (!plain(value) || Object.keys(value).some((name) => !PART_NAMES.has(name)))
67
- malformed();
73
+ 'file',
74
+ ];
75
+ const NAMED_PARTS = `a part named ${PART_NAMES.slice(0, -1).join(', ')} or ${PART_NAMES.at(-1)}`;
76
+ export function readParts(value, path) {
77
+ if (!plain(value))
78
+ malformed(path, 'an object of parts');
79
+ const unknown = Object.keys(value).find((name) => !PART_NAMES.includes(name));
80
+ if (unknown !== undefined)
81
+ malformed(`${path} ${unknown}`, NAMED_PARTS);
68
82
  const parts = {};
69
83
  if (value.fields !== undefined) {
70
- parts.fields = entries(value.fields, (item) => {
84
+ parts.fields = entries(value.fields, `${path} fields`, (item, at) => {
71
85
  if (!plain(item) || !Object.hasOwn(item, 'value') || !frontmatterValue(item.value)) {
72
- malformed();
86
+ malformed(at, '{ value, base } with a frontmatter value');
73
87
  }
74
88
  return item.base === undefined
75
89
  ? { value: item.value }
76
- : { value: item.value, base: fieldValue(item.base) };
90
+ : { value: item.value, base: fieldValue(item.base, `${at}.base`) };
77
91
  });
78
92
  }
79
93
  if (value.sections !== undefined)
80
- parts.sections = entries(value.sections, textPart);
94
+ parts.sections = entries(value.sections, `${path} sections`, textPart);
81
95
  if (value.preamble !== undefined)
82
- parts.preamble = textPart(value.preamble);
96
+ parts.preamble = textPart(value.preamble, `${path} preamble`);
83
97
  if (value.markdown !== undefined)
84
- parts.markdown = textPart(value.markdown);
98
+ parts.markdown = textPart(value.markdown, `${path} markdown`);
85
99
  if (value.creation !== undefined)
86
- parts.creation = creationOf(value.creation);
100
+ parts.creation = creationOf(value.creation, `${path} creation`);
87
101
  if (value.move !== undefined) {
88
102
  if (!plain(value.move))
89
- malformed();
90
- const base = markdownBase(value.move.base);
91
- parts.move = { to: text(value.move.to), ...(base === undefined ? {} : { base }) };
103
+ malformed(`${path} move`, '{ to, room, base }');
104
+ const base = markdownBase(value.move.base, `${path} move.base`);
105
+ const room = optionalText(value.move.room, `${path} move.room`);
106
+ parts.move = {
107
+ to: text(value.move.to, `${path} move.to`),
108
+ ...(room === undefined ? {} : { room }),
109
+ ...(base === undefined ? {} : { base }),
110
+ };
92
111
  }
93
112
  if (value.removal !== undefined) {
94
113
  if (!plain(value.removal))
95
- malformed();
96
- const base = markdownBase(value.removal.base);
114
+ malformed(`${path} removal`, '{ base }');
115
+ const base = markdownBase(value.removal.base, `${path} removal.base`);
97
116
  parts.removal = base === undefined ? {} : { base };
98
117
  }
118
+ if (value.file !== undefined) {
119
+ if (!plain(value.file) || !(value.file.blob instanceof Blob))
120
+ malformed(`${path} file`, '{ blob, base } with a Blob');
121
+ if (Object.keys(value).length > 1)
122
+ throw runtimeError('room-draft-file-exclusive');
123
+ const base = markdownBase(value.file.base, `${path} file.base`);
124
+ parts.file = base === undefined ? { blob: value.file.blob } : { blob: value.file.blob, base };
125
+ }
99
126
  return parts;
100
127
  }
101
128
  function named(record) {
@@ -108,17 +135,78 @@ function kept(prior, base) {
108
135
  if (prior !== undefined)
109
136
  return prior.base;
110
137
  if (base === undefined)
111
- throw new Error('room-draft-base-missing');
138
+ throw runtimeError('room-draft-base-missing');
112
139
  return base;
113
140
  }
141
+ function movePart(current, move) {
142
+ return {
143
+ to: move.to,
144
+ ...(move.room === undefined ? {} : { room: move.room }),
145
+ base: kept(current, move.base),
146
+ };
147
+ }
114
148
  function editsText(parts) {
115
149
  return (parts.preamble !== undefined ||
116
150
  named(parts.fields).length > 0 ||
117
151
  named(parts.sections).length > 0);
118
152
  }
119
- export function held(current, parts) {
153
+ function partNames(parts) {
154
+ const names = [];
155
+ for (const [name, part] of Object.entries(parts)) {
156
+ if (name === 'preamble' || name === 'markdown')
157
+ names.push(name);
158
+ else if ((name === 'fields' || name === 'sections') && plain(part))
159
+ names.push(...Object.keys(part).map((one) => `${name}/${one}`));
160
+ else
161
+ return null;
162
+ }
163
+ return names.sort().join('\u0000');
164
+ }
165
+ function withBaseOf(prior, part) {
166
+ return plain(part) && plain(prior) && Object.hasOwn(prior, 'base')
167
+ ? { ...part, base: prior.base }
168
+ : part;
169
+ }
170
+ export function gatheredParts(earlier, later) {
171
+ if (!plain(earlier) || !plain(later))
172
+ return null;
173
+ const named = partNames(earlier);
174
+ if (named === null || named !== partNames(later))
175
+ return null;
176
+ return Object.fromEntries(Object.entries(later).map(([name, part]) => [
177
+ name,
178
+ name === 'fields' || name === 'sections'
179
+ ? Object.fromEntries(Object.entries(part).map(([one, value]) => [
180
+ one,
181
+ withBaseOf(earlier[name][one], value),
182
+ ]))
183
+ : withBaseOf(earlier[name], part),
184
+ ]));
185
+ }
186
+ export function held(current, parts, file) {
120
187
  if (parts.markdown !== undefined && editsText(parts)) {
121
- throw new Error('room-draft-markdown-exclusive');
188
+ throw runtimeError('room-draft-markdown-exclusive');
189
+ }
190
+ if (file !== undefined) {
191
+ if (current !== undefined && current.file === undefined) {
192
+ throw runtimeError('room-draft-file-exclusive');
193
+ }
194
+ return { file: { ...file, base: current?.file === undefined ? file.base : current.file.base } };
195
+ }
196
+ if (current?.file !== undefined) {
197
+ if (editsText(parts) ||
198
+ parts.markdown !== undefined ||
199
+ parts.creation !== undefined ||
200
+ (parts.move === undefined && parts.removal === undefined)) {
201
+ throw runtimeError('room-draft-file-exclusive');
202
+ }
203
+ return {
204
+ file: current.file,
205
+ ...(parts.move === undefined ? {} : { move: movePart(current.move, parts.move) }),
206
+ ...(parts.removal === undefined
207
+ ? {}
208
+ : { removal: { base: kept(current.removal, parts.removal.base) } }),
209
+ };
122
210
  }
123
211
  const next = {};
124
212
  const fields = named(parts.fields);
@@ -149,24 +237,15 @@ export function held(current, parts) {
149
237
  }
150
238
  if (parts.creation !== undefined)
151
239
  next.creation = parts.creation;
152
- if (parts.move !== undefined) {
153
- next.move = { to: parts.move.to, base: kept(current?.move, parts.move.base) };
154
- }
240
+ if (parts.move !== undefined)
241
+ next.move = movePart(current?.move, parts.move);
155
242
  if (parts.removal !== undefined) {
156
243
  next.removal = { base: kept(current?.removal, parts.removal.base) };
157
244
  }
158
245
  if (Object.keys(next).length === 0)
159
- throw new Error('room-draft-empty');
246
+ throw runtimeError('room-draft-empty');
160
247
  return next;
161
248
  }
162
- export function equalValue(left, right) {
163
- if (left === right)
164
- return true;
165
- return (Array.isArray(left) &&
166
- Array.isArray(right) &&
167
- left.length === right.length &&
168
- left.every((item, index) => equalValue(item, right[index])));
169
- }
170
249
  function sameField(left, right) {
171
250
  if (left === null || right === null)
172
251
  return left === right;
@@ -174,7 +253,7 @@ function sameField(left, right) {
174
253
  }
175
254
  export function underneath(parts, path, visible) {
176
255
  const markdown = visible?.documents[path] ?? null;
177
- const document = visible?.collection.documents[path];
256
+ const document = visible?.collection.document(path);
178
257
  const report = {};
179
258
  const fields = {};
180
259
  for (const [name, part] of named(parts.fields)) {
@@ -207,17 +286,41 @@ export function underneath(parts, path, visible) {
207
286
  report.move = markdown;
208
287
  if (parts.removal !== undefined && markdown !== parts.removal.base)
209
288
  report.removal = markdown;
289
+ if (parts.file !== undefined) {
290
+ const file = binaryBase(visible, path);
291
+ if (file !== parts.file.base || markdown !== null)
292
+ report.file = file;
293
+ }
210
294
  return report;
211
295
  }
212
- export function changedParts(path, report) {
296
+ const UNTYPED_MEDIA_TYPE = 'application/octet-stream';
297
+ export async function heldFile(blob, base) {
298
+ return {
299
+ localId: binaryLocalId(),
300
+ ...(blob instanceof File ? { name: blob.name } : {}),
301
+ byteLength: blob.size,
302
+ mediaType: blob.type === '' ? UNTYPED_MEDIA_TYPE : blob.type,
303
+ sha256: await sha256(blob),
304
+ base,
305
+ };
306
+ }
307
+ export function binaryBase(visible, path) {
308
+ const binary = visible?.binaries[path];
309
+ if (binary === undefined)
310
+ return null;
311
+ return visible?.revisions[path] ?? (binary.state === 'pending' ? binary.localId : null);
312
+ }
313
+ export function changedParts(path, parts, visible) {
314
+ const report = underneath(parts, path, visible);
315
+ const made = parts.file?.base === null;
213
316
  return [
214
- ...(report.creation === undefined ? [] : [{ path, part: 'creation' }]),
215
317
  ...named(report.fields).map(([name]) => ({ path, part: 'field', name })),
216
318
  ...named(report.sections).map(([name]) => ({ path, part: 'section', name })),
217
319
  ...(report.preamble === undefined ? [] : [{ path, part: 'preamble' }]),
218
320
  ...(report.markdown === undefined ? [] : [{ path, part: 'markdown' }]),
219
321
  ...(report.move === undefined ? [] : [{ path, part: 'move' }]),
220
322
  ...(report.removal === undefined ? [] : [{ path, part: 'removal' }]),
323
+ ...(report.file === undefined || made ? [] : [{ path, part: 'file' }]),
221
324
  ];
222
325
  }
223
326
  function joined(existing, returned) {
@@ -227,34 +330,46 @@ function joined(existing, returned) {
227
330
  merged[name] = part;
228
331
  return Object.keys(merged).length === 0 ? undefined : merged;
229
332
  }
230
- function ended(text) {
333
+ export function lineEnded(text) {
231
334
  return text === '' || text.endsWith('\n') ? text : `${text}\n`;
232
335
  }
233
- function frontmatterOf(fields) {
234
- const opened = parse('---\n---\n');
235
- if (!opened.ok)
236
- return malformed();
237
- let document = opened.document;
238
- for (const [name, part] of fields) {
239
- const next = apply(document, { kind: 'field', name, value: part.value, prior: undefined });
240
- if (next.outcome !== 'applied')
241
- return malformed();
242
- document = next.document;
243
- }
244
- return serialize(document);
336
+ function written(start, changes, definition) {
337
+ const next = apply(start, changes, definition);
338
+ return next.outcome === 'applied' ? serialize(next.document) : malformed();
339
+ }
340
+ function empty(definition) {
341
+ const parsed = parse('', '', definition);
342
+ return parsed.ok ? parsed.document : malformed();
245
343
  }
246
- function concatenated(markdown, parts) {
344
+ export function partsAfter(markdown, parts, definitions) {
247
345
  const fields = named(parts.fields);
346
+ const sections = named(parts.sections);
347
+ if (fields.length === 0 && sections.length === 0 && parts.preamble === undefined)
348
+ return markdown;
349
+ const whole = parse(markdown, '', definitions);
350
+ const definition = whole.ok ? definitions?.(whole.document.type) : undefined;
351
+ const head = [
352
+ ...fields.map(([name, part]) => ({
353
+ kind: 'field',
354
+ name,
355
+ value: part.value,
356
+ prior: undefined,
357
+ })),
358
+ ...(parts.preamble === undefined
359
+ ? []
360
+ : [{ kind: 'preamble', value: lineEnded(parts.preamble.value), prior: '' }]),
361
+ ];
248
362
  const pieces = [
249
- ...(fields.length === 0 ? [] : [frontmatterOf(fields)]),
250
- ...(parts.preamble === undefined ? [] : [parts.preamble.value]),
251
- ...named(parts.sections).map(([name, part]) => `## ${name}\n${part.value}`),
363
+ ...(head.length === 0
364
+ ? []
365
+ : [
366
+ written(fields.length === 0 ? empty(definition) : create(undefined, definition), head, definition),
367
+ ]),
368
+ ...sections.map(([name, part]) => written(empty(definition), [{ kind: 'section', name, value: lineEnded(part.value), prior: undefined }], definition)),
252
369
  ];
253
- if (pieces.length === 0)
254
- return markdown;
255
- return `${ended(markdown)}\n${pieces.map(ended).join('')}`;
370
+ return `${lineEnded(markdown)}\n${pieces.join('')}`;
256
371
  }
257
- export function returnedInto(existing, returned) {
372
+ export function returnedInto(existing, returned, definitions) {
258
373
  if (existing === undefined)
259
374
  return returned;
260
375
  const next = { ...existing };
@@ -274,24 +389,57 @@ export function returnedInto(existing, returned) {
274
389
  delete next.fields;
275
390
  delete next.sections;
276
391
  delete next.preamble;
277
- const value = concatenated(whole.value, existing.markdown === undefined ? existing : returned);
392
+ const value = partsAfter(whole.value, existing.markdown === undefined ? existing : returned, definitions);
278
393
  next.markdown = { value, base: whole.base };
279
394
  }
280
395
  const creation = existing.creation ?? returned.creation;
281
396
  const move = existing.move ?? returned.move;
282
397
  const removal = existing.removal ?? returned.removal;
398
+ const file = existing.file ?? returned.file;
283
399
  if (creation !== undefined)
284
400
  next.creation = creation;
285
401
  if (move !== undefined)
286
402
  next.move = move;
287
403
  if (removal !== undefined)
288
404
  next.removal = removal;
405
+ if (file !== undefined)
406
+ next.file = file;
289
407
  return next;
290
408
  }
291
409
  export function moveTarget(move) {
292
410
  const to = normalize(move.to);
293
411
  return to === null || to === '' ? move.to : to;
294
412
  }
413
+ export function readSavedParts(named) {
414
+ const read = named.map(({ path, parts }) => ({ path, parts: readParts(parts, path) }));
415
+ read.forEach(({ path }, at) => {
416
+ if (path === '' || normalize(path) !== path)
417
+ malformed(path, 'a path inside the Room, such as notes/a.md');
418
+ if (read.findIndex((one) => one.path === path) !== at)
419
+ malformed(path, 'each path once in one save');
420
+ });
421
+ return read;
422
+ }
423
+ export function partsChanges(named) {
424
+ const changes = [];
425
+ const preconditions = [];
426
+ for (const { path, parts } of readSavedParts(named)) {
427
+ const parted = held(undefined, parts);
428
+ const made = changesOf(path, parted);
429
+ changes.push(...made.changes);
430
+ preconditions.push(...made.bases);
431
+ for (const change of made.changes) {
432
+ if (change.kind === 'create')
433
+ preconditions.push({ kind: 'absent', path });
434
+ if (change.kind === 'move')
435
+ preconditions.push({ kind: 'absent', path: change.to });
436
+ }
437
+ const revision = parted.markdown?.base ?? parted.move?.base ?? parted.removal?.base;
438
+ if (typeof revision === 'string')
439
+ preconditions.push({ kind: 'revision', path, revision });
440
+ }
441
+ return { changes, preconditions };
442
+ }
295
443
  export function changesOf(path, parts) {
296
444
  const changes = [];
297
445
  const bases = [];
@@ -311,19 +459,80 @@ export function changesOf(path, parts) {
311
459
  bases.push({ kind: 'field', path, name, value: part.base?.value });
312
460
  }
313
461
  for (const [name, part] of named(parts.sections)) {
314
- changes.push({ kind: 'section', path, name, value: part.value });
462
+ changes.push({ kind: 'section', path, name, value: lineEnded(part.value) });
315
463
  bases.push({ kind: 'section', path, name, value: part.base });
316
464
  }
317
465
  if (parts.preamble !== undefined) {
318
- changes.push({ kind: 'preamble', path, value: parts.preamble.value });
466
+ changes.push({ kind: 'preamble', path, value: lineEnded(parts.preamble.value) });
319
467
  bases.push({ kind: 'preamble', path, value: parts.preamble.base });
320
468
  }
321
469
  if (parts.markdown !== undefined) {
322
470
  changes.push({ kind: 'replace', path, content: parts.markdown.value });
323
471
  }
472
+ if (parts.file !== undefined && parts.removal === undefined) {
473
+ const { base, name: _name, ...file } = parts.file;
474
+ const at = parts.move === undefined ? path : moveTarget(parts.move);
475
+ if (base !== null && at !== path)
476
+ changes.push({ kind: 'move', path, to: at });
477
+ changes.push({ kind: 'binary', path: at, ...file });
478
+ if (base === null)
479
+ bases.push({ kind: 'absent', path: at });
480
+ return { changes, bases };
481
+ }
482
+ if (parts.file?.base === null)
483
+ return { changes, bases };
324
484
  if (parts.move !== undefined)
325
485
  changes.push({ kind: 'move', path, to: moveTarget(parts.move) });
326
486
  if (parts.removal !== undefined)
327
487
  changes.push({ kind: 'remove', path });
328
488
  return { changes, bases };
329
489
  }
490
+ function rebased(before, after) {
491
+ return before === undefined ? after : { ...after, base: before.base };
492
+ }
493
+ function rebasedAll(before, after) {
494
+ return {
495
+ ...before,
496
+ ...Object.fromEntries(Object.entries(after).map(([name, part]) => [name, rebased(before?.[name], part)])),
497
+ };
498
+ }
499
+ export function joinedDraft(carried, saved) {
500
+ const draft = saved.find((item) => item.path === carried.path);
501
+ if (draft === undefined)
502
+ return carried;
503
+ const held = carried.parts;
504
+ const next = draft.parts;
505
+ return {
506
+ path: carried.path,
507
+ parts: {
508
+ ...held,
509
+ ...next,
510
+ ...(next.fields === undefined ? {} : { fields: rebasedAll(held.fields, next.fields) }),
511
+ ...(next.sections === undefined
512
+ ? {}
513
+ : { sections: rebasedAll(held.sections, next.sections) }),
514
+ ...(next.preamble === undefined ? {} : { preamble: rebased(held.preamble, next.preamble) }),
515
+ ...(next.markdown === undefined ? {} : { markdown: rebased(held.markdown, next.markdown) }),
516
+ },
517
+ };
518
+ }
519
+ export function withdrawnDrafts(drafts, changes) {
520
+ return drafts.flatMap((draft) => {
521
+ const file = draft.parts.file;
522
+ const at = draft.parts.move?.to ?? draft.path;
523
+ const change = changes.find((item) => (item.kind === 'move' || item.kind === 'remove') && item.path === at);
524
+ if (file === undefined || change === undefined)
525
+ return [draft];
526
+ if (change.kind === 'move') {
527
+ return [
528
+ {
529
+ path: draft.path,
530
+ parts: change.to === draft.path ? { file } : { file, move: { to: change.to, base: null } },
531
+ },
532
+ ];
533
+ }
534
+ return file.base === null
535
+ ? []
536
+ : [{ path: draft.path, parts: { file, removal: { base: null } } }];
537
+ });
538
+ }
@@ -0,0 +1,24 @@
1
+ import { type ChangeSet } from './change-set.js';
2
+ import { type VisibleLayer } from './replica.js';
3
+ import { type RoomDraft, type RoomDraftWrite } from './room-draft.js';
4
+ import type { Runtime } from './runtime.js';
5
+ import type { Store } from './store.js';
6
+ export type RoomDraftSurface = {
7
+ list(): Promise<readonly RoomDraft[]>;
8
+ read(room: string, path: string): Promise<RoomDraft | null>;
9
+ write(room: string, path: string, revision: string | null, parts: unknown, next?: string): Promise<RoomDraftWrite>;
10
+ discard(room: string, path: string, revision: string): Promise<RoomDraftWrite>;
11
+ };
12
+ export type PresentationSurface = {
13
+ read(app: string): Promise<unknown>;
14
+ write(app: string, value: unknown): Promise<void>;
15
+ edit(app: string, members: Readonly<Record<string, unknown>>): Promise<void>;
16
+ };
17
+ export declare function visibleOf(store: Store, locator: string, paths: readonly string[]): Promise<VisibleLayer | undefined>;
18
+ export declare function publishRoomDrafts({ store, socket }: Runtime, waitingOnly: boolean, touched?: ChangeSet['documents'] | null): Promise<void>;
19
+ export declare function emitPresentation({ store, socket }: Runtime, app: string): Promise<void>;
20
+ export declare function roomDraftSurface(runtime: Runtime): RoomDraftSurface;
21
+ export declare function presentationSurface(runtime: Runtime): PresentationSurface;
22
+ export declare function watchRoomDrafts({ store, socket }: Runtime, deliver: (value: unknown) => void): () => void;
23
+ export declare function watchPresentation({ store, socket }: Runtime, app: string, deliver: (value: unknown) => void): () => void;
24
+ //# sourceMappingURL=room-drafts.d.ts.map
@@ -0,0 +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;AAoDD,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"}