@agentshouse/mdruntime 0.1.0-c069136dcb4e8 → 0.1.0-c076b00ebf42a

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 (316) hide show
  1. package/README.md +21 -19
  2. package/dist/acceptance.d.ts +3 -0
  3. package/dist/acceptance.d.ts.map +1 -0
  4. package/dist/acceptance.js +299 -0
  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 +26 -0
  9. package/dist/actions.d.ts.map +1 -0
  10. package/dist/actions.js +302 -0
  11. package/dist/adapter.d.ts +108 -85
  12. package/dist/adapter.d.ts.map +1 -1
  13. package/dist/attached-model.d.ts +3 -11
  14. package/dist/attached-model.d.ts.map +1 -1
  15. package/dist/attached-model.js +20 -60
  16. package/dist/bootstrap.d.ts +9 -5
  17. package/dist/bootstrap.d.ts.map +1 -1
  18. package/dist/bootstrap.js +204 -85
  19. package/dist/cell.d.ts +6 -0
  20. package/dist/cell.d.ts.map +1 -0
  21. package/dist/cell.js +9 -0
  22. package/dist/chain.d.ts +2 -1
  23. package/dist/chain.d.ts.map +1 -1
  24. package/dist/change-set.d.ts +4 -0
  25. package/dist/change-set.d.ts.map +1 -1
  26. package/dist/change-set.js +6 -0
  27. package/dist/change.d.ts +1 -0
  28. package/dist/change.d.ts.map +1 -1
  29. package/dist/change.js +4 -2
  30. package/dist/chat-types.d.ts +3 -0
  31. package/dist/chat-types.d.ts.map +1 -0
  32. package/dist/chat-types.js +11 -0
  33. package/dist/client.d.ts +29 -22
  34. package/dist/client.d.ts.map +1 -1
  35. package/dist/client.js +36 -20
  36. package/dist/collection.d.ts +26 -4
  37. package/dist/collection.d.ts.map +1 -1
  38. package/dist/collection.js +19 -2
  39. package/dist/compile.d.ts +8 -6
  40. package/dist/compile.d.ts.map +1 -1
  41. package/dist/compile.js +286 -336
  42. package/dist/connection.d.ts +5 -142
  43. package/dist/connection.d.ts.map +1 -1
  44. package/dist/connection.js +110 -4970
  45. package/dist/context.d.ts +2 -0
  46. package/dist/context.d.ts.map +1 -0
  47. package/dist/context.js +7 -0
  48. package/dist/conversation-live.d.ts +150 -0
  49. package/dist/conversation-live.d.ts.map +1 -0
  50. package/dist/conversation-live.js +259 -0
  51. package/dist/conversation-row.d.ts +35 -0
  52. package/dist/conversation-row.d.ts.map +1 -0
  53. package/dist/conversation-row.js +55 -0
  54. package/dist/conversation.d.ts +65 -44
  55. package/dist/conversation.d.ts.map +1 -1
  56. package/dist/conversation.js +999 -881
  57. package/dist/declaration.d.ts +10 -0
  58. package/dist/declaration.d.ts.map +1 -0
  59. package/dist/declaration.js +24 -0
  60. package/dist/discovery.d.ts +10 -0
  61. package/dist/discovery.d.ts.map +1 -0
  62. package/dist/discovery.js +150 -0
  63. package/dist/durability.d.ts +19 -0
  64. package/dist/durability.d.ts.map +1 -1
  65. package/dist/durability.js +4 -0
  66. package/dist/entry.d.ts +2 -2
  67. package/dist/entry.d.ts.map +1 -1
  68. package/dist/entry.js +18 -8
  69. package/dist/expectation.d.ts +26 -13
  70. package/dist/expectation.d.ts.map +1 -1
  71. package/dist/expectation.js +72 -19
  72. package/dist/failure.d.ts +3 -0
  73. package/dist/failure.d.ts.map +1 -1
  74. package/dist/failure.js +6 -0
  75. package/dist/figures.d.ts +49 -0
  76. package/dist/figures.d.ts.map +1 -0
  77. package/dist/figures.js +199 -0
  78. package/dist/file.d.ts.map +1 -1
  79. package/dist/file.js +2 -1
  80. package/dist/holdings.d.ts +29 -0
  81. package/dist/holdings.d.ts.map +1 -0
  82. package/dist/holdings.js +95 -0
  83. package/dist/host.d.ts +21 -7
  84. package/dist/host.d.ts.map +1 -1
  85. package/dist/host.js +77 -41
  86. package/dist/identity.d.ts +0 -1
  87. package/dist/identity.d.ts.map +1 -1
  88. package/dist/identity.js +0 -3
  89. package/dist/index.d.ts +34 -12
  90. package/dist/index.d.ts.map +1 -1
  91. package/dist/index.js +16 -5
  92. package/dist/install.d.ts +60 -0
  93. package/dist/install.d.ts.map +1 -0
  94. package/dist/install.js +537 -0
  95. package/dist/lifecycle.d.ts +7 -0
  96. package/dist/lifecycle.d.ts.map +1 -0
  97. package/dist/lifecycle.js +278 -0
  98. package/dist/listing.d.ts +52 -0
  99. package/dist/listing.d.ts.map +1 -0
  100. package/dist/listing.js +152 -0
  101. package/dist/live.d.ts +9 -6
  102. package/dist/live.d.ts.map +1 -1
  103. package/dist/live.js +118 -36
  104. package/dist/locks.d.ts +7 -0
  105. package/dist/locks.d.ts.map +1 -0
  106. package/dist/locks.js +32 -0
  107. package/dist/lost.d.ts +5 -0
  108. package/dist/lost.d.ts.map +1 -0
  109. package/dist/lost.js +49 -0
  110. package/dist/media.d.ts +1 -1
  111. package/dist/media.d.ts.map +1 -1
  112. package/dist/media.js +10 -13
  113. package/dist/memory.d.ts +15 -6
  114. package/dist/memory.d.ts.map +1 -1
  115. package/dist/memory.js +178 -89
  116. package/dist/messages.d.ts +35 -5
  117. package/dist/messages.d.ts.map +1 -1
  118. package/dist/messages.js +108 -36
  119. package/dist/model.d.ts +2 -10
  120. package/dist/model.d.ts.map +1 -1
  121. package/dist/model.js +0 -14
  122. package/dist/models.d.ts +10 -0
  123. package/dist/models.d.ts.map +1 -0
  124. package/dist/models.js +153 -0
  125. package/dist/observation.d.ts +28 -13
  126. package/dist/observation.d.ts.map +1 -1
  127. package/dist/observation.js +185 -81
  128. package/dist/opened.d.ts +1 -1
  129. package/dist/opened.d.ts.map +1 -1
  130. package/dist/opened.js +5 -5
  131. package/dist/opening.d.ts +4 -0
  132. package/dist/opening.d.ts.map +1 -0
  133. package/dist/opening.js +53 -0
  134. package/dist/outcome.d.ts +11 -1
  135. package/dist/outcome.d.ts.map +1 -1
  136. package/dist/outcome.js +26 -2
  137. package/dist/overlay.d.ts +6 -1
  138. package/dist/overlay.d.ts.map +1 -1
  139. package/dist/overlay.js +47 -21
  140. package/dist/page-metadata.d.ts +8 -0
  141. package/dist/page-metadata.d.ts.map +1 -0
  142. package/dist/page-metadata.js +19 -0
  143. package/dist/parts.d.ts +4 -0
  144. package/dist/parts.d.ts.map +1 -0
  145. package/dist/parts.js +13 -0
  146. package/dist/paths.d.ts +1 -0
  147. package/dist/paths.d.ts.map +1 -1
  148. package/dist/paths.js +22 -0
  149. package/dist/preparation.d.ts +41 -0
  150. package/dist/preparation.d.ts.map +1 -0
  151. package/dist/preparation.js +314 -0
  152. package/dist/presence.d.ts +58 -0
  153. package/dist/presence.d.ts.map +1 -0
  154. package/dist/presence.js +233 -0
  155. package/dist/queries.d.ts +16 -0
  156. package/dist/queries.d.ts.map +1 -0
  157. package/dist/queries.js +308 -0
  158. package/dist/query.d.ts +14 -210
  159. package/dist/query.d.ts.map +1 -1
  160. package/dist/query.js +3 -505
  161. package/dist/questions.d.ts +29 -0
  162. package/dist/questions.d.ts.map +1 -0
  163. package/dist/questions.js +115 -0
  164. package/dist/queue.d.ts +40 -0
  165. package/dist/queue.d.ts.map +1 -0
  166. package/dist/queue.js +450 -0
  167. package/dist/reach.d.ts +16 -15
  168. package/dist/reach.d.ts.map +1 -1
  169. package/dist/reach.js +248 -147
  170. package/dist/react.d.ts +17 -3
  171. package/dist/react.d.ts.map +1 -1
  172. package/dist/react.js +33 -1
  173. package/dist/read.d.ts +7 -0
  174. package/dist/read.d.ts.map +1 -0
  175. package/dist/read.js +17 -0
  176. package/dist/readiness.d.ts +9 -6
  177. package/dist/readiness.d.ts.map +1 -1
  178. package/dist/readiness.js +3 -5
  179. package/dist/reads.d.ts +39 -0
  180. package/dist/reads.d.ts.map +1 -0
  181. package/dist/reads.js +178 -0
  182. package/dist/recovery.d.ts +3 -1
  183. package/dist/recovery.d.ts.map +1 -1
  184. package/dist/recovery.js +38 -8
  185. package/dist/refresh.d.ts +2 -1
  186. package/dist/refresh.d.ts.map +1 -1
  187. package/dist/refresh.js +31 -3
  188. package/dist/refusal.d.ts +5 -0
  189. package/dist/refusal.d.ts.map +1 -0
  190. package/dist/refusal.js +55 -0
  191. package/dist/replica.d.ts +11 -16
  192. package/dist/replica.d.ts.map +1 -1
  193. package/dist/replica.js +64 -30
  194. package/dist/retried.d.ts +30 -0
  195. package/dist/retried.d.ts.map +1 -0
  196. package/dist/retried.js +72 -0
  197. package/dist/room-draft.d.ts +7 -8
  198. package/dist/room-draft.d.ts.map +1 -1
  199. package/dist/room-draft.js +113 -111
  200. package/dist/room-drafts.d.ts +24 -0
  201. package/dist/room-drafts.d.ts.map +1 -0
  202. package/dist/room-drafts.js +217 -0
  203. package/dist/rows.d.ts +16 -22
  204. package/dist/rows.d.ts.map +1 -1
  205. package/dist/rows.js +49 -186
  206. package/dist/runtime.d.ts +34 -0
  207. package/dist/runtime.d.ts.map +1 -0
  208. package/dist/runtime.js +1 -0
  209. package/dist/save.d.ts +42 -86
  210. package/dist/save.d.ts.map +1 -1
  211. package/dist/save.js +344 -174
  212. package/dist/saves.d.ts +32 -0
  213. package/dist/saves.d.ts.map +1 -0
  214. package/dist/saves.js +409 -0
  215. package/dist/search.d.ts +12 -63
  216. package/dist/search.d.ts.map +1 -1
  217. package/dist/search.js +9 -52
  218. package/dist/seed.d.ts +11 -2
  219. package/dist/seed.d.ts.map +1 -1
  220. package/dist/seed.js +71 -1
  221. package/dist/shared.d.ts +1 -6
  222. package/dist/shared.d.ts.map +1 -1
  223. package/dist/shared.js +13 -95
  224. package/dist/shown.d.ts +33 -0
  225. package/dist/shown.d.ts.map +1 -0
  226. package/dist/shown.js +309 -0
  227. package/dist/socket/admission.d.ts +7 -0
  228. package/dist/socket/admission.d.ts.map +1 -0
  229. package/dist/socket/admission.js +39 -0
  230. package/dist/socket/answers.d.ts +6 -0
  231. package/dist/socket/answers.d.ts.map +1 -0
  232. package/dist/socket/answers.js +20 -0
  233. package/dist/socket/lanes.d.ts +28 -0
  234. package/dist/socket/lanes.d.ts.map +1 -0
  235. package/dist/socket/lanes.js +103 -0
  236. package/dist/socket/reads.d.ts +10 -0
  237. package/dist/socket/reads.d.ts.map +1 -0
  238. package/dist/socket/reads.js +31 -0
  239. package/dist/socket/session.d.ts +38 -0
  240. package/dist/socket/session.d.ts.map +1 -0
  241. package/dist/socket/session.js +23 -0
  242. package/dist/socket.d.ts +67 -0
  243. package/dist/socket.d.ts.map +1 -0
  244. package/dist/socket.js +164 -0
  245. package/dist/source.d.ts +54 -0
  246. package/dist/source.d.ts.map +1 -0
  247. package/dist/source.js +82 -0
  248. package/dist/status.d.ts +0 -2
  249. package/dist/status.d.ts.map +1 -1
  250. package/dist/status.js +0 -6
  251. package/dist/store/installs.d.ts +30 -0
  252. package/dist/store/installs.d.ts.map +1 -0
  253. package/dist/store/installs.js +40 -0
  254. package/dist/store/readiness.d.ts +11 -0
  255. package/dist/store/readiness.d.ts.map +1 -0
  256. package/dist/store/readiness.js +68 -0
  257. package/dist/store/records.d.ts +217 -0
  258. package/dist/store/records.d.ts.map +1 -0
  259. package/dist/store/records.js +464 -0
  260. package/dist/store/room-held.d.ts +8 -0
  261. package/dist/store/room-held.d.ts.map +1 -0
  262. package/dist/store/room-held.js +17 -0
  263. package/dist/store/rooms-shown.d.ts +8 -0
  264. package/dist/store/rooms-shown.d.ts.map +1 -0
  265. package/dist/store/rooms-shown.js +13 -0
  266. package/dist/store/space.d.ts +11 -0
  267. package/dist/store/space.d.ts.map +1 -0
  268. package/dist/store/space.js +41 -0
  269. package/dist/store/watchers.d.ts +17 -0
  270. package/dist/store/watchers.d.ts.map +1 -0
  271. package/dist/store/watchers.js +56 -0
  272. package/dist/store/writes.d.ts +24 -0
  273. package/dist/store/writes.d.ts.map +1 -0
  274. package/dist/store/writes.js +125 -0
  275. package/dist/store.d.ts +113 -144
  276. package/dist/store.d.ts.map +1 -1
  277. package/dist/store.js +171 -364
  278. package/dist/stored.d.ts +72 -35
  279. package/dist/stored.d.ts.map +1 -1
  280. package/dist/stored.js +340 -197
  281. package/dist/surface.d.ts +89 -0
  282. package/dist/surface.d.ts.map +1 -0
  283. package/dist/surface.js +222 -0
  284. package/dist/sync.d.ts +19 -0
  285. package/dist/sync.d.ts.map +1 -0
  286. package/dist/sync.js +535 -0
  287. package/dist/tables.d.ts +124 -30
  288. package/dist/tables.d.ts.map +1 -1
  289. package/dist/tables.js +242 -62
  290. package/dist/tallies.d.ts +18 -0
  291. package/dist/tallies.d.ts.map +1 -0
  292. package/dist/tallies.js +128 -0
  293. package/dist/validation.d.ts.map +1 -1
  294. package/dist/validation.js +9 -12
  295. package/dist/windows.d.ts +1 -12
  296. package/dist/windows.d.ts.map +1 -1
  297. package/dist/windows.js +2 -75
  298. package/dist/wire.d.ts +58 -9
  299. package/dist/wire.d.ts.map +1 -1
  300. package/dist/wire.js +21 -5
  301. package/package.json +3 -2
  302. package/dist/attempt.d.ts +0 -16
  303. package/dist/attempt.d.ts.map +0 -1
  304. package/dist/attempt.js +0 -70
  305. package/dist/fence.d.ts +0 -6
  306. package/dist/fence.d.ts.map +0 -1
  307. package/dist/fence.js +0 -10
  308. package/dist/fulltext.d.ts +0 -27
  309. package/dist/fulltext.d.ts.map +0 -1
  310. package/dist/fulltext.js +0 -370
  311. package/dist/log.d.ts +0 -5
  312. package/dist/log.d.ts.map +0 -1
  313. package/dist/log.js +0 -14
  314. package/dist/words.d.ts +0 -19
  315. package/dist/words.d.ts.map +0 -1
  316. package/dist/words.js +0 -156
