@statewalker/cellb 0.0.0-stage → 0.1.1

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 (365) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +323 -2
  3. package/dist/adapters/files-backup.d.ts +16 -0
  4. package/dist/adapters/files-backup.js +32 -0
  5. package/dist/adapters/files-backup.js.map +1 -0
  6. package/dist/adapters/files-changelog.d.ts +33 -0
  7. package/dist/adapters/files-changelog.js +96 -0
  8. package/dist/adapters/files-changelog.js.map +1 -0
  9. package/dist/adapters/files-ltx.d.ts +35 -0
  10. package/dist/adapters/files-ltx.js +9 -0
  11. package/dist/adapters/files-ltx.js.map +1 -0
  12. package/dist/adapters/ltx-vfs.d.ts +21 -0
  13. package/dist/adapters/ltx-vfs.js +286 -0
  14. package/dist/adapters/ltx-vfs.js.map +1 -0
  15. package/dist/adapters/node-sqlite.d.ts +45 -0
  16. package/dist/adapters/node-sqlite.js +254 -0
  17. package/dist/adapters/node-sqlite.js.map +1 -0
  18. package/dist/adapters/wasm-page-hook.d.ts +26 -0
  19. package/dist/adapters/wasm-page-hook.js +55 -0
  20. package/dist/adapters/wasm-page-hook.js.map +1 -0
  21. package/dist/adapters/wasm-session.d.ts +11 -0
  22. package/dist/adapters/wasm-session.js +76 -0
  23. package/dist/adapters/wasm-session.js.map +1 -0
  24. package/dist/adapters/wasm-sqlite.d.ts +89 -0
  25. package/dist/adapters/wasm-sqlite.js +258 -0
  26. package/dist/adapters/wasm-sqlite.js.map +1 -0
  27. package/dist/bindings/assets.d.ts +26 -0
  28. package/dist/bindings/assets.js +260 -0
  29. package/dist/bindings/assets.js.map +1 -0
  30. package/dist/bindings/cache.d.ts +16 -0
  31. package/dist/bindings/cache.js +34 -0
  32. package/dist/bindings/cache.js.map +1 -0
  33. package/dist/bindings/celld-kv.d.ts +26 -0
  34. package/dist/bindings/celld-kv.js +81 -0
  35. package/dist/bindings/celld-kv.js.map +1 -0
  36. package/dist/bindings/celld-queues.d.ts +56 -0
  37. package/dist/bindings/celld-queues.js +223 -0
  38. package/dist/bindings/celld-queues.js.map +1 -0
  39. package/dist/bindings/celld-workflows.d.ts +22 -0
  40. package/dist/bindings/celld-workflows.js +54 -0
  41. package/dist/bindings/celld-workflows.js.map +1 -0
  42. package/dist/bindings/cron.d.ts +27 -0
  43. package/dist/bindings/cron.js +232 -0
  44. package/dist/bindings/cron.js.map +1 -0
  45. package/dist/bindings/d1-migrations.d.ts +22 -0
  46. package/dist/bindings/d1-migrations.js +32 -0
  47. package/dist/bindings/d1-migrations.js.map +1 -0
  48. package/dist/bindings/html-rewriter.d.ts +8 -0
  49. package/dist/bindings/html-rewriter.js +75 -0
  50. package/dist/bindings/html-rewriter.js.map +1 -0
  51. package/dist/bindings/r2-celld.d.ts +3 -0
  52. package/dist/bindings/r2-celld.js +113 -0
  53. package/dist/bindings/r2-celld.js.map +1 -0
  54. package/dist/bindings/r2.d.ts +236 -0
  55. package/dist/bindings/r2.js +419 -0
  56. package/dist/bindings/r2.js.map +1 -0
  57. package/dist/bindings/worker-loader.d.ts +83 -0
  58. package/dist/bindings/worker-loader.js +183 -0
  59. package/dist/bindings/worker-loader.js.map +1 -0
  60. package/dist/bindings/workers-ai.d.ts +39 -0
  61. package/dist/bindings/workers-ai.js +175 -0
  62. package/dist/bindings/workers-ai.js.map +1 -0
  63. package/dist/browser.d.ts +7 -0
  64. package/dist/browser.js +8 -0
  65. package/dist/browser.js.map +1 -0
  66. package/dist/bucket/celld-cells.d.ts +86 -0
  67. package/dist/bucket/celld-cells.js +273 -0
  68. package/dist/bucket/celld-cells.js.map +1 -0
  69. package/dist/bucket/celld-format.d.ts +10 -0
  70. package/dist/bucket/celld-format.js +27 -0
  71. package/dist/bucket/celld-format.js.map +1 -0
  72. package/dist/bucket/idb-object-store.d.ts +9 -0
  73. package/dist/bucket/idb-object-store.js +73 -0
  74. package/dist/bucket/idb-object-store.js.map +1 -0
  75. package/dist/bucket/ltx-log.d.ts +34 -0
  76. package/dist/bucket/ltx-log.js +289 -0
  77. package/dist/bucket/ltx-log.js.map +1 -0
  78. package/dist/bucket/object-store.d.ts +51 -0
  79. package/dist/bucket/object-store.js +114 -0
  80. package/dist/bucket/object-store.js.map +1 -0
  81. package/dist/bucket/s3-object-store.d.ts +25 -0
  82. package/dist/bucket/s3-object-store.js +151 -0
  83. package/dist/bucket/s3-object-store.js.map +1 -0
  84. package/dist/bucket/sqlite-object-store.d.ts +10 -0
  85. package/dist/bucket/sqlite-object-store.js +107 -0
  86. package/dist/bucket/sqlite-object-store.js.map +1 -0
  87. package/dist/core/alarms.d.ts +27 -0
  88. package/dist/core/alarms.js +88 -0
  89. package/dist/core/alarms.js.map +1 -0
  90. package/dist/core/async-context.d.ts +34 -0
  91. package/dist/core/async-context.js +50 -0
  92. package/dist/core/async-context.js.map +1 -0
  93. package/dist/core/celld-schema.d.ts +14 -0
  94. package/dist/core/celld-schema.js +34 -0
  95. package/dist/core/celld-schema.js.map +1 -0
  96. package/dist/core/durable-object.d.ts +28 -0
  97. package/dist/core/durable-object.js +31 -0
  98. package/dist/core/durable-object.js.map +1 -0
  99. package/dist/core/gates.d.ts +33 -0
  100. package/dist/core/gates.js +89 -0
  101. package/dist/core/gates.js.map +1 -0
  102. package/dist/core/handles.d.ts +90 -0
  103. package/dist/core/handles.js +224 -0
  104. package/dist/core/handles.js.map +1 -0
  105. package/dist/core/id.d.ts +19 -0
  106. package/dist/core/id.js +64 -0
  107. package/dist/core/id.js.map +1 -0
  108. package/dist/core/namespace.d.ts +38 -0
  109. package/dist/core/namespace.js +141 -0
  110. package/dist/core/namespace.js.map +1 -0
  111. package/dist/core/object-host.d.ts +91 -0
  112. package/dist/core/object-host.js +616 -0
  113. package/dist/core/object-host.js.map +1 -0
  114. package/dist/core/request-body.d.ts +9 -0
  115. package/dist/core/request-body.js +55 -0
  116. package/dist/core/request-body.js.map +1 -0
  117. package/dist/core/runtime.d.ts +121 -0
  118. package/dist/core/runtime.js +366 -0
  119. package/dist/core/runtime.js.map +1 -0
  120. package/dist/core/shard.d.ts +7 -0
  121. package/dist/core/shard.js +10 -0
  122. package/dist/core/shard.js.map +1 -0
  123. package/dist/core/sql-split.d.ts +15 -0
  124. package/dist/core/sql-split.js +101 -0
  125. package/dist/core/sql-split.js.map +1 -0
  126. package/dist/core/sql-storage.d.ts +53 -0
  127. package/dist/core/sql-storage.js +407 -0
  128. package/dist/core/sql-storage.js.map +1 -0
  129. package/dist/core/state.d.ts +44 -0
  130. package/dist/core/state.js +93 -0
  131. package/dist/core/state.js.map +1 -0
  132. package/dist/core/storage.d.ts +103 -0
  133. package/dist/core/storage.js +351 -0
  134. package/dist/core/storage.js.map +1 -0
  135. package/dist/core/worker-rejections.d.ts +21 -0
  136. package/dist/core/worker-rejections.js +55 -0
  137. package/dist/core/worker-rejections.js.map +1 -0
  138. package/dist/index.d.ts +22 -0
  139. package/dist/index.js +23 -0
  140. package/dist/index.js.map +1 -0
  141. package/dist/isolate/browser.d.ts +16 -0
  142. package/dist/isolate/browser.js +37 -0
  143. package/dist/isolate/browser.js.map +1 -0
  144. package/dist/isolate/host.d.ts +24 -0
  145. package/dist/isolate/host.js +74 -0
  146. package/dist/isolate/host.js.map +1 -0
  147. package/dist/isolate/isolate-worker.d.ts +1 -0
  148. package/dist/isolate/isolate-worker.js +53 -0
  149. package/dist/isolate/isolate-worker.js.map +1 -0
  150. package/dist/isolate/isolate.d.ts +10 -0
  151. package/dist/isolate/isolate.js +169 -0
  152. package/dist/isolate/isolate.js.map +1 -0
  153. package/dist/isolate/node-entry.d.ts +1 -0
  154. package/dist/isolate/node-entry.js +12 -0
  155. package/dist/isolate/node-entry.js.map +1 -0
  156. package/dist/isolate/protocol.d.ts +66 -0
  157. package/dist/isolate/protocol.js +205 -0
  158. package/dist/isolate/protocol.js.map +1 -0
  159. package/dist/ltx/crc64.d.ts +6 -0
  160. package/dist/ltx/crc64.js +46 -0
  161. package/dist/ltx/crc64.js.map +1 -0
  162. package/dist/ltx/ltx-page-server.d.ts +65 -0
  163. package/dist/ltx/ltx-page-server.js +309 -0
  164. package/dist/ltx/ltx-page-server.js.map +1 -0
  165. package/dist/ltx/ltx-pages.d.ts +81 -0
  166. package/dist/ltx/ltx-pages.js +315 -0
  167. package/dist/ltx/ltx-pages.js.map +1 -0
  168. package/dist/ltx/ltx-store-worker.d.ts +1 -0
  169. package/dist/ltx/ltx-store-worker.js +38 -0
  170. package/dist/ltx/ltx-store-worker.js.map +1 -0
  171. package/dist/ltx/ltx.d.ts +45 -0
  172. package/dist/ltx/ltx.js +203 -0
  173. package/dist/ltx/ltx.js.map +1 -0
  174. package/dist/ltx/lz4.d.ts +9 -0
  175. package/dist/ltx/lz4.js +156 -0
  176. package/dist/ltx/lz4.js.map +1 -0
  177. package/dist/ltx/opfs-sync-files.d.ts +23 -0
  178. package/dist/ltx/opfs-sync-files.js +191 -0
  179. package/dist/ltx/opfs-sync-files.js.map +1 -0
  180. package/dist/ltx/xxh32.d.ts +1 -0
  181. package/dist/ltx/xxh32.js +43 -0
  182. package/dist/ltx/xxh32.js.map +1 -0
  183. package/dist/miniflare-compat/blob-service.d.ts +13 -0
  184. package/dist/miniflare-compat/blob-service.js +66 -0
  185. package/dist/miniflare-compat/blob-service.js.map +1 -0
  186. package/dist/miniflare-compat/kv-binding.d.ts +44 -0
  187. package/dist/miniflare-compat/kv-binding.js +99 -0
  188. package/dist/miniflare-compat/kv-binding.js.map +1 -0
  189. package/dist/miniflare-compat/shims/assert.d.ts +15 -0
  190. package/dist/miniflare-compat/shims/assert.js +24 -0
  191. package/dist/miniflare-compat/shims/assert.js.map +1 -0
  192. package/dist/miniflare-compat/shims/workerd-cloudflare.d.ts +7 -0
  193. package/dist/miniflare-compat/shims/workerd-cloudflare.js +6 -0
  194. package/dist/miniflare-compat/shims/workerd-cloudflare.js.map +1 -0
  195. package/dist/miniflare-compat/shims/workerd-globals.d.ts +1 -0
  196. package/dist/miniflare-compat/shims/workerd-globals.js +30 -0
  197. package/dist/miniflare-compat/shims/workerd-globals.js.map +1 -0
  198. package/dist/miniflare-compat/shims/workerd-internal.d.ts +20 -0
  199. package/dist/miniflare-compat/shims/workerd-internal.js +23 -0
  200. package/dist/miniflare-compat/shims/workerd-internal.js.map +1 -0
  201. package/dist/miniflare-compat/shims/workerd-performance.d.ts +4 -0
  202. package/dist/miniflare-compat/shims/workerd-performance.js +17 -0
  203. package/dist/miniflare-compat/shims/workerd-performance.js.map +1 -0
  204. package/dist/miniflare-compat/simulator-fetcher.d.ts +9 -0
  205. package/dist/miniflare-compat/simulator-fetcher.js +14 -0
  206. package/dist/miniflare-compat/simulator-fetcher.js.map +1 -0
  207. package/dist/miniflare-compat/vendored.d.ts +15 -0
  208. package/dist/miniflare-compat/vendored.js +27 -0
  209. package/dist/miniflare-compat/vendored.js.map +1 -0
  210. package/dist/node-compat/async_hooks.d.ts +22 -0
  211. package/dist/node-compat/async_hooks.js +176 -0
  212. package/dist/node-compat/async_hooks.js.map +1 -0
  213. package/dist/node-compat/browser-registry.d.ts +3 -0
  214. package/dist/node-compat/browser-registry.js +39 -0
  215. package/dist/node-compat/browser-registry.js.map +1 -0
  216. package/dist/node-compat/crypto.d.ts +60 -0
  217. package/dist/node-compat/crypto.js +143 -0
  218. package/dist/node-compat/crypto.js.map +1 -0
  219. package/dist/node-compat/diagnostics_channel.d.ts +27 -0
  220. package/dist/node-compat/diagnostics_channel.js +46 -0
  221. package/dist/node-compat/diagnostics_channel.js.map +1 -0
  222. package/dist/node-compat/fs.d.ts +35 -0
  223. package/dist/node-compat/fs.js +40 -0
  224. package/dist/node-compat/fs.js.map +1 -0
  225. package/dist/node-compat/globals.d.ts +3 -0
  226. package/dist/node-compat/globals.js +4 -0
  227. package/dist/node-compat/globals.js.map +1 -0
  228. package/dist/node-compat/install.d.ts +5 -0
  229. package/dist/node-compat/install.js +12 -0
  230. package/dist/node-compat/install.js.map +1 -0
  231. package/dist/node-compat/module.d.ts +12 -0
  232. package/dist/node-compat/module.js +36 -0
  233. package/dist/node-compat/module.js.map +1 -0
  234. package/dist/node-compat/modules.d.ts +8 -0
  235. package/dist/node-compat/modules.js +23 -0
  236. package/dist/node-compat/modules.js.map +1 -0
  237. package/dist/node-compat/os.d.ts +36 -0
  238. package/dist/node-compat/os.js +36 -0
  239. package/dist/node-compat/os.js.map +1 -0
  240. package/dist/node-compat/process.d.ts +14 -0
  241. package/dist/node-compat/process.js +16 -0
  242. package/dist/node-compat/process.js.map +1 -0
  243. package/dist/node-compat/shims.d.ts +4 -0
  244. package/dist/node.d.ts +5 -0
  245. package/dist/node.js +6 -0
  246. package/dist/node.js.map +1 -0
  247. package/dist/peer/celld-peer.d.ts +53 -0
  248. package/dist/peer/celld-peer.js +555 -0
  249. package/dist/peer/celld-peer.js.map +1 -0
  250. package/dist/ports.d.ts +183 -0
  251. package/dist/ports.js +10 -0
  252. package/dist/ports.js.map +1 -0
  253. package/dist/project/browser-bundle.d.ts +17 -0
  254. package/dist/project/browser-bundle.js +125 -0
  255. package/dist/project/browser-bundle.js.map +1 -0
  256. package/dist/project/browser-cookies.d.ts +12 -0
  257. package/dist/project/browser-cookies.js +90 -0
  258. package/dist/project/browser-cookies.js.map +1 -0
  259. package/dist/project/browser-host.d.ts +173 -0
  260. package/dist/project/browser-host.js +200 -0
  261. package/dist/project/browser-host.js.map +1 -0
  262. package/dist/project/browser-modules.d.ts +17 -0
  263. package/dist/project/browser-modules.js +89 -0
  264. package/dist/project/browser-modules.js.map +1 -0
  265. package/dist/project/browser-shards.d.ts +62 -0
  266. package/dist/project/browser-shards.js +210 -0
  267. package/dist/project/browser-shards.js.map +1 -0
  268. package/dist/project/browser-tabs.d.ts +103 -0
  269. package/dist/project/browser-tabs.js +418 -0
  270. package/dist/project/browser-tabs.js.map +1 -0
  271. package/dist/project/cloudflare-email.d.ts +8 -0
  272. package/dist/project/cloudflare-email.js +11 -0
  273. package/dist/project/cloudflare-email.js.map +1 -0
  274. package/dist/project/cloudflare-workers.d.ts +12 -0
  275. package/dist/project/cloudflare-workers.js +16 -0
  276. package/dist/project/cloudflare-workers.js.map +1 -0
  277. package/dist/project/host-modules.d.ts +4 -0
  278. package/dist/project/host-modules.js +40 -0
  279. package/dist/project/host-modules.js.map +1 -0
  280. package/dist/project/jsonc.d.ts +2 -0
  281. package/dist/project/jsonc.js +27 -0
  282. package/dist/project/jsonc.js.map +1 -0
  283. package/dist/project/lower-await.d.ts +2 -0
  284. package/dist/project/lower-await.js +151 -0
  285. package/dist/project/lower-await.js.map +1 -0
  286. package/dist/project/node-project.d.ts +38 -0
  287. package/dist/project/node-project.js +373 -0
  288. package/dist/project/node-project.js.map +1 -0
  289. package/dist/project/own-module.d.ts +6 -0
  290. package/dist/project/own-module.js +13 -0
  291. package/dist/project/own-module.js.map +1 -0
  292. package/dist/project/scheduler.d.ts +2 -0
  293. package/dist/project/scheduler.js +3 -0
  294. package/dist/project/scheduler.js.map +1 -0
  295. package/dist/project/site.d.ts +74 -0
  296. package/dist/project/site.js +206 -0
  297. package/dist/project/site.js.map +1 -0
  298. package/dist/project/virtual-modules.d.ts +3 -0
  299. package/dist/project/worker-scope.d.ts +27 -0
  300. package/dist/project/worker-scope.js +46 -0
  301. package/dist/project/worker-scope.js.map +1 -0
  302. package/dist/project/workerd-message-channel.d.ts +13 -0
  303. package/dist/project/workerd-message-channel.js +137 -0
  304. package/dist/project/workerd-message-channel.js.map +1 -0
  305. package/dist/project/workers-global-names.d.ts +6 -0
  306. package/dist/project/workers-global-names.js +15 -0
  307. package/dist/project/workers-global-names.js.map +1 -0
  308. package/dist/project/workers-globals-module.d.ts +8 -0
  309. package/dist/project/workers-globals-module.js +9 -0
  310. package/dist/project/workers-globals-module.js.map +1 -0
  311. package/dist/project/workers-globals.d.ts +9 -0
  312. package/dist/project/workers-globals.js +19 -0
  313. package/dist/project/workers-globals.js.map +1 -0
  314. package/dist/project/wrangler.d.ts +116 -0
  315. package/dist/project/wrangler.js +342 -0
  316. package/dist/project/wrangler.js.map +1 -0
  317. package/dist/router/cell-router.d.ts +72 -0
  318. package/dist/router/cell-router.js +247 -0
  319. package/dist/router/cell-router.js.map +1 -0
  320. package/dist/router/shard-worker.d.ts +44 -0
  321. package/dist/router/shard-worker.js +163 -0
  322. package/dist/router/shard-worker.js.map +1 -0
  323. package/dist/transport/cells-http.d.ts +25 -0
  324. package/dist/transport/cells-http.js +141 -0
  325. package/dist/transport/cells-http.js.map +1 -0
  326. package/dist/transport/cells-link.d.ts +27 -0
  327. package/dist/transport/cells-link.js +71 -0
  328. package/dist/transport/cells-link.js.map +1 -0
  329. package/dist/transport/port.d.ts +26 -0
  330. package/dist/transport/port.js +100 -0
  331. package/dist/transport/port.js.map +1 -0
  332. package/dist/v8/codec.d.ts +6 -0
  333. package/dist/v8/codec.js +9 -0
  334. package/dist/v8/codec.js.map +1 -0
  335. package/dist/v8/serialize.d.ts +10 -0
  336. package/dist/v8/serialize.js +601 -0
  337. package/dist/v8/serialize.js.map +1 -0
  338. package/dist/ws/client.d.ts +25 -0
  339. package/dist/ws/client.js +203 -0
  340. package/dist/ws/client.js.map +1 -0
  341. package/dist/ws/control.d.ts +48 -0
  342. package/dist/ws/control.js +44 -0
  343. package/dist/ws/control.js.map +1 -0
  344. package/dist/ws/frames.d.ts +38 -0
  345. package/dist/ws/frames.js +39 -0
  346. package/dist/ws/frames.js.map +1 -0
  347. package/dist/ws/server.d.ts +99 -0
  348. package/dist/ws/server.js +295 -0
  349. package/dist/ws/server.js.map +1 -0
  350. package/dist/ws/sw-connector.d.ts +10 -0
  351. package/dist/ws/sw-connector.js +25 -0
  352. package/dist/ws/sw-connector.js.map +1 -0
  353. package/dist/ws/upgrade.d.ts +28 -0
  354. package/dist/ws/upgrade.js +75 -0
  355. package/dist/ws/upgrade.js.map +1 -0
  356. package/package.json +111 -3
  357. package/vendor/celld/LICENSE +202 -0
  358. package/vendor/celld/kv.js +1131 -0
  359. package/vendor/celld/queues.js +1656 -0
  360. package/vendor/celld/workflows.js +1610 -0
  361. package/vendor/html-rewriter-wasm/html_rewriter.js +925 -0
  362. package/vendor/html-rewriter-wasm/html_rewriter_bg.wasm +0 -0
  363. package/vendor/miniflare/d1-api.js +738 -0
  364. package/vendor/miniflare/d1-database.js +6978 -0
  365. package/vendor/miniflare/kv-namespace.js +3061 -0
