@superbee/core 0.2.0-pre.4 → 0.2.0-pre.40

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 (612) hide show
  1. package/README.md +1209 -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 +22 -2
  7. package/dist/backend.d.ts.map +1 -1
  8. package/dist/backend.js +153 -38
  9. package/dist/backend.js.map +1 -1
  10. package/dist/blob-contract.d.ts +82 -0
  11. package/dist/blob-contract.d.ts.map +1 -0
  12. package/dist/blob-contract.js +134 -0
  13. package/dist/blob-contract.js.map +1 -0
  14. package/dist/blob-journal.d.ts +303 -0
  15. package/dist/blob-journal.d.ts.map +1 -0
  16. package/dist/blob-journal.js +541 -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 +207 -0
  43. package/dist/bundle-health/report.d.ts.map +1 -0
  44. package/dist/bundle-health/report.js +454 -0
  45. package/dist/bundle-health/report.js.map +1 -0
  46. package/dist/bundle-ops.d.ts +3 -2
  47. package/dist/bundle-ops.d.ts.map +1 -1
  48. package/dist/bundle-ops.js +4 -4
  49. package/dist/bundle-ops.js.map +1 -1
  50. package/dist/bundle.d.ts +3 -4
  51. package/dist/bundle.d.ts.map +1 -1
  52. package/dist/bundle.js +5 -14
  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/code-unit-order.d.ts +15 -0
  59. package/dist/code-unit-order.d.ts.map +1 -0
  60. package/dist/code-unit-order.js +17 -0
  61. package/dist/code-unit-order.js.map +1 -0
  62. package/dist/connector-request.d.ts +112 -0
  63. package/dist/connector-request.d.ts.map +1 -0
  64. package/dist/connector-request.js +495 -0
  65. package/dist/connector-request.js.map +1 -0
  66. package/dist/connectors.d.ts +297 -0
  67. package/dist/connectors.d.ts.map +1 -0
  68. package/dist/connectors.js +1233 -0
  69. package/dist/connectors.js.map +1 -0
  70. package/dist/cross-bundle.d.ts +135 -0
  71. package/dist/cross-bundle.d.ts.map +1 -0
  72. package/dist/cross-bundle.js +191 -0
  73. package/dist/cross-bundle.js.map +1 -0
  74. package/dist/dependencies.d.ts +94 -0
  75. package/dist/dependencies.d.ts.map +1 -0
  76. package/dist/dependencies.js +180 -0
  77. package/dist/dependencies.js.map +1 -0
  78. package/dist/document-codec.d.ts +7 -2
  79. package/dist/document-codec.d.ts.map +1 -1
  80. package/dist/document-codec.js +8 -5
  81. package/dist/document-codec.js.map +1 -1
  82. package/dist/document-field-actions.d.ts +31 -1
  83. package/dist/document-field-actions.d.ts.map +1 -1
  84. package/dist/document-field-actions.js +137 -34
  85. package/dist/document-field-actions.js.map +1 -1
  86. package/dist/document-mutation.d.ts +35 -13
  87. package/dist/document-mutation.d.ts.map +1 -1
  88. package/dist/document-mutation.js +124 -60
  89. package/dist/document-mutation.js.map +1 -1
  90. package/dist/document-transfer.d.ts +208 -0
  91. package/dist/document-transfer.d.ts.map +1 -0
  92. package/dist/document-transfer.js +928 -0
  93. package/dist/document-transfer.js.map +1 -0
  94. package/dist/document-write-policy.d.ts.map +1 -1
  95. package/dist/document-write-policy.js +4 -2
  96. package/dist/document-write-policy.js.map +1 -1
  97. package/dist/domain-model.d.ts +73 -0
  98. package/dist/domain-model.d.ts.map +1 -0
  99. package/dist/domain-model.js +169 -0
  100. package/dist/domain-model.js.map +1 -0
  101. package/dist/engine.d.ts +21 -9
  102. package/dist/engine.d.ts.map +1 -1
  103. package/dist/engine.js +72 -14
  104. package/dist/engine.js.map +1 -1
  105. package/dist/file-journaled-backend-internal.d.ts +21 -0
  106. package/dist/file-journaled-backend-internal.d.ts.map +1 -0
  107. package/dist/file-journaled-backend-internal.js +12 -0
  108. package/dist/file-journaled-backend-internal.js.map +1 -0
  109. package/dist/file-journaled-backend.d.ts +160 -0
  110. package/dist/file-journaled-backend.d.ts.map +1 -0
  111. package/dist/file-journaled-backend.js +1345 -0
  112. package/dist/file-journaled-backend.js.map +1 -0
  113. package/dist/filesystem-host.d.ts +15 -0
  114. package/dist/filesystem-host.d.ts.map +1 -0
  115. package/dist/filesystem-host.js +20 -0
  116. package/dist/filesystem-host.js.map +1 -0
  117. package/dist/filesystem-identity.d.ts +97 -21
  118. package/dist/filesystem-identity.d.ts.map +1 -1
  119. package/dist/filesystem-identity.js +398 -119
  120. package/dist/filesystem-identity.js.map +1 -1
  121. package/dist/filesystem-lock.d.ts +16 -3
  122. package/dist/filesystem-lock.d.ts.map +1 -1
  123. package/dist/filesystem-lock.js +323 -77
  124. package/dist/filesystem-lock.js.map +1 -1
  125. package/dist/filesystem-push-role.d.ts +77 -0
  126. package/dist/filesystem-push-role.d.ts.map +1 -0
  127. package/dist/filesystem-push-role.js +165 -0
  128. package/dist/filesystem-push-role.js.map +1 -0
  129. package/dist/filesystem.d.ts +17 -0
  130. package/dist/filesystem.d.ts.map +1 -0
  131. package/dist/filesystem.js +18 -0
  132. package/dist/filesystem.js.map +1 -0
  133. package/dist/frontmatter.d.ts +8 -6
  134. package/dist/frontmatter.d.ts.map +1 -1
  135. package/dist/frontmatter.js +5 -4
  136. package/dist/frontmatter.js.map +1 -1
  137. package/dist/governed-body-write.d.ts +8 -1
  138. package/dist/governed-body-write.d.ts.map +1 -1
  139. package/dist/governed-body-write.js +9 -2
  140. package/dist/governed-body-write.js.map +1 -1
  141. package/dist/heads-digest.d.ts.map +1 -1
  142. package/dist/heads-digest.js +2 -1
  143. package/dist/heads-digest.js.map +1 -1
  144. package/dist/host-policy-snapshot.d.ts +9 -0
  145. package/dist/host-policy-snapshot.d.ts.map +1 -0
  146. package/dist/host-policy-snapshot.js +33 -0
  147. package/dist/host-policy-snapshot.js.map +1 -0
  148. package/dist/host-text.d.ts +31 -0
  149. package/dist/host-text.d.ts.map +1 -0
  150. package/dist/host-text.js +77 -0
  151. package/dist/host-text.js.map +1 -0
  152. package/dist/hosted-client/binding.d.ts +7 -0
  153. package/dist/hosted-client/binding.d.ts.map +1 -0
  154. package/dist/hosted-client/binding.js +10 -0
  155. package/dist/hosted-client/binding.js.map +1 -0
  156. package/dist/hosted-client/blob-delivery.d.ts +68 -0
  157. package/dist/hosted-client/blob-delivery.d.ts.map +1 -0
  158. package/dist/hosted-client/blob-delivery.js +170 -0
  159. package/dist/hosted-client/blob-delivery.js.map +1 -0
  160. package/dist/hosted-client/blob-write.d.ts +387 -0
  161. package/dist/hosted-client/blob-write.d.ts.map +1 -0
  162. package/dist/hosted-client/blob-write.js +770 -0
  163. package/dist/hosted-client/blob-write.js.map +1 -0
  164. package/dist/hosted-client/bundle-listing.d.ts +46 -0
  165. package/dist/hosted-client/bundle-listing.d.ts.map +1 -0
  166. package/dist/hosted-client/bundle-listing.js +36 -0
  167. package/dist/hosted-client/bundle-listing.js.map +1 -0
  168. package/dist/hosted-client/client.d.ts +219 -0
  169. package/dist/hosted-client/client.d.ts.map +1 -0
  170. package/dist/hosted-client/client.js +309 -0
  171. package/dist/hosted-client/client.js.map +1 -0
  172. package/dist/hosted-client/directory.d.ts +46 -0
  173. package/dist/hosted-client/directory.d.ts.map +1 -0
  174. package/dist/hosted-client/directory.js +74 -0
  175. package/dist/hosted-client/directory.js.map +1 -0
  176. package/dist/hosted-client/errors.d.ts +26 -0
  177. package/dist/hosted-client/errors.d.ts.map +1 -0
  178. package/dist/hosted-client/errors.js +35 -0
  179. package/dist/hosted-client/errors.js.map +1 -0
  180. package/dist/hosted-client/inbox.d.ts +320 -0
  181. package/dist/hosted-client/inbox.d.ts.map +1 -0
  182. package/dist/hosted-client/inbox.js +379 -0
  183. package/dist/hosted-client/inbox.js.map +1 -0
  184. package/dist/hosted-client/index.d.ts +30 -0
  185. package/dist/hosted-client/index.d.ts.map +1 -0
  186. package/dist/hosted-client/index.js +32 -0
  187. package/dist/hosted-client/index.js.map +1 -0
  188. package/dist/hosted-client/journal.d.ts +103 -0
  189. package/dist/hosted-client/journal.d.ts.map +1 -0
  190. package/dist/hosted-client/journal.js +464 -0
  191. package/dist/hosted-client/journal.js.map +1 -0
  192. package/dist/hosted-client/node.d.ts +74 -0
  193. package/dist/hosted-client/node.d.ts.map +1 -0
  194. package/dist/hosted-client/node.js +219 -0
  195. package/dist/hosted-client/node.js.map +1 -0
  196. package/dist/hosted-client/reference.d.ts +12 -0
  197. package/dist/hosted-client/reference.d.ts.map +1 -0
  198. package/dist/hosted-client/reference.js +29 -0
  199. package/dist/hosted-client/reference.js.map +1 -0
  200. package/dist/hosted-client/write.d.ts +217 -0
  201. package/dist/hosted-client/write.d.ts.map +1 -0
  202. package/dist/hosted-client/write.js +418 -0
  203. package/dist/hosted-client/write.js.map +1 -0
  204. package/dist/hosted-transport/answer-rows.d.ts +243 -0
  205. package/dist/hosted-transport/answer-rows.d.ts.map +1 -0
  206. package/dist/hosted-transport/answer-rows.js +457 -0
  207. package/dist/hosted-transport/answer-rows.js.map +1 -0
  208. package/dist/hosted-transport/blob-reads.d.ts +35 -0
  209. package/dist/hosted-transport/blob-reads.d.ts.map +1 -0
  210. package/dist/hosted-transport/blob-reads.js +179 -0
  211. package/dist/hosted-transport/blob-reads.js.map +1 -0
  212. package/dist/hosted-transport/blob-write.d.ts +34 -0
  213. package/dist/hosted-transport/blob-write.d.ts.map +1 -0
  214. package/dist/hosted-transport/blob-write.js +115 -0
  215. package/dist/hosted-transport/blob-write.js.map +1 -0
  216. package/dist/hosted-transport/carrier.d.ts +151 -0
  217. package/dist/hosted-transport/carrier.d.ts.map +1 -0
  218. package/dist/hosted-transport/carrier.js +260 -0
  219. package/dist/hosted-transport/carrier.js.map +1 -0
  220. package/dist/hosted-transport/history-pages.d.ts +55 -0
  221. package/dist/hosted-transport/history-pages.d.ts.map +1 -0
  222. package/dist/hosted-transport/history-pages.js +69 -0
  223. package/dist/hosted-transport/history-pages.js.map +1 -0
  224. package/dist/hosted-transport/index.d.ts +18 -0
  225. package/dist/hosted-transport/index.d.ts.map +1 -0
  226. package/dist/hosted-transport/index.js +18 -0
  227. package/dist/hosted-transport/index.js.map +1 -0
  228. package/dist/hosted-transport/operations.d.ts +85 -0
  229. package/dist/hosted-transport/operations.d.ts.map +1 -0
  230. package/dist/hosted-transport/operations.js +128 -0
  231. package/dist/hosted-transport/operations.js.map +1 -0
  232. package/dist/hosted-transport/paged-reads.d.ts +87 -0
  233. package/dist/hosted-transport/paged-reads.d.ts.map +1 -0
  234. package/dist/hosted-transport/paged-reads.js +238 -0
  235. package/dist/hosted-transport/paged-reads.js.map +1 -0
  236. package/dist/hosted-transport/read-adapter.d.ts +256 -0
  237. package/dist/hosted-transport/read-adapter.d.ts.map +1 -0
  238. package/dist/hosted-transport/read-adapter.js +568 -0
  239. package/dist/hosted-transport/read-adapter.js.map +1 -0
  240. package/dist/hosted-transport/root-write.d.ts +114 -0
  241. package/dist/hosted-transport/root-write.d.ts.map +1 -0
  242. package/dist/hosted-transport/root-write.js +171 -0
  243. package/dist/hosted-transport/root-write.js.map +1 -0
  244. package/dist/hosted-transport/whole-document-transport.d.ts +204 -0
  245. package/dist/hosted-transport/whole-document-transport.d.ts.map +1 -0
  246. package/dist/hosted-transport/whole-document-transport.js +447 -0
  247. package/dist/hosted-transport/whole-document-transport.js.map +1 -0
  248. package/dist/identity-fold.d.ts +18 -0
  249. package/dist/identity-fold.d.ts.map +1 -0
  250. package/dist/identity-fold.js +22 -0
  251. package/dist/identity-fold.js.map +1 -0
  252. package/dist/index.d.ts +41 -11
  253. package/dist/index.d.ts.map +1 -1
  254. package/dist/index.js +31 -9
  255. package/dist/index.js.map +1 -1
  256. package/dist/indexeddb-backend.d.ts +25 -33
  257. package/dist/indexeddb-backend.d.ts.map +1 -1
  258. package/dist/indexeddb-backend.js +264 -8
  259. package/dist/indexeddb-backend.js.map +1 -1
  260. package/dist/inventory-guard.d.ts +58 -0
  261. package/dist/inventory-guard.d.ts.map +1 -0
  262. package/dist/inventory-guard.js +169 -0
  263. package/dist/inventory-guard.js.map +1 -0
  264. package/dist/journaled-backend.d.ts +149 -9
  265. package/dist/journaled-backend.d.ts.map +1 -1
  266. package/dist/journaled-backend.js +64 -58
  267. package/dist/journaled-backend.js.map +1 -1
  268. package/dist/kind-authoring.d.ts +170 -0
  269. package/dist/kind-authoring.d.ts.map +1 -0
  270. package/dist/kind-authoring.js +452 -0
  271. package/dist/kind-authoring.js.map +1 -0
  272. package/dist/kind-changes.d.ts +45 -0
  273. package/dist/kind-changes.d.ts.map +1 -0
  274. package/dist/kind-changes.js +96 -0
  275. package/dist/kind-changes.js.map +1 -0
  276. package/dist/kind-conformance-error.d.ts +15 -0
  277. package/dist/kind-conformance-error.d.ts.map +1 -0
  278. package/dist/kind-conformance-error.js +20 -0
  279. package/dist/kind-conformance-error.js.map +1 -0
  280. package/dist/kind-coverage.d.ts +99 -0
  281. package/dist/kind-coverage.d.ts.map +1 -0
  282. package/dist/kind-coverage.js +186 -0
  283. package/dist/kind-coverage.js.map +1 -0
  284. package/dist/kind-deprecation.d.ts +32 -0
  285. package/dist/kind-deprecation.d.ts.map +1 -0
  286. package/dist/kind-deprecation.js +141 -0
  287. package/dist/kind-deprecation.js.map +1 -0
  288. package/dist/kind-field-mutation.d.ts +4 -0
  289. package/dist/kind-field-mutation.d.ts.map +1 -1
  290. package/dist/kind-field-mutation.js +28 -3
  291. package/dist/kind-field-mutation.js.map +1 -1
  292. package/dist/kinds-load.js +4 -4
  293. package/dist/kinds-load.js.map +1 -1
  294. package/dist/kinds.d.ts +111 -2
  295. package/dist/kinds.d.ts.map +1 -1
  296. package/dist/kinds.js +386 -20
  297. package/dist/kinds.js.map +1 -1
  298. package/dist/link-emit.d.ts +29 -0
  299. package/dist/link-emit.d.ts.map +1 -0
  300. package/dist/link-emit.js +39 -0
  301. package/dist/link-emit.js.map +1 -0
  302. package/dist/link-types.d.ts +27 -0
  303. package/dist/link-types.d.ts.map +1 -0
  304. package/dist/link-types.js +60 -0
  305. package/dist/link-types.js.map +1 -0
  306. package/dist/links.d.ts +52 -3
  307. package/dist/links.d.ts.map +1 -1
  308. package/dist/links.js +259 -18
  309. package/dist/links.js.map +1 -1
  310. package/dist/managed-document-metadata.d.ts +2 -0
  311. package/dist/managed-document-metadata.d.ts.map +1 -0
  312. package/dist/managed-document-metadata.js +9 -0
  313. package/dist/managed-document-metadata.js.map +1 -0
  314. package/dist/memory-backend.d.ts +3 -0
  315. package/dist/memory-backend.d.ts.map +1 -1
  316. package/dist/memory-backend.js +44 -2
  317. package/dist/memory-backend.js.map +1 -1
  318. package/dist/okf-actor.d.ts +1 -0
  319. package/dist/okf-actor.d.ts.map +1 -1
  320. package/dist/okf-actor.js +1 -0
  321. package/dist/okf-actor.js.map +1 -1
  322. package/dist/okf-authoring.d.ts +4 -0
  323. package/dist/okf-authoring.d.ts.map +1 -0
  324. package/dist/okf-authoring.js +12 -0
  325. package/dist/okf-authoring.js.map +1 -0
  326. package/dist/okf-standard-fields.d.ts +3 -0
  327. package/dist/okf-standard-fields.d.ts.map +1 -1
  328. package/dist/okf-standard-fields.js +3 -0
  329. package/dist/okf-standard-fields.js.map +1 -1
  330. package/dist/path-fold.d.ts +39 -0
  331. package/dist/path-fold.d.ts.map +1 -0
  332. package/dist/path-fold.js +41 -0
  333. package/dist/path-fold.js.map +1 -0
  334. package/dist/paths.d.ts +18 -0
  335. package/dist/paths.d.ts.map +1 -1
  336. package/dist/paths.js +32 -0
  337. package/dist/paths.js.map +1 -1
  338. package/dist/platform.d.ts +13 -2
  339. package/dist/platform.d.ts.map +1 -1
  340. package/dist/platform.js +16 -0
  341. package/dist/platform.js.map +1 -1
  342. package/dist/portable-export.d.ts +119 -0
  343. package/dist/portable-export.d.ts.map +1 -0
  344. package/dist/portable-export.js +501 -0
  345. package/dist/portable-export.js.map +1 -0
  346. package/dist/publication-filesystem.d.ts +1 -1
  347. package/dist/publication-filesystem.d.ts.map +1 -1
  348. package/dist/publication-filesystem.js +1 -1
  349. package/dist/publication-filesystem.js.map +1 -1
  350. package/dist/qualified-links.d.ts +67 -0
  351. package/dist/qualified-links.d.ts.map +1 -0
  352. package/dist/qualified-links.js +117 -0
  353. package/dist/qualified-links.js.map +1 -0
  354. package/dist/query-filter.d.ts +16 -2
  355. package/dist/query-filter.d.ts.map +1 -1
  356. package/dist/query-filter.js +40 -1
  357. package/dist/query-filter.js.map +1 -1
  358. package/dist/query-order.d.ts +22 -0
  359. package/dist/query-order.d.ts.map +1 -0
  360. package/dist/query-order.js +43 -0
  361. package/dist/query-order.js.map +1 -0
  362. package/dist/recipe-lifecycle/errors.d.ts +96 -0
  363. package/dist/recipe-lifecycle/errors.d.ts.map +1 -0
  364. package/dist/recipe-lifecycle/errors.js +122 -0
  365. package/dist/recipe-lifecycle/errors.js.map +1 -0
  366. package/dist/recipe-lifecycle/evolution.d.ts +124 -0
  367. package/dist/recipe-lifecycle/evolution.d.ts.map +1 -0
  368. package/dist/recipe-lifecycle/evolution.js +993 -0
  369. package/dist/recipe-lifecycle/evolution.js.map +1 -0
  370. package/dist/recipe-lifecycle/index.d.ts +34 -0
  371. package/dist/recipe-lifecycle/index.d.ts.map +1 -0
  372. package/dist/recipe-lifecycle/index.js +28 -0
  373. package/dist/recipe-lifecycle/index.js.map +1 -0
  374. package/dist/recipe-lifecycle/install.d.ts +155 -0
  375. package/dist/recipe-lifecycle/install.d.ts.map +1 -0
  376. package/dist/recipe-lifecycle/install.js +604 -0
  377. package/dist/recipe-lifecycle/install.js.map +1 -0
  378. package/dist/recipe-lifecycle/legacy-aliases.d.ts +16 -0
  379. package/dist/recipe-lifecycle/legacy-aliases.d.ts.map +1 -0
  380. package/dist/recipe-lifecycle/legacy-aliases.js +51 -0
  381. package/dist/recipe-lifecycle/legacy-aliases.js.map +1 -0
  382. package/dist/recipe-lifecycle/retirement-apply.d.ts +59 -0
  383. package/dist/recipe-lifecycle/retirement-apply.d.ts.map +1 -0
  384. package/dist/recipe-lifecycle/retirement-apply.js +165 -0
  385. package/dist/recipe-lifecycle/retirement-apply.js.map +1 -0
  386. package/dist/recipe-lifecycle/retirement.d.ts +89 -0
  387. package/dist/recipe-lifecycle/retirement.d.ts.map +1 -0
  388. package/dist/recipe-lifecycle/retirement.js +347 -0
  389. package/dist/recipe-lifecycle/retirement.js.map +1 -0
  390. package/dist/recipe-lifecycle/stamp.d.ts +151 -0
  391. package/dist/recipe-lifecycle/stamp.d.ts.map +1 -0
  392. package/dist/recipe-lifecycle/stamp.js +364 -0
  393. package/dist/recipe-lifecycle/stamp.js.map +1 -0
  394. package/dist/recipe-set-preflight.d.ts +139 -0
  395. package/dist/recipe-set-preflight.d.ts.map +1 -0
  396. package/dist/recipe-set-preflight.js +536 -0
  397. package/dist/recipe-set-preflight.js.map +1 -0
  398. package/dist/recipes.d.ts +29 -1
  399. package/dist/recipes.d.ts.map +1 -1
  400. package/dist/recipes.js +137 -1
  401. package/dist/recipes.js.map +1 -1
  402. package/dist/record-overlay/apply.d.ts +43 -0
  403. package/dist/record-overlay/apply.d.ts.map +1 -0
  404. package/dist/record-overlay/apply.js +527 -0
  405. package/dist/record-overlay/apply.js.map +1 -0
  406. package/dist/record-overlay/canonical.d.ts +22 -0
  407. package/dist/record-overlay/canonical.d.ts.map +1 -0
  408. package/dist/record-overlay/canonical.js +47 -0
  409. package/dist/record-overlay/canonical.js.map +1 -0
  410. package/dist/record-overlay/digest.d.ts +4 -0
  411. package/dist/record-overlay/digest.d.ts.map +1 -0
  412. package/dist/record-overlay/digest.js +11 -0
  413. package/dist/record-overlay/digest.js.map +1 -0
  414. package/dist/record-overlay/errors.d.ts +44 -0
  415. package/dist/record-overlay/errors.d.ts.map +1 -0
  416. package/dist/record-overlay/errors.js +55 -0
  417. package/dist/record-overlay/errors.js.map +1 -0
  418. package/dist/record-overlay/findings.d.ts +5 -0
  419. package/dist/record-overlay/findings.d.ts.map +1 -0
  420. package/dist/record-overlay/findings.js +83 -0
  421. package/dist/record-overlay/findings.js.map +1 -0
  422. package/dist/record-overlay/index.d.ts +23 -0
  423. package/dist/record-overlay/index.d.ts.map +1 -0
  424. package/dist/record-overlay/index.js +21 -0
  425. package/dist/record-overlay/index.js.map +1 -0
  426. package/dist/record-overlay/plan.d.ts +12 -0
  427. package/dist/record-overlay/plan.d.ts.map +1 -0
  428. package/dist/record-overlay/plan.js +285 -0
  429. package/dist/record-overlay/plan.js.map +1 -0
  430. package/dist/record-overlay/policy.d.ts +74 -0
  431. package/dist/record-overlay/policy.d.ts.map +1 -0
  432. package/dist/record-overlay/policy.js +235 -0
  433. package/dist/record-overlay/policy.js.map +1 -0
  434. package/dist/record-overlay/redact.d.ts +3 -0
  435. package/dist/record-overlay/redact.d.ts.map +1 -0
  436. package/dist/record-overlay/redact.js +27 -0
  437. package/dist/record-overlay/redact.js.map +1 -0
  438. package/dist/record-overlay/signal-kind.d.ts +30 -0
  439. package/dist/record-overlay/signal-kind.d.ts.map +1 -0
  440. package/dist/record-overlay/signal-kind.js +38 -0
  441. package/dist/record-overlay/signal-kind.js.map +1 -0
  442. package/dist/record-overlay/signal-text.d.ts +45 -0
  443. package/dist/record-overlay/signal-text.d.ts.map +1 -0
  444. package/dist/record-overlay/signal-text.js +116 -0
  445. package/dist/record-overlay/signal-text.js.map +1 -0
  446. package/dist/record-overlay/source-index.d.ts +19 -0
  447. package/dist/record-overlay/source-index.d.ts.map +1 -0
  448. package/dist/record-overlay/source-index.js +102 -0
  449. package/dist/record-overlay/source-index.js.map +1 -0
  450. package/dist/record-overlay/types.d.ts +291 -0
  451. package/dist/record-overlay/types.d.ts.map +1 -0
  452. package/dist/record-overlay/types.js +2 -0
  453. package/dist/record-overlay/types.js.map +1 -0
  454. package/dist/remote-backend.d.ts +58 -13
  455. package/dist/remote-backend.d.ts.map +1 -1
  456. package/dist/remote-backend.js +156 -36
  457. package/dist/remote-backend.js.map +1 -1
  458. package/dist/remote-document-codec.d.ts +2 -1
  459. package/dist/remote-document-codec.d.ts.map +1 -1
  460. package/dist/remote-document-codec.js +3 -2
  461. package/dist/remote-document-codec.js.map +1 -1
  462. package/dist/remote-error.d.ts +17 -1
  463. package/dist/remote-error.d.ts.map +1 -1
  464. package/dist/remote-error.js +32 -2
  465. package/dist/remote-error.js.map +1 -1
  466. package/dist/remote-operations.d.ts +0 -40
  467. package/dist/remote-operations.d.ts.map +1 -1
  468. package/dist/remote-operations.js +26 -6
  469. package/dist/remote-operations.js.map +1 -1
  470. package/dist/remote-parsers.d.ts +1 -1
  471. package/dist/remote-parsers.js +1 -1
  472. package/dist/search/backend-source.d.ts +6 -0
  473. package/dist/search/backend-source.d.ts.map +1 -0
  474. package/dist/search/backend-source.js +33 -0
  475. package/dist/search/backend-source.js.map +1 -0
  476. package/dist/search/contract.d.ts +151 -0
  477. package/dist/search/contract.d.ts.map +1 -0
  478. package/dist/search/contract.js +78 -0
  479. package/dist/search/contract.js.map +1 -0
  480. package/dist/search/errors.d.ts +30 -0
  481. package/dist/search/errors.d.ts.map +1 -0
  482. package/dist/search/errors.js +50 -0
  483. package/dist/search/errors.js.map +1 -0
  484. package/dist/search/identity.d.ts +12 -0
  485. package/dist/search/identity.d.ts.map +1 -0
  486. package/dist/search/identity.js +90 -0
  487. package/dist/search/identity.js.map +1 -0
  488. package/dist/search/index.d.ts +16 -0
  489. package/dist/search/index.d.ts.map +1 -0
  490. package/dist/search/index.js +15 -0
  491. package/dist/search/index.js.map +1 -0
  492. package/dist/search/memory-source.d.ts +36 -0
  493. package/dist/search/memory-source.d.ts.map +1 -0
  494. package/dist/search/memory-source.js +235 -0
  495. package/dist/search/memory-source.js.map +1 -0
  496. package/dist/search/rank.d.ts +34 -0
  497. package/dist/search/rank.d.ts.map +1 -0
  498. package/dist/search/rank.js +129 -0
  499. package/dist/search/rank.js.map +1 -0
  500. package/dist/search/row-text.d.ts +38 -0
  501. package/dist/search/row-text.d.ts.map +1 -0
  502. package/dist/search/row-text.js +88 -0
  503. package/dist/search/row-text.js.map +1 -0
  504. package/dist/search/search.d.ts +28 -0
  505. package/dist/search/search.d.ts.map +1 -0
  506. package/dist/search/search.js +257 -0
  507. package/dist/search/search.js.map +1 -0
  508. package/dist/search/source.d.ts +67 -0
  509. package/dist/search/source.d.ts.map +1 -0
  510. package/dist/search/source.js +2 -0
  511. package/dist/search/source.js.map +1 -0
  512. package/dist/search/text.d.ts +47 -0
  513. package/dist/search/text.d.ts.map +1 -0
  514. package/dist/search/text.js +150 -0
  515. package/dist/search/text.js.map +1 -0
  516. package/dist/site-capabilities.d.ts +345 -0
  517. package/dist/site-capabilities.d.ts.map +1 -0
  518. package/dist/site-capabilities.js +724 -0
  519. package/dist/site-capabilities.js.map +1 -0
  520. package/dist/source-engine/driver.d.ts +40 -0
  521. package/dist/source-engine/driver.d.ts.map +1 -0
  522. package/dist/source-engine/driver.js +392 -0
  523. package/dist/source-engine/driver.js.map +1 -0
  524. package/dist/source-engine/evidence.d.ts +39 -0
  525. package/dist/source-engine/evidence.d.ts.map +1 -0
  526. package/dist/source-engine/evidence.js +54 -0
  527. package/dist/source-engine/evidence.js.map +1 -0
  528. package/dist/source-engine/guard.d.ts +87 -0
  529. package/dist/source-engine/guard.d.ts.map +1 -0
  530. package/dist/source-engine/guard.js +427 -0
  531. package/dist/source-engine/guard.js.map +1 -0
  532. package/dist/source-engine/index.d.ts +33 -0
  533. package/dist/source-engine/index.d.ts.map +1 -0
  534. package/dist/source-engine/index.js +26 -0
  535. package/dist/source-engine/index.js.map +1 -0
  536. package/dist/source-engine/machine-state.d.ts +74 -0
  537. package/dist/source-engine/machine-state.d.ts.map +1 -0
  538. package/dist/source-engine/machine-state.js +48 -0
  539. package/dist/source-engine/machine-state.js.map +1 -0
  540. package/dist/source-engine/observe.d.ts +10 -0
  541. package/dist/source-engine/observe.d.ts.map +1 -0
  542. package/dist/source-engine/observe.js +270 -0
  543. package/dist/source-engine/observe.js.map +1 -0
  544. package/dist/source-engine/overlay.d.ts +50 -0
  545. package/dist/source-engine/overlay.d.ts.map +1 -0
  546. package/dist/source-engine/overlay.js +114 -0
  547. package/dist/source-engine/overlay.js.map +1 -0
  548. package/dist/source-engine/robots.d.ts +53 -0
  549. package/dist/source-engine/robots.d.ts.map +1 -0
  550. package/dist/source-engine/robots.js +158 -0
  551. package/dist/source-engine/robots.js.map +1 -0
  552. package/dist/source-engine/snapshot.d.ts +104 -0
  553. package/dist/source-engine/snapshot.d.ts.map +1 -0
  554. package/dist/source-engine/snapshot.js +240 -0
  555. package/dist/source-engine/snapshot.js.map +1 -0
  556. package/dist/source-engine/types.d.ts +292 -0
  557. package/dist/source-engine/types.d.ts.map +1 -0
  558. package/dist/source-engine/types.js +2 -0
  559. package/dist/source-engine/types.js.map +1 -0
  560. package/dist/source-harness/conformance.d.ts +16 -0
  561. package/dist/source-harness/conformance.d.ts.map +1 -0
  562. package/dist/source-harness/conformance.js +266 -0
  563. package/dist/source-harness/conformance.js.map +1 -0
  564. package/dist/source-harness/fixture.d.ts +97 -0
  565. package/dist/source-harness/fixture.d.ts.map +1 -0
  566. package/dist/source-harness/fixture.js +276 -0
  567. package/dist/source-harness/fixture.js.map +1 -0
  568. package/dist/source-harness/index.d.ts +22 -0
  569. package/dist/source-harness/index.d.ts.map +1 -0
  570. package/dist/source-harness/index.js +19 -0
  571. package/dist/source-harness/index.js.map +1 -0
  572. package/dist/source-harness/peer.d.ts +74 -0
  573. package/dist/source-harness/peer.d.ts.map +1 -0
  574. package/dist/source-harness/peer.js +106 -0
  575. package/dist/source-harness/peer.js.map +1 -0
  576. package/dist/source-profiles/index.d.ts +31 -0
  577. package/dist/source-profiles/index.d.ts.map +1 -0
  578. package/dist/source-profiles/index.js +206 -0
  579. package/dist/source-profiles/index.js.map +1 -0
  580. package/dist/source-profiles/link-header.d.ts +6 -0
  581. package/dist/source-profiles/link-header.d.ts.map +1 -0
  582. package/dist/source-profiles/link-header.js +131 -0
  583. package/dist/source-profiles/link-header.js.map +1 -0
  584. package/dist/storage.d.ts +9 -2
  585. package/dist/storage.d.ts.map +1 -1
  586. package/dist/storage.js +6 -1
  587. package/dist/storage.js.map +1 -1
  588. package/dist/string-identity-agreement.d.ts +35 -0
  589. package/dist/string-identity-agreement.d.ts.map +1 -0
  590. package/dist/string-identity-agreement.js +72 -0
  591. package/dist/string-identity-agreement.js.map +1 -0
  592. package/dist/types.d.ts +41 -6
  593. package/dist/types.d.ts.map +1 -1
  594. package/dist/types.js +0 -10
  595. package/dist/types.js.map +1 -1
  596. package/dist/uncertain-write.d.ts +157 -17
  597. package/dist/uncertain-write.d.ts.map +1 -1
  598. package/dist/uncertain-write.js +86 -30
  599. package/dist/uncertain-write.js.map +1 -1
  600. package/dist/versioning.d.ts +9 -4
  601. package/dist/versioning.d.ts.map +1 -1
  602. package/dist/versioning.js +9 -4
  603. package/dist/versioning.js.map +1 -1
  604. package/dist/view-launch-contract.d.ts +14 -0
  605. package/dist/view-launch-contract.d.ts.map +1 -0
  606. package/dist/view-launch-contract.js +23 -0
  607. package/dist/view-launch-contract.js.map +1 -0
  608. package/dist/write-identity.d.ts +5 -0
  609. package/dist/write-identity.d.ts.map +1 -0
  610. package/dist/write-identity.js +9 -0
  611. package/dist/write-identity.js.map +1 -0
  612. package/package.json +140 -3
