@superbee/core 0.2.0-pre.3 → 0.2.0-pre.31

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 (538) hide show
  1. package/README.md +1084 -0
  2. package/dist/artifact-contract.d.ts +90 -0
  3. package/dist/artifact-contract.d.ts.map +1 -0
  4. package/dist/artifact-contract.js +205 -0
  5. package/dist/artifact-contract.js.map +1 -0
  6. package/dist/backend.d.ts +19 -1
  7. package/dist/backend.d.ts.map +1 -1
  8. package/dist/backend.js +83 -36
  9. package/dist/backend.js.map +1 -1
  10. package/dist/blob-contract.d.ts +80 -0
  11. package/dist/blob-contract.d.ts.map +1 -0
  12. package/dist/blob-contract.js +131 -0
  13. package/dist/blob-contract.js.map +1 -0
  14. package/dist/blob-journal.d.ts +302 -0
  15. package/dist/blob-journal.d.ts.map +1 -0
  16. package/dist/blob-journal.js +540 -0
  17. package/dist/blob-journal.js.map +1 -0
  18. package/dist/body-replace-guards.d.ts +52 -0
  19. package/dist/body-replace-guards.d.ts.map +1 -0
  20. package/dist/body-replace-guards.js +176 -0
  21. package/dist/body-replace-guards.js.map +1 -0
  22. package/dist/builtin-recipes/content.d.ts +93 -0
  23. package/dist/builtin-recipes/content.d.ts.map +1 -0
  24. package/dist/builtin-recipes/content.js +288 -0
  25. package/dist/builtin-recipes/content.js.map +1 -0
  26. package/dist/builtin-recipes.d.ts +10 -0
  27. package/dist/builtin-recipes.d.ts.map +1 -0
  28. package/dist/builtin-recipes.js +97 -0
  29. package/dist/builtin-recipes.js.map +1 -0
  30. package/dist/bundle-health/index.d.ts +14 -0
  31. package/dist/bundle-health/index.d.ts.map +1 -0
  32. package/dist/bundle-health/index.js +12 -0
  33. package/dist/bundle-health/index.js.map +1 -0
  34. package/dist/bundle-health/kind-findings.d.ts +44 -0
  35. package/dist/bundle-health/kind-findings.d.ts.map +1 -0
  36. package/dist/bundle-health/kind-findings.js +68 -0
  37. package/dist/bundle-health/kind-findings.js.map +1 -0
  38. package/dist/bundle-health/legacy-page.d.ts +39 -0
  39. package/dist/bundle-health/legacy-page.d.ts.map +1 -0
  40. package/dist/bundle-health/legacy-page.js +50 -0
  41. package/dist/bundle-health/legacy-page.js.map +1 -0
  42. package/dist/bundle-health/report.d.ts +202 -0
  43. package/dist/bundle-health/report.d.ts.map +1 -0
  44. package/dist/bundle-health/report.js +438 -0
  45. package/dist/bundle-health/report.js.map +1 -0
  46. package/dist/bundle-ops.d.ts +1 -1
  47. package/dist/bundle-ops.d.ts.map +1 -1
  48. package/dist/bundle-ops.js +2 -2
  49. package/dist/bundle-ops.js.map +1 -1
  50. package/dist/bundle.d.ts +2 -1
  51. package/dist/bundle.d.ts.map +1 -1
  52. package/dist/bundle.js +3 -3
  53. package/dist/bundle.js.map +1 -1
  54. package/dist/code-point-order.d.ts +8 -0
  55. package/dist/code-point-order.d.ts.map +1 -0
  56. package/dist/code-point-order.js +20 -0
  57. package/dist/code-point-order.js.map +1 -0
  58. package/dist/connector-request.d.ts +87 -0
  59. package/dist/connector-request.d.ts.map +1 -0
  60. package/dist/connector-request.js +370 -0
  61. package/dist/connector-request.js.map +1 -0
  62. package/dist/connectors.d.ts +262 -0
  63. package/dist/connectors.d.ts.map +1 -0
  64. package/dist/connectors.js +1179 -0
  65. package/dist/connectors.js.map +1 -0
  66. package/dist/cross-bundle.d.ts +135 -0
  67. package/dist/cross-bundle.d.ts.map +1 -0
  68. package/dist/cross-bundle.js +186 -0
  69. package/dist/cross-bundle.js.map +1 -0
  70. package/dist/dependencies.d.ts +94 -0
  71. package/dist/dependencies.d.ts.map +1 -0
  72. package/dist/dependencies.js +180 -0
  73. package/dist/dependencies.js.map +1 -0
  74. package/dist/document-codec.d.ts +5 -1
  75. package/dist/document-codec.d.ts.map +1 -1
  76. package/dist/document-codec.js +7 -4
  77. package/dist/document-codec.js.map +1 -1
  78. package/dist/document-field-actions.d.ts +31 -1
  79. package/dist/document-field-actions.d.ts.map +1 -1
  80. package/dist/document-field-actions.js +137 -34
  81. package/dist/document-field-actions.js.map +1 -1
  82. package/dist/document-mutation.d.ts +22 -10
  83. package/dist/document-mutation.d.ts.map +1 -1
  84. package/dist/document-mutation.js +61 -27
  85. package/dist/document-mutation.js.map +1 -1
  86. package/dist/document-write-policy.d.ts.map +1 -1
  87. package/dist/document-write-policy.js +4 -2
  88. package/dist/document-write-policy.js.map +1 -1
  89. package/dist/domain-model.d.ts +73 -0
  90. package/dist/domain-model.d.ts.map +1 -0
  91. package/dist/domain-model.js +169 -0
  92. package/dist/domain-model.js.map +1 -0
  93. package/dist/engine.d.ts +16 -8
  94. package/dist/engine.d.ts.map +1 -1
  95. package/dist/engine.js +42 -4
  96. package/dist/engine.js.map +1 -1
  97. package/dist/file-journaled-backend-internal.d.ts +21 -0
  98. package/dist/file-journaled-backend-internal.d.ts.map +1 -0
  99. package/dist/file-journaled-backend-internal.js +12 -0
  100. package/dist/file-journaled-backend-internal.js.map +1 -0
  101. package/dist/file-journaled-backend.d.ts +160 -0
  102. package/dist/file-journaled-backend.d.ts.map +1 -0
  103. package/dist/file-journaled-backend.js +1345 -0
  104. package/dist/file-journaled-backend.js.map +1 -0
  105. package/dist/filesystem-host.d.ts +15 -0
  106. package/dist/filesystem-host.d.ts.map +1 -0
  107. package/dist/filesystem-host.js +20 -0
  108. package/dist/filesystem-host.js.map +1 -0
  109. package/dist/filesystem-identity.d.ts +86 -4
  110. package/dist/filesystem-identity.d.ts.map +1 -1
  111. package/dist/filesystem-identity.js +338 -102
  112. package/dist/filesystem-identity.js.map +1 -1
  113. package/dist/filesystem-lock.d.ts +16 -3
  114. package/dist/filesystem-lock.d.ts.map +1 -1
  115. package/dist/filesystem-lock.js +323 -77
  116. package/dist/filesystem-lock.js.map +1 -1
  117. package/dist/filesystem-push-role.d.ts +77 -0
  118. package/dist/filesystem-push-role.d.ts.map +1 -0
  119. package/dist/filesystem-push-role.js +165 -0
  120. package/dist/filesystem-push-role.js.map +1 -0
  121. package/dist/filesystem.d.ts +17 -0
  122. package/dist/filesystem.d.ts.map +1 -0
  123. package/dist/filesystem.js +18 -0
  124. package/dist/filesystem.js.map +1 -0
  125. package/dist/governed-body-write.d.ts +106 -0
  126. package/dist/governed-body-write.d.ts.map +1 -0
  127. package/dist/governed-body-write.js +251 -0
  128. package/dist/governed-body-write.js.map +1 -0
  129. package/dist/host-policy-snapshot.d.ts +9 -0
  130. package/dist/host-policy-snapshot.d.ts.map +1 -0
  131. package/dist/host-policy-snapshot.js +33 -0
  132. package/dist/host-policy-snapshot.js.map +1 -0
  133. package/dist/host-text.d.ts +31 -0
  134. package/dist/host-text.d.ts.map +1 -0
  135. package/dist/host-text.js +77 -0
  136. package/dist/host-text.js.map +1 -0
  137. package/dist/hosted-client/binding.d.ts +7 -0
  138. package/dist/hosted-client/binding.d.ts.map +1 -0
  139. package/dist/hosted-client/binding.js +10 -0
  140. package/dist/hosted-client/binding.js.map +1 -0
  141. package/dist/hosted-client/blob-delivery.d.ts +67 -0
  142. package/dist/hosted-client/blob-delivery.d.ts.map +1 -0
  143. package/dist/hosted-client/blob-delivery.js +169 -0
  144. package/dist/hosted-client/blob-delivery.js.map +1 -0
  145. package/dist/hosted-client/blob-write.d.ts +386 -0
  146. package/dist/hosted-client/blob-write.d.ts.map +1 -0
  147. package/dist/hosted-client/blob-write.js +770 -0
  148. package/dist/hosted-client/blob-write.js.map +1 -0
  149. package/dist/hosted-client/bundle-listing.d.ts +46 -0
  150. package/dist/hosted-client/bundle-listing.d.ts.map +1 -0
  151. package/dist/hosted-client/bundle-listing.js +36 -0
  152. package/dist/hosted-client/bundle-listing.js.map +1 -0
  153. package/dist/hosted-client/client.d.ts +219 -0
  154. package/dist/hosted-client/client.d.ts.map +1 -0
  155. package/dist/hosted-client/client.js +309 -0
  156. package/dist/hosted-client/client.js.map +1 -0
  157. package/dist/hosted-client/directory.d.ts +46 -0
  158. package/dist/hosted-client/directory.d.ts.map +1 -0
  159. package/dist/hosted-client/directory.js +74 -0
  160. package/dist/hosted-client/directory.js.map +1 -0
  161. package/dist/hosted-client/errors.d.ts +26 -0
  162. package/dist/hosted-client/errors.d.ts.map +1 -0
  163. package/dist/hosted-client/errors.js +35 -0
  164. package/dist/hosted-client/errors.js.map +1 -0
  165. package/dist/hosted-client/inbox.d.ts +320 -0
  166. package/dist/hosted-client/inbox.d.ts.map +1 -0
  167. package/dist/hosted-client/inbox.js +379 -0
  168. package/dist/hosted-client/inbox.js.map +1 -0
  169. package/dist/hosted-client/index.d.ts +30 -0
  170. package/dist/hosted-client/index.d.ts.map +1 -0
  171. package/dist/hosted-client/index.js +32 -0
  172. package/dist/hosted-client/index.js.map +1 -0
  173. package/dist/hosted-client/journal.d.ts +103 -0
  174. package/dist/hosted-client/journal.d.ts.map +1 -0
  175. package/dist/hosted-client/journal.js +464 -0
  176. package/dist/hosted-client/journal.js.map +1 -0
  177. package/dist/hosted-client/node.d.ts +74 -0
  178. package/dist/hosted-client/node.d.ts.map +1 -0
  179. package/dist/hosted-client/node.js +219 -0
  180. package/dist/hosted-client/node.js.map +1 -0
  181. package/dist/hosted-client/reference.d.ts +12 -0
  182. package/dist/hosted-client/reference.d.ts.map +1 -0
  183. package/dist/hosted-client/reference.js +29 -0
  184. package/dist/hosted-client/reference.js.map +1 -0
  185. package/dist/hosted-client/write.d.ts +217 -0
  186. package/dist/hosted-client/write.d.ts.map +1 -0
  187. package/dist/hosted-client/write.js +418 -0
  188. package/dist/hosted-client/write.js.map +1 -0
  189. package/dist/hosted-transport/answer-rows.d.ts +243 -0
  190. package/dist/hosted-transport/answer-rows.d.ts.map +1 -0
  191. package/dist/hosted-transport/answer-rows.js +454 -0
  192. package/dist/hosted-transport/answer-rows.js.map +1 -0
  193. package/dist/hosted-transport/blob-reads.d.ts +35 -0
  194. package/dist/hosted-transport/blob-reads.d.ts.map +1 -0
  195. package/dist/hosted-transport/blob-reads.js +179 -0
  196. package/dist/hosted-transport/blob-reads.js.map +1 -0
  197. package/dist/hosted-transport/blob-write.d.ts +34 -0
  198. package/dist/hosted-transport/blob-write.d.ts.map +1 -0
  199. package/dist/hosted-transport/blob-write.js +115 -0
  200. package/dist/hosted-transport/blob-write.js.map +1 -0
  201. package/dist/hosted-transport/carrier.d.ts +151 -0
  202. package/dist/hosted-transport/carrier.d.ts.map +1 -0
  203. package/dist/hosted-transport/carrier.js +260 -0
  204. package/dist/hosted-transport/carrier.js.map +1 -0
  205. package/dist/hosted-transport/history-pages.d.ts +55 -0
  206. package/dist/hosted-transport/history-pages.d.ts.map +1 -0
  207. package/dist/hosted-transport/history-pages.js +69 -0
  208. package/dist/hosted-transport/history-pages.js.map +1 -0
  209. package/dist/hosted-transport/index.d.ts +18 -0
  210. package/dist/hosted-transport/index.d.ts.map +1 -0
  211. package/dist/hosted-transport/index.js +18 -0
  212. package/dist/hosted-transport/index.js.map +1 -0
  213. package/dist/hosted-transport/operations.d.ts +85 -0
  214. package/dist/hosted-transport/operations.d.ts.map +1 -0
  215. package/dist/hosted-transport/operations.js +128 -0
  216. package/dist/hosted-transport/operations.js.map +1 -0
  217. package/dist/hosted-transport/paged-reads.d.ts +87 -0
  218. package/dist/hosted-transport/paged-reads.d.ts.map +1 -0
  219. package/dist/hosted-transport/paged-reads.js +238 -0
  220. package/dist/hosted-transport/paged-reads.js.map +1 -0
  221. package/dist/hosted-transport/read-adapter.d.ts +256 -0
  222. package/dist/hosted-transport/read-adapter.d.ts.map +1 -0
  223. package/dist/hosted-transport/read-adapter.js +568 -0
  224. package/dist/hosted-transport/read-adapter.js.map +1 -0
  225. package/dist/hosted-transport/root-write.d.ts +114 -0
  226. package/dist/hosted-transport/root-write.d.ts.map +1 -0
  227. package/dist/hosted-transport/root-write.js +171 -0
  228. package/dist/hosted-transport/root-write.js.map +1 -0
  229. package/dist/hosted-transport/whole-document-transport.d.ts +204 -0
  230. package/dist/hosted-transport/whole-document-transport.d.ts.map +1 -0
  231. package/dist/hosted-transport/whole-document-transport.js +447 -0
  232. package/dist/hosted-transport/whole-document-transport.js.map +1 -0
  233. package/dist/index.d.ts +34 -10
  234. package/dist/index.d.ts.map +1 -1
  235. package/dist/index.js +26 -8
  236. package/dist/index.js.map +1 -1
  237. package/dist/indexeddb-backend.d.ts +28 -37
  238. package/dist/indexeddb-backend.d.ts.map +1 -1
  239. package/dist/indexeddb-backend.js +467 -113
  240. package/dist/indexeddb-backend.js.map +1 -1
  241. package/dist/journaled-backend.d.ts +232 -15
  242. package/dist/journaled-backend.d.ts.map +1 -1
  243. package/dist/journaled-backend.js +254 -55
  244. package/dist/journaled-backend.js.map +1 -1
  245. package/dist/kind-authoring.d.ts +170 -0
  246. package/dist/kind-authoring.d.ts.map +1 -0
  247. package/dist/kind-authoring.js +451 -0
  248. package/dist/kind-authoring.js.map +1 -0
  249. package/dist/kind-conformance-error.d.ts +15 -0
  250. package/dist/kind-conformance-error.d.ts.map +1 -0
  251. package/dist/kind-conformance-error.js +20 -0
  252. package/dist/kind-conformance-error.js.map +1 -0
  253. package/dist/kind-coverage.d.ts +99 -0
  254. package/dist/kind-coverage.d.ts.map +1 -0
  255. package/dist/kind-coverage.js +186 -0
  256. package/dist/kind-coverage.js.map +1 -0
  257. package/dist/kind-field-mutation.d.ts +4 -0
  258. package/dist/kind-field-mutation.d.ts.map +1 -1
  259. package/dist/kind-field-mutation.js +28 -3
  260. package/dist/kind-field-mutation.js.map +1 -1
  261. package/dist/kinds-load.js +4 -4
  262. package/dist/kinds-load.js.map +1 -1
  263. package/dist/kinds.d.ts +65 -2
  264. package/dist/kinds.d.ts.map +1 -1
  265. package/dist/kinds.js +341 -21
  266. package/dist/kinds.js.map +1 -1
  267. package/dist/link-types.d.ts +26 -0
  268. package/dist/link-types.d.ts.map +1 -0
  269. package/dist/link-types.js +57 -0
  270. package/dist/link-types.js.map +1 -0
  271. package/dist/links.d.ts +21 -3
  272. package/dist/links.d.ts.map +1 -1
  273. package/dist/links.js +213 -14
  274. package/dist/links.js.map +1 -1
  275. package/dist/managed-document-metadata.d.ts +2 -0
  276. package/dist/managed-document-metadata.d.ts.map +1 -0
  277. package/dist/managed-document-metadata.js +9 -0
  278. package/dist/managed-document-metadata.js.map +1 -0
  279. package/dist/memory-backend.d.ts.map +1 -1
  280. package/dist/memory-backend.js +6 -2
  281. package/dist/memory-backend.js.map +1 -1
  282. package/dist/paths.d.ts +16 -0
  283. package/dist/paths.d.ts.map +1 -1
  284. package/dist/paths.js +25 -0
  285. package/dist/paths.js.map +1 -1
  286. package/dist/platform.d.ts +13 -2
  287. package/dist/platform.d.ts.map +1 -1
  288. package/dist/platform.js +16 -0
  289. package/dist/platform.js.map +1 -1
  290. package/dist/portable-export.d.ts +119 -0
  291. package/dist/portable-export.d.ts.map +1 -0
  292. package/dist/portable-export.js +501 -0
  293. package/dist/portable-export.js.map +1 -0
  294. package/dist/publication-filesystem.d.ts +1 -1
  295. package/dist/publication-filesystem.d.ts.map +1 -1
  296. package/dist/publication-filesystem.js +1 -1
  297. package/dist/publication-filesystem.js.map +1 -1
  298. package/dist/qualified-links.d.ts +67 -0
  299. package/dist/qualified-links.d.ts.map +1 -0
  300. package/dist/qualified-links.js +117 -0
  301. package/dist/qualified-links.js.map +1 -0
  302. package/dist/query-filter.d.ts +16 -2
  303. package/dist/query-filter.d.ts.map +1 -1
  304. package/dist/query-filter.js +40 -1
  305. package/dist/query-filter.js.map +1 -1
  306. package/dist/query-order.d.ts +22 -0
  307. package/dist/query-order.d.ts.map +1 -0
  308. package/dist/query-order.js +42 -0
  309. package/dist/query-order.js.map +1 -0
  310. package/dist/recipe-lifecycle/errors.d.ts +96 -0
  311. package/dist/recipe-lifecycle/errors.d.ts.map +1 -0
  312. package/dist/recipe-lifecycle/errors.js +122 -0
  313. package/dist/recipe-lifecycle/errors.js.map +1 -0
  314. package/dist/recipe-lifecycle/evolution.d.ts +112 -0
  315. package/dist/recipe-lifecycle/evolution.d.ts.map +1 -0
  316. package/dist/recipe-lifecycle/evolution.js +941 -0
  317. package/dist/recipe-lifecycle/evolution.js.map +1 -0
  318. package/dist/recipe-lifecycle/index.d.ts +30 -0
  319. package/dist/recipe-lifecycle/index.d.ts.map +1 -0
  320. package/dist/recipe-lifecycle/index.js +26 -0
  321. package/dist/recipe-lifecycle/index.js.map +1 -0
  322. package/dist/recipe-lifecycle/install.d.ts +155 -0
  323. package/dist/recipe-lifecycle/install.d.ts.map +1 -0
  324. package/dist/recipe-lifecycle/install.js +594 -0
  325. package/dist/recipe-lifecycle/install.js.map +1 -0
  326. package/dist/recipe-lifecycle/legacy-aliases.d.ts +16 -0
  327. package/dist/recipe-lifecycle/legacy-aliases.d.ts.map +1 -0
  328. package/dist/recipe-lifecycle/legacy-aliases.js +51 -0
  329. package/dist/recipe-lifecycle/legacy-aliases.js.map +1 -0
  330. package/dist/recipe-lifecycle/stamp.d.ts +151 -0
  331. package/dist/recipe-lifecycle/stamp.d.ts.map +1 -0
  332. package/dist/recipe-lifecycle/stamp.js +364 -0
  333. package/dist/recipe-lifecycle/stamp.js.map +1 -0
  334. package/dist/recipe-set-preflight.d.ts +139 -0
  335. package/dist/recipe-set-preflight.d.ts.map +1 -0
  336. package/dist/recipe-set-preflight.js +536 -0
  337. package/dist/recipe-set-preflight.js.map +1 -0
  338. package/dist/recipes.d.ts +29 -1
  339. package/dist/recipes.d.ts.map +1 -1
  340. package/dist/recipes.js +137 -1
  341. package/dist/recipes.js.map +1 -1
  342. package/dist/record-overlay/apply.d.ts +43 -0
  343. package/dist/record-overlay/apply.d.ts.map +1 -0
  344. package/dist/record-overlay/apply.js +527 -0
  345. package/dist/record-overlay/apply.js.map +1 -0
  346. package/dist/record-overlay/canonical.d.ts +22 -0
  347. package/dist/record-overlay/canonical.d.ts.map +1 -0
  348. package/dist/record-overlay/canonical.js +47 -0
  349. package/dist/record-overlay/canonical.js.map +1 -0
  350. package/dist/record-overlay/digest.d.ts +4 -0
  351. package/dist/record-overlay/digest.d.ts.map +1 -0
  352. package/dist/record-overlay/digest.js +11 -0
  353. package/dist/record-overlay/digest.js.map +1 -0
  354. package/dist/record-overlay/errors.d.ts +44 -0
  355. package/dist/record-overlay/errors.d.ts.map +1 -0
  356. package/dist/record-overlay/errors.js +55 -0
  357. package/dist/record-overlay/errors.js.map +1 -0
  358. package/dist/record-overlay/findings.d.ts +5 -0
  359. package/dist/record-overlay/findings.d.ts.map +1 -0
  360. package/dist/record-overlay/findings.js +83 -0
  361. package/dist/record-overlay/findings.js.map +1 -0
  362. package/dist/record-overlay/index.d.ts +23 -0
  363. package/dist/record-overlay/index.d.ts.map +1 -0
  364. package/dist/record-overlay/index.js +21 -0
  365. package/dist/record-overlay/index.js.map +1 -0
  366. package/dist/record-overlay/plan.d.ts +12 -0
  367. package/dist/record-overlay/plan.d.ts.map +1 -0
  368. package/dist/record-overlay/plan.js +285 -0
  369. package/dist/record-overlay/plan.js.map +1 -0
  370. package/dist/record-overlay/policy.d.ts +69 -0
  371. package/dist/record-overlay/policy.d.ts.map +1 -0
  372. package/dist/record-overlay/policy.js +228 -0
  373. package/dist/record-overlay/policy.js.map +1 -0
  374. package/dist/record-overlay/redact.d.ts +3 -0
  375. package/dist/record-overlay/redact.d.ts.map +1 -0
  376. package/dist/record-overlay/redact.js +27 -0
  377. package/dist/record-overlay/redact.js.map +1 -0
  378. package/dist/record-overlay/signal-kind.d.ts +30 -0
  379. package/dist/record-overlay/signal-kind.d.ts.map +1 -0
  380. package/dist/record-overlay/signal-kind.js +38 -0
  381. package/dist/record-overlay/signal-kind.js.map +1 -0
  382. package/dist/record-overlay/signal-text.d.ts +45 -0
  383. package/dist/record-overlay/signal-text.d.ts.map +1 -0
  384. package/dist/record-overlay/signal-text.js +116 -0
  385. package/dist/record-overlay/signal-text.js.map +1 -0
  386. package/dist/record-overlay/source-index.d.ts +19 -0
  387. package/dist/record-overlay/source-index.d.ts.map +1 -0
  388. package/dist/record-overlay/source-index.js +102 -0
  389. package/dist/record-overlay/source-index.js.map +1 -0
  390. package/dist/record-overlay/types.d.ts +291 -0
  391. package/dist/record-overlay/types.d.ts.map +1 -0
  392. package/dist/record-overlay/types.js +2 -0
  393. package/dist/record-overlay/types.js.map +1 -0
  394. package/dist/remote-backend.d.ts +67 -67
  395. package/dist/remote-backend.d.ts.map +1 -1
  396. package/dist/remote-backend.js +168 -201
  397. package/dist/remote-backend.js.map +1 -1
  398. package/dist/remote-document-codec.d.ts +2 -1
  399. package/dist/remote-document-codec.d.ts.map +1 -1
  400. package/dist/remote-document-codec.js +3 -2
  401. package/dist/remote-document-codec.js.map +1 -1
  402. package/dist/remote-error.d.ts +38 -0
  403. package/dist/remote-error.d.ts.map +1 -0
  404. package/dist/remote-error.js +59 -0
  405. package/dist/remote-error.js.map +1 -0
  406. package/dist/remote-operations.d.ts +0 -40
  407. package/dist/remote-operations.d.ts.map +1 -1
  408. package/dist/remote-operations.js +26 -6
  409. package/dist/remote-operations.js.map +1 -1
  410. package/dist/remote-parsers.d.ts +86 -0
  411. package/dist/remote-parsers.d.ts.map +1 -0
  412. package/dist/remote-parsers.js +181 -0
  413. package/dist/remote-parsers.js.map +1 -0
  414. package/dist/remote.d.ts +5 -2
  415. package/dist/remote.d.ts.map +1 -1
  416. package/dist/remote.js +5 -1
  417. package/dist/remote.js.map +1 -1
  418. package/dist/search/backend-source.d.ts +6 -0
  419. package/dist/search/backend-source.d.ts.map +1 -0
  420. package/dist/search/backend-source.js +33 -0
  421. package/dist/search/backend-source.js.map +1 -0
  422. package/dist/search/contract.d.ts +151 -0
  423. package/dist/search/contract.d.ts.map +1 -0
  424. package/dist/search/contract.js +78 -0
  425. package/dist/search/contract.js.map +1 -0
  426. package/dist/search/errors.d.ts +30 -0
  427. package/dist/search/errors.d.ts.map +1 -0
  428. package/dist/search/errors.js +50 -0
  429. package/dist/search/errors.js.map +1 -0
  430. package/dist/search/identity.d.ts +12 -0
  431. package/dist/search/identity.d.ts.map +1 -0
  432. package/dist/search/identity.js +90 -0
  433. package/dist/search/identity.js.map +1 -0
  434. package/dist/search/index.d.ts +16 -0
  435. package/dist/search/index.d.ts.map +1 -0
  436. package/dist/search/index.js +15 -0
  437. package/dist/search/index.js.map +1 -0
  438. package/dist/search/memory-source.d.ts +36 -0
  439. package/dist/search/memory-source.d.ts.map +1 -0
  440. package/dist/search/memory-source.js +235 -0
  441. package/dist/search/memory-source.js.map +1 -0
  442. package/dist/search/rank.d.ts +34 -0
  443. package/dist/search/rank.d.ts.map +1 -0
  444. package/dist/search/rank.js +129 -0
  445. package/dist/search/rank.js.map +1 -0
  446. package/dist/search/row-text.d.ts +38 -0
  447. package/dist/search/row-text.d.ts.map +1 -0
  448. package/dist/search/row-text.js +88 -0
  449. package/dist/search/row-text.js.map +1 -0
  450. package/dist/search/search.d.ts +28 -0
  451. package/dist/search/search.d.ts.map +1 -0
  452. package/dist/search/search.js +257 -0
  453. package/dist/search/search.js.map +1 -0
  454. package/dist/search/source.d.ts +67 -0
  455. package/dist/search/source.d.ts.map +1 -0
  456. package/dist/search/source.js +2 -0
  457. package/dist/search/source.js.map +1 -0
  458. package/dist/search/text.d.ts +47 -0
  459. package/dist/search/text.d.ts.map +1 -0
  460. package/dist/search/text.js +150 -0
  461. package/dist/search/text.js.map +1 -0
  462. package/dist/site-capabilities.d.ts +345 -0
  463. package/dist/site-capabilities.d.ts.map +1 -0
  464. package/dist/site-capabilities.js +724 -0
  465. package/dist/site-capabilities.js.map +1 -0
  466. package/dist/source-engine/guard.d.ts +78 -0
  467. package/dist/source-engine/guard.d.ts.map +1 -0
  468. package/dist/source-engine/guard.js +423 -0
  469. package/dist/source-engine/guard.js.map +1 -0
  470. package/dist/source-engine/index.d.ts +26 -0
  471. package/dist/source-engine/index.d.ts.map +1 -0
  472. package/dist/source-engine/index.js +21 -0
  473. package/dist/source-engine/index.js.map +1 -0
  474. package/dist/source-engine/machine-state.d.ts +74 -0
  475. package/dist/source-engine/machine-state.d.ts.map +1 -0
  476. package/dist/source-engine/machine-state.js +48 -0
  477. package/dist/source-engine/machine-state.js.map +1 -0
  478. package/dist/source-engine/observe.d.ts +18 -0
  479. package/dist/source-engine/observe.d.ts.map +1 -0
  480. package/dist/source-engine/observe.js +620 -0
  481. package/dist/source-engine/observe.js.map +1 -0
  482. package/dist/source-engine/overlay.d.ts +49 -0
  483. package/dist/source-engine/overlay.d.ts.map +1 -0
  484. package/dist/source-engine/overlay.js +114 -0
  485. package/dist/source-engine/overlay.js.map +1 -0
  486. package/dist/source-engine/robots.d.ts +53 -0
  487. package/dist/source-engine/robots.d.ts.map +1 -0
  488. package/dist/source-engine/robots.js +158 -0
  489. package/dist/source-engine/robots.js.map +1 -0
  490. package/dist/source-engine/types.d.ts +287 -0
  491. package/dist/source-engine/types.d.ts.map +1 -0
  492. package/dist/source-engine/types.js +2 -0
  493. package/dist/source-engine/types.js.map +1 -0
  494. package/dist/source-harness/conformance.d.ts +16 -0
  495. package/dist/source-harness/conformance.d.ts.map +1 -0
  496. package/dist/source-harness/conformance.js +266 -0
  497. package/dist/source-harness/conformance.js.map +1 -0
  498. package/dist/source-harness/fixture.d.ts +95 -0
  499. package/dist/source-harness/fixture.d.ts.map +1 -0
  500. package/dist/source-harness/fixture.js +273 -0
  501. package/dist/source-harness/fixture.js.map +1 -0
  502. package/dist/source-harness/index.d.ts +22 -0
  503. package/dist/source-harness/index.d.ts.map +1 -0
  504. package/dist/source-harness/index.js +19 -0
  505. package/dist/source-harness/index.js.map +1 -0
  506. package/dist/source-harness/peer.d.ts +74 -0
  507. package/dist/source-harness/peer.d.ts.map +1 -0
  508. package/dist/source-harness/peer.js +106 -0
  509. package/dist/source-harness/peer.js.map +1 -0
  510. package/dist/source-profiles/index.d.ts +31 -0
  511. package/dist/source-profiles/index.d.ts.map +1 -0
  512. package/dist/source-profiles/index.js +206 -0
  513. package/dist/source-profiles/index.js.map +1 -0
  514. package/dist/source-profiles/link-header.d.ts +6 -0
  515. package/dist/source-profiles/link-header.d.ts.map +1 -0
  516. package/dist/source-profiles/link-header.js +131 -0
  517. package/dist/source-profiles/link-header.js.map +1 -0
  518. package/dist/storage.d.ts +6 -2
  519. package/dist/storage.d.ts.map +1 -1
  520. package/dist/storage.js +4 -1
  521. package/dist/storage.js.map +1 -1
  522. package/dist/types.d.ts +38 -5
  523. package/dist/types.d.ts.map +1 -1
  524. package/dist/types.js +0 -10
  525. package/dist/types.js.map +1 -1
  526. package/dist/uncertain-write.d.ts +161 -19
  527. package/dist/uncertain-write.d.ts.map +1 -1
  528. package/dist/uncertain-write.js +90 -31
  529. package/dist/uncertain-write.js.map +1 -1
  530. package/dist/versioning.d.ts +9 -4
  531. package/dist/versioning.d.ts.map +1 -1
  532. package/dist/versioning.js +9 -4
  533. package/dist/versioning.js.map +1 -1
  534. package/dist/write-identity.d.ts +5 -0
  535. package/dist/write-identity.d.ts.map +1 -0
  536. package/dist/write-identity.js +9 -0
  537. package/dist/write-identity.js.map +1 -0
  538. package/package.json +107 -2
