@aigne/afs-did-space 1.12.0-beta.5

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 (510) hide show
  1. package/LICENSE.md +26 -0
  2. package/README.md +129 -0
  3. package/dist/_virtual/_@oxc-project_runtime@0.108.0/helpers/decorate.cjs +11 -0
  4. package/dist/_virtual/_@oxc-project_runtime@0.108.0/helpers/decorate.mjs +10 -0
  5. package/dist/_virtual/rolldown_runtime.cjs +29 -0
  6. package/dist/afs-metadata-context.cjs +20 -0
  7. package/dist/afs-metadata-context.d.cts +21 -0
  8. package/dist/afs-metadata-context.d.cts.map +1 -0
  9. package/dist/afs-metadata-context.d.mts +21 -0
  10. package/dist/afs-metadata-context.d.mts.map +1 -0
  11. package/dist/afs-metadata-context.mjs +18 -0
  12. package/dist/afs-metadata-context.mjs.map +1 -0
  13. package/dist/blocklet-hook.cjs +180 -0
  14. package/dist/blocklet-hook.d.cts +29 -0
  15. package/dist/blocklet-hook.d.cts.map +1 -0
  16. package/dist/blocklet-hook.d.mts +29 -0
  17. package/dist/blocklet-hook.d.mts.map +1 -0
  18. package/dist/blocklet-hook.mjs +178 -0
  19. package/dist/blocklet-hook.mjs.map +1 -0
  20. package/dist/changelog-schema.cjs +603 -0
  21. package/dist/changelog-schema.d.cts +395 -0
  22. package/dist/changelog-schema.d.cts.map +1 -0
  23. package/dist/changelog-schema.d.mts +395 -0
  24. package/dist/changelog-schema.d.mts.map +1 -0
  25. package/dist/changelog-schema.mjs +570 -0
  26. package/dist/changelog-schema.mjs.map +1 -0
  27. package/dist/changelog-write.cjs +80 -0
  28. package/dist/changelog-write.d.cts +70 -0
  29. package/dist/changelog-write.d.cts.map +1 -0
  30. package/dist/changelog-write.d.mts +70 -0
  31. package/dist/changelog-write.d.mts.map +1 -0
  32. package/dist/changelog-write.mjs +77 -0
  33. package/dist/changelog-write.mjs.map +1 -0
  34. package/dist/cid-byte-cache.cjs +126 -0
  35. package/dist/cid-byte-cache.d.cts +46 -0
  36. package/dist/cid-byte-cache.d.cts.map +1 -0
  37. package/dist/cid-byte-cache.d.mts +47 -0
  38. package/dist/cid-byte-cache.d.mts.map +1 -0
  39. package/dist/cid-byte-cache.mjs +125 -0
  40. package/dist/cid-byte-cache.mjs.map +1 -0
  41. package/dist/cid.cjs +68 -0
  42. package/dist/cid.d.cts +22 -0
  43. package/dist/cid.d.cts.map +1 -0
  44. package/dist/cid.d.mts +22 -0
  45. package/dist/cid.d.mts.map +1 -0
  46. package/dist/cid.mjs +65 -0
  47. package/dist/cid.mjs.map +1 -0
  48. package/dist/client.cjs +221 -0
  49. package/dist/client.d.cts +72 -0
  50. package/dist/client.d.cts.map +1 -0
  51. package/dist/client.d.mts +72 -0
  52. package/dist/client.d.mts.map +1 -0
  53. package/dist/client.mjs +220 -0
  54. package/dist/client.mjs.map +1 -0
  55. package/dist/cloudflare.cjs +510 -0
  56. package/dist/cloudflare.d.cts +307 -0
  57. package/dist/cloudflare.d.cts.map +1 -0
  58. package/dist/cloudflare.d.mts +308 -0
  59. package/dist/cloudflare.d.mts.map +1 -0
  60. package/dist/cloudflare.mjs +507 -0
  61. package/dist/cloudflare.mjs.map +1 -0
  62. package/dist/ctime-backfill.cjs +272 -0
  63. package/dist/ctime-backfill.d.cts +169 -0
  64. package/dist/ctime-backfill.d.cts.map +1 -0
  65. package/dist/ctime-backfill.d.mts +169 -0
  66. package/dist/ctime-backfill.d.mts.map +1 -0
  67. package/dist/ctime-backfill.mjs +267 -0
  68. package/dist/ctime-backfill.mjs.map +1 -0
  69. package/dist/d1-gc-queue.cjs +80 -0
  70. package/dist/d1-gc-queue.d.cts +59 -0
  71. package/dist/d1-gc-queue.d.cts.map +1 -0
  72. package/dist/d1-gc-queue.d.mts +59 -0
  73. package/dist/d1-gc-queue.d.mts.map +1 -0
  74. package/dist/d1-gc-queue.mjs +81 -0
  75. package/dist/d1-gc-queue.mjs.map +1 -0
  76. package/dist/d1-resolve-store.cjs +189 -0
  77. package/dist/d1-resolve-store.d.cts +93 -0
  78. package/dist/d1-resolve-store.d.cts.map +1 -0
  79. package/dist/d1-resolve-store.d.mts +93 -0
  80. package/dist/d1-resolve-store.d.mts.map +1 -0
  81. package/dist/d1-resolve-store.mjs +190 -0
  82. package/dist/d1-resolve-store.mjs.map +1 -0
  83. package/dist/d1-schema.cjs +361 -0
  84. package/dist/d1-schema.d.cts +237 -0
  85. package/dist/d1-schema.d.cts.map +1 -0
  86. package/dist/d1-schema.d.mts +237 -0
  87. package/dist/d1-schema.d.mts.map +1 -0
  88. package/dist/d1-schema.mjs +341 -0
  89. package/dist/d1-schema.mjs.map +1 -0
  90. package/dist/d1-share-store.cjs +0 -0
  91. package/dist/d1-share-store.d.cts +53 -0
  92. package/dist/d1-share-store.d.cts.map +1 -0
  93. package/dist/d1-share-store.d.mts +53 -0
  94. package/dist/d1-share-store.d.mts.map +1 -0
  95. package/dist/d1-share-store.mjs +0 -0
  96. package/dist/d1-share-store.mjs.map +1 -0
  97. package/dist/d1-tree-index.cjs +1098 -0
  98. package/dist/d1-tree-index.d.cts +203 -0
  99. package/dist/d1-tree-index.d.cts.map +1 -0
  100. package/dist/d1-tree-index.d.mts +203 -0
  101. package/dist/d1-tree-index.d.mts.map +1 -0
  102. package/dist/d1-tree-index.mjs +1094 -0
  103. package/dist/d1-tree-index.mjs.map +1 -0
  104. package/dist/data-backend.cjs +147 -0
  105. package/dist/data-backend.d.cts +30 -0
  106. package/dist/data-backend.d.cts.map +1 -0
  107. package/dist/data-backend.d.mts +30 -0
  108. package/dist/data-backend.d.mts.map +1 -0
  109. package/dist/data-backend.mjs +148 -0
  110. package/dist/data-backend.mjs.map +1 -0
  111. package/dist/dedup-backfill.cjs +278 -0
  112. package/dist/dedup-backfill.d.cts +165 -0
  113. package/dist/dedup-backfill.d.cts.map +1 -0
  114. package/dist/dedup-backfill.d.mts +165 -0
  115. package/dist/dedup-backfill.d.mts.map +1 -0
  116. package/dist/dedup-backfill.mjs +273 -0
  117. package/dist/dedup-backfill.mjs.map +1 -0
  118. package/dist/did-space-like.d.cts +2 -0
  119. package/dist/did-space-like.d.mts +2 -0
  120. package/dist/did-utils.cjs +44 -0
  121. package/dist/did-utils.d.cts +25 -0
  122. package/dist/did-utils.d.cts.map +1 -0
  123. package/dist/did-utils.d.mts +25 -0
  124. package/dist/did-utils.d.mts.map +1 -0
  125. package/dist/did-utils.mjs +43 -0
  126. package/dist/did-utils.mjs.map +1 -0
  127. package/dist/dirty-path-queue.cjs +31 -0
  128. package/dist/dirty-path-queue.d.cts +104 -0
  129. package/dist/dirty-path-queue.d.cts.map +1 -0
  130. package/dist/dirty-path-queue.d.mts +104 -0
  131. package/dist/dirty-path-queue.d.mts.map +1 -0
  132. package/dist/dirty-path-queue.mjs +31 -0
  133. package/dist/dirty-path-queue.mjs.map +1 -0
  134. package/dist/dirty-path-schema.cjs +142 -0
  135. package/dist/dirty-path-schema.d.cts +90 -0
  136. package/dist/dirty-path-schema.d.cts.map +1 -0
  137. package/dist/dirty-path-schema.d.mts +90 -0
  138. package/dist/dirty-path-schema.d.mts.map +1 -0
  139. package/dist/dirty-path-schema.mjs +136 -0
  140. package/dist/dirty-path-schema.mjs.map +1 -0
  141. package/dist/download-actions.cjs +43 -0
  142. package/dist/download-actions.mjs +40 -0
  143. package/dist/download-actions.mjs.map +1 -0
  144. package/dist/fs-object-store.cjs +153 -0
  145. package/dist/fs-object-store.d.cts +21 -0
  146. package/dist/fs-object-store.d.cts.map +1 -0
  147. package/dist/fs-object-store.d.mts +22 -0
  148. package/dist/fs-object-store.d.mts.map +1 -0
  149. package/dist/fs-object-store.mjs +153 -0
  150. package/dist/fs-object-store.mjs.map +1 -0
  151. package/dist/gc-queue.d.cts +43 -0
  152. package/dist/gc-queue.d.cts.map +1 -0
  153. package/dist/gc-queue.d.mts +43 -0
  154. package/dist/gc-queue.d.mts.map +1 -0
  155. package/dist/index.cjs +2712 -0
  156. package/dist/index.d.cts +504 -0
  157. package/dist/index.d.cts.map +1 -0
  158. package/dist/index.d.mts +505 -0
  159. package/dist/index.d.mts.map +1 -0
  160. package/dist/index.mjs +2537 -0
  161. package/dist/index.mjs.map +1 -0
  162. package/dist/inline-content-migration.cjs +212 -0
  163. package/dist/inline-content-migration.d.cts +110 -0
  164. package/dist/inline-content-migration.d.cts.map +1 -0
  165. package/dist/inline-content-migration.d.mts +111 -0
  166. package/dist/inline-content-migration.d.mts.map +1 -0
  167. package/dist/inline-content-migration.mjs +207 -0
  168. package/dist/inline-content-migration.mjs.map +1 -0
  169. package/dist/inline-content.cjs +145 -0
  170. package/dist/inline-content.d.cts +98 -0
  171. package/dist/inline-content.d.cts.map +1 -0
  172. package/dist/inline-content.d.mts +98 -0
  173. package/dist/inline-content.d.mts.map +1 -0
  174. package/dist/inline-content.mjs +137 -0
  175. package/dist/inline-content.mjs.map +1 -0
  176. package/dist/local-changelog.cjs +241 -0
  177. package/dist/local-changelog.d.cts +119 -0
  178. package/dist/local-changelog.d.cts.map +1 -0
  179. package/dist/local-changelog.d.mts +119 -0
  180. package/dist/local-changelog.d.mts.map +1 -0
  181. package/dist/local-changelog.mjs +240 -0
  182. package/dist/local-changelog.mjs.map +1 -0
  183. package/dist/local.cjs +435 -0
  184. package/dist/local.d.cts +254 -0
  185. package/dist/local.d.cts.map +1 -0
  186. package/dist/local.d.mts +254 -0
  187. package/dist/local.d.mts.map +1 -0
  188. package/dist/local.mjs +427 -0
  189. package/dist/local.mjs.map +1 -0
  190. package/dist/memory-gc-queue.cjs +36 -0
  191. package/dist/memory-gc-queue.d.cts +22 -0
  192. package/dist/memory-gc-queue.d.cts.map +1 -0
  193. package/dist/memory-gc-queue.d.mts +22 -0
  194. package/dist/memory-gc-queue.d.mts.map +1 -0
  195. package/dist/memory-gc-queue.mjs +36 -0
  196. package/dist/memory-gc-queue.mjs.map +1 -0
  197. package/dist/memory-tree-index.cjs +734 -0
  198. package/dist/memory-tree-index.d.cts +159 -0
  199. package/dist/memory-tree-index.d.cts.map +1 -0
  200. package/dist/memory-tree-index.d.mts +159 -0
  201. package/dist/memory-tree-index.d.mts.map +1 -0
  202. package/dist/memory-tree-index.mjs +735 -0
  203. package/dist/memory-tree-index.mjs.map +1 -0
  204. package/dist/metadata-db.cjs +562 -0
  205. package/dist/metadata-db.d.cts +102 -0
  206. package/dist/metadata-db.d.cts.map +1 -0
  207. package/dist/metadata-db.d.mts +102 -0
  208. package/dist/metadata-db.d.mts.map +1 -0
  209. package/dist/metadata-db.mjs +562 -0
  210. package/dist/metadata-db.mjs.map +1 -0
  211. package/dist/mime-utils.cjs +2 -0
  212. package/dist/mime-utils.d.cts +2 -0
  213. package/dist/mime-utils.d.mts +2 -0
  214. package/dist/mime-utils.mjs +3 -0
  215. package/dist/object-key.cjs +41 -0
  216. package/dist/object-key.d.cts +25 -0
  217. package/dist/object-key.d.cts.map +1 -0
  218. package/dist/object-key.d.mts +25 -0
  219. package/dist/object-key.d.mts.map +1 -0
  220. package/dist/object-key.mjs +40 -0
  221. package/dist/object-key.mjs.map +1 -0
  222. package/dist/packages/session/dist/index.cjs +788 -0
  223. package/dist/packages/session/dist/index.mjs +782 -0
  224. package/dist/packages/session/dist/index.mjs.map +1 -0
  225. package/dist/platform/r2/dist/types.d.cts +49 -0
  226. package/dist/platform/r2/dist/types.d.cts.map +1 -0
  227. package/dist/prefix-range.cjs +33 -0
  228. package/dist/prefix-range.d.cts +29 -0
  229. package/dist/prefix-range.d.cts.map +1 -0
  230. package/dist/prefix-range.d.mts +29 -0
  231. package/dist/prefix-range.d.mts.map +1 -0
  232. package/dist/prefix-range.mjs +33 -0
  233. package/dist/prefix-range.mjs.map +1 -0
  234. package/dist/prefixed-tree-index.cjs +238 -0
  235. package/dist/prefixed-tree-index.d.cts +85 -0
  236. package/dist/prefixed-tree-index.d.cts.map +1 -0
  237. package/dist/prefixed-tree-index.d.mts +85 -0
  238. package/dist/prefixed-tree-index.d.mts.map +1 -0
  239. package/dist/prefixed-tree-index.mjs +239 -0
  240. package/dist/prefixed-tree-index.mjs.map +1 -0
  241. package/dist/presign-signer.cjs +7 -0
  242. package/dist/presign-signer.d.cts +99 -0
  243. package/dist/presign-signer.d.cts.map +1 -0
  244. package/dist/presign-signer.d.mts +99 -0
  245. package/dist/presign-signer.d.mts.map +1 -0
  246. package/dist/presign-signer.mjs +7 -0
  247. package/dist/presign-signer.mjs.map +1 -0
  248. package/dist/providers/platform/r2/dist/index.d.mts +3 -0
  249. package/dist/providers/platform/r2/dist/types.d.mts +49 -0
  250. package/dist/providers/platform/r2/dist/types.d.mts.map +1 -0
  251. package/dist/reconcile.cjs +184 -0
  252. package/dist/reconcile.d.cts +26 -0
  253. package/dist/reconcile.d.cts.map +1 -0
  254. package/dist/reconcile.d.mts +26 -0
  255. package/dist/reconcile.d.mts.map +1 -0
  256. package/dist/reconcile.mjs +184 -0
  257. package/dist/reconcile.mjs.map +1 -0
  258. package/dist/reference-check.cjs +49 -0
  259. package/dist/reference-check.d.cts +10 -0
  260. package/dist/reference-check.d.cts.map +1 -0
  261. package/dist/reference-check.d.mts +10 -0
  262. package/dist/reference-check.d.mts.map +1 -0
  263. package/dist/reference-check.mjs +48 -0
  264. package/dist/reference-check.mjs.map +1 -0
  265. package/dist/remote-afs.cjs +681 -0
  266. package/dist/remote-afs.d.cts +236 -0
  267. package/dist/remote-afs.d.cts.map +1 -0
  268. package/dist/remote-afs.d.mts +236 -0
  269. package/dist/remote-afs.d.mts.map +1 -0
  270. package/dist/remote-afs.mjs +676 -0
  271. package/dist/remote-afs.mjs.map +1 -0
  272. package/dist/rename-guard.cjs +18 -0
  273. package/dist/rename-guard.mjs +18 -0
  274. package/dist/rename-guard.mjs.map +1 -0
  275. package/dist/resolve.cjs +260 -0
  276. package/dist/resolve.d.cts +113 -0
  277. package/dist/resolve.d.cts.map +1 -0
  278. package/dist/resolve.d.mts +113 -0
  279. package/dist/resolve.d.mts.map +1 -0
  280. package/dist/resolve.mjs +260 -0
  281. package/dist/resolve.mjs.map +1 -0
  282. package/dist/rsync-content.cjs +33 -0
  283. package/dist/rsync-content.mjs +33 -0
  284. package/dist/rsync-content.mjs.map +1 -0
  285. package/dist/rsync.cjs +400 -0
  286. package/dist/rsync.d.cts +157 -0
  287. package/dist/rsync.d.cts.map +1 -0
  288. package/dist/rsync.d.mts +157 -0
  289. package/dist/rsync.d.mts.map +1 -0
  290. package/dist/rsync.mjs +397 -0
  291. package/dist/rsync.mjs.map +1 -0
  292. package/dist/run-gc.cjs +57 -0
  293. package/dist/run-gc.d.cts +40 -0
  294. package/dist/run-gc.d.cts.map +1 -0
  295. package/dist/run-gc.d.mts +41 -0
  296. package/dist/run-gc.d.mts.map +1 -0
  297. package/dist/run-gc.mjs +57 -0
  298. package/dist/run-gc.mjs.map +1 -0
  299. package/dist/scope-id.cjs +70 -0
  300. package/dist/scope-id.d.cts +35 -0
  301. package/dist/scope-id.d.cts.map +1 -0
  302. package/dist/scope-id.d.mts +35 -0
  303. package/dist/scope-id.d.mts.map +1 -0
  304. package/dist/scope-id.mjs +68 -0
  305. package/dist/scope-id.mjs.map +1 -0
  306. package/dist/scope-migration-node.cjs +172 -0
  307. package/dist/scope-migration-node.d.cts +44 -0
  308. package/dist/scope-migration-node.d.cts.map +1 -0
  309. package/dist/scope-migration-node.d.mts +44 -0
  310. package/dist/scope-migration-node.d.mts.map +1 -0
  311. package/dist/scope-migration-node.mjs +171 -0
  312. package/dist/scope-migration-node.mjs.map +1 -0
  313. package/dist/scope-migration.cjs +155 -0
  314. package/dist/scope-migration.d.cts +65 -0
  315. package/dist/scope-migration.d.cts.map +1 -0
  316. package/dist/scope-migration.d.mts +65 -0
  317. package/dist/scope-migration.d.mts.map +1 -0
  318. package/dist/scope-migration.mjs +154 -0
  319. package/dist/scope-migration.mjs.map +1 -0
  320. package/dist/share-declaration.cjs +225 -0
  321. package/dist/share-declaration.d.cts +30 -0
  322. package/dist/share-declaration.d.cts.map +1 -0
  323. package/dist/share-declaration.d.mts +32 -0
  324. package/dist/share-declaration.d.mts.map +1 -0
  325. package/dist/share-declaration.mjs +221 -0
  326. package/dist/share-declaration.mjs.map +1 -0
  327. package/dist/share-hook.cjs +63 -0
  328. package/dist/share-hook.mjs +62 -0
  329. package/dist/share-hook.mjs.map +1 -0
  330. package/dist/share-resolve.cjs +176 -0
  331. package/dist/share-resolve.d.cts +36 -0
  332. package/dist/share-resolve.d.cts.map +1 -0
  333. package/dist/share-resolve.d.mts +36 -0
  334. package/dist/share-resolve.d.mts.map +1 -0
  335. package/dist/share-resolve.mjs +177 -0
  336. package/dist/share-resolve.mjs.map +1 -0
  337. package/dist/share-serve.cjs +145 -0
  338. package/dist/share-serve.d.cts +30 -0
  339. package/dist/share-serve.d.cts.map +1 -0
  340. package/dist/share-serve.d.mts +30 -0
  341. package/dist/share-serve.d.mts.map +1 -0
  342. package/dist/share-serve.mjs +144 -0
  343. package/dist/share-serve.mjs.map +1 -0
  344. package/dist/share-store.cjs +25 -0
  345. package/dist/share-store.d.cts +65 -0
  346. package/dist/share-store.d.cts.map +1 -0
  347. package/dist/share-store.d.mts +65 -0
  348. package/dist/share-store.d.mts.map +1 -0
  349. package/dist/share-store.mjs +25 -0
  350. package/dist/share-store.mjs.map +1 -0
  351. package/dist/share-virtual-path.cjs +102 -0
  352. package/dist/share-virtual-path.mjs +101 -0
  353. package/dist/share-virtual-path.mjs.map +1 -0
  354. package/dist/space-resolver.cjs +54 -0
  355. package/dist/space-resolver.d.cts +34 -0
  356. package/dist/space-resolver.d.cts.map +1 -0
  357. package/dist/space-resolver.d.mts +34 -0
  358. package/dist/space-resolver.d.mts.map +1 -0
  359. package/dist/space-resolver.mjs +55 -0
  360. package/dist/space-resolver.mjs.map +1 -0
  361. package/dist/sqlite-gc-queue.cjs +51 -0
  362. package/dist/sqlite-gc-queue.d.cts +22 -0
  363. package/dist/sqlite-gc-queue.d.cts.map +1 -0
  364. package/dist/sqlite-gc-queue.d.mts +22 -0
  365. package/dist/sqlite-gc-queue.d.mts.map +1 -0
  366. package/dist/sqlite-gc-queue.mjs +52 -0
  367. package/dist/sqlite-gc-queue.mjs.map +1 -0
  368. package/dist/sqlite-resolve-store.cjs +163 -0
  369. package/dist/sqlite-resolve-store.d.cts +50 -0
  370. package/dist/sqlite-resolve-store.d.cts.map +1 -0
  371. package/dist/sqlite-resolve-store.d.mts +50 -0
  372. package/dist/sqlite-resolve-store.d.mts.map +1 -0
  373. package/dist/sqlite-resolve-store.mjs +164 -0
  374. package/dist/sqlite-resolve-store.mjs.map +1 -0
  375. package/dist/sqlite-share-store.cjs +157 -0
  376. package/dist/sqlite-share-store.d.cts +31 -0
  377. package/dist/sqlite-share-store.d.cts.map +1 -0
  378. package/dist/sqlite-share-store.d.mts +31 -0
  379. package/dist/sqlite-share-store.d.mts.map +1 -0
  380. package/dist/sqlite-share-store.mjs +157 -0
  381. package/dist/sqlite-share-store.mjs.map +1 -0
  382. package/dist/sqlite-tree-index.cjs +901 -0
  383. package/dist/sqlite-tree-index.d.cts +107 -0
  384. package/dist/sqlite-tree-index.d.cts.map +1 -0
  385. package/dist/sqlite-tree-index.d.mts +107 -0
  386. package/dist/sqlite-tree-index.d.mts.map +1 -0
  387. package/dist/sqlite-tree-index.mjs +902 -0
  388. package/dist/sqlite-tree-index.mjs.map +1 -0
  389. package/dist/sync-engine.cjs +1324 -0
  390. package/dist/sync-engine.d.cts +473 -0
  391. package/dist/sync-engine.d.cts.map +1 -0
  392. package/dist/sync-engine.d.mts +473 -0
  393. package/dist/sync-engine.d.mts.map +1 -0
  394. package/dist/sync-engine.mjs +1315 -0
  395. package/dist/sync-engine.mjs.map +1 -0
  396. package/dist/sync-state.cjs +303 -0
  397. package/dist/sync-state.d.cts +224 -0
  398. package/dist/sync-state.d.cts.map +1 -0
  399. package/dist/sync-state.d.mts +224 -0
  400. package/dist/sync-state.d.mts.map +1 -0
  401. package/dist/sync-state.mjs +297 -0
  402. package/dist/sync-state.mjs.map +1 -0
  403. package/dist/timestamp.cjs +92 -0
  404. package/dist/timestamp.mjs +91 -0
  405. package/dist/timestamp.mjs.map +1 -0
  406. package/dist/transports/http.cjs +54 -0
  407. package/dist/transports/http.d.cts +26 -0
  408. package/dist/transports/http.d.cts.map +1 -0
  409. package/dist/transports/http.d.mts +26 -0
  410. package/dist/transports/http.d.mts.map +1 -0
  411. package/dist/transports/http.mjs +54 -0
  412. package/dist/transports/http.mjs.map +1 -0
  413. package/dist/transports/static.cjs +55 -0
  414. package/dist/transports/static.d.cts +28 -0
  415. package/dist/transports/static.d.cts.map +1 -0
  416. package/dist/transports/static.d.mts +28 -0
  417. package/dist/transports/static.d.mts.map +1 -0
  418. package/dist/transports/static.mjs +55 -0
  419. package/dist/transports/static.mjs.map +1 -0
  420. package/dist/transports/types.cjs +13 -0
  421. package/dist/transports/types.d.cts +72 -0
  422. package/dist/transports/types.d.cts.map +1 -0
  423. package/dist/transports/types.d.mts +72 -0
  424. package/dist/transports/types.d.mts.map +1 -0
  425. package/dist/transports/types.mjs +13 -0
  426. package/dist/transports/types.mjs.map +1 -0
  427. package/dist/transports/ws.cjs +207 -0
  428. package/dist/transports/ws.d.cts +47 -0
  429. package/dist/transports/ws.d.cts.map +1 -0
  430. package/dist/transports/ws.d.mts +47 -0
  431. package/dist/transports/ws.d.mts.map +1 -0
  432. package/dist/transports/ws.mjs +206 -0
  433. package/dist/transports/ws.mjs.map +1 -0
  434. package/dist/tree-index.cjs +333 -0
  435. package/dist/tree-index.d.cts +524 -0
  436. package/dist/tree-index.d.cts.map +1 -0
  437. package/dist/tree-index.d.mts +524 -0
  438. package/dist/tree-index.d.mts.map +1 -0
  439. package/dist/tree-index.mjs +322 -0
  440. package/dist/tree-index.mjs.map +1 -0
  441. package/dist/tree-query.cjs +655 -0
  442. package/dist/tree-query.d.cts +70 -0
  443. package/dist/tree-query.d.cts.map +1 -0
  444. package/dist/tree-query.d.mts +70 -0
  445. package/dist/tree-query.d.mts.map +1 -0
  446. package/dist/tree-query.mjs +648 -0
  447. package/dist/tree-query.mjs.map +1 -0
  448. package/dist/upload-actions.cjs +97 -0
  449. package/dist/upload-actions.d.cts +19 -0
  450. package/dist/upload-actions.d.cts.map +1 -0
  451. package/dist/upload-actions.d.mts +21 -0
  452. package/dist/upload-actions.d.mts.map +1 -0
  453. package/dist/upload-actions.mjs +90 -0
  454. package/dist/upload-actions.mjs.map +1 -0
  455. package/dist/upload-session-store.cjs +185 -0
  456. package/dist/upload-session-store.d.cts +99 -0
  457. package/dist/upload-session-store.d.cts.map +1 -0
  458. package/dist/upload-session-store.d.mts +99 -0
  459. package/dist/upload-session-store.d.mts.map +1 -0
  460. package/dist/upload-session-store.mjs +184 -0
  461. package/dist/upload-session-store.mjs.map +1 -0
  462. package/dist/url-normalize.cjs +61 -0
  463. package/dist/url-normalize.d.cts +33 -0
  464. package/dist/url-normalize.d.cts.map +1 -0
  465. package/dist/url-normalize.d.mts +33 -0
  466. package/dist/url-normalize.d.mts.map +1 -0
  467. package/dist/url-normalize.mjs +61 -0
  468. package/dist/url-normalize.mjs.map +1 -0
  469. package/dist/versioned-content-backends.cjs +155 -0
  470. package/dist/versioned-content-backends.d.cts +49 -0
  471. package/dist/versioned-content-backends.d.cts.map +1 -0
  472. package/dist/versioned-content-backends.d.mts +49 -0
  473. package/dist/versioned-content-backends.d.mts.map +1 -0
  474. package/dist/versioned-content-backends.mjs +154 -0
  475. package/dist/versioned-content-backends.mjs.map +1 -0
  476. package/dist/versioned-content-index.cjs +102 -0
  477. package/dist/versioned-content-index.d.cts +46 -0
  478. package/dist/versioned-content-index.d.cts.map +1 -0
  479. package/dist/versioned-content-index.d.mts +46 -0
  480. package/dist/versioned-content-index.d.mts.map +1 -0
  481. package/dist/versioned-content-index.mjs +103 -0
  482. package/dist/versioned-content-index.mjs.map +1 -0
  483. package/dist/versioned-content-store.cjs +121 -0
  484. package/dist/versioned-content-store.d.cts +90 -0
  485. package/dist/versioned-content-store.d.cts.map +1 -0
  486. package/dist/versioned-content-store.d.mts +90 -0
  487. package/dist/versioned-content-store.d.mts.map +1 -0
  488. package/dist/versioned-content-store.mjs +122 -0
  489. package/dist/versioned-content-store.mjs.map +1 -0
  490. package/dist/versioned-scope.cjs +39 -0
  491. package/dist/versioned-scope.d.cts +57 -0
  492. package/dist/versioned-scope.d.cts.map +1 -0
  493. package/dist/versioned-scope.d.mts +57 -0
  494. package/dist/versioned-scope.d.mts.map +1 -0
  495. package/dist/versioned-scope.mjs +37 -0
  496. package/dist/versioned-scope.mjs.map +1 -0
  497. package/migrations/0001_tree_entries.sql +17 -0
  498. package/migrations/0002_resolve_entries.sql +7 -0
  499. package/migrations/0003_entries_v2.sql +38 -0
  500. package/migrations/0004_gc_queue.sql +5 -0
  501. package/migrations/0006_resolve_enhance.sql +14 -0
  502. package/migrations/0007_resolve_created_at.sql +10 -0
  503. package/migrations/0008_changelog.sql +34 -0
  504. package/migrations/0009_device_sync_state.sql +29 -0
  505. package/migrations/0010_scope_meta.sql +33 -0
  506. package/migrations/0011_shares.sql +25 -0
  507. package/migrations/0012_scope_meta_file_count.sql +41 -0
  508. package/migrations/0013_scope_meta_total_bytes.sql +47 -0
  509. package/migrations/0014_rename_tables.sql +62 -0
  510. package/package.json +102 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inline-content-migration.mjs","names":[],"sources":["../src/inline-content-migration.ts"],"sourcesContent":["/**\n * inline-content-migration — one-time backfill of the inline `content` column\n * for upload-plane-synced rows that were committed metadata-only\n * (inline-content-commit §7, mechanism A: server paged sweep).\n *\n * The forward fix (Phases 1-2) stops NEW upload-plane commits from dropping the\n * inline copy; this sweep repairs EXISTING `content IS NULL` rows so the\n * collection query (json_extract over the content column) sees them too.\n *\n * Trigger surface (resolved at Phase 6): an OFFLINE script calls\n * {@link backfillInlineContent} — NOT a permanent exec action. The core loop\n * here is backend-agnostic (the SQL lives in {@link InlineBackfillBackend}\n * adapters) so it is unit-testable against a mock D1 + MemoryObjectStore, and a\n * thin script wires the real DB + object store.\n *\n * Invariants:\n * - **R2 is the only place the bytes live**, so each candidate = 1 R2 GET. Size\n * the page to the deployment tier (≤40/free, a few hundred/paid) and run it\n * OFF the hot path, throttled — this is exactly the回源 the commit path\n * refuses to do (§10).\n * - **Text judged by `detectMimeType(path)`, NOT the `mime_type` column** — old\n * upload-plane rows have `mime_type` NULL too (toEntry sent none), so a\n * column filter would skip the very rows we fix. The mime is backfilled here.\n * - **Idempotent**: only `content IS NULL` rows are selected, and `backfillRow`\n * re-checks `content IS NULL`, so a re-run is a no-op. The path cursor\n * advances past EVERY scanned row (including skips) so a single invocation\n * can't loop; a fresh invocation re-scans from the start and naturally\n * re-selects the still-NULL rows a prior pass deferred.\n * - **Per-row fail-soft**: object 404 → skip + log (never fail the page);\n * transient R2 error → bounded retry then defer (row stays NULL → re-selected\n * next pass); cid mismatch → skip (never store bytes that don't hash to cid).\n */\n\nimport type { ObjectStore } from \"@aigne/afs-r2\";\nimport { computeCID } from \"./cid.js\";\nimport { DEFAULT_INLINE_THRESHOLD, decodeInlineText } from \"./inline-content.js\";\nimport { detectMimeType, isTextMime } from \"./mime-utils.js\";\nimport { objectKeyForCid } from \"./object-key.js\";\n\n/** A content-NULL file row eligible for inline backfill. */\nexport interface InlineBackfillCandidate {\n path: string;\n cid: string;\n size: number;\n}\n\n/** Backend-specific SQL for the sweep (D1 vs Node SQLite). */\nexport interface InlineBackfillBackend {\n /**\n * Select up to `limit` content-NULL FILE rows with `path > cursor` and\n * `size <= threshold`, ordered by `path ASC` (the keyset cursor). Empty array\n * ⇒ no more candidates after `cursor`.\n */\n selectCandidates(\n cursor: string,\n limit: number,\n threshold: number,\n ): Promise<InlineBackfillCandidate[]>;\n /**\n * Set `content` + `mime_type` for `path` ONLY IF the row is still\n * `content IS NULL` (idempotent — a concurrent/earlier fill wins). `mimeType`\n * is `null` for extensionless / unknown-extension paths — stored as SQL NULL\n * to match the write path (so `isTextMime(null)` stays true and the read path\n * still serves the inline copy; an empty string would flip `isTextMime` false).\n */\n backfillRow(path: string, content: string, mimeType: string | null): Promise<void>;\n}\n\nexport interface InlineBackfillOptions {\n /** `size <= threshold` filter (default {@link DEFAULT_INLINE_THRESHOLD} = 2 KB). */\n threshold?: number;\n /** Rows per page = R2 GETs per page. Default 40 (free-tier 50-subrequest safe). */\n pageSize?: number;\n /** Cap pages this invocation (cross-invocation paging). Default unbounded. */\n maxPages?: number;\n /** Sleep (ms) after each R2 read to pace subrequests. Default 0. */\n throttleMs?: number;\n /** Bounded retries on a transient R2 error before deferring the row. Default 2. */\n retries?: number;\n /** Injectable sleep (tests pass a no-op). */\n sleep?: (ms: number) => Promise<void>;\n /** Progress / skip logger. */\n log?: (msg: string) => void;\n}\n\nexport interface InlineBackfillStats {\n scanned: number;\n backfilled: number;\n skippedNonText: number;\n skippedMissing: number;\n skippedMismatch: number;\n deferredError: number;\n pages: number;\n lastCursor: string;\n /** True when a page came back empty (the sweep reached the end). */\n done: boolean;\n}\n\nconst defaultSleep = (ms: number) => new Promise<void>((r) => setTimeout(r, ms));\n\n/**\n * Page over content-NULL rows and backfill the inline copy from R2. Returns\n * stats; resumable across invocations (a fresh call re-scans from the start and\n * re-selects whatever is still NULL).\n */\nexport async function backfillInlineContent(\n backend: InlineBackfillBackend,\n objectStore: ObjectStore,\n opts: InlineBackfillOptions = {},\n): Promise<InlineBackfillStats> {\n const threshold = opts.threshold ?? DEFAULT_INLINE_THRESHOLD;\n const pageSize = opts.pageSize ?? 40;\n const maxPages = opts.maxPages ?? Number.POSITIVE_INFINITY;\n const retries = opts.retries ?? 2;\n const throttleMs = opts.throttleMs ?? 0;\n const sleep = opts.sleep ?? defaultSleep;\n const log = opts.log ?? (() => {});\n\n const stats: InlineBackfillStats = {\n scanned: 0,\n backfilled: 0,\n skippedNonText: 0,\n skippedMissing: 0,\n skippedMismatch: 0,\n deferredError: 0,\n pages: 0,\n lastCursor: \"\",\n done: false,\n };\n\n let cursor = \"\";\n while (stats.pages < maxPages) {\n const rows = await backend.selectCandidates(cursor, pageSize, threshold);\n if (rows.length === 0) {\n stats.done = true;\n break;\n }\n stats.pages++;\n for (const row of rows) {\n stats.scanned++;\n cursor = row.path; // advance past EVERY scanned row so a single pass can't loop\n stats.lastCursor = cursor;\n\n // Text judged by path, NOT the (likely-NULL) mime_type column.\n const mime = detectMimeType(row.path);\n if (!isTextMime(mime)) {\n stats.skippedNonText++;\n continue;\n }\n\n // Read the bytes from R2 (the only place they live). 404 → skip; transient\n // → bounded retry then defer (stays NULL → re-selected next invocation).\n let bytes: Uint8Array | null = null;\n let lastErr: unknown;\n let absent = false;\n for (let attempt = 0; attempt <= retries; attempt++) {\n try {\n const obj = await objectStore.get(objectKeyForCid(row.cid));\n if (!obj) {\n absent = true;\n } else {\n bytes = new Uint8Array(await obj.arrayBuffer());\n }\n lastErr = undefined;\n break;\n } catch (e) {\n lastErr = e;\n if (attempt < retries) await sleep(throttleMs || 50);\n }\n }\n if (lastErr !== undefined) {\n stats.deferredError++;\n log(`defer ${row.path}: R2 read error ${String(lastErr)}`);\n continue;\n }\n if (absent) {\n stats.skippedMissing++;\n log(`skip ${row.path}: object ${row.cid} missing (404)`);\n continue;\n }\n\n // Decode (text-mime + ≤hard-cap + strict UTF-8) — null = not inlinable.\n const content = decodeInlineText(bytes as Uint8Array, mime ?? undefined);\n if (content === null) {\n stats.skippedNonText++;\n continue;\n }\n // Never store bytes that don't hash to the row cid (write-path contract).\n if ((await computeCID(content)) !== row.cid) {\n stats.skippedMismatch++;\n log(`skip ${row.path}: cid mismatch (content hash != ${row.cid})`);\n continue;\n }\n\n await backend.backfillRow(row.path, content, mime ?? null);\n stats.backfilled++;\n if (throttleMs > 0) await sleep(throttleMs);\n }\n }\n return stats;\n}\n\nconst SELECT_SQL =\n \"SELECT path, cid, size FROM ds_entries WHERE scope = ? AND kind = 'file' \" +\n \"AND content IS NULL AND size <= ? AND path > ? ORDER BY path ASC LIMIT ?\";\nconst UPDATE_SQL =\n \"UPDATE ds_entries SET content = ?, mime_type = ? WHERE scope = ? AND path = ? AND content IS NULL\";\n\n/** D1 (Cloudflare) backend adapter — the same SQL the index uses. */\nexport function makeD1InlineBackfillBackend(db: D1Database, scope: string): InlineBackfillBackend {\n return {\n async selectCandidates(cursor, limit, threshold) {\n const res = await db.prepare(SELECT_SQL).bind(scope, threshold, cursor, limit).all();\n return ((res.results ?? []) as Array<Record<string, unknown>>).map((r) => ({\n path: String(r.path),\n cid: String(r.cid),\n size: Number(r.size),\n }));\n },\n async backfillRow(path, content, mimeType) {\n await db.prepare(UPDATE_SQL).bind(content, mimeType, scope, path).run();\n },\n };\n}\n\n/**\n * Minimal libsql client shape the SQLite adapter needs (Node `_metadata.db`).\n * `args` is narrowed to `(string | number)[]` — exactly what the sweep binds —\n * so a real `@libsql/client` `Client` is structurally assignable (a wider\n * `unknown[]` is not assignable to libsql's `InValue[]`).\n */\nexport interface LibsqlLike {\n execute(stmt: { sql: string; args: (string | number | null)[] }): Promise<{\n rows: Array<Record<string, unknown>>;\n }>;\n}\n\n/** Node SQLite (libsql) backend adapter. */\nexport function makeSqliteInlineBackfillBackend(\n db: LibsqlLike,\n scope: string,\n): InlineBackfillBackend {\n return {\n async selectCandidates(cursor, limit, threshold) {\n const res = await db.execute({ sql: SELECT_SQL, args: [scope, threshold, cursor, limit] });\n return res.rows.map((r) => ({\n path: String(r.path),\n cid: String(r.cid),\n size: Number(r.size),\n }));\n },\n async backfillRow(path, content, mimeType) {\n await db.execute({ sql: UPDATE_SQL, args: [content, mimeType, scope, path] });\n },\n };\n}\n\nconst DISTINCT_NULL_SCOPES_SQL =\n \"SELECT DISTINCT scope FROM ds_entries WHERE kind = 'file' AND content IS NULL AND size <= ?\";\n\n/**\n * CF D1 over the HTTP API (`POST /accounts/{acct}/d1/database/{db}/query`) — the\n * OFFLINE realization of mechanism A for staging/prod CF: a Node process holds a\n * Cloudflare API token with D1-edit and runs the SAME paged sweep SQL the worker\n * would, while reading R2 objects out-of-band (the script supplies the\n * ObjectStore — e.g. R2 presigned GET). `fetchImpl` is injectable for tests.\n */\nexport interface D1HttpConfig {\n accountId: string;\n databaseId: string;\n apiToken: string;\n scope: string;\n fetchImpl?: typeof fetch;\n /**\n * Bounded retries for TRANSIENT D1 HTTP failures (5xx — incl. the occasional\n * `code 7500 internal error` — / 429 / network) with exponential backoff. A\n * one-off CF hiccup must NOT abort a multi-thousand-row sweep. Permanent 4xx\n * (auth/SQL) throw immediately. Default 4. `sleep` injectable for tests.\n */\n maxRetries?: number;\n sleep?: (ms: number) => Promise<void>;\n}\n\n/** Run one D1 HTTP query (with transient-error retry); returns the rows or throws. */\nasync function d1HttpQuery(\n cfg: Omit<D1HttpConfig, \"scope\">,\n sql: string,\n params: (string | number | null)[],\n): Promise<Array<Record<string, unknown>>> {\n const f = cfg.fetchImpl ?? fetch;\n const sleep = cfg.sleep ?? defaultSleep;\n const maxRetries = cfg.maxRetries ?? 4;\n const url = `https://api.cloudflare.com/client/v4/accounts/${cfg.accountId}/d1/database/${cfg.databaseId}/query`;\n for (let attempt = 0; ; attempt++) {\n let status = 0;\n let json:\n | {\n success?: boolean;\n errors?: unknown;\n result?: Array<{ results?: Array<Record<string, unknown>> }>;\n }\n | undefined;\n let networkErr: unknown;\n try {\n const res = await f(url, {\n method: \"POST\",\n headers: { authorization: `Bearer ${cfg.apiToken}`, \"content-type\": \"application/json\" },\n body: JSON.stringify({ sql, params }),\n });\n status = res.status;\n json = await res.json();\n } catch (e) {\n networkErr = e; // network/parse failure → transient\n }\n if (!networkErr && status >= 200 && status < 300 && json?.success !== false) {\n return json?.result?.[0]?.results ?? [];\n }\n // 5xx / 429 / network → transient (retry); 4xx (auth/SQL) → permanent (throw now).\n const transient = networkErr != null || status >= 500 || status === 429;\n const msg = networkErr\n ? `D1 HTTP network error: ${String(networkErr).slice(0, 160)}`\n : `D1 HTTP ${status}: ${JSON.stringify(json?.errors ?? json).slice(0, 200)}`;\n if (!transient || attempt >= maxRetries) throw new Error(msg);\n await sleep(Math.min(2000, 200 * 2 ** attempt));\n }\n}\n\n/** CF D1 HTTP-API backend adapter (offline mechanism A for staging/prod). */\nexport function makeD1HttpInlineBackfillBackend(cfg: D1HttpConfig): InlineBackfillBackend {\n return {\n async selectCandidates(cursor, limit, threshold) {\n const rows = await d1HttpQuery(cfg, SELECT_SQL, [cfg.scope, threshold, cursor, limit]);\n return rows.map((r) => ({ path: String(r.path), cid: String(r.cid), size: Number(r.size) }));\n },\n async backfillRow(path, content, mimeType) {\n await d1HttpQuery(cfg, UPDATE_SQL, [content, mimeType, cfg.scope, path]);\n },\n };\n}\n\n/**\n * List the distinct scopes that still have content-NULL file rows (≤ threshold)\n * on a CF D1, so a bulk sweep can migrate each scope-aware. One HTTP query.\n */\nexport async function listD1NullContentScopes(\n cfg: Omit<D1HttpConfig, \"scope\">,\n threshold: number = DEFAULT_INLINE_THRESHOLD,\n): Promise<string[]> {\n const rows = await d1HttpQuery(cfg, DISTINCT_NULL_SCOPES_SQL, [threshold]);\n return rows.map((r) => String(r.scope));\n}\n"],"mappings":"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"}