@@ -15,6 +15,15 @@
15
15
  * entirely between two probes of one observation can be traversed by the operating system
16
16
  * during a listing or open, but its bytes can never be returned as EXACT, because the leaf
17
17
  * witness at the post-walk must match the entry the requested path reaches.
18
+ * - A bulk read runs its observations inside one {@link ObservationPass}: the same protocol per
19
+ * path, but a directory's listing is taken once and reused while the directory's change
20
+ * witness proves its entry set unchanged, and every EXACT verdict that used a reused listing has
21
+ * its post-walk repeated at the end of the pass without trusting timestamps. Listing the parent
22
+ * per observation would make a pass over a directory of N documents read O(N²) directory
23
+ * entries. The speedup assumes local disks, whose directory times advance on every entry change;
24
+ * on Linux any other filesystem type lists per use, and elsewhere a mount whose times can lie
25
+ * (network or FUSE attribute caches, settable Windows directory times) is covered by the
26
+ * end-of-pass re-verification, short of an inode number reused within the pass.
18
27
  * - Mutations hold one cross-process lock keyed by a pure fold of the root and `rel`, decide
19
28
  * inside it, create directories one segment at a time with a spelling check, and publish a
20
29
  * first-created leaf with `link` so the host's own equivalence refuses a second spelling the