@@ -1,3 +1,4 @@
1
+ import { captureNewDocumentIntent } from "./journaled-backend.js";
1
2
  /**
2
3
  * IndexedDB-backed {@link JournaledBackend}: the browser-local working copy's first persistent
3
4
  * store candidate, sitting behind the same core seam as {@link FilesystemBackend} and
@@ -32,7 +33,7 @@
32
33
  import { resolveContentType } from "./content-type.js";
33
34
  import { MalformedDocumentError, parseMarkdown, stringifyDoc } from "./frontmatter.js";
34
35
  import { mutationActorFromFrontmatter } from "./mutation-attribution.js";
35
- import { assertJournalResolutionOptions, assertJournalSnapshot, IntentHoldConflict, IntentStateConflict, } from "./journaled-backend.js";
36
+ import { assertDeletionIntent, deletionIntentRecord, JournalSnapshotConflict, assertJournalGuard, assertJournalIntentChanges, assertJournalMetaChanges, assertMetaWrite, captureJournalGuardOption, captureJournalDeleteOptions, captureJournalWriteOptions, captureIntentUpdate, captureMetaWrite, captureJournalValue, captureRetireAcknowledged, JournalGuardConflict, assertJournalResolutionOptions, assertJournalSnapshot, IntentHoldConflict, IntentStateConflict, } from "./journaled-backend.js";
36
37
  import { assertSafeBlobKey, assertSafeConceptId, assertSafeReservedDir, assertSafeReservedFilename, compareStorageKeys, pathFromConceptId } from "./paths.js";
37
38
  import { parseLeadingFrontmatter } from "./portable-frontmatter.js";
38
39
  import { blobVersion, defaultActor, VersionConflict, versionOfBytes } from "./versioning.js";
@@ -105,12 +106,31 @@ function editionOf(index) {
105
106
  throw error;
106
107
  }
107
108
  }
109
+ /**
110
+ * One listing row from a stored record: the frontmatter is what `readWithJournal` parses for
111
+ * the record under `edition` (the split takes the body as a substring it never parses), or
112
+ * `null` with the parser's error when the leading block does not parse.
113
+ */
114
+ function headOf(record, intents, meta, edition) {
115
+ const head = { id: record.id, version: record.version, updatedBy: record.updatedBy, updatedAt: record.updatedAt, raw: record.raw, intents, meta };
116
+ let frontmatter;
117
+ try {
118
+ frontmatter = parseMarkdown(record.raw, pathFromConceptId(record.id), { okfVersion: edition }).frontmatter;
119
+ }
120
+ catch (error) {
121
+ if (!(error instanceof MalformedDocumentError))
122
+ throw error;
123
+ return { ...head, frontmatter: null, malformed: error };
124
+ }
125
+ return { ...head, frontmatter };
126
+ }
108
127
  /**
109
128
  * A persistent browser-local OKF store implementing the {@link JournaledBackend} contract over
110
129
  * IndexedDB. One instance per bundle per JavaScript realm; several instances over the same
111
130
  * database name are peers whose conditional writes are serialized by the database.
112
131
  */