@@ -0,0 +1,203 @@
1
+ import { crc64 } from "./crc64.js";
2
+ import { lz4Compress, lz4Decompress, lz4FrameCompress, lz4FrameDecompress } from "./lz4.js";
3
+ /**
4
+ * LTX v3 (superfly/ltx v0.5.2), byte for byte as celld writes it — see
5
+ * crates/ltx/reference/ltx-format.md in denoland/celld. Big-endian integers, 100-byte
6
+ * header, size-prefixed LZ4 page blocks, page index, 16-byte trailer, CRC-64/ISO checksums
7
+ * with the top bit always set.
8
+ */
9
+ export const CHECKSUM_FLAG = 1n << 63n;
10
+ const HEADER_SIZE = 100;
11
+ const PAGE_HEADER_FLAG_SIZE = 1;
12
+ /** Header flag: the file carries no rolling database checksums (what celld 0.6.2 writes). */
13
+ export const HEADER_FLAG_NO_CHECKSUM = 1 << 1;
14
+ const be32 = (n) => {
15
+ const b = new Uint8Array(4);
16
+ new DataView(b.buffer).setUint32(0, n);
17
+ return b;
18
+ };
19
+ const be64 = (n) => {
20
+ const b = new Uint8Array(8);
21
+ new DataView(b.buffer).setBigUint64(0, BigInt.asUintN(64, n));
22
+ return b;
23
+ };
24
+ const uvarint = (n) => {
25
+ const out = [];
26
+ while (n >= 0x80) {
27
+ out.push((n & 0x7f) | 0x80);
28
+ n = Math.floor(n / 128);
29
+ }
30
+ out.push(n);
31
+ return out;
32
+ };
33
+ /** The SQLite lock page (never stored, excluded from checksums). */
34
+ export const lockPgno = (pageSize) => Math.floor(0x40000000 / pageSize) + 1;
35
+ export const checksumPage = (pgno, data) => CHECKSUM_FLAG | crc64(be32(pgno), data);
36
+ /** Rolling database checksum over pages 1..n (lock page excluded). */
37
+ export function databaseChecksum(pageSize, pageAt, n) {
38
+ const lock = lockPgno(pageSize);
39
+ let sum = CHECKSUM_FLAG;
40
+ for (let p = 1; p <= n; p++)
41
+ if (p !== lock)
42
+ sum = CHECKSUM_FLAG | (sum ^ checksumPage(p, pageAt(p)));
43
+ return sum;
44
+ }
45
+ /** Offset just past the LZ4 frame starting at `o` (blocks up to the end mark, content checksum). */
46
+ function endOfFrame(b, o) {
47
+ const v = new DataView(b.buffer, b.byteOffset, b.byteLength);
48
+ const flg = b[o + 4];
49
+ o += 6 + (flg & 0x08 ? 8 : 0) + (flg & 0x01 ? 4 : 0) + 1;
50
+ for (;;) {
51
+ const word = v.getUint32(o, true);
52
+ o += 4;
53
+ if (word === 0)
54
+ break;
55
+ o += (word & 0x7fffffff) + (flg & 0x10 ? 4 : 0);
56
+ }
57
+ return o + (flg & 0x04 ? 4 : 0);
58
+ }
59
+ /**
60
+ * `format: "legacy"` (default) writes one LZ4 frame per page, as celld 0.6.2 does; `"block"`
61
+ * writes v0.5.2's size-prefixed blocks (celld's decoder accepts both).
62
+ */
63
+ export function encodeLtx(file, format = "legacy") {
64
+ const h = file.header;
65
+ const header = new Uint8Array(HEADER_SIZE);
66
+ const v = new DataView(header.buffer);
67
+ header.set(new TextEncoder().encode("LTX1"), 0);
68
+ // celld's validator: with checksums on, a snapshot needs a real post-apply checksum and an
69
+ // incremental a pre-apply one; with both at 0 the file must say NO_CHECKSUM (as celld's do).
70
+ const flags = h.flags ??
71
+ (h.preApplyChecksum === 0n && file.postApplyChecksum === 0n ? HEADER_FLAG_NO_CHECKSUM : 0);
72
+ v.setUint32(4, flags);
73
+ v.setUint32(8, h.pageSize);
74
+ v.setUint32(12, h.commit);
75
+ v.setBigUint64(16, h.minTXID);
76
+ v.setBigUint64(24, h.maxTXID);
77
+ v.setBigInt64(32, BigInt(h.timestamp));
78
+ v.setBigUint64(40, h.preApplyChecksum);
79
+ v.setBigInt64(48, h.walOffset ?? 0n);
80
+ v.setBigInt64(56, h.walSize ?? 0n);
81
+ v.setUint32(64, h.walSalt1 ?? 0);
82
+ v.setUint32(68, h.walSalt2 ?? 0);
83
+ v.setBigUint64(72, h.nodeID ?? 0n);
84
+ const out = [header];
85
+ const feed = [header];
86
+ const index = [];
87
+ let offset = HEADER_SIZE;
88
+ const lock = lockPgno(h.pageSize);
89
+ for (const [pgno, data] of [...file.pages].sort((a, b) => a[0] - b[0])) {
90
+ if (pgno === lock)
91
+ continue;
92
+ const ph = new Uint8Array(6);
93
+ new DataView(ph.buffer).setUint32(0, pgno);
94
+ if (format === "block") {
95
+ new DataView(ph.buffer).setUint16(4, PAGE_HEADER_FLAG_SIZE);
96
+ const compressed = lz4Compress(data);
97
+ const size = be32(compressed.length);
98
+ out.push(ph, size, compressed);
99
+ feed.push(ph, size, data);
100
+ index.push(...uvarint(pgno), ...uvarint(offset), ...uvarint(6 + 4 + compressed.length));
101
+ offset += 6 + 4 + compressed.length;
102
+ }
103
+ else {
104
+ const frame = lz4FrameCompress(data);
105
+ out.push(ph, frame);
106
+ feed.push(ph, data);
107
+ index.push(...uvarint(pgno), ...uvarint(offset), ...uvarint(6 + frame.length));
108
+ offset += 6 + frame.length;
109
+ }
110
+ }
111
+ const empty = new Uint8Array(6);
112
+ index.push(...uvarint(0));
113
+ const idx = Uint8Array.from(index);
114
+ const idxLen = be64(BigInt(idx.length));
115
+ const post = be64(file.postApplyChecksum);
116
+ out.push(empty, idx, idxLen);
117
+ feed.push(empty, idx, idxLen, post);
118
+ const fileChecksum = CHECKSUM_FLAG | crc64(...feed);
119
+ out.push(post, be64(fileChecksum));
120
+ const total = new Uint8Array(out.reduce((n, b) => n + b.length, 0));
121
+ let o = 0;
122
+ for (const b of out) {
123
+ total.set(b, o);
124
+ o += b.length;
125
+ }
126
+ return total;
127
+ }
128
+ export function decodeLtx(bytes) {
129
+ const v = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
130
+ if (new TextDecoder().decode(bytes.subarray(0, 4)) !== "LTX1")
131
+ throw new Error("ltx: bad magic");
132
+ const flags = v.getUint32(4);
133
+ const header = {
134
+ flags,
135
+ walOffset: v.getBigInt64(48),
136
+ walSize: v.getBigInt64(56),
137
+ walSalt1: v.getUint32(64),
138
+ walSalt2: v.getUint32(68),
139
+ pageSize: v.getUint32(8),
140
+ commit: v.getUint32(12),
141
+ minTXID: v.getBigUint64(16),
142
+ maxTXID: v.getBigUint64(24),
143
+ timestamp: Number(v.getBigInt64(32)),
144
+ preApplyChecksum: v.getBigUint64(40),
145
+ nodeID: v.getBigUint64(72),
146
+ };
147
+ const feed = [bytes.subarray(0, HEADER_SIZE)];
148
+ const pages = new Map();
149
+ let o = HEADER_SIZE;
150
+ for (;;) {
151
+ const pgno = v.getUint32(o);
152
+ const pflags = v.getUint16(o + 4);
153
+ feed.push(bytes.subarray(o, o + 6));
154
+ o += 6;
155
+ if (pgno === 0)
156
+ break;
157
+ let data;
158
+ if (pflags & PAGE_HEADER_FLAG_SIZE) {
159
+ const size = v.getUint32(o);
160
+ feed.push(bytes.subarray(o, o + 4));
161
+ o += 4;
162
+ data = lz4Decompress(bytes.subarray(o, o + size), header.pageSize);
163
+ o += size;
164
+ }
165
+ else {
166
+ // legacy (v0.5.1, what celld writes today): one LZ4 frame, its length found by parsing
167
+ const start = o;
168
+ o = endOfFrame(bytes, o);
169
+ data = lz4FrameDecompress(bytes.subarray(start, o), header.pageSize);
170
+ }
171
+ feed.push(data);
172
+ pages.set(pgno, data);
173
+ }
174
+ // page index: varints until 0, then u64 length
175
+ const idxStart = o;
176
+ for (;;) {
177
+ let x = 0;
178
+ let shift = 0;
179
+ let b;
180
+ do {
181
+ b = bytes[o++];
182
+ x += (b & 0x7f) * 2 ** shift;
183
+ shift += 7;
184
+ } while (b & 0x80);
185
+ if (x === 0)
186
+ break;
187
+ for (let k = 0; k < 2; k++)
188
+ do
189
+ b = bytes[o++];
190
+ while (b & 0x80);
191
+ }
192
+ feed.push(bytes.subarray(idxStart, o + 8));
193
+ o += 8;
194
+ const postApplyChecksum = v.getBigUint64(o);
195
+ const fileChecksum = v.getBigUint64(o + 8);
196
+ feed.push(bytes.subarray(o, o + 8));
197
+ if (!(flags & 2) && (CHECKSUM_FLAG | crc64(...feed)) !== fileChecksum)
198
+ throw new Error("ltx: file checksum mismatch");
199
+ return { header, pages, postApplyChecksum };
200
+ }
201
+ /** `<minTXID:016x>-<maxTXID:016x>.ltx` */
202
+ export const ltxFileName = (min, max) => `${min.toString(16).padStart(16, "0")}-${max.toString(16).padStart(16, "0")}.ltx`;
203
+ //# sourceMappingURL=ltx.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ltx.js","sourceRoot":"","sources":["../../src/ltx/ltx.ts"],"names":[],"mappings":"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","sourcesContent":["import { crc64 } from \"./crc64.js\";\nimport { lz4Compress, lz4Decompress, lz4FrameCompress, lz4FrameDecompress } from \"./lz4.js\";\n\n/**\n * LTX v3 (superfly/ltx v0.5.2), byte for byte as celld writes it — see\n * crates/ltx/reference/ltx-format.md in denoland/celld. Big-endian integers, 100-byte\n * header, size-prefixed LZ4 page blocks, page index, 16-byte trailer, CRC-64/ISO checksums\n * with the top bit always set.\n */\nexport const CHECKSUM_FLAG = 1n << 63n;\nconst HEADER_SIZE = 100;\nconst PAGE_HEADER_FLAG_SIZE = 1;\n\n/** Header flag: the file carries no rolling database checksums (what celld 0.6.2 writes). */\nexport const HEADER_FLAG_NO_CHECKSUM = 1 << 1;\n\nexport interface LtxHeader {\n /** Header flags; defaults to NO_CHECKSUM when both rolling checksums are 0 (celld's files). */\n flags?: number;\n /** WAL position the file was cut from (litestream WAL mode; 0 in journal mode). */\n walOffset?: bigint;\n walSize?: bigint;\n walSalt1?: number;\n walSalt2?: number;\n pageSize: number;\n /** Database size after the transaction, in pages. */\n commit: number;\n minTXID: bigint;\n maxTXID: bigint;\n timestamp: number;\n preApplyChecksum: bigint;\n nodeID?: bigint;\n}\n\nexport interface LtxFile {\n header: LtxHeader;\n /** pgno → page bytes, ascending. */\n pages: Map<number, Uint8Array>;\n postApplyChecksum: bigint;\n}\n\nconst be32 = (n: number) => {\n const b = new Uint8Array(4);\n new DataView(b.buffer).setUint32(0, n);\n return b;\n};\nconst be64 = (n: bigint) => {\n const b = new Uint8Array(8);\n new DataView(b.buffer).setBigUint64(0, BigInt.asUintN(64, n));\n return b;\n};\nconst uvarint = (n: number): number[] => {\n const out: number[] = [];\n while (n >= 0x80) {\n out.push((n & 0x7f) | 0x80);\n n = Math.floor(n / 128);\n }\n out.push(n);\n return out;\n};\n\n/** The SQLite lock page (never stored, excluded from checksums). */\nexport const lockPgno = (pageSize: number) => Math.floor(0x40000000 / pageSize) + 1;\n\nexport const checksumPage = (pgno: number, data: Uint8Array) =>\n CHECKSUM_FLAG | crc64(be32(pgno), data);\n\n/** Rolling database checksum over pages 1..n (lock page excluded). */\nexport function databaseChecksum(\n pageSize: number,\n pageAt: (pgno: number) => Uint8Array,\n n: number,\n): bigint {\n const lock = lockPgno(pageSize);\n let sum = CHECKSUM_FLAG;\n for (let p = 1; p <= n; p++)\n if (p !== lock) sum = CHECKSUM_FLAG | (sum ^ checksumPage(p, pageAt(p)));\n return sum;\n}\n\n/** Offset just past the LZ4 frame starting at `o` (blocks up to the end mark, content checksum). */\nfunction endOfFrame(b: Uint8Array, o: number): number {\n const v = new DataView(b.buffer, b.byteOffset, b.byteLength);\n const flg = b[o + 4];\n o += 6 + (flg & 0x08 ? 8 : 0) + (flg & 0x01 ? 4 : 0) + 1;\n for (;;) {\n const word = v.getUint32(o, true);\n o += 4;\n if (word === 0) break;\n o += (word & 0x7fffffff) + (flg & 0x10 ? 4 : 0);\n }\n return o + (flg & 0x04 ? 4 : 0);\n}\n\n/**\n * `format: \"legacy\"` (default) writes one LZ4 frame per page, as celld 0.6.2 does; `\"block\"`\n * writes v0.5.2's size-prefixed blocks (celld's decoder accepts both).\n */\nexport function encodeLtx(file: LtxFile, format: \"legacy\" | \"block\" = \"legacy\"): Uint8Array {\n const h = file.header;\n const header = new Uint8Array(HEADER_SIZE);\n const v = new DataView(header.buffer);\n header.set(new TextEncoder().encode(\"LTX1\"), 0);\n // celld's validator: with checksums on, a snapshot needs a real post-apply checksum and an\n // incremental a pre-apply one; with both at 0 the file must say NO_CHECKSUM (as celld's do).\n const flags =\n h.flags ??\n (h.preApplyChecksum === 0n && file.postApplyChecksum === 0n ? HEADER_FLAG_NO_CHECKSUM : 0);\n v.setUint32(4, flags);\n v.setUint32(8, h.pageSize);\n v.setUint32(12, h.commit);\n v.setBigUint64(16, h.minTXID);\n v.setBigUint64(24, h.maxTXID);\n v.setBigInt64(32, BigInt(h.timestamp));\n v.setBigUint64(40, h.preApplyChecksum);\n v.setBigInt64(48, h.walOffset ?? 0n);\n v.setBigInt64(56, h.walSize ?? 0n);\n v.setUint32(64, h.walSalt1 ?? 0);\n v.setUint32(68, h.walSalt2 ?? 0);\n v.setBigUint64(72, h.nodeID ?? 0n);\n\n const out: Uint8Array[] = [header];\n const feed: Uint8Array[] = [header];\n const index: number[] = [];\n let offset = HEADER_SIZE;\n const lock = lockPgno(h.pageSize);\n for (const [pgno, data] of [...file.pages].sort((a, b) => a[0] - b[0])) {\n if (pgno === lock) continue;\n const ph = new Uint8Array(6);\n new DataView(ph.buffer).setUint32(0, pgno);\n if (format === \"block\") {\n new DataView(ph.buffer).setUint16(4, PAGE_HEADER_FLAG_SIZE);\n const compressed = lz4Compress(data);\n const size = be32(compressed.length);\n out.push(ph, size, compressed);\n feed.push(ph, size, data);\n index.push(...uvarint(pgno), ...uvarint(offset), ...uvarint(6 + 4 + compressed.length));\n offset += 6 + 4 + compressed.length;\n } else {\n const frame = lz4FrameCompress(data);\n out.push(ph, frame);\n feed.push(ph, data);\n index.push(...uvarint(pgno), ...uvarint(offset), ...uvarint(6 + frame.length));\n offset += 6 + frame.length;\n }\n }\n const empty = new Uint8Array(6);\n index.push(...uvarint(0));\n const idx = Uint8Array.from(index);\n const idxLen = be64(BigInt(idx.length));\n const post = be64(file.postApplyChecksum);\n out.push(empty, idx, idxLen);\n feed.push(empty, idx, idxLen, post);\n const fileChecksum = CHECKSUM_FLAG | crc64(...feed);\n out.push(post, be64(fileChecksum));\n const total = new Uint8Array(out.reduce((n, b) => n + b.length, 0));\n let o = 0;\n for (const b of out) {\n total.set(b, o);\n o += b.length;\n }\n return total;\n}\n\nexport function decodeLtx(bytes: Uint8Array): LtxFile {\n const v = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);\n if (new TextDecoder().decode(bytes.subarray(0, 4)) !== \"LTX1\") throw new Error(\"ltx: bad magic\");\n const flags = v.getUint32(4);\n const header: LtxHeader = {\n flags,\n walOffset: v.getBigInt64(48),\n walSize: v.getBigInt64(56),\n walSalt1: v.getUint32(64),\n walSalt2: v.getUint32(68),\n pageSize: v.getUint32(8),\n commit: v.getUint32(12),\n minTXID: v.getBigUint64(16),\n maxTXID: v.getBigUint64(24),\n timestamp: Number(v.getBigInt64(32)),\n preApplyChecksum: v.getBigUint64(40),\n nodeID: v.getBigUint64(72),\n };\n const feed: Uint8Array[] = [bytes.subarray(0, HEADER_SIZE)];\n const pages = new Map<number, Uint8Array>();\n let o = HEADER_SIZE;\n for (;;) {\n const pgno = v.getUint32(o);\n const pflags = v.getUint16(o + 4);\n feed.push(bytes.subarray(o, o + 6));\n o += 6;\n if (pgno === 0) break;\n let data: Uint8Array;\n if (pflags & PAGE_HEADER_FLAG_SIZE) {\n const size = v.getUint32(o);\n feed.push(bytes.subarray(o, o + 4));\n o += 4;\n data = lz4Decompress(bytes.subarray(o, o + size), header.pageSize);\n o += size;\n } else {\n // legacy (v0.5.1, what celld writes today): one LZ4 frame, its length found by parsing\n const start = o;\n o = endOfFrame(bytes, o);\n data = lz4FrameDecompress(bytes.subarray(start, o), header.pageSize);\n }\n feed.push(data);\n pages.set(pgno, data);\n }\n // page index: varints until 0, then u64 length\n const idxStart = o;\n for (;;) {\n let x = 0;\n let shift = 0;\n let b: number;\n do {\n b = bytes[o++];\n x += (b & 0x7f) * 2 ** shift;\n shift += 7;\n } while (b & 0x80);\n if (x === 0) break;\n for (let k = 0; k < 2; k++)\n do b = bytes[o++];\n while (b & 0x80);\n }\n feed.push(bytes.subarray(idxStart, o + 8));\n o += 8;\n const postApplyChecksum = v.getBigUint64(o);\n const fileChecksum = v.getBigUint64(o + 8);\n feed.push(bytes.subarray(o, o + 8));\n if (!(flags & 2) && (CHECKSUM_FLAG | crc64(...feed)) !== fileChecksum)\n throw new Error(\"ltx: file checksum mismatch\");\n return { header, pages, postApplyChecksum };\n}\n\n/** `<minTXID:016x>-<maxTXID:016x>.ltx` */\nexport const ltxFileName = (min: bigint, max: bigint) =>\n `${min.toString(16).padStart(16, \"0\")}-${max.toString(16).padStart(16, \"0\")}.ltx`;\n"]}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * LZ4 block format (raw blocks, no frame): a standard decoder, and a simple greedy encoder
3
+ * with a 4-byte hash table. Any valid block decodes the same, so LTX checksums (computed on
4
+ * uncompressed pages) do not depend on the encoder's choices.
5
+ */
6
+ export declare function lz4Decompress(src: Uint8Array, outSize: number, partial?: boolean): Uint8Array;
7
+ export declare function lz4Compress(src: Uint8Array): Uint8Array;
8
+ export declare function lz4FrameDecompress(src: Uint8Array, outSize: number): Uint8Array;
9
+ export declare function lz4FrameCompress(data: Uint8Array): Uint8Array;
@@ -0,0 +1,156 @@
1
+ import { xxh32 } from "./xxh32.js";
2
+ /**
3
+ * LZ4 block format (raw blocks, no frame): a standard decoder, and a simple greedy encoder
4
+ * with a 4-byte hash table. Any valid block decodes the same, so LTX checksums (computed on
5
+ * uncompressed pages) do not depend on the encoder's choices.
6
+ */
7
+ export function lz4Decompress(src, outSize, partial = false) {
8
+ const out = new Uint8Array(outSize);
9
+ let si = 0;
10
+ let di = 0;
11
+ while (si < src.length) {
12
+ const token = src[si++];
13
+ let lit = token >>> 4;
14
+ if (lit === 15) {
15
+ let b;
16
+ do {
17
+ b = src[si++];
18
+ lit += b;
19
+ } while (b === 255);
20
+ }
21
+ out.set(src.subarray(si, si + lit), di);
22
+ si += lit;
23
+ di += lit;
24
+ if (si >= src.length)
25
+ break; // last sequence has literals only
26
+ const offset = src[si] | (src[si + 1] << 8);
27
+ si += 2;
28
+ let len = (token & 15) + 4;
29
+ if ((token & 15) === 15) {
30
+ let b;
31
+ do {
32
+ b = src[si++];
33
+ len += b;
34
+ } while (b === 255);
35
+ }
36
+ if (offset === 0 || offset > di)
37
+ throw new Error("lz4: bad match offset");
38
+ for (let i = 0; i < len; i++, di++)
39
+ out[di] = out[di - offset];
40
+ }
41
+ if (!partial && di !== outSize)
42
+ throw new Error(`lz4: decoded ${di} bytes, expected ${outSize}`);
43
+ return partial ? out.subarray(0, di) : out;
44
+ }
45
+ export function lz4Compress(src) {
46
+ const n = src.length;
47
+ const out = new Uint8Array(n + Math.ceil(n / 255) + 16);
48
+ const table = new Int32Array(1 << 14).fill(-1);
49
+ const hash = (i) => (Math.imul(src[i] | (src[i + 1] << 8) | (src[i + 2] << 16) | (src[i + 3] << 24), 2654435761) >>>
50
+ 18) &
51
+ 0x3fff;
52
+ let si = 0;
53
+ let di = 0;
54
+ let anchor = 0;
55
+ const writeLen = (len) => {
56
+ while (len >= 255) {
57
+ out[di++] = 255;
58
+ len -= 255;
59
+ }
60
+ out[di++] = len;
61
+ };
62
+ const LAST_LITERALS = 5;
63
+ const MF_LIMIT = 12;
64
+ while (si + MF_LIMIT < n) {
65
+ const h = hash(si);
66
+ const ref = table[h];
67
+ table[h] = si;
68
+ if (ref >= 0 &&
69
+ si - ref <= 0xffff &&
70
+ src[ref] === src[si] &&
71
+ src[ref + 1] === src[si + 1] &&
72
+ src[ref + 2] === src[si + 2] &&
73
+ src[ref + 3] === src[si + 3]) {
74
+ let len = 4;
75
+ while (si + len < n - LAST_LITERALS && src[ref + len] === src[si + len])
76
+ len++;
77
+ const lit = si - anchor;
78
+ const tokenPos = di++;
79
+ out[tokenPos] = (Math.min(lit, 15) << 4) | Math.min(len - 4, 15);
80
+ if (lit >= 15)
81
+ writeLen(lit - 15);
82
+ out.set(src.subarray(anchor, si), di);
83
+ di += lit;
84
+ const off = si - ref;
85
+ out[di++] = off & 0xff;
86
+ out[di++] = off >>> 8;
87
+ if (len - 4 >= 15)
88
+ writeLen(len - 4 - 15);
89
+ si += len;
90
+ anchor = si;
91
+ }
92
+ else
93
+ si++;
94
+ }
95
+ const lit = n - anchor;
96
+ out[di++] = Math.min(lit, 15) << 4;
97
+ if (lit >= 15)
98
+ writeLen(lit - 15);
99
+ out.set(src.subarray(anchor), di);
100
+ di += lit;
101
+ return out.slice(0, di);
102
+ }
103
+ /**
104
+ * LZ4 frames as superfly/ltx v0.5.1 writes them (celld's current page format): magic,
105
+ * FLG 0x64 (v1, independent blocks, content checksum), BD 0x40 (64 KiB blocks), header
106
+ * checksum, data blocks, end mark, xxHash32 of the content.
107
+ */
108
+ const FRAME_MAGIC = 0x184d2204;
109
+ export function lz4FrameDecompress(src, outSize) {
110
+ const v = new DataView(src.buffer, src.byteOffset, src.byteLength);
111
+ if (v.getUint32(0, true) !== FRAME_MAGIC)
112
+ throw new Error("lz4: bad frame magic");
113
+ const flg = src[4];
114
+ let o = 6 + (flg & 0x08 ? 8 : 0) + (flg & 0x01 ? 4 : 0) + 1; // FLG BD [size] [dict] HC
115
+ const out = new Uint8Array(outSize);
116
+ let di = 0;
117
+ for (;;) {
118
+ const word = v.getUint32(o, true);
119
+ o += 4;
120
+ if (word === 0)
121
+ break;
122
+ const size = word & 0x7fffffff;
123
+ const block = src.subarray(o, o + size);
124
+ o += size + (flg & 0x10 ? 4 : 0);
125
+ if (word & 0x80000000) {
126
+ out.set(block, di);
127
+ di += size;
128
+ }
129
+ else {
130
+ const part = lz4Decompress(block, Math.min(65536, outSize - di), true);
131
+ out.set(part, di);
132
+ di += part.length;
133
+ }
134
+ }
135
+ if (flg & 0x04 && v.getUint32(o, true) !== xxh32(out))
136
+ throw new Error("lz4: frame content checksum mismatch");
137
+ return out;
138
+ }
139
+ export function lz4FrameCompress(data) {
140
+ const descriptor = Uint8Array.of(0x64, 0x40);
141
+ const hc = (xxh32(descriptor) >>> 8) & 0xff;
142
+ const block = lz4Compress(data);
143
+ const raw = block.length >= data.length; // store uncompressed when it does not shrink
144
+ const body = raw ? data : block;
145
+ const out = new Uint8Array(4 + 3 + 4 + body.length + 4 + 4);
146
+ const v = new DataView(out.buffer);
147
+ v.setUint32(0, FRAME_MAGIC, true);
148
+ out.set(descriptor, 4);
149
+ out[6] = hc;
150
+ v.setUint32(7, (body.length | (raw ? 0x80000000 : 0)) >>> 0, true);
151
+ out.set(body, 11);
152
+ v.setUint32(11 + body.length, 0, true);
153
+ v.setUint32(15 + body.length, xxh32(data), true);
154
+ return out;
155
+ }
156
+ //# sourceMappingURL=lz4.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lz4.js","sourceRoot":"","sources":["../../src/ltx/lz4.ts"],"names":[],"mappings":"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","sourcesContent":["import { xxh32 } from \"./xxh32.js\";\n\n/**\n * LZ4 block format (raw blocks, no frame): a standard decoder, and a simple greedy encoder\n * with a 4-byte hash table. Any valid block decodes the same, so LTX checksums (computed on\n * uncompressed pages) do not depend on the encoder's choices.\n */\nexport function lz4Decompress(src: Uint8Array, outSize: number, partial = false): Uint8Array {\n const out = new Uint8Array(outSize);\n let si = 0;\n let di = 0;\n while (si < src.length) {\n const token = src[si++];\n let lit = token >>> 4;\n if (lit === 15) {\n let b: number;\n do {\n b = src[si++];\n lit += b;\n } while (b === 255);\n }\n out.set(src.subarray(si, si + lit), di);\n si += lit;\n di += lit;\n if (si >= src.length) break; // last sequence has literals only\n const offset = src[si] | (src[si + 1] << 8);\n si += 2;\n let len = (token & 15) + 4;\n if ((token & 15) === 15) {\n let b: number;\n do {\n b = src[si++];\n len += b;\n } while (b === 255);\n }\n if (offset === 0 || offset > di) throw new Error(\"lz4: bad match offset\");\n for (let i = 0; i < len; i++, di++) out[di] = out[di - offset];\n }\n if (!partial && di !== outSize) throw new Error(`lz4: decoded ${di} bytes, expected ${outSize}`);\n return partial ? out.subarray(0, di) : out;\n}\n\nexport function lz4Compress(src: Uint8Array): Uint8Array {\n const n = src.length;\n const out = new Uint8Array(n + Math.ceil(n / 255) + 16);\n const table = new Int32Array(1 << 14).fill(-1);\n const hash = (i: number) =>\n (Math.imul(src[i] | (src[i + 1] << 8) | (src[i + 2] << 16) | (src[i + 3] << 24), 2654435761) >>>\n 18) &\n 0x3fff;\n let si = 0;\n let di = 0;\n let anchor = 0;\n const writeLen = (len: number) => {\n while (len >= 255) {\n out[di++] = 255;\n len -= 255;\n }\n out[di++] = len;\n };\n const LAST_LITERALS = 5;\n const MF_LIMIT = 12;\n while (si + MF_LIMIT < n) {\n const h = hash(si);\n const ref = table[h];\n table[h] = si;\n if (\n ref >= 0 &&\n si - ref <= 0xffff &&\n src[ref] === src[si] &&\n src[ref + 1] === src[si + 1] &&\n src[ref + 2] === src[si + 2] &&\n src[ref + 3] === src[si + 3]\n ) {\n let len = 4;\n while (si + len < n - LAST_LITERALS && src[ref + len] === src[si + len]) len++;\n const lit = si - anchor;\n const tokenPos = di++;\n out[tokenPos] = (Math.min(lit, 15) << 4) | Math.min(len - 4, 15);\n if (lit >= 15) writeLen(lit - 15);\n out.set(src.subarray(anchor, si), di);\n di += lit;\n const off = si - ref;\n out[di++] = off & 0xff;\n out[di++] = off >>> 8;\n if (len - 4 >= 15) writeLen(len - 4 - 15);\n si += len;\n anchor = si;\n } else si++;\n }\n const lit = n - anchor;\n out[di++] = Math.min(lit, 15) << 4;\n if (lit >= 15) writeLen(lit - 15);\n out.set(src.subarray(anchor), di);\n di += lit;\n return out.slice(0, di);\n}\n\n/**\n * LZ4 frames as superfly/ltx v0.5.1 writes them (celld's current page format): magic,\n * FLG 0x64 (v1, independent blocks, content checksum), BD 0x40 (64 KiB blocks), header\n * checksum, data blocks, end mark, xxHash32 of the content.\n */\nconst FRAME_MAGIC = 0x184d2204;\n\nexport function lz4FrameDecompress(src: Uint8Array, outSize: number): Uint8Array {\n const v = new DataView(src.buffer, src.byteOffset, src.byteLength);\n if (v.getUint32(0, true) !== FRAME_MAGIC) throw new Error(\"lz4: bad frame magic\");\n const flg = src[4];\n let o = 6 + (flg & 0x08 ? 8 : 0) + (flg & 0x01 ? 4 : 0) + 1; // FLG BD [size] [dict] HC\n const out = new Uint8Array(outSize);\n let di = 0;\n for (;;) {\n const word = v.getUint32(o, true);\n o += 4;\n if (word === 0) break;\n const size = word & 0x7fffffff;\n const block = src.subarray(o, o + size);\n o += size + (flg & 0x10 ? 4 : 0);\n if (word & 0x80000000) {\n out.set(block, di);\n di += size;\n } else {\n const part = lz4Decompress(block, Math.min(65536, outSize - di), true);\n out.set(part, di);\n di += part.length;\n }\n }\n if (flg & 0x04 && v.getUint32(o, true) !== xxh32(out))\n throw new Error(\"lz4: frame content checksum mismatch\");\n return out;\n}\n\nexport function lz4FrameCompress(data: Uint8Array): Uint8Array {\n const descriptor = Uint8Array.of(0x64, 0x40);\n const hc = (xxh32(descriptor) >>> 8) & 0xff;\n const block = lz4Compress(data);\n const raw = block.length >= data.length; // store uncompressed when it does not shrink\n const body = raw ? data : block;\n const out = new Uint8Array(4 + 3 + 4 + body.length + 4 + 4);\n const v = new DataView(out.buffer);\n v.setUint32(0, FRAME_MAGIC, true);\n out.set(descriptor, 4);\n out[6] = hc;\n v.setUint32(7, (body.length | (raw ? 0x80000000 : 0)) >>> 0, true);\n out.set(body, 11);\n v.setUint32(11 + body.length, 0, true);\n v.setUint32(15 + body.length, xxh32(data), true);\n return out;\n}\n"]}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * The FilesApi the LTX store needs (exists, stats, list, read with ranges, write, remove, move)
3
+ * on OPFS through SyncAccessHandles: for a worker that alone owns its directory (the LTX store
4
+ * worker). A write is one synchronous `write()` per chunk into a fresh handle, against a
5
+ * `createWritable()` stream (a swap file, then a copy) in the asynchronous API.
6
+ */
7
+ import type { FilesApi } from "@statewalker/webrun-files";
8
+ type Dir = FileSystemDirectoryHandle;
9
+ /** Time spent per step of writes (ms), for traces. */
10
+ export declare const opfsSyncWriteStats: {
11
+ writes: number;
12
+ lookupMs: number;
13
+ openMs: number;
14
+ writeMs: number;
15
+ flushMs: number;
16
+ closeMs: number;
17
+ };
18
+ /** A write the origin's storage quota refused: what was written, and what the quota allows. */
19
+ export declare class StorageQuotaError extends Error {
20
+ name: string;
21
+ }
22
+ export declare function opfsSyncFiles(root: Dir): FilesApi;
23
+ export {};
@@ -0,0 +1,191 @@
1
+ /** Time spent per step of writes (ms), for traces. */
2
+ export const opfsSyncWriteStats = {
3
+ writes: 0,
4
+ lookupMs: 0,
5
+ openMs: 0,
6
+ writeMs: 0,
7
+ flushMs: 0,
8
+ closeMs: 0,
9
+ };
10
+ /** A write the origin's storage quota refused: what was written, and what the quota allows. */
11
+ export class StorageQuotaError extends Error {
12
+ name = "QuotaExceededError";
13
+ }
14
+ function quotaError(path, at, wrote, of) {
15
+ return new StorageQuotaError(`storage quota exceeded writing ${path} (${Math.round(at / 1e6)} MB written${wrote !== undefined ? `; the last write took ${wrote} of ${of} bytes` : ""}): free space in this origin's storage`);
16
+ }
17
+ export function opfsSyncFiles(root) {
18
+ const parts = (path) => path.split("/").filter(Boolean);
19
+ /** "Not there" is undefined; any other failure (quota, state, security) is thrown as is. */
20
+ const absent = (err) => {
21
+ const name = err?.name;
22
+ if (name === "NotFoundError" || name === "TypeMismatchError")
23
+ return undefined;
24
+ throw err;
25
+ };
26
+ const dirOf = async (segs, create) => {
27
+ let d = root;
28
+ for (const s of segs) {
29
+ try {
30
+ d = await d.getDirectoryHandle(s, { create });
31
+ }
32
+ catch (err) {
33
+ return absent(err);
34
+ }
35
+ }
36
+ return d;
37
+ };
38
+ const fileOf = async (path, create = false) => {
39
+ const p = parts(path);
40
+ const d = await dirOf(p.slice(0, -1), create);
41
+ if (!d || !p.length)
42
+ return undefined;
43
+ try {
44
+ return await d.getFileHandle(p[p.length - 1], { create });
45
+ }
46
+ catch (err) {
47
+ return absent(err);
48
+ }
49
+ };
50
+ /** `f` renamed to `to`, replacing a file there. */
51
+ const moveInto = async (f, to) => {
52
+ const t = parts(to);
53
+ const d = await dirOf(t.slice(0, -1), true);
54
+ if (!d)
55
+ throw new Error(`opfs: cannot create the directory of ${to}`);
56
+ const movable = f;
57
+ if (!movable.move)
58
+ throw new Error("opfs: FileSystemHandle.move() is not supported");
59
+ try {
60
+ await movable.move(d, t[t.length - 1]);
61
+ }
62
+ catch (err) {
63
+ // Where a move does not replace an existing file: remove it, then move.
64
+ if (err?.name !== "InvalidModificationError")
65
+ throw err;
66
+ await d.removeEntry(t[t.length - 1]);
67
+ await movable.move(d, t[t.length - 1]);
68
+ }
69
+ };
70
+ const sync = (f) => f.createSyncAccessHandle();
71
+ const api = {
72
+ async exists(path) {
73
+ return !!(await fileOf(path)) || !!(await dirOf(parts(path), false));
74
+ },
75
+ async stats(path) {
76
+ const f = await fileOf(path);
77
+ if (f) {
78
+ const file = await f.getFile();
79
+ return { kind: "file", size: file.size, lastModified: file.lastModified };
80
+ }
81
+ return (await dirOf(parts(path), false)) ? { kind: "directory" } : undefined;
82
+ },
83
+ async *list(path) {
84
+ const d = await dirOf(parts(path), false);
85
+ if (!d)
86
+ return;
87
+ const base = `/${parts(path).join("/")}`.replace(/\/$/, "");
88
+ const out = [];
89
+ for await (const [name, h] of d.entries()) {
90
+ const p = `${base}/${name}`;
91
+ if (h.kind === "file") {
92
+ const file = await h.getFile();
93
+ out.push({
94
+ kind: "file",
95
+ name,
96
+ path: p,
97
+ size: file.size,
98
+ lastModified: file.lastModified,
99
+ });
100
+ }
101
+ else
102
+ out.push({ kind: "directory", name, path: p });
103
+ }
104
+ out.sort((a, b) => (a.name < b.name ? -1 : 1));
105
+ yield* out;
106
+ },
107
+ async *read(path, o) {
108
+ const f = await fileOf(path);
109
+ if (!f)
110
+ return;
111
+ // Reads go through the File snapshot (no exclusive handle needed).
112
+ const file = await f.getFile();
113
+ const start = o?.start ?? 0;
114
+ const end = o?.length !== undefined ? Math.min(file.size, start + o.length) : file.size;
115
+ if (end > start)
116
+ yield new Uint8Array(await file.slice(start, end).arrayBuffer());
117
+ },
118
+ async write(path, content) {
119
+ // Into a temporary file, moved into place once complete: a reader never sees a partial
120
+ // file, and a failed write (quota) leaves nothing behind under `path`.
121
+ const st = opfsSyncWriteStats;
122
+ const p = parts(path);
123
+ const tmp = `/${[...p.slice(0, -1), `${p[p.length - 1]}.part-${Math.random().toString(36).slice(2, 10)}`].join("/")}`;
124
+ let t = performance.now();
125
+ const f = await fileOf(tmp, true);
126
+ if (!f)
127
+ throw new Error(`opfs: cannot create ${tmp}`);
128
+ st.lookupMs += performance.now() - t;
129
+ t = performance.now();
130
+ const h = await sync(f);
131
+ st.openMs += performance.now() - t;
132
+ let at = 0;
133
+ try {
134
+ try {
135
+ t = performance.now();
136
+ for await (const c of content) {
137
+ const n = h.write(c, { at });
138
+ // Past the quota, Chromium's SyncAccessHandle does not throw: write() returns an
139
+ // error code as an unsigned count (4294967288 = -8), or a short count. Adding it to
140
+ // the offset put the next chunk gigabytes past the end of the file.
141
+ if (n !== c.length)
142
+ throw quotaError(path, at, n, c.length);
143
+ at += n;
144
+ }
145
+ st.writeMs += performance.now() - t;
146
+ t = performance.now();
147
+ h.flush();
148
+ st.flushMs += performance.now() - t;
149
+ }
150
+ finally {
151
+ t = performance.now();
152
+ h.close();
153
+ st.closeMs += performance.now() - t;
154
+ st.writes++;
155
+ }
156
+ await moveInto(f, path);
157
+ }
158
+ catch (err) {
159
+ await api.remove?.(tmp).catch(() => false);
160
+ if (err?.name === "QuotaExceededError")
161
+ throw quotaError(path, at);
162
+ throw err;
163
+ }
164
+ },
165
+ async remove(path) {
166
+ const p = parts(path);
167
+ const d = await dirOf(p.slice(0, -1), false);
168
+ if (!d)
169
+ return false;
170
+ try {
171
+ await d.removeEntry(p[p.length - 1], { recursive: true });
172
+ return true;
173
+ }
174
+ catch {
175
+ return false;
176
+ }
177
+ },
178
+ async move(source, target) {
179
+ const f = await fileOf(source);
180
+ if (!f)
181
+ return false;
182
+ await moveInto(f, target);
183
+ return true;
184
+ },
185
+ async mkdir(path) {
186
+ await dirOf(parts(path), true);
187
+ },
188
+ };
189
+ return api;
190
+ }
191
+ //# sourceMappingURL=opfs-sync-files.js.map