@@ -37,8 +46,8 @@
37
46
  * and the root's spelling is folded into the lock key rather than verified.
38
47
  *
39
48
  * Every filesystem call goes through a {@link FilesystemIdentityPort} passed to the protocol
40
- * functions. Production binds {@link nodeFilesystemIdentityPort} once, as a module constant;
41
- * nothing on a backend instance can substitute it. Normalizing stores that rewrite names on
49
+ * functions. Production constructs a Node binding with the backend's captured host policy;
50
+ * the policy supplies classifications, never a replacement identity protocol. Normalizing stores that rewrite names on
42
51
  * write (legacy HFS+) are unsupported: an id whose NFD form differs from its own form is written
43
52
  * and then refused as an alias on every later observation, never silently aliased.
44
53
  */
@@ -46,13 +55,15 @@ import { promises as fs } from "node:fs";
46
55
  import path from "node:path";
47
56
  import { createHash, randomUUID } from "node:crypto";
48
57
  import { ConcurrentReplacementError, FilesystemIdentityAliasError, InvalidInputError } from "./errors.js";
49
- import { acquireFilesystemIdentityLock } from "./filesystem-lock.js";
50
- const WINDOWS_REPLACE_CONFLICT_CODES = new Set(["EACCES", "EBUSY", "EPERM"]);
58
+ import { acquireFilesystemIdentityLock, filesystemMutationLockRoot } from "./filesystem-lock.js";
59
+ import { captureFilesystemHostPolicy } from "./filesystem-host.js";
60
+ import { foldSegment } from "./identity-fold.js";
61
+ export { foldSegment };
51
62
  /**
52
- * Windows can transiently deny replacement while another process is closing a read handle or a
63
+ * A host can transiently deny replacement while another process is closing a read handle or a
53
64
  * scanner holds the destination. An in-place rename retry cannot remain bound to the complete
54
65
  * parent-and-leaf observation: either can change after any final check. Abort this attempt instead,
55
- * mapping only the errno values Node uses for a Windows replacement sharing violation to the typed
66
+ * mapping only a host-classified replacement conflict to the typed
56
67
  * contention signal owned by the higher-level fresh read/decide/CAS loop. Every other platform and
57
68
  * errno remains the original immediate failure.
58
69
  */