113
132
  export class IndexedDbBackend {
133
+ journalSnapshotCas = true;
114
134
  /**
115
135
  * What a resolved write promises: the IndexedDB transaction reported `complete`. Whether the
116
136
  * committed pages survive power loss is the browser's and the operating system's decision.
@@ -251,9 +271,47 @@ export class IndexedDbBackend {
251
271
  * report the transaction's AbortError and the cause would be lost.
252
272
  */
253
273
  async #transact(stores, mode, body) {
254
- const db = await this.#open();
274
+ // Starting a transaction throws synchronously on a handle closed between the open resolving
275
+ // and this line, which is what a `close()` issued in the same turn as an in-flight call
276
+ // produces. `close()` promises that the next operation reopens lazily, and the cold path gets
277
+ // that for free by joining the next open; this is the warm equivalent. Retrying is safe here
278
+ // and only here: the throw means no transaction exists, so nothing was attempted and the
279
+ // retry cannot repeat work. A second failure is the host's own answer and propagates, which
280
+ // is also what a genuinely bad store name does after one wasted reopen.
281
+ let db = await this.#open();
282
+ let transaction;
283
+ try {
284
+ transaction = db.transaction(stores, mode);
285
+ }
286
+ catch (firstFailure) {
287
+ if (this.#db === db)
288
+ this.close();
289
+ db = await this.#open();
290
+ try {
291
+ transaction = db.transaction(stores, mode);
292
+ }
293
+ catch (retryFailure) {
294
+ // The retry's failure is what the caller acts on. When the two differ the first one was
295
+ // never about a closed handle, so it is the more informative of the pair and is kept as
296
+ // the cause rather than discarded.
297
+ const failure = asError(retryFailure);
298
+ if (failure !== firstFailure && failure.cause == null) {
299
+ // Attaching a cause is a convenience and is never worth replacing the host's own error.
300
+ // This error belongs to the host, which may hand back a frozen one or one whose `cause`
301
+ // is a getter; assigning to either throws in strict mode, and that TypeError would reach
302
+ // the caller in place of the real failure.
303
+ try {
304
+ failure.cause = firstFailure;
305
+ }
306
+ catch {
307
+ // Surface the host's error exactly as it came.
308
+ }
309
+ }
310
+ throw failure;
311
+ }
312
+ }
255
313
  return new Promise((resolve, reject) => {
256
- const tx = db.transaction(stores, mode);
314
+ const tx = transaction;
257
315
  let result = null;
258
316
  let failure = null;
259
317
  tx.oncomplete = () => {
@@ -481,6 +539,54 @@ export class IndexedDbBackend {
481
539
  // pending-change record and no record exists for an edit that never committed. Settling an
482
540
  // intent is a compare-and-swap on the intent's own `state`, so a stale realm cannot settle
483
541
  // an intent another realm already settled.
542
+ /**
543
+ * Remove acknowledged intents of one target and named meta rows in one transaction, after
544
+ * comparing the target's full guard in that same transaction.
545
+ */
546
+ async retireAcknowledged(target, options) {
547
+ assertSafeConceptId(target);
548
+ const { guard: expected, requestIds, removeMeta } = captureRetireAcknowledged(target, options);
549
+ await this.#transact([DOCUMENTS, INTENTS, META], "readwrite", (tx, done, fail, guard) => {
550
+ this.#checkJournalGuard(tx, expected, () => {
551
+ for (const requestId of requestIds) {
552
+ const removal = tx.objectStore(INTENTS).delete(requestId);
553
+ removal.onerror = () => fail(requestError(removal, `IndexedDB intent retirement failed for '${requestId}'`));
554
+ }
555
+ for (const key of removeMeta ?? []) {
556
+ const removal = tx.objectStore(META).delete(key);
557
+ removal.onerror = () => fail(requestError(removal, `IndexedDB meta delete failed for '${key}'`));
558
+ }
559
+ done(undefined);
560
+ }, fail, guard);
561
+ });
562
+ }
563
+ /** Read and compare a complete guard inside its caller's still-active transaction. */
564
+ #checkJournalGuard(tx, expected, next, fail, guard) {
565
+ if (expected === undefined) {
566
+ next();
567
+ return;
568
+ }
569
+ const current = { target: expected.target, document: null, intents: [], meta: [] };
570
+ let pending = 2 + expected.meta.length;
571
+ const finish = () => { if (--pending === 0) {
572
+ assertJournalGuard(expected, current);
573
+ next();
574
+ } };
575
+ const read = (request, accept) => {
576
+ request.onerror = () => fail(requestError(request, "IndexedDB journal guard read failed"));
577
+ request.onsuccess = guard(() => { accept(request.result); finish(); });
578
+ };
579
+ read(tx.objectStore(DOCUMENTS).get(expected.target), value => {
580
+ const row = value;
581
+ current.document = row ? { version: row.version, raw: row.raw } : null;
582
+ });
583
+ read(tx.objectStore(INTENTS).getAll(), value => { current.intents = value.filter(row => row.target === expected.target); });
584
+ for (const entry of expected.meta)
585
+ read(tx.objectStore(META).get(entry.key), value => {
586
+ const row = value;
587
+ current.meta.push({ key: entry.key, expected: row === undefined ? { present: false } : { present: true, value: row.value } });
588
+ });
589
+ }
484
590
  /**
485
591
  * One transaction over documents, intents, and meta: the document compare-and-swap of
486
592
  * {@link write}, plus (optionally) deleting a superseded intent, recording a new intent for
@@ -491,15 +597,27 @@ export class IndexedDbBackend {
491
597
  * {@link IntentHoldConflict} before the document is touched.
492
598
  */
493
599
  async writeJournaled(id, doc, options = {}) {
600
+ const snapshotGuard = captureJournalGuardOption(options, id);
601
+ if (snapshotGuard !== undefined) {
602
+ options = captureJournalWriteOptions(options);
603
+ doc = captureJournalValue(doc);
604
+ }
494
605
  assertSafeConceptId(id);
495
606
  assertJournalResolutionOptions(id, options);
607
+ if (options.intent)
608
+ options = { ...options, intent: captureNewDocumentIntent(options.intent) };
496
609
  const raw = stringifyDoc(doc.frontmatter, doc.body ?? "");
497
610
  const version = versionOfBytes(raw);
611
+ if (snapshotGuard && (doc.id !== id || (options.intent && options.intent.target !== id)))
612
+ throw new JournalGuardConflict(id);
613
+ const suppliedMeta = typeof options.meta === "function" ? options.meta({ version, raw }) : options.meta;
614
+ assertJournalMetaChanges(snapshotGuard, suppliedMeta ?? [], options.removeMeta);
615
+ options = structuredClone({ ...options, meta: suppliedMeta, ...(snapshotGuard ? { guard: snapshotGuard } : {}) });
498
616
  const updatedBy = options.actor?.trim() || defaultActor();
499
617
  const now = new Date().toISOString();
500
618
  const expected = options.expectedVersion;
501
619
  const { intent, supersede, requireSettled } = options;
502
- const meta = typeof options.meta === "function" ? options.meta({ version, raw }) : options.meta;
620
+ const meta = options.meta;
503
621
  return this.#transact([DOCUMENTS, INTENTS, META], "readwrite", (tx, done, fail, guard) => {
504
622
  const documents = tx.objectStore(DOCUMENTS);
505
623
  const intents = tx.objectStore(INTENTS);
@@ -513,6 +631,10 @@ export class IndexedDbBackend {
513
631
  const put = metaStore.put(row);
514
632
  put.onerror = () => fail(requestError(put, `IndexedDB meta write failed for '${row.key}'`));
515
633
  }
634
+ for (const key of options.removeMeta ?? []) {
635
+ const remove = metaStore.delete(key);
636
+ remove.onerror = () => fail(requestError(remove, `IndexedDB meta delete failed for '${key}'`));
637
+ }
516
638
  };
517
639
  const recordIntent = () => {
518
640
  if (!intent) {
@@ -569,31 +691,55 @@ export class IndexedDbBackend {
569
691
  removeSuperseded();
570
692
  });
571
693
  };
572
- if (options.resolveIntents) {
573
- request(intents.getAll(), "resolution snapshot", (rows) => {
574
- assertJournalSnapshot(id, options.resolveIntents.expected, rows, intent?.requestId);
575
- for (const row of options.resolveIntents.expected) {
576
- const removal = intents.delete(row.requestId);
577
- removal.onerror = () => fail(requestError(removal, "IndexedDB resolution delete failed"));
694
+ const apply = () => {
695
+ if (options.resolveIntents) {
696
+ request(intents.getAll(), "resolution snapshot", (rows) => {
697
+ assertJournalSnapshot(id, options.resolveIntents.expected, rows, intent?.requestId);
698
+ for (const row of options.resolveIntents.expected) {
699
+ const removal = intents.delete(row.requestId);
700
+ removal.onerror = () => fail(requestError(removal, "IndexedDB resolution delete failed"));
701
+ }
702
+ writeDocument();
703
+ });
704
+ return;
705
+ }
706
+ if (!requireSettled) {
707
+ writeDocument();
708
+ return;
709
+ }
710
+ // The journal has no target index; this scan shares the write's transaction.
711
+ request(intents.getAll(), "intent scan", (rows) => {
712
+ const holder = rows.find((row) => row.target === id && row.state !== "acknowledged");
713
+ if (holder) {
714
+ fail(new IntentHoldConflict(id, holder.requestId, holder.state));
715
+ return;
578
716
  }
579
717
  writeDocument();
580
718
  });
581
- return;
582
- }
583
- if (!requireSettled) {
584
- writeDocument();
585
- return;
586
- }
587
- // The journal has no index by target, so the hold check scans it; the scan runs inside
588
- // this transaction, which is what makes the answer hold for the write that follows.
589
- request(intents.getAll(), "intent scan", (rows) => {
590
- const holder = rows.find((row) => row.target === id && row.state !== "acknowledged");
591
- if (holder) {
592
- fail(new IntentHoldConflict(id, holder.requestId, holder.state));
719
+ };
720
+ const checkIdentities = () => {
721
+ if (!snapshotGuard) {
722
+ apply();
593
723
  return;
594
724
  }
595
- writeDocument();
596
- });
725
+ const checkSuperseded = (existingIdentity) => {
726
+ if (!supersede) {
727
+ assertJournalIntentChanges(snapshotGuard, existingIdentity, undefined);
728
+ apply();
729
+ return;
730
+ }
731
+ request(intents.get(supersede.requestId), "superseded identity read", row => {
732
+ assertJournalIntentChanges(snapshotGuard, existingIdentity, row);
733
+ apply();
734
+ });
735
+ };
736
+ if (!intent) {
737
+ checkSuperseded(undefined);
738
+ return;
739
+ }
740
+ request(intents.get(intent.requestId), "new identity read", row => checkSuperseded(row));
741
+ };
742
+ this.#checkJournalGuard(tx, snapshotGuard, checkIdentities, fail, guard);
597
743
  });
598
744
  }
599
745
  /**
@@ -606,85 +752,138 @@ export class IndexedDbBackend {
606
752
  * with `false` even under a compare-and-swap.
607
753
  */
608
754
  async deleteJournaled(id, options = {}) {
755
+ options = captureJournalDeleteOptions(id, options);
609
756
  assertSafeConceptId(id);
610
757
  assertJournalResolutionOptions(id, options);
758
+ assertDeletionIntent(id, options);
611
759
  const expected = options.expectedVersion;
612
760
  const { requireSettled, onHeld } = options;
613
761
  const puts = options.meta ?? [];
614
762
  const removals = options.removeMeta ?? [];
763
+ const intent = options.intent ? structuredClone(options.intent) : undefined;
764
+ const supersede = options.supersede ? { ...options.supersede } : undefined;
765
+ const now = new Date().toISOString();
615
766
  return this.#transact([DOCUMENTS, INTENTS, META], "readwrite", (tx, done, fail, guard) => {
616
- const documents = tx.objectStore(DOCUMENTS);
617
- const intents = tx.objectStore(INTENTS);
618
- const metaStore = tx.objectStore(META);
619
- const request = (req, label, next) => {
620
- req.onerror = () => fail(requestError(req, `IndexedDB ${label} failed for '${id}'`));
621
- req.onsuccess = guard(() => next(req.result));
622
- };
623
- const putMeta = (rows) => {
624
- for (const row of rows) {
625
- const put = metaStore.put(row);
626
- put.onerror = () => fail(requestError(put, `IndexedDB meta write failed for '${row.key}'`));
627
- }
628
- };
629
- const applyMeta = () => {
630
- putMeta(puts);
631
- for (const key of removals) {
632
- const removal = metaStore.delete(key);
633
- removal.onerror = () => fail(requestError(removal, `IndexedDB meta delete failed for '${key}'`));
634
- }
635
- };
636
- const deleteDocument = () => {
637
- request(documents.get(id), "read", (current) => {
638
- const record = current;
639
- if (options.resolveIntents && expected !== (record?.version ?? null)) {
640
- fail(new VersionConflict(id, expected, record?.version ?? null));
641
- return;
767
+ this.#checkJournalGuard(tx, options.guard, () => {
768
+ const documents = tx.objectStore(DOCUMENTS);
769
+ const intents = tx.objectStore(INTENTS);
770
+ const metaStore = tx.objectStore(META);
771
+ const request = (req, label, next) => {
772
+ req.onerror = () => fail(requestError(req, `IndexedDB ${label} failed for '${id}'`));
773
+ req.onsuccess = guard(() => next(req.result));
774
+ };
775
+ const putMeta = (rows) => {
776
+ for (const row of rows) {
777
+ const put = metaStore.put(row);
778
+ put.onerror = () => fail(requestError(put, `IndexedDB meta write failed for '${row.key}'`));
779
+ }
780
+ };
781
+ const applyMeta = () => {
782
+ putMeta(puts);
783
+ for (const key of removals) {
784
+ const removal = metaStore.delete(key);
785
+ removal.onerror = () => fail(requestError(removal, `IndexedDB meta delete failed for '${key}'`));
642
786
  }
643
- if (!record) {
787
+ };
788
+ // The superseded intent and the recorded deletion intent, in the same transaction as the
789
+ // deletion and its meta rows, as `writeJournaled` records a write's.
790
+ const journal = (outcome) => {
791
+ const record = (sequence) => {
792
+ if (!intent) {
793
+ applyMeta();
794
+ done({ outcome });
795
+ return;
796
+ }
797
+ const row = deletionIntentRecord(intent, sequence, now);
798
+ const counter = metaStore.put({ key: INTENT_SEQUENCE_KEY, value: sequence });
799
+ counter.onerror = () => fail(requestError(counter, "IndexedDB sequence write failed"));
800
+ const put = intents.put(row);
801
+ put.onerror = () => fail(requestError(put, `IndexedDB intent write failed for '${row.requestId}'`));
644
802
  applyMeta();
645
- done({ outcome: "absent" });
803
+ done({ outcome, intent: row });
804
+ };
805
+ const next = () => {
806
+ if (!intent) {
807
+ record(0);
808
+ return;
809
+ }
810
+ request(intents.get(intent.requestId), "intent read", (taken) => {
811
+ if (taken !== undefined) {
812
+ fail(new JournalSnapshotConflict(id));
813
+ return;
814
+ }
815
+ request(metaStore.get(INTENT_SEQUENCE_KEY), "sequence read", (current) => {
816
+ const previous = current?.value;
817
+ record((typeof previous === "number" ? previous : 0) + 1);
818
+ });
819
+ });
820
+ };
821
+ if (!supersede) {
822
+ next();
646
823
  return;
647
824
  }
648
- if (expected !== undefined && expected !== record.version) {
649
- fail(new VersionConflict(id, expected, record.version));
825
+ request(intents.get(supersede.requestId), "intent read", (current) => {
826
+ const existing = current;
827
+ if (!existing || existing.target !== id || existing.state !== supersede.expectedState || existing.attempts !== supersede.expectedAttempts) {
828
+ fail(new IntentStateConflict(supersede.requestId, supersede.expectedState, existing?.state ?? null));
829
+ return;
830
+ }
831
+ const removal = intents.delete(supersede.requestId);
832
+ removal.onerror = () => fail(requestError(removal, `IndexedDB intent delete failed for '${supersede.requestId}'`));
833
+ next();
834
+ });
835
+ };
836
+ const deleteDocument = () => {
837
+ request(documents.get(id), "read", (current) => {
838
+ const record = current;
839
+ if (options.resolveIntents && expected !== (record?.version ?? null)) {
840
+ fail(new VersionConflict(id, expected, record?.version ?? null));
841
+ return;
842
+ }
843
+ if (!record) {
844
+ journal("absent");
845
+ return;
846
+ }
847
+ if (expected !== undefined && expected !== record.version) {
848
+ fail(new VersionConflict(id, expected, record.version));
849
+ return;
850
+ }
851
+ const removal = documents.delete(id);
852
+ removal.onerror = () => fail(requestError(removal, `IndexedDB delete failed for '${id}'`));
853
+ journal("deleted");
854
+ });
855
+ };
856
+ if (options.resolveIntents) {
857
+ request(intents.getAll(), "resolution snapshot", (rows) => {
858
+ assertJournalSnapshot(id, options.resolveIntents.expected, rows, intent?.requestId);
859
+ for (const row of options.resolveIntents.expected) {
860
+ const removal = intents.delete(row.requestId);
861
+ removal.onerror = () => fail(requestError(removal, "IndexedDB resolution delete failed"));
862
+ }
863
+ deleteDocument();
864
+ });
865
+ return;
866
+ }
867
+ if (!requireSettled) {
868
+ deleteDocument();
869
+ return;
870
+ }
871
+ // The same in-transaction hold scan as `writeJournaled`: the answer holds for the deletion
872
+ // that follows, and for the `onHeld` rows put in its place.
873
+ request(intents.getAll(), "intent scan", (rows) => {
874
+ const holder = rows.find((row) => row.target === id && row.state !== "acknowledged");
875
+ if (holder) {
876
+ if (!onHeld) {
877
+ fail(new IntentHoldConflict(id, holder.requestId, holder.state));
878
+ return;
879
+ }
880
+ putMeta(onHeld.meta);
881
+ done({ outcome: "held", requestId: holder.requestId, state: holder.state });
650
882
  return;
651
883
  }
652
- const removal = documents.delete(id);
653
- removal.onerror = () => fail(requestError(removal, `IndexedDB delete failed for '${id}'`));
654
- applyMeta();
655
- done({ outcome: "deleted" });
656
- });
657
- };
658
- if (options.resolveIntents) {
659
- request(intents.getAll(), "resolution snapshot", (rows) => {
660
- assertJournalSnapshot(id, options.resolveIntents.expected, rows);
661
- for (const row of options.resolveIntents.expected) {
662
- const removal = intents.delete(row.requestId);
663
- removal.onerror = () => fail(requestError(removal, "IndexedDB resolution delete failed"));
664
- }
665
884
  deleteDocument();
666
885
  });
667
- return;
668
- }
669
- if (!requireSettled) {
670
- deleteDocument();
671
- return;
672
- }
673
- // The same in-transaction hold scan as `writeJournaled`: the answer holds for the deletion
674
- // that follows, and for the `onHeld` rows put in its place.
675
- request(intents.getAll(), "intent scan", (rows) => {
676
- const holder = rows.find((row) => row.target === id && row.state !== "acknowledged");
677
- if (holder) {
678
- if (!onHeld) {
679
- fail(new IntentHoldConflict(id, holder.requestId, holder.state));
680
- return;
681
- }
682
- putMeta(onHeld.meta);
683
- done({ outcome: "held", requestId: holder.requestId, state: holder.state });
684
- return;
685
- }
686
- deleteDocument();
687
- });
886
+ }, fail, guard);
688
887
  });
689
888
  }
690
889
  /**
@@ -740,6 +939,132 @@ export class IndexedDbBackend {
740
939
  const { frontmatter, body } = parseMarkdown(record.raw, pathFromConceptId(id), { okfVersion: editionOf(index) });
741
940
  return { document: { doc: { id, frontmatter, body }, version: record.version }, raw: record.raw, intents: rows, meta };
742
941
  }
942
+ /**
943
+ * Every document's head with its intents and the meta rows named for it, from ONE readonly
944
+ * transaction over documents, reserved, intents, and meta: {@link readWithJournal} over the
945
+ * whole store. The root index, the journal (grouped by target, since it has no index by
946
+ * target) and the `shared` keys are read once, then the documents are walked by cursor, each
947
+ * row's own keys read with it, so a caller's `project` sees one record at a time and the
948
+ * listing holds only what it keeps plus the journal it read up front, intents' content
949
+ * included. The frontmatter is the one `readWithJournal` would parse
950
+ * for the record, under the edition the root index declared at this moment; the body is
951
+ * never parsed. Rows come back in `list` order.
952
+ */
953
+ async readHeads(options = {}) {
954
+ const keysOf = options.meta ?? (() => []);
955
+ const sharedKeys = [...new Set(options.shared ?? [])];
956
+ const project = options.project ?? ((head) => head);
957
+ const rows = await this.#transact([DOCUMENTS, RESERVED, INTENTS, META], "readonly", (tx, done, fail, guard) => {
958
+ const out = [];
959
+ let edition;
960
+ const byTarget = new Map();
961
+ const shared = new Map();
962
+ // Rows still being assembled, plus one for the cursor walk itself; the listing is done
963
+ // when the walk has ended and every row's meta reads have landed.
964
+ let outstanding = 1;
965
+ const finish = () => {
966
+ if (--outstanding === 0)
967
+ done(out);
968
+ };
969
+ // A parse or projection failure aborts the transaction through `fail`; after it no
970
+ // request is placed and no request's own error is reported, so the caller's error is
971
+ // the rejection, not the aborted transaction's refusal of the requests still in flight.
972
+ let stopped = false;
973
+ const stop = (error) => {
974
+ if (stopped)
975
+ return;
976
+ stopped = true;
977
+ fail(error);
978
+ };
979
+ const metaStore = tx.objectStore(META);
980
+ const readMeta = (key, into, then) => {
981
+ const request = metaStore.get(key);
982
+ request.onerror = () => stop(requestError(request, `IndexedDB meta read failed for '${key}'`));
983
+ request.onsuccess = guard(() => {
984
+ const row = request.result;
985
+ if (row !== undefined)
986
+ into.set(key, row.value);
987
+ then();
988
+ });
989
+ };
990
+ const walk = () => {
991
+ const cursor = tx.objectStore(DOCUMENTS).openCursor();
992
+ cursor.onerror = () => stop(requestError(cursor, "IndexedDB document scan failed"));
993
+ cursor.onsuccess = guard(() => {
994
+ const current = cursor.result;
995
+ if (!current) {
996
+ finish();
997
+ return;
998
+ }
999
+ const record = current.value;
1000
+ const intents = byTarget.get(record.id) ?? [];
1001
+ const keys = [...new Set(keysOf(record.id, intents))].filter((key) => !shared.has(key) && !sharedKeys.includes(key));
1002
+ const meta = new Map(shared);
1003
+ let pending = keys.length;
1004
+ outstanding += 1;
1005
+ const complete = () => {
1006
+ try {
1007
+ out.push({ id: record.id, row: project(headOf(record, intents, meta, edition)) });
1008
+ }
1009
+ catch (error) {
1010
+ stop(asError(error));
1011
+ return;
1012
+ }
1013
+ finish();
1014
+ };
1015
+ if (pending === 0)
1016
+ complete();
1017
+ else {
1018
+ for (const key of keys) {
1019
+ readMeta(key, meta, () => {
1020
+ if (--pending === 0)
1021
+ complete();
1022
+ });
1023
+ }
1024
+ }
1025
+ if (!stopped)
1026
+ current.continue();
1027
+ });
1028
+ };
1029
+ const readShared = () => {
1030
+ let pending = sharedKeys.length;
1031
+ if (pending === 0) {
1032
+ walk();
1033
+ return;
1034
+ }
1035
+ for (const key of sharedKeys) {
1036
+ readMeta(key, shared, () => {
1037
+ if (--pending === 0)
1038
+ walk();
1039
+ });
1040
+ }
1041
+ };
1042
+ // The index, the journal and the shared rows land before the walk starts, so every row
1043
+ // is built under one edition and sees its whole journal, whatever order the host
1044
+ // answers requests in.
1045
+ const rootIndex = tx.objectStore(RESERVED).get(reservedKey("", "index.md"));
1046
+ rootIndex.onerror = () => stop(requestError(rootIndex, "IndexedDB root index read failed"));
1047
+ rootIndex.onsuccess = guard(() => {
1048
+ edition = editionOf(rootIndex.result);
1049
+ const scan = tx.objectStore(INTENTS).getAll();
1050
+ scan.onerror = () => stop(requestError(scan, "IndexedDB journal scan failed"));
1051
+ scan.onsuccess = guard(() => {
1052
+ for (const row of scan.result) {
1053
+ const list = byTarget.get(row.target);
1054
+ if (list)
1055
+ list.push(row);
1056
+ else
1057
+ byTarget.set(row.target, [row]);
1058
+ }
1059
+ for (const list of byTarget.values())
1060
+ list.sort((a, b) => a.sequence - b.sequence);
1061
+ readShared();
1062
+ });
1063
+ });
1064
+ });
1065
+ rows.sort((a, b) => compareStorageKeys(a.id, b.id));
1066
+ return rows.map((entry) => entry.row);
1067
+ }
743
1068
  /** Intents in local commit order, optionally restricted to one or more states. */
744
1069
  async listIntents(state) {
745
1070
  const wanted = state === undefined ? null : new Set(typeof state === "string" ? [state] : state);
@@ -760,38 +1085,67 @@ export class IndexedDbBackend {
760
1085
  * missing record rejects with {@link IntentStateConflict} and writes nothing.
761
1086
  */
762
1087
  async updateIntent(requestId, expectedState, patch, options = {}) {
1088
+ ({ patch, options } = captureIntentUpdate(patch, options));
763
1089
  const now = new Date().toISOString();
764
- return this.#transact([INTENTS, META], "readwrite", (tx, done, fail, guard) => {
765
- const intents = tx.objectStore(INTENTS);
766
- const read = intents.get(requestId);
767
- read.onerror = () => fail(requestError(read, `IndexedDB intent read failed for '${requestId}'`));
768
- read.onsuccess = guard(() => {
769
- const current = read.result;
770
- if (!current || current.state !== expectedState) {
771
- fail(new IntentStateConflict(requestId, expectedState, current?.state ?? null));
772
- return;
773
- }
774
- const next = { ...current, ...patch, requestId, sequence: current.sequence, updatedAt: now };
775
- const put = intents.put(next);
776
- put.onerror = () => fail(requestError(put, `IndexedDB intent write failed for '${requestId}'`));
777
- const metaStore = tx.objectStore(META);
778
- for (const row of options.meta ?? []) {
779
- const metaPut = metaStore.put(row);
780
- metaPut.onerror = () => fail(requestError(metaPut, `IndexedDB meta write failed for '${row.key}'`));
781
- }
782
- done(next);
783
- });
1090
+ const raw = options.document ? stringifyDoc(options.document.frontmatter, options.document.body ?? "") : undefined;
1091
+ const replacement = raw === undefined ? undefined : { id: options.document.id, raw, version: versionOfBytes(raw), updatedBy: defaultActor(), updatedAt: now };
1092
+ return this.#transact([DOCUMENTS, INTENTS, META], "readwrite", (tx, done, fail, guard) => {
1093
+ this.#checkJournalGuard(tx, options.guard, () => {
1094
+ const intents = tx.objectStore(INTENTS);
1095
+ const read = intents.get(requestId);
1096
+ read.onerror = () => fail(requestError(read, `IndexedDB intent read failed for '${requestId}'`));
1097
+ read.onsuccess = guard(() => {
1098
+ const current = read.result;
1099
+ if (!current || current.state !== expectedState) {
1100
+ fail(new IntentStateConflict(requestId, expectedState, current?.state ?? null));
1101
+ return;
1102
+ }
1103
+ if (options.guard && current.target !== options.guard.target)
1104
+ throw new JournalGuardConflict(current.target);
1105
+ const next = { ...current, ...patch, requestId, sequence: current.sequence, updatedAt: now };
1106
+ if (replacement) {
1107
+ const write = tx.objectStore(DOCUMENTS).put(replacement);
1108
+ write.onerror = () => fail(requestError(write, "IndexedDB replacement write failed"));
1109
+ }
1110
+ const put = intents.put(next);
1111
+ put.onerror = () => fail(requestError(put, `IndexedDB intent write failed for '${requestId}'`));
1112
+ const metaStore = tx.objectStore(META);
1113
+ for (const row of options.meta ?? []) {
1114
+ const metaPut = metaStore.put(row);
1115
+ metaPut.onerror = () => fail(requestError(metaPut, `IndexedDB meta write failed for '${row.key}'`));
1116
+ }
1117
+ done(next);
1118
+ });
1119
+ }, fail, guard);
784
1120
  });