@@ -1,60 +1,70 @@
1
- import { apply, equalValue, frontmatterValue, parse, serialize, } from '@agentshouse/mdmodel';
1
+ import { apply, create, documentValue, equalValue, parse, serialize, } from '@agentshouse/mdmodel';
2
+ import { 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
- function malformed() {
13
- throw runtimeError('room-draft-malformed');
14
+ function malformed(at, needs) {
15
+ throw runtimeError('room-draft-malformed', at === undefined ? 'room-draft-malformed' : `room-draft-malformed at ${at}: ${needs}`);
14
16
  }
15
17
  function plain(value) {
16
18
  return typeof value === 'object' && value !== null && !Array.isArray(value);
17
19
  }
18
- function text(value) {
19
- return typeof value === 'string' ? value : malformed();
20
+ function text(value, at) {
21
+ return typeof value === 'string' ? value : malformed(at, 'text');
20
22
  }
21
- function optionalText(value) {
22
- return value === undefined ? undefined : text(value);
23
+ function optionalText(value, at) {
24
+ return value === undefined ? undefined : text(value, at);
23
25
  }
24
- function markdownBase(value) {
25
- return value === null ? null : optionalText(value);
26
+ function markdownBase(value, at) {
27
+ return value === null ? null : optionalText(value, at);
26
28
  }
27
- function entries(value, each) {
29
+ function entries(value, at, each) {
28
30
  if (!plain(value))
29
- malformed();
31
+ malformed(at, 'an object of named values');
30
32
  const read = {};
31
33
  for (const [name, item] of Object.entries(value))
32
- read[name] = each(item);
34
+ read[name] = each(item, `${at}.${name}`);
33
35
  return read;
34
36
  }
35
- function fieldValue(value) {
37
+ function documentValueAt(item, at) {
38
+ return documentValue(item) ? item : malformed(at, 'a document value');
39
+ }
40
+ function fieldValue(value, at) {
36
41
  if (value === null)
37
42
  return null;
38
- if (!plain(value) || !Object.hasOwn(value, 'value') || !frontmatterValue(value.value)) {
39
- malformed();
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');
40
45
  }
41
46
  return { value: value.value };
42
47
  }
43
- function textPart(value) {
48
+ function textPart(value, at) {
44
49
  if (!plain(value))
45
- malformed();
46
- const base = optionalText(value.base);
47
- return { value: text(value.value), ...(base === undefined ? {} : { base }) };
50
+ malformed(at, '{ value, base }');
51
+ const base = optionalText(value.base, `${at}.base`);
52
+ return { value: text(value.value, `${at}.value`), ...(base === undefined ? {} : { base }) };
48
53
  }
49
- function creationOf(value) {
54
+ function creationOf(value, at) {
50
55
  if (!plain(value))
51
- malformed();
56
+ malformed(at, '{ type, fields, sections }, or { markdown }');
52
57
  if (Object.hasOwn(value, 'markdown'))
53
- return { markdown: text(value.markdown) };
54
- const fields = entries(value.fields, (item) => (frontmatterValue(item) ? item : malformed()));
55
- return { type: text(value.type), fields, sections: entries(value.sections, text) };
58
+ return { markdown: text(value.markdown, `${at}.markdown`) };
59
+ if (typeof value.type !== 'string')
60
+ malformed(`${at}.type`, 'a type name, or markdown in place of type, fields and sections');
61
+ return {
62
+ type: value.type,
63
+ fields: entries(value.fields, `${at}.fields`, documentValueAt),
64
+ sections: entries(value.sections, `${at}.sections`, text),
65
+ };
56
66
  }
57
- const PART_NAMES = new Set([
67
+ const PART_NAMES = [
58
68
  'fields',
59
69
  'sections',
60
70
  'preamble',
@@ -63,52 +73,56 @@ const PART_NAMES = new Set([
63
73
  'move',
64
74
  'removal',
65
75
  'file',
66
- ]);
67
- export function readParts(value) {
68
- if (!plain(value) || Object.keys(value).some((name) => !PART_NAMES.has(name)))
69
- malformed();
76
+ ];
77
+ const NAMED_PARTS = `a part named ${PART_NAMES.slice(0, -1).join(', ')} or ${PART_NAMES.slice(-1).join('')}`;
78
+ export function readParts(value, path) {
79
+ if (!plain(value))
80
+ malformed(path, 'an object of parts');
81
+ const unknown = Object.keys(value).find((name) => !PART_NAMES.includes(name));
82
+ if (unknown !== undefined)
83
+ malformed(`${path} ${unknown}`, NAMED_PARTS);
70
84
  const parts = {};
71
85
  if (value.fields !== undefined) {
72
- parts.fields = entries(value.fields, (item) => {
73
- if (!plain(item) || !Object.hasOwn(item, 'value') || !frontmatterValue(item.value)) {
74
- malformed();
86
+ parts.fields = entries(value.fields, `${path} fields`, (item, at) => {
87
+ if (!plain(item) || !Object.hasOwn(item, 'value') || !documentValue(item.value)) {
88
+ malformed(at, '{ value, base } with a document value');
75
89
  }
76
90
  return item.base === undefined
77
91
  ? { value: item.value }
78
- : { value: item.value, base: fieldValue(item.base) };
92
+ : { value: item.value, base: fieldValue(item.base, `${at}.base`) };
79
93
  });
80
94
  }
81
95
  if (value.sections !== undefined)
82
- parts.sections = entries(value.sections, textPart);
96
+ parts.sections = entries(value.sections, `${path} sections`, textPart);
83
97
  if (value.preamble !== undefined)
84
- parts.preamble = textPart(value.preamble);
98
+ parts.preamble = textPart(value.preamble, `${path} preamble`);
85
99
  if (value.markdown !== undefined)
86
- parts.markdown = textPart(value.markdown);
100
+ parts.markdown = textPart(value.markdown, `${path} markdown`);
87
101
  if (value.creation !== undefined)
88
- parts.creation = creationOf(value.creation);
102
+ parts.creation = creationOf(value.creation, `${path} creation`);
89
103
  if (value.move !== undefined) {
90
104
  if (!plain(value.move))
91
- malformed();
92
- const base = markdownBase(value.move.base);
93
- const room = optionalText(value.move.room);
105
+ malformed(`${path} move`, '{ to, room, base }');
106
+ const base = markdownBase(value.move.base, `${path} move.base`);
107
+ const room = optionalText(value.move.room, `${path} move.room`);
94
108
  parts.move = {
95
- to: text(value.move.to),
109
+ to: text(value.move.to, `${path} move.to`),
96
110
  ...(room === undefined ? {} : { room }),
97
111
  ...(base === undefined ? {} : { base }),
98
112
  };
99
113
  }
100
114
  if (value.removal !== undefined) {
101
115
  if (!plain(value.removal))
102
- malformed();
103
- const base = markdownBase(value.removal.base);
116
+ malformed(`${path} removal`, '{ base }');
117
+ const base = markdownBase(value.removal.base, `${path} removal.base`);
104
118
  parts.removal = base === undefined ? {} : { base };
105
119
  }
106
120
  if (value.file !== undefined) {
107
121
  if (!plain(value.file) || !(value.file.blob instanceof Blob))
108
- malformed();
122
+ malformed(`${path} file`, '{ blob, base } with a Blob');
109
123
  if (Object.keys(value).length > 1)
110
124
  throw runtimeError('room-draft-file-exclusive');
111
- const base = markdownBase(value.file.base);
125
+ const base = markdownBase(value.file.base, `${path} file.base`);
112
126
  parts.file = base === undefined ? { blob: value.file.blob } : { blob: value.file.blob, base };
113
127
  }
114
128
  return parts;
@@ -243,8 +257,10 @@ export function underneath(parts, path, visible) {
243
257
  const markdown = visible?.documents[path] ?? null;
244
258
  const document = visible?.collection.document(path);
245
259
  const report = {};
260
+ const unread = document?.type !== undefined &&
261
+ governing(visible.collection.composition, path).status === 'unavailable';
246
262
  const fields = {};
247
- for (const [name, part] of named(parts.fields)) {
263
+ for (const [name, part] of unread ? [] : named(parts.fields)) {
248
264
  const current = document !== undefined && Object.hasOwn(document.fields, name)
249
265
  ? { value: document.fields[name] }
250
266
  : null;
@@ -254,7 +270,7 @@ export function underneath(parts, path, visible) {
254
270
  if (Object.keys(fields).length > 0)
255
271
  report.fields = fields;
256
272
  const sections = {};
257
- for (const [name, part] of named(parts.sections)) {
273
+ for (const [name, part] of unread ? [] : named(parts.sections)) {
258
274
  const current = document !== undefined && Object.hasOwn(document.sections, name)
259
275
  ? document.sections[name]
260
276
  : null;
@@ -264,8 +280,9 @@ export function underneath(parts, path, visible) {
264
280
  if (Object.keys(sections).length > 0)
265
281
  report.sections = sections;
266
282
  const preamble = document?.preamble ?? null;
267
- if (parts.preamble !== undefined && preamble !== parts.preamble.base)
283
+ if (!unread && parts.preamble !== undefined && preamble !== parts.preamble.base) {
268
284
  report.preamble = preamble;
285
+ }
269
286
  if (parts.markdown !== undefined && markdown !== parts.markdown.base)
270
287
  report.markdown = markdown;
271
288
  if (parts.creation !== undefined && markdown !== null)
@@ -281,13 +298,12 @@ export function underneath(parts, path, visible) {
281
298
  }
282
299
  return report;
283
300
  }
284
- const UNTYPED_MEDIA_TYPE = 'application/octet-stream';
285
301
  export async function heldFile(blob, base) {
286
302
  return {
287
303
  localId: binaryLocalId(),
288
304
  ...(blob instanceof File ? { name: blob.name } : {}),
289
305
  byteLength: blob.size,
290
- mediaType: blob.type === '' ? UNTYPED_MEDIA_TYPE : blob.type,
306
+ mediaType: declaredType(blob),
291
307
  sha256: await sha256(blob),
292
308
  base,
293
309
  };
@@ -318,33 +334,45 @@ function joined(existing, returned) {
318
334
  merged[name] = part;
319
335
  return Object.keys(merged).length === 0 ? undefined : merged;
320
336
  }
321
- function ended(text) {
337
+ export function lineEnded(text) {
322
338
  return text === '' || text.endsWith('\n') ? text : `${text}\n`;
323
339
  }
324
- function frontmatterOf(fields) {
325
- const opened = parse('---\n---\n');
326
- if (!opened.ok)
327
- return malformed();
328
- const next = apply(opened.document, fields.map(([name, part]) => ({
329
- kind: 'field',
330
- name,
331
- value: part.value,
332
- prior: undefined,
333
- })));
334
- return next.outcome === 'applied' ? serialize(next.document) : malformed();
340
+ function written(start, changes, definition) {
341
+ const next = apply(start, changes, definition);
342
+ return next.outcome === 'applied' ? next.document : malformed();
343
+ }
344
+ function empty(definition) {
345
+ const parsed = parse('', '', definition);
346
+ return parsed.ok ? parsed.document : malformed();
335
347
  }
336
- export function partsAfter(markdown, parts) {
348
+ export function partsAfter(markdown, parts, definitions) {
337
349
  const fields = named(parts.fields);
350
+ const sections = named(parts.sections);
351
+ if (fields.length === 0 && sections.length === 0 && parts.preamble === undefined)
352
+ return markdown;
353
+ const whole = parse(markdown, '', definitions);
354
+ const type = whole.ok ? whole.document.type : undefined;
355
+ const definition = definitions?.(type);
356
+ if (type !== undefined && definition === undefined)
357
+ return null;
358
+ const valued = fields.length === 0
359
+ ? empty(definition)
360
+ : written(create(type, definition), fields.map(([name, part]) => ({
361
+ kind: 'field',
362
+ name,
363
+ value: part.value,
364
+ prior: undefined,
365
+ })), definition);
366
+ const head = parts.preamble === undefined
367
+ ? valued
368
+ : written(valued, [{ kind: 'preamble', value: lineEnded(parts.preamble.value), prior: valued.preamble }], definition);
338
369
  const pieces = [
339
- ...(fields.length === 0 ? [] : [frontmatterOf(fields)]),
340
- ...(parts.preamble === undefined ? [] : [parts.preamble.value]),
341
- ...named(parts.sections).map(([name, part]) => `## ${name}\n${part.value}`),
370
+ ...(fields.length === 0 && parts.preamble === undefined ? [] : [serialize(head)]),
371
+ ...sections.map(([name, part]) => serialize(written(empty(definition), [{ kind: 'section', name, value: lineEnded(part.value), prior: undefined }], definition))),
342
372
  ];
343
- if (pieces.length === 0)
344
- return markdown;
345
- return `${ended(markdown)}\n${pieces.map(ended).join('')}`;
373
+ return `${lineEnded(markdown)}\n${pieces.join('')}`;
346
374
  }
347
- export function returnedInto(existing, returned) {
375
+ export function returnedInto(existing, returned, definitions) {
348
376
  if (existing === undefined)
349
377
  return returned;
350
378
  const next = { ...existing };
@@ -364,7 +392,9 @@ export function returnedInto(existing, returned) {
364
392
  delete next.fields;
365
393
  delete next.sections;
366
394
  delete next.preamble;
367
- const value = partsAfter(whole.value, existing.markdown === undefined ? existing : returned);
395
+ const value = partsAfter(whole.value, existing.markdown === undefined ? existing : returned, definitions);
396
+ if (value === null)
397
+ return null;
368
398
  next.markdown = { value, base: whole.base };
369
399
  }
370
400
  const creation = existing.creation ?? returned.creation;
@@ -386,12 +416,13 @@ export function moveTarget(move) {
386
416
  return to === null || to === '' ? move.to : to;
387
417
  }
388
418
  export function readSavedParts(named) {
389
- const read = named.map(({ path, parts }) => ({ path, parts: readParts(parts) }));
390
- if (read.some(({ path }, at) => path === '' ||
391
- normalize(path) !== path ||
392
- read.findIndex((one) => one.path === path) !== at)) {
393
- throw runtimeError('room-draft-malformed');
394
- }
419
+ const read = named.map(({ path, parts }) => ({ path, parts: readParts(parts, path) }));
420
+ read.forEach(({ path }, at) => {
421
+ if (path === '' || normalize(path) !== path)
422
+ malformed(path, 'a path inside the Room, such as notes/a.md');
423
+ if (read.findIndex((one) => one.path === path) !== at)
424
+ malformed(path, 'each path once in one save');
425
+ });
395
426
  return read;
396
427
  }
397
428
  export function partsChanges(named) {
@@ -433,11 +464,11 @@ export function changesOf(path, parts) {
433
464
  bases.push({ kind: 'field', path, name, value: part.base?.value });
434
465
  }
435
466
  for (const [name, part] of named(parts.sections)) {
436
- changes.push({ kind: 'section', path, name, value: part.value });
467
+ changes.push({ kind: 'section', path, name, value: lineEnded(part.value) });
437
468
  bases.push({ kind: 'section', path, name, value: part.base });
438
469
  }
439
470
  if (parts.preamble !== undefined) {
440
- changes.push({ kind: 'preamble', path, value: parts.preamble.value });
471
+ changes.push({ kind: 'preamble', path, value: lineEnded(parts.preamble.value) });
441
472
  bases.push({ kind: 'preamble', path, value: parts.preamble.base });
442
473
  }
443
474
  if (parts.markdown !== undefined) {
@@ -461,35 +492,6 @@ export function changesOf(path, parts) {
461
492
  changes.push({ kind: 'remove', path });
462
493
  return { changes, bases };
463
494
  }
464
- function rebased(before, after) {
465
- return before === undefined ? after : { ...after, base: before.base };
466
- }
467
- function rebasedAll(before, after) {
468
- return {
469
- ...before,
470
- ...Object.fromEntries(Object.entries(after).map(([name, part]) => [name, rebased(before?.[name], part)])),
471
- };
472
- }
473
- export function joinedDraft(carried, saved) {
474
- const draft = saved.find((item) => item.path === carried.path);
475
- if (draft === undefined)
476
- return carried;
477
- const held = carried.parts;
478
- const next = draft.parts;
479
- return {
480
- path: carried.path,
481
- parts: {
482
- ...held,
483
- ...next,
484
- ...(next.fields === undefined ? {} : { fields: rebasedAll(held.fields, next.fields) }),
485
- ...(next.sections === undefined
486
- ? {}
487
- : { sections: rebasedAll(held.sections, next.sections) }),
488
- ...(next.preamble === undefined ? {} : { preamble: rebased(held.preamble, next.preamble) }),
489
- ...(next.markdown === undefined ? {} : { markdown: rebased(held.markdown, next.markdown) }),
490
- },
491
- };
492
- }
493
495
  export function withdrawnDrafts(drafts, changes) {
494
496
  return drafts.flatMap((draft) => {
495
497
  const file = draft.parts.file;
@@ -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"}
@@ -0,0 +1,217 @@
1
+ import { plain } from '@agentshouse/mdmodel';
2
+ import { changeSet } from './change-set.js';
3
+ import { collectionOf } from './collection.js';
4
+ import { runtimeError, uncaught } from './failure.js';
5
+ import { roomDraftRevision } from './identity.js';
6
+ import { normalize } from './paths.js';
7
+ import { slicing } from './replica.js';
8
+ import { binaryBase, gatheredParts, held, heldFile, readParts, staleWrite, underneath, } from './room-draft.js';
9
+ import { stepped } from './turn.js';
10
+ const ROOM_DRAFTS = 'room-drafts';
11
+ const presentationTopic = (app) => `presentation\u0000${app}`;
12
+ export async function visibleOf(store, locator, paths) {
13
+ const kept = await store.record(locator);
14
+ if (kept === undefined)
15
+ return undefined;
16
+ const local = await store.open();
17
+ const slice = await stepped(slicing(await local.entries(kept.key, 'visible', paths), paths));
18
+ return { ...slice, collection: collectionOf(slice.documents, store.composed(kept)) };
19
+ }
20
+ function roomDraftOf(record, visible) {
21
+ return structuredClone({
22
+ room: record.locator,
23
+ path: record.path,
24
+ revision: record.revision,
25
+ parts: record.parts,
26
+ changedUnderneath: underneath(record.parts, record.path, visible),
27
+ returned: record.returned,
28
+ });
29
+ }
30
+ async function roomDraftsOf(store, records) {
31
+ const rooms = new Map();
32
+ for (const record of records) {
33
+ const paths = rooms.get(record.locator) ?? [];
34
+ paths.push(record.path);
35
+ rooms.set(record.locator, paths);
36
+ }
37
+ const layers = new Map();
38
+ for (const [locator, paths] of rooms) {
39
+ layers.set(locator, await visibleOf(store, locator, paths));
40
+ }
41
+ return records.map((record) => roomDraftOf(record, layers.get(record.locator)));
42
+ }
43
+ function inOrder(records) {
44
+ return [...records].sort((left, right) => {
45
+ if (left.locator !== right.locator)
46
+ return left.locator < right.locator ? -1 : 1;
47
+ if (left.path !== right.path)
48
+ return left.path < right.path ? -1 : 1;
49
+ return 0;
50
+ });
51
+ }
52
+ async function snapshotRoomDrafts(store) {
53
+ return roomDraftsOf(store, inOrder(await store.drafts()));
54
+ }
55
+ export function publishRoomDrafts({ store, socket }, waitingOnly, touched = null) {
56
+ const unwatched = () => socket.closed() || store.watching(ROOM_DRAFTS).length === 0;
57
+ if (unwatched())
58
+ return Promise.resolve();
59
+ return store.publication(async () => {
60
+ if (unwatched())
61
+ return;
62
+ const records = await store.drafts();
63
+ if (socket.closed())
64
+ return;
65
+ if (touched !== null &&
66
+ !records.some((record) => touched.some(({ locator, path }) => locator === record.locator && (path === null || path === record.path)))) {
67
+ return;
68
+ }
69
+ const value = await roomDraftsOf(store, inOrder(records));
70
+ if (socket.closed())
71
+ return;
72
+ const answered = store.watching(ROOM_DRAFTS, waitingOnly ? 'waiting' : 'all');
73
+ for (const watcher of answered)
74
+ watcher.answer(value);
75
+ });
76
+ }
77
+ async function presentationOf(store, app) {
78
+ const value = await (await store.open()).presentation(app);
79
+ return value === undefined ? null : structuredClone(value);
80
+ }
81
+ export function emitPresentation({ store, socket }, app) {
82
+ const topic = presentationTopic(app);
83
+ const listening = () => store.watching(topic, 'ready');
84
+ if (socket.closed() || listening().length === 0)
85
+ return Promise.resolve();
86
+ return store.publication(async () => {
87
+ if (socket.closed() || listening().length === 0)
88
+ return;
89
+ const value = await presentationOf(store, app);
90
+ if (socket.closed())
91
+ return;
92
+ for (const watcher of listening())
93
+ watcher.answer(value);
94
+ });
95
+ }
96
+ async function writtenRoomDraft({ store }, room, path, revision, input, next) {
97
+ const parts = readParts(input, path);
98
+ if (path === '' || normalize(path) !== path)
99
+ throw runtimeError('room-draft-malformed', `room-draft-malformed at ${path}: a path inside the Room, such as notes/a.md`);
100
+ const local = await store.open();
101
+ const current = await store.draft(room, path);
102
+ if ((current?.revision ?? null) !== revision) {
103
+ return staleWrite(current === undefined ? null : (await roomDraftsOf(store, [current]))[0]);
104
+ }
105
+ const file = parts.file === undefined
106
+ ? undefined
107
+ : await heldFile(parts.file.blob, parts.file.base === undefined
108
+ ? binaryBase(await visibleOf(store, room, [path]), path)
109
+ : parts.file.base);
110
+ const record = {
111
+ locator: room,
112
+ path,
113
+ revision: next,
114
+ parts: held(current?.parts, parts, file),
115
+ returned: current?.returned ?? null,
116
+ };
117
+ await local.keepRoomDraft(record, parts.file === undefined || file === undefined
118
+ ? []
119
+ : [{ key: file.localId, blob: parts.file.blob }]);
120
+ await store.changed(changeSet(room, { drafts: [path] }));
121
+ return { outcome: 'written', roomDraft: (await roomDraftsOf(store, [record]))[0] };
122
+ }
123
+ async function keptPresentation({ store }, app, value) {
124
+ await (await store.open()).present({ app, value });
125
+ await store.changed(changeSet('', { presentation: app }));
126
+ }
127
+ export function roomDraftSurface(runtime) {
128
+ const { store } = runtime;
129
+ return {
130
+ list() {
131
+ return store
132
+ .exclusive(async () => {
133
+ await store.open();
134
+ return snapshotRoomDrafts(store);
135
+ })
136
+ .then((listed) => {
137
+ publishRoomDrafts(runtime, true);
138
+ return listed;
139
+ });
140
+ },
141
+ async read(room, path) {
142
+ const record = await store.draft(room, path);
143
+ return record === undefined ? null : (await roomDraftsOf(store, [record]))[0];
144
+ },
145
+ write(room, path, revision, input, next = roomDraftRevision()) {
146
+ if (typeof next !== 'string' || next === '')
147
+ return Promise.reject(runtimeError('room-draft-malformed'));
148
+ return store.gathered(`room-draft\u0000${room}\u0000${path}`, { revision, input, next }, (earlier, later) => {
149
+ if (later.revision !== earlier.next)
150
+ return null;
151
+ const parts = gatheredParts(earlier.input, later.input);
152
+ return parts === null
153
+ ? null
154
+ : { revision: earlier.revision, input: parts, next: later.next };
155
+ }, (written) => writtenRoomDraft(runtime, room, path, written.revision, written.input, written.next));
156
+ },
157
+ discard(room, path, revision) {
158
+ return store.exclusive(async () => {
159
+ const local = await store.open();
160
+ const current = await store.draft(room, path);
161
+ if (current === undefined || current.revision !== revision) {
162
+ return staleWrite(current === undefined ? null : (await roomDraftsOf(store, [current]))[0]);
163
+ }
164
+ await local.discardRoomDraft(room, path);
165
+ await store.changed(changeSet(room, { drafts: [path] }));
166
+ return { outcome: 'written', roomDraft: null };
167
+ });
168
+ },
169
+ };
170
+ }
171
+ export function presentationSurface(runtime) {
172
+ const { store } = runtime;
173
+ return {
174
+ read(app) {
175
+ return store.exclusive(() => presentationOf(store, app));
176
+ },
177
+ write(app, value) {
178
+ return store.exclusive(() => keptPresentation(runtime, app, structuredClone(value)));
179
+ },
180
+ edit(app, members) {
181
+ return store.gathered(`presentation\u0000${app}`, structuredClone(members), (earlier, later) => ({ ...earlier, ...later }), async (edited) => {
182
+ const kept = await (await store.open()).presentation(app);
183
+ await keptPresentation(runtime, app, Object.fromEntries([
184
+ ...Object.entries(plain(kept) ? kept : {}).filter(([member]) => !Object.hasOwn(edited, member)),
185
+ ...Object.entries(edited).filter(([, value]) => value !== null),
186
+ ]));
187
+ });
188
+ },
189
+ };
190
+ }
191
+ export function watchRoomDrafts({ store, socket }, deliver) {
192
+ const watcher = store.watch(ROOM_DRAFTS, deliver);
193
+ const unwatched = () => socket.closed() || !watcher.held();
194
+ void store
195
+ .exclusive(async () => {
196
+ await store.open();
197
+ })
198
+ .then(() => store.publication(async () => {
199
+ if (unwatched())
200
+ return;
201
+ const value = await snapshotRoomDrafts(store);
202
+ if (!unwatched())
203
+ watcher.answer(value);
204
+ }), uncaught);
205
+ return watcher.stop;
206
+ }
207
+ export function watchPresentation({ store, socket }, app, deliver) {
208
+ const watcher = store.watch(presentationTopic(app), deliver);
209
+ void store
210
+ .exclusive(async () => {
211
+ const value = await presentationOf(store, app);
212
+ if (!socket.closed() && watcher.held())
213
+ watcher.answer(value);
214
+ })
215
+ .catch(uncaught);
216
+ return watcher.stop;
217
+ }