@@ -61,8 +72,7 @@ async function replaceExistingLeaf(port, tmp, target, rel) {
61
72
  await port.rename(tmp, target);
62
73
  }
63
74
  catch (err) {
64
- const code = err.code ?? "";
65
- if ((port.platform ?? process.platform) === "win32" && WINDOWS_REPLACE_CONFLICT_CODES.has(code)) {
75
+ if (port.isReplacementConflict?.(err)) {
66
76
  throw new ConcurrentReplacementError(rel, 1, 10);
67
77
  }
68
78
  throw err;
@@ -117,18 +127,6 @@ function relSegments(rel) {
117
127
  return segments;
118
128
  }
119
129
  // ── identity key ──────────────────────────────────────────────────────────────
120
- /**
121
- * NFKD, then Unicode FULL case folding applied as lower-upper-lower (locale-independent). A plain
122
- * lower-case fold misses the pairs a case-insensitive host equates through full case mapping
123
- * (ß/ss, ẞ/SS, final sigma ς/σ, iota-subscript ᾈ/ἀι and its family): two such spellings would get
124
- * different keys, both first-creation writers would realize ABSENT, and the second rename would
125
- * silently replace the first document. The round trip through upper case expands every such
126
- * pair to a common form, so the fold is a superset of every supported host's equivalence;
127
- * over-folding (dotless ı with i) only adds serialization, never removes exclusion.
128
- */
129
- export function foldSegment(segment) {
130
- return segment.normalize("NFKD").toLowerCase().toUpperCase().toLowerCase();
131
- }
132
130
  /** The physical path of the longest existing ancestor of `resolved`, plus the absent remainder. */
133
131
  async function existingAnchor(resolved) {
134
132
  const tail = [];
@@ -155,12 +153,65 @@ async function existingAnchor(resolved) {
155
153
  * and identical for every case or normalization spelling of any segment. It depends on nothing
156
154
  * else: not the environment, the clock, the process, or the host name.
157
155
  */
158
- export async function identityKey(root, rel) {
159
- const foldedRel = relSegments(rel).map(foldSegment).join("/");
156
+ async function foldedPhysicalRoot(root) {
160
157
  const { anchor, tail } = await existingAnchor(path.resolve(root));
161
158
  const anchorSegments = anchor.split(path.sep).filter((segment, index) => index === 0 || segment !== "");
162
- const foldedRoot = [...anchorSegments, ...tail].map(foldSegment).join("/");
163
- return createHash("sha256").update(`superbee-identity/v1\0${foldedRoot}\0${foldedRel}`).digest("hex");
159
+ return [...anchorSegments, ...tail].map(foldSegment).join("/");
160
+ }
161
+ export async function identityKey(root, rel) {
162
+ const foldedRel = relSegments(rel).map(foldSegment).join("/");
163
+ return createHash("sha256").update(`superbee-identity/v1\0${await foldedPhysicalRoot(root)}\0${foldedRel}`).digest("hex");
164
+ }
165
+ /** Same root key before/after directory creation; physical replacement is a separate witness. */
166
+ export async function filesystemRootMutationKey(root) {
167
+ return createHash("sha256").update(`superbee-root-mutation/v1\0${await foldedPhysicalRoot(root)}`).digest("hex");
168
+ }
169
+ /** Existing physical-root/ancestor witnesses supplement the stable coordination pathname. */
170
+ export async function filesystemRootWitness(port, root) {
171
+ const physical = await fs.realpath(root);
172
+ const witnesses = [];
173
+ let current = physical;
174
+ for (;;) {
175
+ const witness = await port.probe(current);
176
+ if (!witness || witness.kind !== "directory")
177
+ throw new InvalidInputError("Inventory guard root identity is unavailable.");
178
+ witnesses.push([current, witness.dev, witness.ino]);
179
+ const parent = path.dirname(current);
180
+ if (parent === current)
181
+ break;
182
+ current = parent;
183
+ }
184
+ return createHash("sha256").update(JSON.stringify(witnesses)).digest("hex");
185
+ }
186
+ const rootMutationQueues = new Map();
187
+ /** Internal per-backend root coordinator; never re-exported by a public entrypoint. */
188
+ export function createFilesystemMutationCoordinator(_port, root, hostPolicy) {
189
+ const policy = captureFilesystemHostPolicy(hostPolicy);
190
+ let lockRoot;
191
+ const namespace = () => lockRoot ??= filesystemMutationLockRoot(root, policy);
192
+ return Object.freeze({
193
+ namespace,
194
+ async run(body) {
195
+ const key = await filesystemRootMutationKey(root);
196
+ const lockRoot = namespace();
197
+ const queueKey = `${lockRoot}:${key}`;
198
+ const previous = rootMutationQueues.get(queueKey) ?? Promise.resolve();
199
+ const run = previous.then(async () => {
200
+ const release = await acquireFilesystemIdentityLock(key, root, { portableRoot: root, lockRoot, hostPolicy: policy });
201
+ try {
202
+ return await body();
203
+ }
204
+ finally {
205
+ await release();
206
+ }
207
+ });
208
+ const settled = run.then(() => { }, () => { });
209
+ rootMutationQueues.set(queueKey, settled);
210
+ void settled.then(() => { if (rootMutationQueues.get(queueKey) === settled)
211
+ rootMutationQueues.delete(queueKey); });
212
+ return run;
213
+ },
214
+ });
164
215
  }
165
216
  // ── pure decisions ────────────────────────────────────────────────────────────
166
217
  function sameWitness(a, b) {
@@ -219,6 +270,13 @@ async function probeSegment(port, candidate, rel, segment) {
219
270
  function hasExact(listing, segment) {
220
271
  return listing.some((entry) => entry.name === segment);
221
272
  }
273
+ /** One fresh `entries` call per use: the single-read protocol. */
274
+ function freshListings(port) {
275
+ return async (dir) => {
276
+ const listing = await port.entries(dir);
277
+ return listing === null ? null : { has: (name) => hasExact(listing, name) };
278
+ };
279
+ }
222
280
  /**
223
281
  * M-REALIZE: per segment, root to leaf, it must exist and the parent listing must carry its exact
224
282
  * spelling. A listing-only alias decision is sound here because the identity lock is held: no
@@ -277,15 +335,15 @@ async function recordWalk(port, rootResolved, segments, rel) {
277
335
  * (`handle` given) applies that leaf table against the handle's inode, probing the leaf
278
336
  * unconditionally.
279
337
  */
280
- async function confirmedWalk(port, rootResolved, segments, rel, recorded, handle) {
338
+ async function confirmedWalk(port, rootResolved, segments, rel, recorded, handle, listings = freshListings(port)) {
281
339
  let parent = rootResolved;
282
340
  for (let index = 0; index < segments.length; index++) {
283
341
  const segment = segments[index];
284
342
  const candidate = path.join(parent, segment);
285
- const listing = await port.entries(parent);
343
+ const listing = await listings(parent);
286
344
  if (listing === null)
287
345
  return "absent";
288
- const listed = hasExact(listing, segment);
346
+ const listed = listing.has(segment);
289
347
  if (handle !== null && index === segments.length - 1) {
290
348
  const verdict = classifyLeaf({ listed, probe: await probeSegment(port, candidate, rel, segment), handle });
291
349
  if (verdict === "aliased")
@@ -316,14 +374,17 @@ function countRestart(restarts, rel) {
316
374
  * from O-PROBE, bounded; the handle is closed before any restart opens another.
317
375
  */
318
376
  export async function observeExact(port, root, rel, read) {
377
+ return observeWith(port, path.resolve(root), rel, read, freshListings(port));
378
+ }
379
+ /** The observation protocol of {@link observeExact}, with the parent listings drawn from `listings`. */
380
+ async function observeWith(port, rootResolved, rel, read, listings, onExact) {
319
381
  const segments = relSegments(rel);
320
- const rootResolved = path.resolve(root);
321
382
  const target = path.join(rootResolved, ...segments);
322
383
  for (let restarts = 0;;) {
323
384
  const recorded = await recordWalk(port, rootResolved, segments, rel);
324
385
  if (recorded === null)
325
386
  return { state: "absent" };
326
- const verified = await confirmedWalk(port, rootResolved, segments, rel, recorded, null);
387
+ const verified = await confirmedWalk(port, rootResolved, segments, rel, recorded, null, listings);
327
388
  if (verified === "absent")
328
389
  return { state: "absent" };
329
390
  if (verified === "restart") {
@@ -337,10 +398,9 @@ export async function observeExact(port, root, rel, read) {
337
398
  catch (err) {
338
399
  if (isAbsentPathError(err))
339
400
  return { state: "absent" };
340
- // Win32 can report EPERM when a concurrent delete/replace briefly denies an open. That is
341
- // an uncertain generation, not a durable permission verdict; re-run the witnessed walk and
401
+ // A host-classified transient open failure reports an uncertain generation; re-run the witnessed walk and
342
402
  // let the existing bound turn persistent contention into ConcurrentReplacementError.
343
- if (process.platform === "win32" && err.code === "EPERM") {
403
+ if (port.isTransientOpenError?.(err)) {
344
404
  restarts = countRestart(restarts, rel);
345
405
  continue;
346
406
  }
@@ -352,13 +412,15 @@ export async function observeExact(port, root, rel, read) {
352
412
  value = await read(opened.handle, target);
353
413
  if (value === null)
354
414
  return { state: "absent" };
355
- verdict = await confirmedWalk(port, rootResolved, segments, rel, recorded, opened);
415
+ verdict = await confirmedWalk(port, rootResolved, segments, rel, recorded, opened, listings);
356
416
  }
357
417
  finally {
358
418
  await port.close(opened.handle);
359
419
  }
360
- if (verdict === "exact")
420
+ if (verdict === "exact") {
421
+ onExact?.(recorded, { dev: opened.dev, ino: opened.ino });
361
422
  return { state: "exact", value };
423
+ }
362
424
  if (verdict === "absent")
363
425
  return { state: "absent" };
364
426
  restarts = countRestart(restarts, rel);
@@ -385,6 +447,154 @@ export async function probeExact(port, root, rel) {
385
447
  restarts = countRestart(restarts, rel);
386
448
  }
387
449
  }
450
+ // ── observation pass ──────────────────────────────────────────────────────────
451
+ /**
452
+ * How long a directory's modification and status-change times must have been still before a
453
+ * listing of it may be reused. A change that lands in the same timestamp tick as the directory's
454
+ * previous change leaves both times unchanged, so a witness is only a change detector once the
455
+ * clock has moved past that tick. Three seconds covers the coarsest supported granularity (FAT's
456
+ * two-second mtime) plus margin; finer clocks (APFS, ext4, NTFS) are covered with room to spare.
457
+ * A time in the future (clock skew) is never settled.
458
+ */
459
+ const SETTLED_AFTER_NS = 3000000000n;
460
+ function witnessKey(witness) {
461
+ return `${witness.dev}:${witness.ino}:${witness.mtimeNs}:${witness.ctimeNs}`;
462
+ }
463
+ /**
464
+ * Open an {@link ObservationPass} over `(port, root)`.
465
+ *
466
+ * Every observation runs the exact single-read protocol of {@link observeExact} — recorded walk,
467
+ * confirmed pre-walk, open, read, confirmed post-walk with the handle still open, bounded
468
+ * restarts — and differs only in where a walk's parent listing comes from. The first time a
469
+ * directory is needed the pass takes `witness, entries, witness`; when the two witnesses agree and
470
+ * the directory's times have settled, that listing is kept. Each later use re-takes the witness
471
+ * (one `stat`, constant cost) and reuses the kept listing only if the witness is unchanged;
472
+ * otherwise it lists afresh exactly as a single read would.
473
+ *
474
+ * Two independent arguments make a reused listing safe:
475
+ *
476
+ * 1. Timestamps (the fast path is right in the moment). Where a directory's times advance on every
477
+ * entry change — local APFS, HFS+, ext4, XFS, btrfs, NTFS, FAT — an unchanged settled witness
478
+ * means the entry set is the kept listing at the moment of use, so every verdict is the one a
479
+ * single read reaches against the same state.
480
+ * 2. Re-verification (no timestamps trusted). Where the witness can lie — attribute caches on
481
+ * network and FUSE mounts, settable directory times on Windows, a clock stepped backwards — an
482
+ * observation that used a reused listing may be wrong in the moment, so its verdict is not
483
+ * trusted: a refusal or absence reached through a reused listing is re-taken at once by
484
+ * {@link observeExact}, and `finish` repeats the post-walk of every EXACT verdict that used one
485
+ * against fresh listings (one per directory) and fresh probes. Each segment must still be
486
+ * listed under its exact spelling and reach the inode recorded for it, the leaf the inode the
487
+ * bytes were read from; anything else is returned for a fresh single read. Since published
488
+ * bytes are immutable per inode, a verdict that passes is a state of this identity at `finish`.
489
+ * What this cannot see is the read file being deleted and its inode NUMBER reused by a new file
490
+ * under the same spelling within the pass, because the handle is closed by then.
491
+ *
492
+ * On Linux, a mount whose filesystem type is not a known local one (NFS, SMB, FUSE, 9p, ...) gets
493
+ * no directory witness at all, so it lists exactly as single reads do.
494
+ */
495
+ export function openObservationPass(port, root, now = Date.now) {
496
+ const rootResolved = path.resolve(root);
497
+ const kept = new Map();
498
+ const reusedVerdicts = [];
499
+ const fresh = freshListings(port);
500
+ const witnessOf = port.directoryWitness?.bind(port);
501
+ const settled = (witness) => {
502
+ const nowNs = BigInt(Math.floor(now())) * 1000000n;
503
+ const latest = witness.mtimeNs > witness.ctimeNs ? witness.mtimeNs : witness.ctimeNs;
504
+ return nowNs - latest >= SETTLED_AFTER_NS;
505
+ };
506
+ /** Listings for one observation; `reused()` says whether any came from the kept set. */
507
+ const listingsFor = () => {
508
+ let reused = false;
509
+ if (witnessOf === undefined)
510
+ return { source: fresh, reused: () => false };
511
+ const source = async (dir) => {
512
+ const keep = kept.get(dir);
513
+ if (keep !== undefined) {
514
+ const current = await witnessOf(dir);
515
+ if (current !== null && witnessKey(current) === keep.witness) {
516
+ reused = true;
517
+ return keep.names;
518
+ }
519
+ kept.delete(dir);
520
+ }
521
+ const before = await witnessOf(dir);
522
+ const listing = await port.entries(dir);
523
+ if (listing === null)
524
+ return null;
525
+ const names = new Set(listing.map((entry) => entry.name));
526
+ const after = await witnessOf(dir);
527
+ if (before !== null && after !== null && witnessKey(before) === witnessKey(after) && settled(after)) {
528
+ kept.set(dir, { witness: witnessKey(after), names });
529
+ }
530
+ return names;
531
+ };
532
+ return { source, reused: () => reused };
533
+ };
534
+ return {
535
+ async observe(rel, read) {
536
+ const listings = listingsFor();
537
+ let exact;
538
+ let observed;
539
+ try {
540
+ observed = await observeWith(port, rootResolved, rel, read, listings.source, (recorded, handle) => {
541
+ exact = { rel, segments: relSegments(rel), recorded, handle };
542
+ });
543
+ }
544
+ catch (error) {
545
+ if (!listings.reused())
546
+ throw error;
547
+ return observeExact(port, rootResolved, rel, read);
548
+ }
549
+ if (!listings.reused())
550
+ return observed;
551
+ if (observed.state === "absent")
552
+ return observeExact(port, rootResolved, rel, read);
553
+ if (exact !== undefined)
554
+ reusedVerdicts.push(exact);
555
+ return observed;
556
+ },
557
+ async finish() {
558
+ const retry = new Set();
559
+ const endListings = new Map();
560
+ const listedAtEnd = async (dir) => {
561
+ if (!endListings.has(dir)) {
562
+ const listing = await port.entries(dir);
563
+ endListings.set(dir, listing === null ? null : new Set(listing.map((entry) => entry.name)));
564
+ }
565
+ return endListings.get(dir);
566
+ };
567
+ try {
568
+ for (const verdict of reusedVerdicts) {
569
+ if (!(await holdsAtEnd(port, rootResolved, verdict, listedAtEnd)))
570
+ retry.add(verdict.rel);
571
+ }
572
+ }
573
+ finally {
574
+ kept.clear();
575
+ reusedVerdicts.length = 0;
576
+ }
577
+ return [...retry];
578
+ },
579
+ };
580
+ }
581
+ /** The post-walk of one EXACT verdict, repeated against end-of-pass listings and fresh probes. */
582
+ async function holdsAtEnd(port, rootResolved, verdict, listedAtEnd) {
583
+ let parent = rootResolved;
584
+ for (let index = 0; index < verdict.segments.length; index++) {
585
+ const segment = verdict.segments[index];
586
+ const listing = await listedAtEnd(parent);
587
+ if (listing === null || !listing.has(segment))
588
+ return false;
589
+ const candidate = path.join(parent, segment);
590
+ const probed = await port.probe(candidate);
591
+ const expected = index === verdict.segments.length - 1 ? verdict.handle : verdict.recorded[index];
592
+ if (probed === null || probed.kind === "symlink" || !sameWitness(probed, expected))
593
+ return false;
594
+ parent = candidate;
595
+ }
596
+ return true;
597
+ }
388
598
  // ── mutation ──────────────────────────────────────────────────────────────────
389
599
  /**
390
600
  * Roots (resolved) whose filesystem refused a hard link. Learned lazily on the first creation
@@ -394,7 +604,15 @@ export async function probeExact(port, root, rel) {
394
604
  * first-creation writers of a host-equated pair the fold misses are not excluded" applies there
395
605
  * and only there.
396
606
  */
397
- const linkUnsupportedRoots = new Set();
607
+ const linkUnsupportedRoots = new WeakMap();
608
+ function unsupportedLinkRoots(port) {
609
+ let roots = linkUnsupportedRoots.get(port);
610
+ if (!roots) {
611
+ roots = new Set();
612
+ linkUnsupportedRoots.set(port, roots);
613
+ }
614
+ return roots;
615
+ }
398
616
  /**
399
617
  * Process-local queue per identity key, shared by every `FilesystemBackend` instance: the
400
618
  * engine constructs a fresh adapter per bundle operation, so an instance-level map would
@@ -508,7 +726,7 @@ async function createExactLeaf(port, tmp, target, rel, leaf, rootResolved) {
508
726
  return;
509
727
  }
510
728
  if (outcome === "unsupported") {
511
- linkUnsupportedRoots.add(rootResolved);
729
+ unsupportedLinkRoots(port).add(rootResolved);
512
730
  await port.rename(tmp, target);
513
731
  return;
514
732
  }
@@ -556,7 +774,7 @@ export async function mutateExact(port, root, rel, body) {
556
774
  await replaceExistingLeaf(port, tmp, target, rel);
557
775
  return;
558
776
  }
559
- if (linkUnsupportedRoots.has(rootResolved)) {
777
+ if (unsupportedLinkRoots(port).has(rootResolved)) {
560
778
  await port.rename(tmp, target);
561
779
  return;
562
780
  }
@@ -588,88 +806,149 @@ function kindOf(stats) {
588
806
  return "file";
589
807
  return "other";
590
808
  }
591
- /** The one production binding: `node:fs`, the temp-file convention, and the identity lock. */
592
- export const nodeFilesystemIdentityPort = Object.freeze({
593
- platform: process.platform,
594
- async probe(target) {
595
- let lstats;
596
- try {
597
- lstats = await fs.lstat(target);
598
- }
599
- catch (err) {
600
- if (isAbsentPathError(err))
601
- return null;
602
- throw err;
603
- }
604
- return { kind: kindOf(lstats), dev: lstats.dev, ino: lstats.ino };
605
- },
606
- async entries(dir) {
607
- try {
608
- const dirents = await fs.readdir(dir, { withFileTypes: true });
609
- return dirents.map((dirent) => ({ name: dirent.name, kind: kindOf(dirent) }));
809
+ /**
810
+ * Linux filesystem types (`statfs` magic numbers) whose directory times are kept by the local
811
+ * kernel and advance on every entry change. Anything else on Linux — NFS, SMB/CIFS, FUSE, 9p,
812
+ * Ceph, and every type not named here — gets no directory witness, so an observation pass lists it
813
+ * exactly as single reads do. Other platforms expose no stable type through Node, so their
814
+ * witnesses are offered and the pass's end-of-pass re-verification is what covers a remote mount.
815
+ */
816
+ const LOCAL_LINUX_FILESYSTEMS = new Set([
817
+ 0xef53, // ext2/3/4
818
+ 0x58465342, // xfs
819
+ 0x9123683e, // btrfs
820
+ 0x01021994, // tmpfs
821
+ 0x858458f6, // ramfs
822
+ 0x794c7630, // overlayfs
823
+ 0x2fc12fc1, // zfs
824
+ 0xf2f52010, // f2fs
825
+ 0xca451a4e, // bcachefs
826
+ 0x4d44, // vfat
827
+ 0x2011bab0, // exfat
828
+ 0x7366746e, // ntfs3
829
+ 0x482b, // hfsplus
830
+ ]);
831
+ /** Whether a directory witness may be offered on `platform` for a filesystem of `filesystemType`. */
832
+ export function directoryWitnessTrusted(platform, filesystemType) {
833
+ if (platform !== "linux")
834
+ return true;
835
+ return filesystemType !== null && LOCAL_LINUX_FILESYSTEMS.has(filesystemType);
836
+ }
837
+ /** Whether `dir`'s filesystem may offer directory witnesses, asked once per device per port. */
838
+ function witnessTrust() {
839
+ const devices = new Map();
840
+ return (dev, dir) => {
841
+ if (process.platform !== "linux")
842
+ return Promise.resolve(true);
843
+ let trusted = devices.get(dev);
844
+ if (trusted === undefined) {
845
+ trusted = fs.statfs(dir).then((info) => directoryWitnessTrusted("linux", Number(info.type)), () => false);
846
+ devices.set(dev, trusted);
610
847
  }
611
- catch (err) {
612
- if (isAbsentPathError(err))
848
+ return trusted;
849
+ };
850
+ }
851
+ /** The one production binding: `node:fs`, the temp-file convention, and the identity lock. */
852
+ export function createNodeFilesystemIdentityPort(hostPolicy) {
853
+ const policy = captureFilesystemHostPolicy(hostPolicy);
854
+ const witnessTrustedOn = witnessTrust();
855
+ return Object.freeze({
856
+ isTransientOpenError: policy.isTransientOpenError,
857
+ isReplacementConflict: policy.isReplacementConflict,
858
+ async probe(target) {
859
+ let lstats;
860
+ try {
861
+ lstats = await fs.lstat(target);
862
+ }
863
+ catch (err) {
864
+ if (isAbsentPathError(err))
865
+ return null;
866
+ throw err;
867
+ }
868
+ return { kind: kindOf(lstats), dev: lstats.dev, ino: lstats.ino };
869
+ },
870
+ async entries(dir) {
871
+ try {
872
+ const dirents = await fs.readdir(dir, { withFileTypes: true });
873
+ return dirents.map((dirent) => ({ name: dirent.name, kind: kindOf(dirent) }));
874
+ }
875
+ catch (err) {
876
+ if (isAbsentPathError(err))
877
+ return null;
878
+ throw err;
879
+ }
880
+ },
881
+ async directoryWitness(dir) {
882
+ let stats;
883
+ try {
884
+ stats = await fs.stat(dir, { bigint: true });
885
+ }
886
+ catch (err) {
887
+ if (isAbsentPathError(err))
888
+ return null;
889
+ throw err;
890
+ }
891
+ if (!(await witnessTrustedOn(stats.dev, dir)))
613
892
  return null;
614
- throw err;
615
- }
616
- },
617
- async open(target) {
618
- const handle = await fs.open(target, "r");
619
- try {
620
- const stats = await handle.stat();
621
- return { handle, dev: stats.dev, ino: stats.ino };
622
- }
623
- catch (err) {
624
- await handle.close().catch(() => { });
625
- throw err;
626
- }
627
- },
628
- readAll(handle) {
629
- return handle.readFile();
630
- },
631
- close(handle) {
632
- return handle.close();
633
- },
634
- async stat(target) {
635
- return { mtime: (await fs.stat(target)).mtime };
636
- },
637
- async mkdir(dir) {
638
- try {
639
- await fs.mkdir(dir);
640
- return "created";
641
- }
642
- catch (err) {
643
- if (err.code === "EEXIST")
644
- return "exists";
645
- throw err;
646
- }
647
- },
648
- async writeTemp(dir, name, bytes) {
649
- await fs.writeFile(path.join(dir, name), bytes);
650
- },
651
- async link(from, to) {
652
- try {
653
- await fs.link(from, to);
654
- return "linked";
655
- }
656
- catch (err) {
657
- const code = err.code;
658
- if (code === "EEXIST")
659
- return "exists";
660
- if (code === "EPERM" || code === "ENOTSUP" || code === "EOPNOTSUPP" || code === "EXDEV")
661
- return "unsupported";
662
- throw err;
663
- }
664
- },
665
- async rename(from, to) {
666
- await fs.rename(from, to);
667
- },
668
- async unlink(target) {
669
- await fs.unlink(target);
670
- },
671
- claim(key, identity) {
672
- return acquireFilesystemIdentityLock(key, `${identity.root}:${identity.rel}`, { portableRoot: identity.root });
673
- },
674
- });
893
+ return { dev: stats.dev, ino: stats.ino, mtimeNs: stats.mtimeNs, ctimeNs: stats.ctimeNs };
894
+ },
895
+ async open(target) {
896
+ const handle = await fs.open(target, "r");
897
+ try {
898
+ const stats = await handle.stat();
899
+ return { handle, dev: stats.dev, ino: stats.ino };
900
+ }
901
+ catch (err) {
902
+ await handle.close().catch(() => { });
903
+ throw err;
904
+ }
905
+ },
906
+ readAll(handle) {
907
+ return handle.readFile();
908
+ },
909
+ close(handle) {
910
+ return handle.close();
911
+ },
912
+ async stat(target) {
913
+ return { mtime: (await fs.stat(target)).mtime };
914
+ },
915
+ async mkdir(dir) {
916
+ try {
917
+ await fs.mkdir(dir);
918
+ return "created";
919
+ }
920
+ catch (err) {
921
+ if (err.code === "EEXIST")
922
+ return "exists";
923
+ throw err;
924
+ }
925
+ },
926
+ async writeTemp(dir, name, bytes) {
927
+ await fs.writeFile(path.join(dir, name), bytes);
928
+ },
929
+ async link(from, to) {
930
+ try {
931
+ await fs.link(from, to);
932
+ return "linked";
933
+ }
934
+ catch (err) {
935
+ const code = err.code;
936
+ if (code === "EEXIST")
937
+ return "exists";
938
+ if (code === "EPERM" || code === "ENOTSUP" || code === "EOPNOTSUPP" || code === "EXDEV")
939
+ return "unsupported";
940
+ throw err;
941
+ }
942
+ },
943
+ async rename(from, to) {
944
+ await fs.rename(from, to);
945
+ },
946
+ async unlink(target) {
947
+ await fs.unlink(target);
948
+ },
949
+ claim(key, identity) {
950
+ return acquireFilesystemIdentityLock(key, `${identity.root}:${identity.rel}`, { portableRoot: identity.root, hostPolicy: policy });
951
+ },
952
+ });
953
+ }
675
954
  //# sourceMappingURL=filesystem-identity.js.map