785
1121
  }
786
1122
  async readMeta(key) {
787
1123
  const row = await this.#getOne(META, key);
788
1124
  return row === undefined ? undefined : row.value;
789
1125
  }
790
- async writeMeta(key, value) {
791
- await this.#transact(META, "readwrite", (tx, done, fail) => {
792
- const put = tx.objectStore(META).put({ key, value });
793
- put.onerror = () => fail(requestError(put, `IndexedDB meta write failed for '${key}'`));
794
- done(undefined);
1126
+ async writeMeta(key, value, options = {}) {
1127
+ options = captureMetaWrite(options);
1128
+ value = options.expected !== undefined || options.requireEmptyJournal ? captureJournalValue(value) : structuredClone(value);
1129
+ await this.#transact([INTENTS, META], "readwrite", (tx, done, fail, guard) => {
1130
+ const meta = tx.objectStore(META);
1131
+ const read = meta.get(key);
1132
+ read.onerror = () => fail(requestError(read, "IndexedDB admission read failed"));
1133
+ read.onsuccess = guard(() => {
1134
+ const row = read.result;
1135
+ const finish = (intents) => {
1136
+ assertMetaWrite(key, options, row === undefined ? { present: false } : { present: true, value: row.value }, intents);
1137
+ const put = meta.put({ key, value });
1138
+ put.onerror = () => fail(requestError(put, `IndexedDB meta write failed for '${key}'`));
1139
+ done(undefined);
1140
+ };
1141
+ if (!options.requireEmptyJournal) {
1142
+ finish([]);
1143
+ return;
1144
+ }
1145
+ const scan = tx.objectStore(INTENTS).getAll();
1146
+ scan.onerror = () => fail(requestError(scan, "IndexedDB admission journal scan failed"));
1147
+ scan.onsuccess = guard(() => finish(scan.result));
1148
+ });
795
1149
  });
796
1150
  }
797
1151
  // ── blobs ──────────────────────────────────────────────────────────────────────────────