@@ -0,0 +1,145 @@
1
+ const require_rolldown_runtime = require('./_virtual/rolldown_runtime.cjs');
2
+ const require_cid = require('./cid.cjs');
3
+ require('./mime-utils.cjs');
4
+ let _aigne_afs_provider_utils = require("@aigne/afs-provider-utils");
5
+
6
+ //#region src/inline-content.ts
7
+ /**
8
+ * Inline content — Layer 0 generic TreeIndex capability contract (Phase 0).
9
+ *
10
+ * A TreeIndex row may carry a small inline copy of the file's bytes in a
11
+ * `content` column, eliminating the per-entry object fetch on bulk reads.
12
+ * Four contract clauses (conformance suite:
13
+ * `@aigne/afs-testing` → `suites/inline-content.ts`):
14
+ *
15
+ * 1. **cid-verified** — whenever `content` is present, `hash(content) === cid`
16
+ * holds. The cid is always computed; writes verify once and REJECT a
17
+ * mismatched pair. The cid stays the identity; content is just a co-located
18
+ * copy of the same bytes — it can never go stale and never breaks any
19
+ * cid-addressed mechanism.
20
+ *
21
+ * 2. **Two store classes** (statically determined at construction — no runtime
22
+ * probing):
23
+ * - **CAS store** (object backend present; cid is a public address): the
24
+ * blob write can NEVER be skipped — that is a type invariant, not a
25
+ * policy ("skip the blob" does not exist on the interface). The only
26
+ * switch is the binary `inlineCache: "on" | "off"` constructor option
27
+ * (mechanism default OFF — unknown callers keep byte-identical
28
+ * behavior). With `on` (write-through): content ≤ threshold is written
29
+ * into the index row in the SAME put; over-threshold rows stay NULL and
30
+ * reads go to objects (NOT an error).
31
+ * **Read equivalence**: an index-content hit (hash verified) ≡ an
32
+ * objects read; verification failure falls back to objects (+ repair
33
+ * log), never surfacing corrupt bytes.
34
+ * - **Pure derived index** (no object backend): content IS the primary
35
+ * data; cid is merely a checksum; the authority is the ingested source.
36
+ * No sync ⇒ every write skips the changelog (enforced by the
37
+ * constructor, not by call sites) and uses the fixed device sentinel
38
+ * {@link INGEST_DEVICE_ID}. Over-threshold content is a HARD ERROR
39
+ * (there is no blob to fall back to).
40
+ *
41
+ * 3. **Projection control** — `listEntries(prefix, { includeContent: true })`;
42
+ * default OFF: the default SELECT does not touch the content column, so
43
+ * every existing list path is zero-regression, zero extra bytes.
44
+ *
45
+ * 4. **Two-value threshold** (do not conflate): the app-level
46
+ * `inlineThreshold` is configurable (default {@link DEFAULT_INLINE_THRESHOLD});
47
+ * the DDL-level {@link INLINE_CONTENT_HARD_CAP} is a fixed constant baked
48
+ * into the table CHECK (`CHECK (content IS NULL OR LENGTH(content) <=
49
+ * <HARD_CAP>)`). A CHECK inside the table schema is not configurable
50
+ * (SQLite requires a table rebuild to change it) — it is a defensive upper
51
+ * bound only. Configurability lives ONLY at the app layer; startup asserts
52
+ * `inlineThreshold <= INLINE_CONTENT_HARD_CAP` via
53
+ * {@link assertInlineThreshold}.
54
+ *
55
+ * Physical layout is NOT locked by this contract — the conformance suite
56
+ * asserts API behavior only (this plan inlines a column on `entries`; a
57
+ * cid-keyed sibling table would satisfy the same contract).
58
+ */
59
+ /** DDL-level hard cap for an inline content column, in bytes (fixed constant). */
60
+ const INLINE_CONTENT_HARD_CAP = 64 * 1024;
61
+ /**
62
+ * Default app-level inline threshold, in bytes (configurable per deployment).
63
+ * Mind the two semantics: CAS write-through over-threshold = cache miss
64
+ * (reads fall back to objects); pure derived index over-threshold = HARD
65
+ * ERROR (no blob fallback) — construction sites with bigger payloads pass
66
+ * their own `inlineThreshold`.
67
+ */
68
+ const DEFAULT_INLINE_THRESHOLD = 2 * 1024;
69
+ /**
70
+ * Fixed `deviceId` sentinel for pure-derived-index writes (`PutOpts.deviceId`
71
+ * is required by the TreeIndex mutation contract, but a derived index has no
72
+ * device — it is rebuilt from source, never synced).
73
+ */
74
+ const INGEST_DEVICE_ID = "system:ingest";
75
+ /** Normalize constructor options into a validated config (mechanism default OFF). */
76
+ function resolveInlineConfig(opts) {
77
+ const inlineThreshold = opts?.inlineThreshold ?? DEFAULT_INLINE_THRESHOLD;
78
+ assertInlineThreshold(inlineThreshold);
79
+ return {
80
+ inlineCache: opts?.inlineCache ?? "off",
81
+ inlineThreshold
82
+ };
83
+ }
84
+ /** UTF-8 byte length of a string (the threshold/hard-cap unit is bytes). */
85
+ function utf8ByteLength(s) {
86
+ return new TextEncoder().encode(s).length;
87
+ }
88
+ /**
89
+ * Put-side inline decision shared by all TreeIndex impls.
90
+ *
91
+ * Returns the string to store in the content column, or `null` (store NULL):
92
+ * - no content supplied / `inlineCache: "off"` → null (legacy behavior)
93
+ * - content over the threshold → null (CAS semantics: NOT an error — the
94
+ * object backend is authoritative; pure derived indexes enforce their
95
+ * hard error one level up, in `VersionedContentIndex`)
96
+ * - content containing an embedded NUL → null (libsql binds TEXT as a
97
+ * C string and truncates at the first `\0`, which would break the
98
+ * read-equivalence invariant; such content stays objects-only —
99
+ * best-effort semantics make this a legal miss)
100
+ * - otherwise verify `hash(content) === cid` ONCE at write time; a
101
+ * mismatched pair is REJECTED (cid-verified contract clause 1).
102
+ */
103
+ async function resolveInlineContent(entry, config) {
104
+ if (entry.content === void 0 || config.inlineCache !== "on") return null;
105
+ if (entry.content.includes("\0")) return null;
106
+ if (utf8ByteLength(entry.content) > config.inlineThreshold) return null;
107
+ const actual = await require_cid.computeCID(entry.content);
108
+ if (actual !== entry.cid) throw new Error(`inline content rejected: hash(content) ${actual} does not match entry cid ${entry.cid}`);
109
+ return entry.content;
110
+ }
111
+ /**
112
+ * Byte-payload → inline-text candidate for write paths that carry raw bytes
113
+ * (sync/internal writes). Returns the decoded string ONLY when the payload is
114
+ * plausibly inlinable: text mime, within the hard cap, and STRICT UTF-8
115
+ * (fatal decode — a lossy decode would re-encode to different bytes and fail
116
+ * the cid verification anyway). Null = don't offer inline content.
117
+ */
118
+ function decodeInlineText(bytes, mimeType) {
119
+ if (bytes.length > INLINE_CONTENT_HARD_CAP) return null;
120
+ if (!(0, _aigne_afs_provider_utils.isTextMime)(mimeType)) return null;
121
+ try {
122
+ return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
123
+ } catch {
124
+ return null;
125
+ }
126
+ }
127
+ /**
128
+ * Startup assertion: the configurable app threshold must be a positive
129
+ * integer within the DDL hard cap. Throws on misconfiguration (failing fast
130
+ * beats silently writing rows the CHECK constraint will reject).
131
+ */
132
+ function assertInlineThreshold(threshold) {
133
+ if (!Number.isInteger(threshold) || threshold <= 0) throw new Error(`inlineThreshold must be a positive integer, got ${threshold}`);
134
+ if (threshold > INLINE_CONTENT_HARD_CAP) throw new Error(`inlineThreshold (${threshold}) exceeds the DDL hard cap (${INLINE_CONTENT_HARD_CAP}) — the CHECK constraint would reject inline rows`);
135
+ }
136
+
137
+ //#endregion
138
+ exports.DEFAULT_INLINE_THRESHOLD = DEFAULT_INLINE_THRESHOLD;
139
+ exports.INGEST_DEVICE_ID = INGEST_DEVICE_ID;
140
+ exports.INLINE_CONTENT_HARD_CAP = INLINE_CONTENT_HARD_CAP;
141
+ exports.assertInlineThreshold = assertInlineThreshold;
142
+ exports.decodeInlineText = decodeInlineText;
143
+ exports.resolveInlineConfig = resolveInlineConfig;
144
+ exports.resolveInlineContent = resolveInlineContent;
145
+ exports.utf8ByteLength = utf8ByteLength;
@@ -0,0 +1,98 @@
1
+ //#region src/inline-content.d.ts
2
+ /**
3
+ * Inline content — Layer 0 generic TreeIndex capability contract (Phase 0).
4
+ *
5
+ * A TreeIndex row may carry a small inline copy of the file's bytes in a
6
+ * `content` column, eliminating the per-entry object fetch on bulk reads.
7
+ * Four contract clauses (conformance suite:
8
+ * `@aigne/afs-testing` → `suites/inline-content.ts`):
9
+ *
10
+ * 1. **cid-verified** — whenever `content` is present, `hash(content) === cid`
11
+ * holds. The cid is always computed; writes verify once and REJECT a
12
+ * mismatched pair. The cid stays the identity; content is just a co-located
13
+ * copy of the same bytes — it can never go stale and never breaks any
14
+ * cid-addressed mechanism.
15
+ *
16
+ * 2. **Two store classes** (statically determined at construction — no runtime
17
+ * probing):
18
+ * - **CAS store** (object backend present; cid is a public address): the
19
+ * blob write can NEVER be skipped — that is a type invariant, not a
20
+ * policy ("skip the blob" does not exist on the interface). The only
21
+ * switch is the binary `inlineCache: "on" | "off"` constructor option
22
+ * (mechanism default OFF — unknown callers keep byte-identical
23
+ * behavior). With `on` (write-through): content ≤ threshold is written
24
+ * into the index row in the SAME put; over-threshold rows stay NULL and
25
+ * reads go to objects (NOT an error).
26
+ * **Read equivalence**: an index-content hit (hash verified) ≡ an
27
+ * objects read; verification failure falls back to objects (+ repair
28
+ * log), never surfacing corrupt bytes.
29
+ * - **Pure derived index** (no object backend): content IS the primary
30
+ * data; cid is merely a checksum; the authority is the ingested source.
31
+ * No sync ⇒ every write skips the changelog (enforced by the
32
+ * constructor, not by call sites) and uses the fixed device sentinel
33
+ * {@link INGEST_DEVICE_ID}. Over-threshold content is a HARD ERROR
34
+ * (there is no blob to fall back to).
35
+ *
36
+ * 3. **Projection control** — `listEntries(prefix, { includeContent: true })`;
37
+ * default OFF: the default SELECT does not touch the content column, so
38
+ * every existing list path is zero-regression, zero extra bytes.
39
+ *
40
+ * 4. **Two-value threshold** (do not conflate): the app-level
41
+ * `inlineThreshold` is configurable (default {@link DEFAULT_INLINE_THRESHOLD});
42
+ * the DDL-level {@link INLINE_CONTENT_HARD_CAP} is a fixed constant baked
43
+ * into the table CHECK (`CHECK (content IS NULL OR LENGTH(content) <=
44
+ * <HARD_CAP>)`). A CHECK inside the table schema is not configurable
45
+ * (SQLite requires a table rebuild to change it) — it is a defensive upper
46
+ * bound only. Configurability lives ONLY at the app layer; startup asserts
47
+ * `inlineThreshold <= INLINE_CONTENT_HARD_CAP` via
48
+ * {@link assertInlineThreshold}.
49
+ *
50
+ * Physical layout is NOT locked by this contract — the conformance suite
51
+ * asserts API behavior only (this plan inlines a column on `entries`; a
52
+ * cid-keyed sibling table would satisfy the same contract).
53
+ */
54
+ /** DDL-level hard cap for an inline content column, in bytes (fixed constant). */
55
+ declare const INLINE_CONTENT_HARD_CAP: number;
56
+ /**
57
+ * Default app-level inline threshold, in bytes (configurable per deployment).
58
+ * Mind the two semantics: CAS write-through over-threshold = cache miss
59
+ * (reads fall back to objects); pure derived index over-threshold = HARD
60
+ * ERROR (no blob fallback) — construction sites with bigger payloads pass
61
+ * their own `inlineThreshold`.
62
+ */
63
+ declare const DEFAULT_INLINE_THRESHOLD: number;
64
+ /**
65
+ * Binary CAS write-through switch. Mechanism default is `"off"`; a store that
66
+ * wants read acceleration opts in EXPLICITLY at its construction site.
67
+ */
68
+ type InlineCacheMode = "on" | "off";
69
+ /**
70
+ * Fixed `deviceId` sentinel for pure-derived-index writes (`PutOpts.deviceId`
71
+ * is required by the TreeIndex mutation contract, but a derived index has no
72
+ * device — it is rebuilt from source, never synced).
73
+ */
74
+ declare const INGEST_DEVICE_ID = "system:ingest";
75
+ /** Construction-time options shared by inline-capable TreeIndex impls. */
76
+ interface InlineContentOptions {
77
+ /** CAS write-through switch — default `"off"` (no behavior change). */
78
+ inlineCache?: InlineCacheMode;
79
+ /** App-level inline threshold in bytes — default {@link DEFAULT_INLINE_THRESHOLD}. */
80
+ inlineThreshold?: number;
81
+ }
82
+ /**
83
+ * Byte-payload → inline-text candidate for write paths that carry raw bytes
84
+ * (sync/internal writes). Returns the decoded string ONLY when the payload is
85
+ * plausibly inlinable: text mime, within the hard cap, and STRICT UTF-8
86
+ * (fatal decode — a lossy decode would re-encode to different bytes and fail
87
+ * the cid verification anyway). Null = don't offer inline content.
88
+ */
89
+ declare function decodeInlineText(bytes: Uint8Array, mimeType: string | undefined): string | null;
90
+ /**
91
+ * Startup assertion: the configurable app threshold must be a positive
92
+ * integer within the DDL hard cap. Throws on misconfiguration (failing fast
93
+ * beats silently writing rows the CHECK constraint will reject).
94
+ */
95
+ declare function assertInlineThreshold(threshold: number): void;
96
+ //#endregion
97
+ export { DEFAULT_INLINE_THRESHOLD, INGEST_DEVICE_ID, INLINE_CONTENT_HARD_CAP, InlineCacheMode, InlineContentOptions, assertInlineThreshold, decodeInlineText };
98
+ //# sourceMappingURL=inline-content.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inline-content.d.cts","names":[],"sources":["../src/inline-content.ts"],"mappings":";;AAyDA;;;;;AASA;;;;;AAMA;;;;;AAOA;;;;;AAGA;;;;;;;;;AA+DA;;;;;;;;;AAeA;;;;;;;;;;;;;;cAvGa,uBAAA;;;;;;;;cASA,wBAAA;;;;;KAMD,eAAA;;;;;;cAOC,gBAAA;;UAGI,oBAAA;;EAEf,WAAA,GAAc,eAAA;;EAEd,eAAA;AAAA;;;;;;;;iBA2Dc,gBAAA,CAAiB,KAAA,EAAO,UAAA,EAAY,QAAA;;;;;;iBAepC,qBAAA,CAAsB,SAAA"}
@@ -0,0 +1,98 @@
1
+ //#region src/inline-content.d.ts
2
+ /**
3
+ * Inline content — Layer 0 generic TreeIndex capability contract (Phase 0).
4
+ *
5
+ * A TreeIndex row may carry a small inline copy of the file's bytes in a
6
+ * `content` column, eliminating the per-entry object fetch on bulk reads.
7
+ * Four contract clauses (conformance suite:
8
+ * `@aigne/afs-testing` → `suites/inline-content.ts`):
9
+ *
10
+ * 1. **cid-verified** — whenever `content` is present, `hash(content) === cid`
11
+ * holds. The cid is always computed; writes verify once and REJECT a
12
+ * mismatched pair. The cid stays the identity; content is just a co-located
13
+ * copy of the same bytes — it can never go stale and never breaks any
14
+ * cid-addressed mechanism.
15
+ *
16
+ * 2. **Two store classes** (statically determined at construction — no runtime
17
+ * probing):
18
+ * - **CAS store** (object backend present; cid is a public address): the
19
+ * blob write can NEVER be skipped — that is a type invariant, not a
20
+ * policy ("skip the blob" does not exist on the interface). The only
21
+ * switch is the binary `inlineCache: "on" | "off"` constructor option
22
+ * (mechanism default OFF — unknown callers keep byte-identical
23
+ * behavior). With `on` (write-through): content ≤ threshold is written
24
+ * into the index row in the SAME put; over-threshold rows stay NULL and
25
+ * reads go to objects (NOT an error).
26
+ * **Read equivalence**: an index-content hit (hash verified) ≡ an
27
+ * objects read; verification failure falls back to objects (+ repair
28
+ * log), never surfacing corrupt bytes.
29
+ * - **Pure derived index** (no object backend): content IS the primary
30
+ * data; cid is merely a checksum; the authority is the ingested source.
31
+ * No sync ⇒ every write skips the changelog (enforced by the
32
+ * constructor, not by call sites) and uses the fixed device sentinel
33
+ * {@link INGEST_DEVICE_ID}. Over-threshold content is a HARD ERROR
34
+ * (there is no blob to fall back to).
35
+ *
36
+ * 3. **Projection control** — `listEntries(prefix, { includeContent: true })`;
37
+ * default OFF: the default SELECT does not touch the content column, so
38
+ * every existing list path is zero-regression, zero extra bytes.
39
+ *
40
+ * 4. **Two-value threshold** (do not conflate): the app-level
41
+ * `inlineThreshold` is configurable (default {@link DEFAULT_INLINE_THRESHOLD});
42
+ * the DDL-level {@link INLINE_CONTENT_HARD_CAP} is a fixed constant baked
43
+ * into the table CHECK (`CHECK (content IS NULL OR LENGTH(content) <=
44
+ * <HARD_CAP>)`). A CHECK inside the table schema is not configurable
45
+ * (SQLite requires a table rebuild to change it) — it is a defensive upper
46
+ * bound only. Configurability lives ONLY at the app layer; startup asserts
47
+ * `inlineThreshold <= INLINE_CONTENT_HARD_CAP` via
48
+ * {@link assertInlineThreshold}.
49
+ *
50
+ * Physical layout is NOT locked by this contract — the conformance suite
51
+ * asserts API behavior only (this plan inlines a column on `entries`; a
52
+ * cid-keyed sibling table would satisfy the same contract).
53
+ */
54
+ /** DDL-level hard cap for an inline content column, in bytes (fixed constant). */
55
+ declare const INLINE_CONTENT_HARD_CAP: number;
56
+ /**
57
+ * Default app-level inline threshold, in bytes (configurable per deployment).
58
+ * Mind the two semantics: CAS write-through over-threshold = cache miss
59
+ * (reads fall back to objects); pure derived index over-threshold = HARD
60
+ * ERROR (no blob fallback) — construction sites with bigger payloads pass
61
+ * their own `inlineThreshold`.
62
+ */
63
+ declare const DEFAULT_INLINE_THRESHOLD: number;
64
+ /**
65
+ * Binary CAS write-through switch. Mechanism default is `"off"`; a store that
66
+ * wants read acceleration opts in EXPLICITLY at its construction site.
67
+ */
68
+ type InlineCacheMode = "on" | "off";
69
+ /**
70
+ * Fixed `deviceId` sentinel for pure-derived-index writes (`PutOpts.deviceId`
71
+ * is required by the TreeIndex mutation contract, but a derived index has no
72
+ * device — it is rebuilt from source, never synced).
73
+ */
74
+ declare const INGEST_DEVICE_ID = "system:ingest";
75
+ /** Construction-time options shared by inline-capable TreeIndex impls. */
76
+ interface InlineContentOptions {
77
+ /** CAS write-through switch — default `"off"` (no behavior change). */
78
+ inlineCache?: InlineCacheMode;
79
+ /** App-level inline threshold in bytes — default {@link DEFAULT_INLINE_THRESHOLD}. */
80
+ inlineThreshold?: number;
81
+ }
82
+ /**
83
+ * Byte-payload → inline-text candidate for write paths that carry raw bytes
84
+ * (sync/internal writes). Returns the decoded string ONLY when the payload is
85
+ * plausibly inlinable: text mime, within the hard cap, and STRICT UTF-8
86
+ * (fatal decode — a lossy decode would re-encode to different bytes and fail
87
+ * the cid verification anyway). Null = don't offer inline content.
88
+ */
89
+ declare function decodeInlineText(bytes: Uint8Array, mimeType: string | undefined): string | null;
90
+ /**
91
+ * Startup assertion: the configurable app threshold must be a positive
92
+ * integer within the DDL hard cap. Throws on misconfiguration (failing fast
93
+ * beats silently writing rows the CHECK constraint will reject).
94
+ */
95
+ declare function assertInlineThreshold(threshold: number): void;
96
+ //#endregion
97
+ export { DEFAULT_INLINE_THRESHOLD, INGEST_DEVICE_ID, INLINE_CONTENT_HARD_CAP, InlineCacheMode, InlineContentOptions, assertInlineThreshold, decodeInlineText };
98
+ //# sourceMappingURL=inline-content.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inline-content.d.mts","names":[],"sources":["../src/inline-content.ts"],"mappings":";;AAyDA;;;;;AASA;;;;;AAMA;;;;;AAOA;;;;;AAGA;;;;;;;;;AA+DA;;;;;;;;;AAeA;;;;;;;;;;;;;;cAvGa,uBAAA;;;;;;;;cASA,wBAAA;;;;;KAMD,eAAA;;;;;;cAOC,gBAAA;;UAGI,oBAAA;;EAEf,WAAA,GAAc,eAAA;;EAEd,eAAA;AAAA;;;;;;;;iBA2Dc,gBAAA,CAAiB,KAAA,EAAO,UAAA,EAAY,QAAA;;;;;;iBAepC,qBAAA,CAAsB,SAAA"}
@@ -0,0 +1,137 @@
1
+ import { computeCID } from "./cid.mjs";
2
+ import { isTextMime } from "./mime-utils.mjs";
3
+
4
+ //#region src/inline-content.ts
5
+ /**
6
+ * Inline content — Layer 0 generic TreeIndex capability contract (Phase 0).
7
+ *
8
+ * A TreeIndex row may carry a small inline copy of the file's bytes in a
9
+ * `content` column, eliminating the per-entry object fetch on bulk reads.
10
+ * Four contract clauses (conformance suite:
11
+ * `@aigne/afs-testing` → `suites/inline-content.ts`):
12
+ *
13
+ * 1. **cid-verified** — whenever `content` is present, `hash(content) === cid`
14
+ * holds. The cid is always computed; writes verify once and REJECT a
15
+ * mismatched pair. The cid stays the identity; content is just a co-located
16
+ * copy of the same bytes — it can never go stale and never breaks any
17
+ * cid-addressed mechanism.
18
+ *
19
+ * 2. **Two store classes** (statically determined at construction — no runtime
20
+ * probing):
21
+ * - **CAS store** (object backend present; cid is a public address): the
22
+ * blob write can NEVER be skipped — that is a type invariant, not a
23
+ * policy ("skip the blob" does not exist on the interface). The only
24
+ * switch is the binary `inlineCache: "on" | "off"` constructor option
25
+ * (mechanism default OFF — unknown callers keep byte-identical
26
+ * behavior). With `on` (write-through): content ≤ threshold is written
27
+ * into the index row in the SAME put; over-threshold rows stay NULL and
28
+ * reads go to objects (NOT an error).
29
+ * **Read equivalence**: an index-content hit (hash verified) ≡ an
30
+ * objects read; verification failure falls back to objects (+ repair
31
+ * log), never surfacing corrupt bytes.
32
+ * - **Pure derived index** (no object backend): content IS the primary
33
+ * data; cid is merely a checksum; the authority is the ingested source.
34
+ * No sync ⇒ every write skips the changelog (enforced by the
35
+ * constructor, not by call sites) and uses the fixed device sentinel
36
+ * {@link INGEST_DEVICE_ID}. Over-threshold content is a HARD ERROR
37
+ * (there is no blob to fall back to).
38
+ *
39
+ * 3. **Projection control** — `listEntries(prefix, { includeContent: true })`;
40
+ * default OFF: the default SELECT does not touch the content column, so
41
+ * every existing list path is zero-regression, zero extra bytes.
42
+ *
43
+ * 4. **Two-value threshold** (do not conflate): the app-level
44
+ * `inlineThreshold` is configurable (default {@link DEFAULT_INLINE_THRESHOLD});
45
+ * the DDL-level {@link INLINE_CONTENT_HARD_CAP} is a fixed constant baked
46
+ * into the table CHECK (`CHECK (content IS NULL OR LENGTH(content) <=
47
+ * <HARD_CAP>)`). A CHECK inside the table schema is not configurable
48
+ * (SQLite requires a table rebuild to change it) — it is a defensive upper
49
+ * bound only. Configurability lives ONLY at the app layer; startup asserts
50
+ * `inlineThreshold <= INLINE_CONTENT_HARD_CAP` via
51
+ * {@link assertInlineThreshold}.
52
+ *
53
+ * Physical layout is NOT locked by this contract — the conformance suite
54
+ * asserts API behavior only (this plan inlines a column on `entries`; a
55
+ * cid-keyed sibling table would satisfy the same contract).
56
+ */
57
+ /** DDL-level hard cap for an inline content column, in bytes (fixed constant). */
58
+ const INLINE_CONTENT_HARD_CAP = 64 * 1024;
59
+ /**
60
+ * Default app-level inline threshold, in bytes (configurable per deployment).
61
+ * Mind the two semantics: CAS write-through over-threshold = cache miss
62
+ * (reads fall back to objects); pure derived index over-threshold = HARD
63
+ * ERROR (no blob fallback) — construction sites with bigger payloads pass
64
+ * their own `inlineThreshold`.
65
+ */
66
+ const DEFAULT_INLINE_THRESHOLD = 2 * 1024;
67
+ /**
68
+ * Fixed `deviceId` sentinel for pure-derived-index writes (`PutOpts.deviceId`
69
+ * is required by the TreeIndex mutation contract, but a derived index has no
70
+ * device — it is rebuilt from source, never synced).
71
+ */
72
+ const INGEST_DEVICE_ID = "system:ingest";
73
+ /** Normalize constructor options into a validated config (mechanism default OFF). */
74
+ function resolveInlineConfig(opts) {
75
+ const inlineThreshold = opts?.inlineThreshold ?? DEFAULT_INLINE_THRESHOLD;
76
+ assertInlineThreshold(inlineThreshold);
77
+ return {
78
+ inlineCache: opts?.inlineCache ?? "off",
79
+ inlineThreshold
80
+ };
81
+ }
82
+ /** UTF-8 byte length of a string (the threshold/hard-cap unit is bytes). */
83
+ function utf8ByteLength(s) {
84
+ return new TextEncoder().encode(s).length;
85
+ }
86
+ /**
87
+ * Put-side inline decision shared by all TreeIndex impls.
88
+ *
89
+ * Returns the string to store in the content column, or `null` (store NULL):
90
+ * - no content supplied / `inlineCache: "off"` → null (legacy behavior)
91
+ * - content over the threshold → null (CAS semantics: NOT an error — the
92
+ * object backend is authoritative; pure derived indexes enforce their
93
+ * hard error one level up, in `VersionedContentIndex`)
94
+ * - content containing an embedded NUL → null (libsql binds TEXT as a
95
+ * C string and truncates at the first `\0`, which would break the
96
+ * read-equivalence invariant; such content stays objects-only —
97
+ * best-effort semantics make this a legal miss)
98
+ * - otherwise verify `hash(content) === cid` ONCE at write time; a
99
+ * mismatched pair is REJECTED (cid-verified contract clause 1).
100
+ */
101
+ async function resolveInlineContent(entry, config) {
102
+ if (entry.content === void 0 || config.inlineCache !== "on") return null;
103
+ if (entry.content.includes("\0")) return null;
104
+ if (utf8ByteLength(entry.content) > config.inlineThreshold) return null;
105
+ const actual = await computeCID(entry.content);
106
+ if (actual !== entry.cid) throw new Error(`inline content rejected: hash(content) ${actual} does not match entry cid ${entry.cid}`);
107
+ return entry.content;
108
+ }
109
+ /**
110
+ * Byte-payload → inline-text candidate for write paths that carry raw bytes
111
+ * (sync/internal writes). Returns the decoded string ONLY when the payload is
112
+ * plausibly inlinable: text mime, within the hard cap, and STRICT UTF-8
113
+ * (fatal decode — a lossy decode would re-encode to different bytes and fail
114
+ * the cid verification anyway). Null = don't offer inline content.
115
+ */
116
+ function decodeInlineText(bytes, mimeType) {
117
+ if (bytes.length > INLINE_CONTENT_HARD_CAP) return null;
118
+ if (!isTextMime(mimeType)) return null;
119
+ try {
120
+ return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
121
+ } catch {
122
+ return null;
123
+ }
124
+ }
125
+ /**
126
+ * Startup assertion: the configurable app threshold must be a positive
127
+ * integer within the DDL hard cap. Throws on misconfiguration (failing fast
128
+ * beats silently writing rows the CHECK constraint will reject).
129
+ */
130
+ function assertInlineThreshold(threshold) {
131
+ if (!Number.isInteger(threshold) || threshold <= 0) throw new Error(`inlineThreshold must be a positive integer, got ${threshold}`);
132
+ if (threshold > INLINE_CONTENT_HARD_CAP) throw new Error(`inlineThreshold (${threshold}) exceeds the DDL hard cap (${INLINE_CONTENT_HARD_CAP}) — the CHECK constraint would reject inline rows`);
133
+ }
134
+
135
+ //#endregion
136
+ export { DEFAULT_INLINE_THRESHOLD, INGEST_DEVICE_ID, INLINE_CONTENT_HARD_CAP, assertInlineThreshold, decodeInlineText, resolveInlineConfig, resolveInlineContent, utf8ByteLength };
137
+ //# sourceMappingURL=inline-content.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inline-content.mjs","names":[],"sources":["../src/inline-content.ts"],"sourcesContent":["/**\n * Inline content — Layer 0 generic TreeIndex capability contract (Phase 0).\n *\n * A TreeIndex row may carry a small inline copy of the file's bytes in a\n * `content` column, eliminating the per-entry object fetch on bulk reads.\n * Four contract clauses (conformance suite:\n * `@aigne/afs-testing` → `suites/inline-content.ts`):\n *\n * 1. **cid-verified** — whenever `content` is present, `hash(content) === cid`\n * holds. The cid is always computed; writes verify once and REJECT a\n * mismatched pair. The cid stays the identity; content is just a co-located\n * copy of the same bytes — it can never go stale and never breaks any\n * cid-addressed mechanism.\n *\n * 2. **Two store classes** (statically determined at construction — no runtime\n * probing):\n * - **CAS store** (object backend present; cid is a public address): the\n * blob write can NEVER be skipped — that is a type invariant, not a\n * policy (\"skip the blob\" does not exist on the interface). The only\n * switch is the binary `inlineCache: \"on\" | \"off\"` constructor option\n * (mechanism default OFF — unknown callers keep byte-identical\n * behavior). With `on` (write-through): content ≤ threshold is written\n * into the index row in the SAME put; over-threshold rows stay NULL and\n * reads go to objects (NOT an error).\n * **Read equivalence**: an index-content hit (hash verified) ≡ an\n * objects read; verification failure falls back to objects (+ repair\n * log), never surfacing corrupt bytes.\n * - **Pure derived index** (no object backend): content IS the primary\n * data; cid is merely a checksum; the authority is the ingested source.\n * No sync ⇒ every write skips the changelog (enforced by the\n * constructor, not by call sites) and uses the fixed device sentinel\n * {@link INGEST_DEVICE_ID}. Over-threshold content is a HARD ERROR\n * (there is no blob to fall back to).\n *\n * 3. **Projection control** — `listEntries(prefix, { includeContent: true })`;\n * default OFF: the default SELECT does not touch the content column, so\n * every existing list path is zero-regression, zero extra bytes.\n *\n * 4. **Two-value threshold** (do not conflate): the app-level\n * `inlineThreshold` is configurable (default {@link DEFAULT_INLINE_THRESHOLD});\n * the DDL-level {@link INLINE_CONTENT_HARD_CAP} is a fixed constant baked\n * into the table CHECK (`CHECK (content IS NULL OR LENGTH(content) <=\n * <HARD_CAP>)`). A CHECK inside the table schema is not configurable\n * (SQLite requires a table rebuild to change it) — it is a defensive upper\n * bound only. Configurability lives ONLY at the app layer; startup asserts\n * `inlineThreshold <= INLINE_CONTENT_HARD_CAP` via\n * {@link assertInlineThreshold}.\n *\n * Physical layout is NOT locked by this contract — the conformance suite\n * asserts API behavior only (this plan inlines a column on `entries`; a\n * cid-keyed sibling table would satisfy the same contract).\n */\n\nimport { computeCID } from \"./cid.js\";\nimport { isTextMime } from \"./mime-utils.js\";\n\n/** DDL-level hard cap for an inline content column, in bytes (fixed constant). */\nexport const INLINE_CONTENT_HARD_CAP = 64 * 1024;\n\n/**\n * Default app-level inline threshold, in bytes (configurable per deployment).\n * Mind the two semantics: CAS write-through over-threshold = cache miss\n * (reads fall back to objects); pure derived index over-threshold = HARD\n * ERROR (no blob fallback) — construction sites with bigger payloads pass\n * their own `inlineThreshold`.\n */\nexport const DEFAULT_INLINE_THRESHOLD = 2 * 1024;\n\n/**\n * Binary CAS write-through switch. Mechanism default is `\"off\"`; a store that\n * wants read acceleration opts in EXPLICITLY at its construction site.\n */\nexport type InlineCacheMode = \"on\" | \"off\";\n\n/**\n * Fixed `deviceId` sentinel for pure-derived-index writes (`PutOpts.deviceId`\n * is required by the TreeIndex mutation contract, but a derived index has no\n * device — it is rebuilt from source, never synced).\n */\nexport const INGEST_DEVICE_ID = \"system:ingest\";\n\n/** Construction-time options shared by inline-capable TreeIndex impls. */\nexport interface InlineContentOptions {\n /** CAS write-through switch — default `\"off\"` (no behavior change). */\n inlineCache?: InlineCacheMode;\n /** App-level inline threshold in bytes — default {@link DEFAULT_INLINE_THRESHOLD}. */\n inlineThreshold?: number;\n}\n\n/** Resolved (defaulted + validated) inline configuration of a TreeIndex impl. */\nexport interface ResolvedInlineConfig {\n inlineCache: InlineCacheMode;\n inlineThreshold: number;\n}\n\n/** Normalize constructor options into a validated config (mechanism default OFF). */\nexport function resolveInlineConfig(opts?: InlineContentOptions): ResolvedInlineConfig {\n const inlineThreshold = opts?.inlineThreshold ?? DEFAULT_INLINE_THRESHOLD;\n assertInlineThreshold(inlineThreshold);\n return { inlineCache: opts?.inlineCache ?? \"off\", inlineThreshold };\n}\n\n/** UTF-8 byte length of a string (the threshold/hard-cap unit is bytes). */\nexport function utf8ByteLength(s: string): number {\n return new TextEncoder().encode(s).length;\n}\n\n/**\n * Put-side inline decision shared by all TreeIndex impls.\n *\n * Returns the string to store in the content column, or `null` (store NULL):\n * - no content supplied / `inlineCache: \"off\"` → null (legacy behavior)\n * - content over the threshold → null (CAS semantics: NOT an error — the\n * object backend is authoritative; pure derived indexes enforce their\n * hard error one level up, in `VersionedContentIndex`)\n * - content containing an embedded NUL → null (libsql binds TEXT as a\n * C string and truncates at the first `\\0`, which would break the\n * read-equivalence invariant; such content stays objects-only —\n * best-effort semantics make this a legal miss)\n * - otherwise verify `hash(content) === cid` ONCE at write time; a\n * mismatched pair is REJECTED (cid-verified contract clause 1).\n */\nexport async function resolveInlineContent(\n entry: { cid: string; content?: string },\n config: ResolvedInlineConfig,\n): Promise<string | null> {\n if (entry.content === undefined || config.inlineCache !== \"on\") return null;\n if (entry.content.includes(\"\\0\")) return null;\n if (utf8ByteLength(entry.content) > config.inlineThreshold) return null;\n const actual = await computeCID(entry.content);\n if (actual !== entry.cid) {\n throw new Error(\n `inline content rejected: hash(content) ${actual} does not match entry cid ${entry.cid}`,\n );\n }\n return entry.content;\n}\n\n/**\n * Byte-payload → inline-text candidate for write paths that carry raw bytes\n * (sync/internal writes). Returns the decoded string ONLY when the payload is\n * plausibly inlinable: text mime, within the hard cap, and STRICT UTF-8\n * (fatal decode — a lossy decode would re-encode to different bytes and fail\n * the cid verification anyway). Null = don't offer inline content.\n */\nexport function decodeInlineText(bytes: Uint8Array, mimeType: string | undefined): string | null {\n if (bytes.length > INLINE_CONTENT_HARD_CAP) return null;\n if (!isTextMime(mimeType)) return null;\n try {\n return new TextDecoder(\"utf-8\", { fatal: true }).decode(bytes);\n } catch {\n return null;\n }\n}\n\n/**\n * Startup assertion: the configurable app threshold must be a positive\n * integer within the DDL hard cap. Throws on misconfiguration (failing fast\n * beats silently writing rows the CHECK constraint will reject).\n */\nexport function assertInlineThreshold(threshold: number): void {\n if (!Number.isInteger(threshold) || threshold <= 0) {\n throw new Error(`inlineThreshold must be a positive integer, got ${threshold}`);\n }\n if (threshold > INLINE_CONTENT_HARD_CAP) {\n throw new Error(\n `inlineThreshold (${threshold}) exceeds the DDL hard cap (${INLINE_CONTENT_HARD_CAP}) — the CHECK constraint would reject inline rows`,\n );\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyDA,MAAa,0BAA0B,KAAK;;;;;;;;AAS5C,MAAa,2BAA2B,IAAI;;;;;;AAa5C,MAAa,mBAAmB;;AAiBhC,SAAgB,oBAAoB,MAAmD;CACrF,MAAM,kBAAkB,MAAM,mBAAmB;AACjD,uBAAsB,gBAAgB;AACtC,QAAO;EAAE,aAAa,MAAM,eAAe;EAAO;EAAiB;;;AAIrE,SAAgB,eAAe,GAAmB;AAChD,QAAO,IAAI,aAAa,CAAC,OAAO,EAAE,CAAC;;;;;;;;;;;;;;;;;AAkBrC,eAAsB,qBACpB,OACA,QACwB;AACxB,KAAI,MAAM,YAAY,UAAa,OAAO,gBAAgB,KAAM,QAAO;AACvE,KAAI,MAAM,QAAQ,SAAS,KAAK,CAAE,QAAO;AACzC,KAAI,eAAe,MAAM,QAAQ,GAAG,OAAO,gBAAiB,QAAO;CACnE,MAAM,SAAS,MAAM,WAAW,MAAM,QAAQ;AAC9C,KAAI,WAAW,MAAM,IACnB,OAAM,IAAI,MACR,0CAA0C,OAAO,4BAA4B,MAAM,MACpF;AAEH,QAAO,MAAM;;;;;;;;;AAUf,SAAgB,iBAAiB,OAAmB,UAA6C;AAC/F,KAAI,MAAM,SAAS,wBAAyB,QAAO;AACnD,KAAI,CAAC,WAAW,SAAS,CAAE,QAAO;AAClC,KAAI;AACF,SAAO,IAAI,YAAY,SAAS,EAAE,OAAO,MAAM,CAAC,CAAC,OAAO,MAAM;SACxD;AACN,SAAO;;;;;;;;AASX,SAAgB,sBAAsB,WAAyB;AAC7D,KAAI,CAAC,OAAO,UAAU,UAAU,IAAI,aAAa,EAC/C,OAAM,IAAI,MAAM,mDAAmD,YAAY;AAEjF,KAAI,YAAY,wBACd,OAAM,IAAI,MACR,oBAAoB,UAAU,8BAA8B,wBAAwB,mDACrF"}