@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,99 @@
1
+ import { Client } from "@libsql/client";
2
+
3
+ //#region src/upload-session-store.d.ts
4
+ /**
5
+ * Prepared-session TTL (design §9 / §15). Hours-scale and DELIBERATELY far
6
+ * shorter than `DEFAULT_GC_GRACE_MS` (7 days): in-flight protection cannot lean
7
+ * on the GC grace window (prepared TTL ≪ grace), so the prepared-session UNION
8
+ * in reference-check.ts is the real protection. 2h is ample for a large
9
+ * first-sync batch's uploads to land + commit.
10
+ */
11
+ declare const UPLOAD_SESSION_TTL_MS: number;
12
+ type UploadSessionStatus = "prepared" | "committed" | "aborted" | "expired";
13
+ type UploadSessionEntryStatus = "needs_upload" | "already_present" | "committed" | "failed";
14
+ interface UploadSessionEntryInput {
15
+ path: string;
16
+ cid: string;
17
+ objectKey: string;
18
+ checksumSha256: string;
19
+ size: number;
20
+ mimeType?: string | null;
21
+ ifMatch?: string | null;
22
+ deviceId?: string | null;
23
+ mtime?: number | null;
24
+ status: UploadSessionEntryStatus;
25
+ }
26
+ interface NewUploadSession {
27
+ id: string;
28
+ scope: string;
29
+ caller?: string | null;
30
+ /** Absolute expiry (ms epoch). Caller computes from UPLOAD_SESSION_TTL_MS. */
31
+ expiresAt: number;
32
+ /** Defaults to Date.now() when omitted. */
33
+ createdAt?: number;
34
+ entries: UploadSessionEntryInput[];
35
+ }
36
+ interface UploadSessionEntry extends UploadSessionEntryInput {
37
+ mimeType: string | null;
38
+ ifMatch: string | null;
39
+ deviceId: string | null;
40
+ mtime: number | null;
41
+ }
42
+ interface UploadSession {
43
+ id: string;
44
+ scope: string;
45
+ caller: string | null;
46
+ expiresAt: number;
47
+ status: UploadSessionStatus;
48
+ createdAt: number;
49
+ entries: UploadSessionEntry[];
50
+ }
51
+ interface UploadSessionStore {
52
+ ensureTable(): Promise<void>;
53
+ /** Persist a new `prepared` session + its entries. Throws on empty entries. */
54
+ createSession(input: NewUploadSession): Promise<void>;
55
+ /** Read a session + its entries, or null if unknown. */
56
+ getSession(id: string): Promise<UploadSession | null>;
57
+ /** Update per-entry statuses by path. Unknown paths are silently ignored. */
58
+ markEntries(id: string, updates: Array<{
59
+ path: string;
60
+ status: UploadSessionEntryStatus;
61
+ }>): Promise<void>;
62
+ /** Flip the session to `committed`. */
63
+ markCommitted(id: string): Promise<void>;
64
+ /** Flip the session to `aborted`. */
65
+ markAborted(id: string): Promise<void>;
66
+ /** Delete sessions (and their entries) past their expires_at, regardless of status. Returns count. */
67
+ sweepExpired(now: number): Promise<number>;
68
+ }
69
+ declare class D1UploadSessionStore implements UploadSessionStore {
70
+ private readonly db;
71
+ constructor(db: D1Database);
72
+ ensureTable(): Promise<void>;
73
+ createSession(input: NewUploadSession): Promise<void>;
74
+ getSession(id: string): Promise<UploadSession | null>;
75
+ markEntries(id: string, updates: Array<{
76
+ path: string;
77
+ status: UploadSessionEntryStatus;
78
+ }>): Promise<void>;
79
+ markCommitted(id: string): Promise<void>;
80
+ markAborted(id: string): Promise<void>;
81
+ sweepExpired(now: number): Promise<number>;
82
+ }
83
+ declare class SqliteUploadSessionStore implements UploadSessionStore {
84
+ private readonly client;
85
+ constructor(client: Client);
86
+ ensureTable(): Promise<void>;
87
+ createSession(input: NewUploadSession): Promise<void>;
88
+ getSession(id: string): Promise<UploadSession | null>;
89
+ markEntries(id: string, updates: Array<{
90
+ path: string;
91
+ status: UploadSessionEntryStatus;
92
+ }>): Promise<void>;
93
+ markCommitted(id: string): Promise<void>;
94
+ markAborted(id: string): Promise<void>;
95
+ sweepExpired(now: number): Promise<number>;
96
+ }
97
+ //#endregion
98
+ export { D1UploadSessionStore, NewUploadSession, SqliteUploadSessionStore, UPLOAD_SESSION_TTL_MS, UploadSession, UploadSessionEntry, UploadSessionEntryInput, UploadSessionEntryStatus, UploadSessionStatus, UploadSessionStore };
99
+ //# sourceMappingURL=upload-session-store.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upload-session-store.d.cts","names":[],"sources":["../src/upload-session-store.ts"],"mappings":";;;;;;;;;;cAkCa,qBAAA;AAAA,KAED,mBAAA;AAAA,KACA,wBAAA;AAAA,UAEK,uBAAA;EACf,IAAA;EACA,GAAA;EACA,SAAA;EACA,cAAA;EACA,IAAA;EACA,QAAA;EACA,OAAA;EACA,QAAA;EACA,KAAA;EACA,MAAA,EAAQ,wBAAA;AAAA;AAAA,UAGO,gBAAA;EACf,EAAA;EACA,KAAA;EACA,MAAA;EAKgC;EAHhC,SAAA;EAMe;EAJf,SAAA;EACA,OAAA,EAAS,uBAAA;AAAA;AAAA,UAGM,kBAAA,SAA2B,uBAAA;EAC1C,QAAA;EACA,OAAA;EACA,QAAA;EACA,KAAA;AAAA;AAAA,UAGe,aAAA;EACf,EAAA;EACA,KAAA;EACA,MAAA;EACA,SAAA;EACA,MAAA,EAAQ,mBAAA;EACR,SAAA;EACA,OAAA,EAAS,kBAAA;AAAA;AAAA,UAGM,kBAAA;EACf,WAAA,IAAe,OAAA;EALf;EAOA,aAAA,CAAc,KAAA,EAAO,gBAAA,GAAmB,OAAA;EAN/B;EAQT,UAAA,CAAW,EAAA,WAAa,OAAA,CAAQ,aAAA;EARL;EAU3B,WAAA,CACE,EAAA,UACA,OAAA,EAAS,KAAA;IAAQ,IAAA;IAAc,MAAA,EAAQ,wBAAA;EAAA,KACtC,OAAA;EAPkB;EASrB,aAAA,CAAc,EAAA,WAAa,OAAA;EAPK;EAShC,WAAA,CAAY,EAAA,WAAa,OAAA;EALgB;EAOzC,YAAA,CAAa,GAAA,WAAc,OAAA;AAAA;AAAA,cAiDhB,oBAAA,YAAgC,kBAAA;EAAA,iBACd,EAAA;cAAA,EAAA,EAAI,UAAA;EAE3B,WAAA,CAAA,GAAe,OAAA;EASf,aAAA,CAAc,KAAA,EAAO,gBAAA,GAAmB,OAAA;EAYxC,UAAA,CAAW,EAAA,WAAa,OAAA,CAAQ,aAAA;EAUhC,WAAA,CACJ,EAAA,UACA,OAAA,EAAS,KAAA;IAAQ,IAAA;IAAc,MAAA,EAAQ,wBAAA;EAAA,KACtC,OAAA;EAQG,aAAA,CAAc,EAAA,WAAa,OAAA;EAI3B,WAAA,CAAY,EAAA,WAAa,OAAA;EAIzB,YAAA,CAAa,GAAA,WAAc,OAAA;AAAA;AAAA,cAUtB,wBAAA,YAAoC,kBAAA;EAAA,iBAClB,MAAA;cAAA,MAAA,EAAQ,MAAA;EAE/B,WAAA,CAAA,GAAe,OAAA;EAMf,aAAA,CAAc,KAAA,EAAO,gBAAA,GAAmB,OAAA;EAsBxC,UAAA,CAAW,EAAA,WAAa,OAAA,CAAQ,aAAA;EAUhC,WAAA,CACJ,EAAA,UACA,OAAA,EAAS,KAAA;IAAQ,IAAA;IAAc,MAAA,EAAQ,wBAAA;EAAA,KACtC,OAAA;EAWG,aAAA,CAAc,EAAA,WAAa,OAAA;EAI3B,WAAA,CAAY,EAAA,WAAa,OAAA;EAIzB,YAAA,CAAa,GAAA,WAAc,OAAA;AAAA"}
@@ -0,0 +1,99 @@
1
+ import { Client } from "@libsql/client";
2
+
3
+ //#region src/upload-session-store.d.ts
4
+ /**
5
+ * Prepared-session TTL (design §9 / §15). Hours-scale and DELIBERATELY far
6
+ * shorter than `DEFAULT_GC_GRACE_MS` (7 days): in-flight protection cannot lean
7
+ * on the GC grace window (prepared TTL ≪ grace), so the prepared-session UNION
8
+ * in reference-check.ts is the real protection. 2h is ample for a large
9
+ * first-sync batch's uploads to land + commit.
10
+ */
11
+ declare const UPLOAD_SESSION_TTL_MS: number;
12
+ type UploadSessionStatus = "prepared" | "committed" | "aborted" | "expired";
13
+ type UploadSessionEntryStatus = "needs_upload" | "already_present" | "committed" | "failed";
14
+ interface UploadSessionEntryInput {
15
+ path: string;
16
+ cid: string;
17
+ objectKey: string;
18
+ checksumSha256: string;
19
+ size: number;
20
+ mimeType?: string | null;
21
+ ifMatch?: string | null;
22
+ deviceId?: string | null;
23
+ mtime?: number | null;
24
+ status: UploadSessionEntryStatus;
25
+ }
26
+ interface NewUploadSession {
27
+ id: string;
28
+ scope: string;
29
+ caller?: string | null;
30
+ /** Absolute expiry (ms epoch). Caller computes from UPLOAD_SESSION_TTL_MS. */
31
+ expiresAt: number;
32
+ /** Defaults to Date.now() when omitted. */
33
+ createdAt?: number;
34
+ entries: UploadSessionEntryInput[];
35
+ }
36
+ interface UploadSessionEntry extends UploadSessionEntryInput {
37
+ mimeType: string | null;
38
+ ifMatch: string | null;
39
+ deviceId: string | null;
40
+ mtime: number | null;
41
+ }
42
+ interface UploadSession {
43
+ id: string;
44
+ scope: string;
45
+ caller: string | null;
46
+ expiresAt: number;
47
+ status: UploadSessionStatus;
48
+ createdAt: number;
49
+ entries: UploadSessionEntry[];
50
+ }
51
+ interface UploadSessionStore {
52
+ ensureTable(): Promise<void>;
53
+ /** Persist a new `prepared` session + its entries. Throws on empty entries. */
54
+ createSession(input: NewUploadSession): Promise<void>;
55
+ /** Read a session + its entries, or null if unknown. */
56
+ getSession(id: string): Promise<UploadSession | null>;
57
+ /** Update per-entry statuses by path. Unknown paths are silently ignored. */
58
+ markEntries(id: string, updates: Array<{
59
+ path: string;
60
+ status: UploadSessionEntryStatus;
61
+ }>): Promise<void>;
62
+ /** Flip the session to `committed`. */
63
+ markCommitted(id: string): Promise<void>;
64
+ /** Flip the session to `aborted`. */
65
+ markAborted(id: string): Promise<void>;
66
+ /** Delete sessions (and their entries) past their expires_at, regardless of status. Returns count. */
67
+ sweepExpired(now: number): Promise<number>;
68
+ }
69
+ declare class D1UploadSessionStore implements UploadSessionStore {
70
+ private readonly db;
71
+ constructor(db: D1Database);
72
+ ensureTable(): Promise<void>;
73
+ createSession(input: NewUploadSession): Promise<void>;
74
+ getSession(id: string): Promise<UploadSession | null>;
75
+ markEntries(id: string, updates: Array<{
76
+ path: string;
77
+ status: UploadSessionEntryStatus;
78
+ }>): Promise<void>;
79
+ markCommitted(id: string): Promise<void>;
80
+ markAborted(id: string): Promise<void>;
81
+ sweepExpired(now: number): Promise<number>;
82
+ }
83
+ declare class SqliteUploadSessionStore implements UploadSessionStore {
84
+ private readonly client;
85
+ constructor(client: Client);
86
+ ensureTable(): Promise<void>;
87
+ createSession(input: NewUploadSession): Promise<void>;
88
+ getSession(id: string): Promise<UploadSession | null>;
89
+ markEntries(id: string, updates: Array<{
90
+ path: string;
91
+ status: UploadSessionEntryStatus;
92
+ }>): Promise<void>;
93
+ markCommitted(id: string): Promise<void>;
94
+ markAborted(id: string): Promise<void>;
95
+ sweepExpired(now: number): Promise<number>;
96
+ }
97
+ //#endregion
98
+ export { D1UploadSessionStore, NewUploadSession, SqliteUploadSessionStore, UPLOAD_SESSION_TTL_MS, UploadSession, UploadSessionEntry, UploadSessionEntryInput, UploadSessionEntryStatus, UploadSessionStatus, UploadSessionStore };
99
+ //# sourceMappingURL=upload-session-store.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upload-session-store.d.mts","names":[],"sources":["../src/upload-session-store.ts"],"mappings":";;;;;;;;;;cAkCa,qBAAA;AAAA,KAED,mBAAA;AAAA,KACA,wBAAA;AAAA,UAEK,uBAAA;EACf,IAAA;EACA,GAAA;EACA,SAAA;EACA,cAAA;EACA,IAAA;EACA,QAAA;EACA,OAAA;EACA,QAAA;EACA,KAAA;EACA,MAAA,EAAQ,wBAAA;AAAA;AAAA,UAGO,gBAAA;EACf,EAAA;EACA,KAAA;EACA,MAAA;EAKgC;EAHhC,SAAA;EAMe;EAJf,SAAA;EACA,OAAA,EAAS,uBAAA;AAAA;AAAA,UAGM,kBAAA,SAA2B,uBAAA;EAC1C,QAAA;EACA,OAAA;EACA,QAAA;EACA,KAAA;AAAA;AAAA,UAGe,aAAA;EACf,EAAA;EACA,KAAA;EACA,MAAA;EACA,SAAA;EACA,MAAA,EAAQ,mBAAA;EACR,SAAA;EACA,OAAA,EAAS,kBAAA;AAAA;AAAA,UAGM,kBAAA;EACf,WAAA,IAAe,OAAA;EALf;EAOA,aAAA,CAAc,KAAA,EAAO,gBAAA,GAAmB,OAAA;EAN/B;EAQT,UAAA,CAAW,EAAA,WAAa,OAAA,CAAQ,aAAA;EARL;EAU3B,WAAA,CACE,EAAA,UACA,OAAA,EAAS,KAAA;IAAQ,IAAA;IAAc,MAAA,EAAQ,wBAAA;EAAA,KACtC,OAAA;EAPkB;EASrB,aAAA,CAAc,EAAA,WAAa,OAAA;EAPK;EAShC,WAAA,CAAY,EAAA,WAAa,OAAA;EALgB;EAOzC,YAAA,CAAa,GAAA,WAAc,OAAA;AAAA;AAAA,cAiDhB,oBAAA,YAAgC,kBAAA;EAAA,iBACd,EAAA;cAAA,EAAA,EAAI,UAAA;EAE3B,WAAA,CAAA,GAAe,OAAA;EASf,aAAA,CAAc,KAAA,EAAO,gBAAA,GAAmB,OAAA;EAYxC,UAAA,CAAW,EAAA,WAAa,OAAA,CAAQ,aAAA;EAUhC,WAAA,CACJ,EAAA,UACA,OAAA,EAAS,KAAA;IAAQ,IAAA;IAAc,MAAA,EAAQ,wBAAA;EAAA,KACtC,OAAA;EAQG,aAAA,CAAc,EAAA,WAAa,OAAA;EAI3B,WAAA,CAAY,EAAA,WAAa,OAAA;EAIzB,YAAA,CAAa,GAAA,WAAc,OAAA;AAAA;AAAA,cAUtB,wBAAA,YAAoC,kBAAA;EAAA,iBAClB,MAAA;cAAA,MAAA,EAAQ,MAAA;EAE/B,WAAA,CAAA,GAAe,OAAA;EAMf,aAAA,CAAc,KAAA,EAAO,gBAAA,GAAmB,OAAA;EAsBxC,UAAA,CAAW,EAAA,WAAa,OAAA,CAAQ,aAAA;EAUhC,WAAA,CACJ,EAAA,UACA,OAAA,EAAS,KAAA;IAAQ,IAAA;IAAc,MAAA,EAAQ,wBAAA;EAAA,KACtC,OAAA;EAWG,aAAA,CAAc,EAAA,WAAa,OAAA;EAI3B,WAAA,CAAY,EAAA,WAAa,OAAA;EAIzB,YAAA,CAAa,GAAA,WAAc,OAAA;AAAA"}
@@ -0,0 +1,184 @@
1
+ import { UPLOAD_SESSIONS_INDEX_SQL, UPLOAD_SESSIONS_TABLE_SQL, UPLOAD_SESSION_ENTRIES_TABLE_SQL } from "./d1-schema.mjs";
2
+
3
+ //#region src/upload-session-store.ts
4
+ /**
5
+ * Prepared-session TTL (design §9 / §15). Hours-scale and DELIBERATELY far
6
+ * shorter than `DEFAULT_GC_GRACE_MS` (7 days): in-flight protection cannot lean
7
+ * on the GC grace window (prepared TTL ≪ grace), so the prepared-session UNION
8
+ * in reference-check.ts is the real protection. 2h is ample for a large
9
+ * first-sync batch's uploads to land + commit.
10
+ */
11
+ const UPLOAD_SESSION_TTL_MS = 7200 * 1e3;
12
+ function assertNonEmpty(input) {
13
+ if (!input.entries || input.entries.length === 0) throw new Error("createSession: entries must be non-empty");
14
+ }
15
+ /**
16
+ * Statement strings shared by BOTH backends (D1 binds positionally, libsql via
17
+ * `args`) — hoisted so the two impls can never drift on column lists / WHERE
18
+ * clauses. Mirrors reference-check.ts's hoisted-SQL style.
19
+ */
20
+ const SQL = {
21
+ insertSession: "INSERT INTO ds_upload_sessions (id, scope, caller, expires_at, status, created_at) VALUES (?, ?, ?, ?, 'prepared', ?)",
22
+ insertEntry: "INSERT INTO ds_upload_session_entries (session_id, path, cid, object_key, checksum_sha256, size, mime_type, if_match, device_id, mtime, status) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
23
+ selectSession: "SELECT * FROM ds_upload_sessions WHERE id = ?",
24
+ selectEntries: "SELECT * FROM ds_upload_session_entries WHERE session_id = ?",
25
+ updateEntryStatus: "UPDATE ds_upload_session_entries SET status = ? WHERE session_id = ? AND path = ?",
26
+ markCommitted: "UPDATE ds_upload_sessions SET status = 'committed' WHERE id = ?",
27
+ markAborted: "UPDATE ds_upload_sessions SET status = 'aborted' WHERE id = ?",
28
+ sweepEntries: "DELETE FROM ds_upload_session_entries WHERE session_id IN (SELECT id FROM ds_upload_sessions WHERE expires_at < ?)",
29
+ sweepSessions: "DELETE FROM ds_upload_sessions WHERE expires_at < ?"
30
+ };
31
+ /** Positional bind args for `insertEntry` (shared by both backends). */
32
+ function entryArgs(sessionId, e) {
33
+ return [
34
+ sessionId,
35
+ e.path,
36
+ e.cid,
37
+ e.objectKey,
38
+ e.checksumSha256,
39
+ e.size,
40
+ e.mimeType ?? null,
41
+ e.ifMatch ?? null,
42
+ e.deviceId ?? null,
43
+ e.mtime ?? null,
44
+ e.status
45
+ ];
46
+ }
47
+ var D1UploadSessionStore = class {
48
+ constructor(db) {
49
+ this.db = db;
50
+ }
51
+ async ensureTable() {
52
+ const stmts = [
53
+ this.db.prepare(UPLOAD_SESSIONS_TABLE_SQL),
54
+ this.db.prepare(UPLOAD_SESSION_ENTRIES_TABLE_SQL),
55
+ ...UPLOAD_SESSIONS_INDEX_SQL.map((sql) => this.db.prepare(sql))
56
+ ];
57
+ await this.db.batch(stmts);
58
+ }
59
+ async createSession(input) {
60
+ assertNonEmpty(input);
61
+ const createdAt = input.createdAt ?? Date.now();
62
+ const stmts = [this.db.prepare(SQL.insertSession).bind(input.id, input.scope, input.caller ?? null, input.expiresAt, createdAt), ...input.entries.map((e) => this.db.prepare(SQL.insertEntry).bind(...entryArgs(input.id, e)))];
63
+ await this.db.batch(stmts);
64
+ }
65
+ async getSession(id) {
66
+ const row = await this.db.prepare(SQL.selectSession).bind(id).first();
67
+ if (!row) return null;
68
+ return rowToSession(row, (await this.db.prepare(SQL.selectEntries).bind(id).all()).results);
69
+ }
70
+ async markEntries(id, updates) {
71
+ if (updates.length === 0) return;
72
+ const stmts = updates.map((u) => this.db.prepare(SQL.updateEntryStatus).bind(u.status, id, u.path));
73
+ await this.db.batch(stmts);
74
+ }
75
+ async markCommitted(id) {
76
+ await this.db.prepare(SQL.markCommitted).bind(id).run();
77
+ }
78
+ async markAborted(id) {
79
+ await this.db.prepare(SQL.markAborted).bind(id).run();
80
+ }
81
+ async sweepExpired(now) {
82
+ await this.db.prepare(SQL.sweepEntries).bind(now).run();
83
+ return (await this.db.prepare(SQL.sweepSessions).bind(now).run()).meta?.changes ?? 0;
84
+ }
85
+ };
86
+ var SqliteUploadSessionStore = class {
87
+ constructor(client) {
88
+ this.client = client;
89
+ }
90
+ async ensureTable() {
91
+ await this.client.execute(UPLOAD_SESSIONS_TABLE_SQL);
92
+ await this.client.execute(UPLOAD_SESSION_ENTRIES_TABLE_SQL);
93
+ for (const sql of UPLOAD_SESSIONS_INDEX_SQL) await this.client.execute(sql);
94
+ }
95
+ async createSession(input) {
96
+ assertNonEmpty(input);
97
+ const createdAt = input.createdAt ?? Date.now();
98
+ const stmts = [{
99
+ sql: SQL.insertSession,
100
+ args: [
101
+ input.id,
102
+ input.scope,
103
+ input.caller ?? null,
104
+ input.expiresAt,
105
+ createdAt
106
+ ]
107
+ }, ...input.entries.map((e) => ({
108
+ sql: SQL.insertEntry,
109
+ args: entryArgs(input.id, e)
110
+ }))];
111
+ await this.client.batch(stmts, "write");
112
+ }
113
+ async getSession(id) {
114
+ const sessionRes = await this.client.execute({
115
+ sql: SQL.selectSession,
116
+ args: [id]
117
+ });
118
+ if (sessionRes.rows.length === 0) return null;
119
+ const entriesRes = await this.client.execute({
120
+ sql: SQL.selectEntries,
121
+ args: [id]
122
+ });
123
+ return rowToSession(sessionRes.rows[0], entriesRes.rows);
124
+ }
125
+ async markEntries(id, updates) {
126
+ if (updates.length === 0) return;
127
+ await this.client.batch(updates.map((u) => ({
128
+ sql: SQL.updateEntryStatus,
129
+ args: [
130
+ u.status,
131
+ id,
132
+ u.path
133
+ ]
134
+ })), "write");
135
+ }
136
+ async markCommitted(id) {
137
+ await this.client.execute({
138
+ sql: SQL.markCommitted,
139
+ args: [id]
140
+ });
141
+ }
142
+ async markAborted(id) {
143
+ await this.client.execute({
144
+ sql: SQL.markAborted,
145
+ args: [id]
146
+ });
147
+ }
148
+ async sweepExpired(now) {
149
+ await this.client.execute({
150
+ sql: SQL.sweepEntries,
151
+ args: [now]
152
+ });
153
+ return (await this.client.execute({
154
+ sql: SQL.sweepSessions,
155
+ args: [now]
156
+ })).rowsAffected ?? 0;
157
+ }
158
+ };
159
+ function rowToSession(s, entryRows) {
160
+ return {
161
+ id: String(s.id),
162
+ scope: String(s.scope),
163
+ caller: s.caller == null ? null : String(s.caller),
164
+ expiresAt: Number(s.expires_at),
165
+ status: String(s.status),
166
+ createdAt: Number(s.created_at),
167
+ entries: entryRows.map((e) => ({
168
+ path: String(e.path),
169
+ cid: String(e.cid),
170
+ objectKey: String(e.object_key),
171
+ checksumSha256: String(e.checksum_sha256),
172
+ size: Number(e.size),
173
+ mimeType: e.mime_type == null ? null : String(e.mime_type),
174
+ ifMatch: e.if_match == null ? null : String(e.if_match),
175
+ deviceId: e.device_id == null ? null : String(e.device_id),
176
+ mtime: e.mtime == null ? null : Number(e.mtime),
177
+ status: String(e.status)
178
+ }))
179
+ };
180
+ }
181
+
182
+ //#endregion
183
+ export { D1UploadSessionStore, SqliteUploadSessionStore, UPLOAD_SESSION_TTL_MS };
184
+ //# sourceMappingURL=upload-session-store.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upload-session-store.mjs","names":[],"sources":["../src/upload-session-store.ts"],"sourcesContent":["/**\n * upload-session-store.ts — recoverable upload-session registry (design §9).\n *\n * Two backends behind ONE interface (same split as `GcQueue`):\n * - `D1UploadSessionStore` — Cloudflare D1\n * - `SqliteUploadSessionStore` — Node `_metadata.db` (libsql)\n * External behavior is identical (§9 \"Node/local … external behavior 必须一致\").\n *\n * The store persists the prepared → committed/aborted/expired lifecycle so:\n * 1. `commit-upload` (P2) re-validates the client's entries against the\n * prepared contract recorded here (never trusts client-claimed proof);\n * 2. GC protects objects referenced by a non-expired `prepared` session\n * (in-flight protection — see reference-check.ts).\n *\n * scope discipline (§9): `scope` is ALWAYS `this._scope` (the de-identified\n * storage scope), and `caller` may hold ONLY a blocklet bareInstanceId, never a\n * user DID. Enforcement of those values is the writer's job (the prepare-upload\n * handler) + the table CHECKs; this store just persists what it is given.\n */\n\nimport type { InValue, Client as LibsqlClient } from \"@libsql/client\";\nimport {\n UPLOAD_SESSION_ENTRIES_TABLE_SQL,\n UPLOAD_SESSIONS_INDEX_SQL,\n UPLOAD_SESSIONS_TABLE_SQL,\n} from \"./d1-schema.js\";\n\n/**\n * Prepared-session TTL (design §9 / §15). Hours-scale and DELIBERATELY far\n * shorter than `DEFAULT_GC_GRACE_MS` (7 days): in-flight protection cannot lean\n * on the GC grace window (prepared TTL ≪ grace), so the prepared-session UNION\n * in reference-check.ts is the real protection. 2h is ample for a large\n * first-sync batch's uploads to land + commit.\n */\nexport const UPLOAD_SESSION_TTL_MS = 2 * 60 * 60 * 1000;\n\nexport type UploadSessionStatus = \"prepared\" | \"committed\" | \"aborted\" | \"expired\";\nexport type UploadSessionEntryStatus = \"needs_upload\" | \"already_present\" | \"committed\" | \"failed\";\n\nexport interface UploadSessionEntryInput {\n path: string;\n cid: string;\n objectKey: string;\n checksumSha256: string;\n size: number;\n mimeType?: string | null;\n ifMatch?: string | null;\n deviceId?: string | null;\n mtime?: number | null;\n status: UploadSessionEntryStatus;\n}\n\nexport interface NewUploadSession {\n id: string;\n scope: string;\n caller?: string | null;\n /** Absolute expiry (ms epoch). Caller computes from UPLOAD_SESSION_TTL_MS. */\n expiresAt: number;\n /** Defaults to Date.now() when omitted. */\n createdAt?: number;\n entries: UploadSessionEntryInput[];\n}\n\nexport interface UploadSessionEntry extends UploadSessionEntryInput {\n mimeType: string | null;\n ifMatch: string | null;\n deviceId: string | null;\n mtime: number | null;\n}\n\nexport interface UploadSession {\n id: string;\n scope: string;\n caller: string | null;\n expiresAt: number;\n status: UploadSessionStatus;\n createdAt: number;\n entries: UploadSessionEntry[];\n}\n\nexport interface UploadSessionStore {\n ensureTable(): Promise<void>;\n /** Persist a new `prepared` session + its entries. Throws on empty entries. */\n createSession(input: NewUploadSession): Promise<void>;\n /** Read a session + its entries, or null if unknown. */\n getSession(id: string): Promise<UploadSession | null>;\n /** Update per-entry statuses by path. Unknown paths are silently ignored. */\n markEntries(\n id: string,\n updates: Array<{ path: string; status: UploadSessionEntryStatus }>,\n ): Promise<void>;\n /** Flip the session to `committed`. */\n markCommitted(id: string): Promise<void>;\n /** Flip the session to `aborted`. */\n markAborted(id: string): Promise<void>;\n /** Delete sessions (and their entries) past their expires_at, regardless of status. Returns count. */\n sweepExpired(now: number): Promise<number>;\n}\n\nfunction assertNonEmpty(input: NewUploadSession): void {\n if (!input.entries || input.entries.length === 0) {\n throw new Error(\"createSession: entries must be non-empty\");\n }\n}\n\n/**\n * Statement strings shared by BOTH backends (D1 binds positionally, libsql via\n * `args`) — hoisted so the two impls can never drift on column lists / WHERE\n * clauses. Mirrors reference-check.ts's hoisted-SQL style.\n */\nconst SQL = {\n insertSession:\n \"INSERT INTO ds_upload_sessions (id, scope, caller, expires_at, status, created_at) VALUES (?, ?, ?, ?, 'prepared', ?)\",\n insertEntry:\n \"INSERT INTO ds_upload_session_entries (session_id, path, cid, object_key, checksum_sha256, size, mime_type, if_match, device_id, mtime, status) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\",\n selectSession: \"SELECT * FROM ds_upload_sessions WHERE id = ?\",\n selectEntries: \"SELECT * FROM ds_upload_session_entries WHERE session_id = ?\",\n updateEntryStatus:\n \"UPDATE ds_upload_session_entries SET status = ? WHERE session_id = ? AND path = ?\",\n markCommitted: \"UPDATE ds_upload_sessions SET status = 'committed' WHERE id = ?\",\n markAborted: \"UPDATE ds_upload_sessions SET status = 'aborted' WHERE id = ?\",\n sweepEntries:\n \"DELETE FROM ds_upload_session_entries WHERE session_id IN (SELECT id FROM ds_upload_sessions WHERE expires_at < ?)\",\n sweepSessions: \"DELETE FROM ds_upload_sessions WHERE expires_at < ?\",\n} as const;\n\n/** Positional bind args for `insertEntry` (shared by both backends). */\nfunction entryArgs(sessionId: string, e: UploadSessionEntryInput): unknown[] {\n return [\n sessionId,\n e.path,\n e.cid,\n e.objectKey,\n e.checksumSha256,\n e.size,\n e.mimeType ?? null,\n e.ifMatch ?? null,\n e.deviceId ?? null,\n e.mtime ?? null,\n e.status,\n ];\n}\n\n// ─── D1 (Cloudflare) ────────────────────────────────────────────────────────\n\nexport class D1UploadSessionStore implements UploadSessionStore {\n constructor(private readonly db: D1Database) {}\n\n async ensureTable(): Promise<void> {\n const stmts = [\n this.db.prepare(UPLOAD_SESSIONS_TABLE_SQL),\n this.db.prepare(UPLOAD_SESSION_ENTRIES_TABLE_SQL),\n ...UPLOAD_SESSIONS_INDEX_SQL.map((sql) => this.db.prepare(sql)),\n ];\n await this.db.batch(stmts);\n }\n\n async createSession(input: NewUploadSession): Promise<void> {\n assertNonEmpty(input);\n const createdAt = input.createdAt ?? Date.now();\n const stmts = [\n this.db\n .prepare(SQL.insertSession)\n .bind(input.id, input.scope, input.caller ?? null, input.expiresAt, createdAt),\n ...input.entries.map((e) => this.db.prepare(SQL.insertEntry).bind(...entryArgs(input.id, e))),\n ];\n await this.db.batch(stmts);\n }\n\n async getSession(id: string): Promise<UploadSession | null> {\n const row = await this.db.prepare(SQL.selectSession).bind(id).first();\n if (!row) return null;\n const entries = await this.db.prepare(SQL.selectEntries).bind(id).all();\n return rowToSession(\n row as Record<string, unknown>,\n entries.results as Array<Record<string, unknown>>,\n );\n }\n\n async markEntries(\n id: string,\n updates: Array<{ path: string; status: UploadSessionEntryStatus }>,\n ): Promise<void> {\n if (updates.length === 0) return;\n const stmts = updates.map((u) =>\n this.db.prepare(SQL.updateEntryStatus).bind(u.status, id, u.path),\n );\n await this.db.batch(stmts);\n }\n\n async markCommitted(id: string): Promise<void> {\n await this.db.prepare(SQL.markCommitted).bind(id).run();\n }\n\n async markAborted(id: string): Promise<void> {\n await this.db.prepare(SQL.markAborted).bind(id).run();\n }\n\n async sweepExpired(now: number): Promise<number> {\n // Delete entries first (no cascade in SQLite without PRAGMA), then sessions.\n await this.db.prepare(SQL.sweepEntries).bind(now).run();\n const res = await this.db.prepare(SQL.sweepSessions).bind(now).run();\n return res.meta?.changes ?? 0;\n }\n}\n\n// ─── libsql (Node) ──────────────────────────────────────────────────────────\n\nexport class SqliteUploadSessionStore implements UploadSessionStore {\n constructor(private readonly client: LibsqlClient) {}\n\n async ensureTable(): Promise<void> {\n await this.client.execute(UPLOAD_SESSIONS_TABLE_SQL);\n await this.client.execute(UPLOAD_SESSION_ENTRIES_TABLE_SQL);\n for (const sql of UPLOAD_SESSIONS_INDEX_SQL) await this.client.execute(sql);\n }\n\n async createSession(input: NewUploadSession): Promise<void> {\n assertNonEmpty(input);\n const createdAt = input.createdAt ?? Date.now();\n const stmts = [\n {\n sql: SQL.insertSession,\n args: [\n input.id,\n input.scope,\n input.caller ?? null,\n input.expiresAt,\n createdAt,\n ] as InValue[],\n },\n ...input.entries.map((e) => ({\n sql: SQL.insertEntry,\n args: entryArgs(input.id, e) as InValue[],\n })),\n ];\n await this.client.batch(stmts, \"write\");\n }\n\n async getSession(id: string): Promise<UploadSession | null> {\n const sessionRes = await this.client.execute({ sql: SQL.selectSession, args: [id] });\n if (sessionRes.rows.length === 0) return null;\n const entriesRes = await this.client.execute({ sql: SQL.selectEntries, args: [id] });\n return rowToSession(\n sessionRes.rows[0] as unknown as Record<string, unknown>,\n entriesRes.rows as unknown as Array<Record<string, unknown>>,\n );\n }\n\n async markEntries(\n id: string,\n updates: Array<{ path: string; status: UploadSessionEntryStatus }>,\n ): Promise<void> {\n if (updates.length === 0) return;\n await this.client.batch(\n updates.map((u) => ({\n sql: SQL.updateEntryStatus,\n args: [u.status, id, u.path] as InValue[],\n })),\n \"write\",\n );\n }\n\n async markCommitted(id: string): Promise<void> {\n await this.client.execute({ sql: SQL.markCommitted, args: [id] });\n }\n\n async markAborted(id: string): Promise<void> {\n await this.client.execute({ sql: SQL.markAborted, args: [id] });\n }\n\n async sweepExpired(now: number): Promise<number> {\n await this.client.execute({ sql: SQL.sweepEntries, args: [now] });\n const res = await this.client.execute({ sql: SQL.sweepSessions, args: [now] });\n return res.rowsAffected ?? 0;\n }\n}\n\n// ─── shared row mapping ───────────────────────────────────────────────────────\n\nfunction rowToSession(\n s: Record<string, unknown>,\n entryRows: Array<Record<string, unknown>>,\n): UploadSession {\n return {\n id: String(s.id),\n scope: String(s.scope),\n caller: s.caller == null ? null : String(s.caller),\n expiresAt: Number(s.expires_at),\n status: String(s.status) as UploadSessionStatus,\n createdAt: Number(s.created_at),\n entries: entryRows.map((e) => ({\n path: String(e.path),\n cid: String(e.cid),\n objectKey: String(e.object_key),\n checksumSha256: String(e.checksum_sha256),\n size: Number(e.size),\n mimeType: e.mime_type == null ? null : String(e.mime_type),\n ifMatch: e.if_match == null ? null : String(e.if_match),\n deviceId: e.device_id == null ? null : String(e.device_id),\n mtime: e.mtime == null ? null : Number(e.mtime),\n status: String(e.status) as UploadSessionEntryStatus,\n })),\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,61 @@
1
+
2
+ //#region src/url-normalize.ts
3
+ /**
4
+ * URL normalization for item dedup (#492).
5
+ *
6
+ * Produces a stable identity key for a saved URL so the same bookmark saved
7
+ * from different surfaces (clean link, shared-with-tracking, different param
8
+ * order, different anchor) collapses to one entry. Normalization is
9
+ * intentionally CONSERVATIVE — it only removes parts that are never part of a
10
+ * page's identity, so two genuinely different pages are never merged:
11
+ *
12
+ * - scheme + host are lower-cased and default ports dropped (the `URL`
13
+ * constructor does this per RFC 3986);
14
+ * - the fragment (`#...`) is dropped — an anchor is a client-side scroll
15
+ * target, never server identity;
16
+ * - the well-known `utm_*` family and unambiguous click IDs (fbclid, gclid, …)
17
+ * are stripped;
18
+ * - remaining params are sorted so order doesn't create phantom duplicates.
19
+ *
20
+ * Ambiguous params like `ref` / `source` / `campaign` / `id` are deliberately
21
+ * NOT stripped: they are load-bearing on many sites, and dropping them would
22
+ * collapse distinct pages into one — a silent data loss on the merge step.
23
+ * Only the `utm_` prefix and the explicit click-ID list below are removed.
24
+ *
25
+ * This is the shared normalization contract: every writer (web / native / AI)
26
+ * that dedups by URL should key off this function so behavior is identical
27
+ * across surfaces.
28
+ *
29
+ * Returns the original string unchanged if it is not a parseable absolute URL.
30
+ */
31
+ /** Unambiguous click / tracking params (non-`utm_`) safe to strip everywhere. */
32
+ const STRIP_PARAMS = new Set([
33
+ "fbclid",
34
+ "gclid",
35
+ "gbraid",
36
+ "wbraid",
37
+ "dclid",
38
+ "msclkid",
39
+ "yclid",
40
+ "mc_eid",
41
+ "igshid",
42
+ "twclid",
43
+ "ttclid"
44
+ ]);
45
+ function normalizeItemUrl(raw) {
46
+ let u;
47
+ try {
48
+ u = new URL(raw);
49
+ } catch {
50
+ return raw;
51
+ }
52
+ u.hash = "";
53
+ const kept = new URLSearchParams();
54
+ for (const [k, v] of u.searchParams) if (!k.startsWith("utm_") && !STRIP_PARAMS.has(k)) kept.append(k, v);
55
+ u.search = kept.toString();
56
+ u.searchParams.sort();
57
+ return u.toString();
58
+ }
59
+
60
+ //#endregion
61
+ exports.normalizeItemUrl = normalizeItemUrl;
@@ -0,0 +1,33 @@
1
+ //#region src/url-normalize.d.ts
2
+ /**
3
+ * URL normalization for item dedup (#492).
4
+ *
5
+ * Produces a stable identity key for a saved URL so the same bookmark saved
6
+ * from different surfaces (clean link, shared-with-tracking, different param
7
+ * order, different anchor) collapses to one entry. Normalization is
8
+ * intentionally CONSERVATIVE — it only removes parts that are never part of a
9
+ * page's identity, so two genuinely different pages are never merged:
10
+ *
11
+ * - scheme + host are lower-cased and default ports dropped (the `URL`
12
+ * constructor does this per RFC 3986);
13
+ * - the fragment (`#...`) is dropped — an anchor is a client-side scroll
14
+ * target, never server identity;
15
+ * - the well-known `utm_*` family and unambiguous click IDs (fbclid, gclid, …)
16
+ * are stripped;
17
+ * - remaining params are sorted so order doesn't create phantom duplicates.
18
+ *
19
+ * Ambiguous params like `ref` / `source` / `campaign` / `id` are deliberately
20
+ * NOT stripped: they are load-bearing on many sites, and dropping them would
21
+ * collapse distinct pages into one — a silent data loss on the merge step.
22
+ * Only the `utm_` prefix and the explicit click-ID list below are removed.
23
+ *
24
+ * This is the shared normalization contract: every writer (web / native / AI)
25
+ * that dedups by URL should key off this function so behavior is identical
26
+ * across surfaces.
27
+ *
28
+ * Returns the original string unchanged if it is not a parseable absolute URL.
29
+ */
30
+ declare function normalizeItemUrl(raw: string): string;
31
+ //#endregion
32
+ export { normalizeItemUrl };
33
+ //# sourceMappingURL=url-normalize.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"url-normalize.d.cts","names":[],"sources":["../src/url-normalize.ts"],"mappings":";;AA4CA;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAAgB,gBAAA,CAAiB,GAAA"}
@@ -0,0 +1,33 @@
1
+ //#region src/url-normalize.d.ts
2
+ /**
3
+ * URL normalization for item dedup (#492).
4
+ *
5
+ * Produces a stable identity key for a saved URL so the same bookmark saved
6
+ * from different surfaces (clean link, shared-with-tracking, different param
7
+ * order, different anchor) collapses to one entry. Normalization is
8
+ * intentionally CONSERVATIVE — it only removes parts that are never part of a
9
+ * page's identity, so two genuinely different pages are never merged:
10
+ *
11
+ * - scheme + host are lower-cased and default ports dropped (the `URL`
12
+ * constructor does this per RFC 3986);
13
+ * - the fragment (`#...`) is dropped — an anchor is a client-side scroll
14
+ * target, never server identity;
15
+ * - the well-known `utm_*` family and unambiguous click IDs (fbclid, gclid, …)
16
+ * are stripped;
17
+ * - remaining params are sorted so order doesn't create phantom duplicates.
18
+ *
19
+ * Ambiguous params like `ref` / `source` / `campaign` / `id` are deliberately
20
+ * NOT stripped: they are load-bearing on many sites, and dropping them would
21
+ * collapse distinct pages into one — a silent data loss on the merge step.
22
+ * Only the `utm_` prefix and the explicit click-ID list below are removed.
23
+ *
24
+ * This is the shared normalization contract: every writer (web / native / AI)
25
+ * that dedups by URL should key off this function so behavior is identical
26
+ * across surfaces.
27
+ *
28
+ * Returns the original string unchanged if it is not a parseable absolute URL.
29
+ */
30
+ declare function normalizeItemUrl(raw: string): string;
31
+ //#endregion
32
+ export { normalizeItemUrl };
33
+ //# sourceMappingURL=url-normalize.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"url-normalize.d.mts","names":[],"sources":["../src/url-normalize.ts"],"mappings":";;AA4CA;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAAgB,gBAAA,CAAiB,GAAA"}
@@ -0,0 +1,61 @@
1
+ //#region src/url-normalize.ts
2
+ /**
3
+ * URL normalization for item dedup (#492).
4
+ *
5
+ * Produces a stable identity key for a saved URL so the same bookmark saved
6
+ * from different surfaces (clean link, shared-with-tracking, different param
7
+ * order, different anchor) collapses to one entry. Normalization is
8
+ * intentionally CONSERVATIVE — it only removes parts that are never part of a
9
+ * page's identity, so two genuinely different pages are never merged:
10
+ *
11
+ * - scheme + host are lower-cased and default ports dropped (the `URL`
12
+ * constructor does this per RFC 3986);
13
+ * - the fragment (`#...`) is dropped — an anchor is a client-side scroll
14
+ * target, never server identity;
15
+ * - the well-known `utm_*` family and unambiguous click IDs (fbclid, gclid, …)
16
+ * are stripped;
17
+ * - remaining params are sorted so order doesn't create phantom duplicates.
18
+ *
19
+ * Ambiguous params like `ref` / `source` / `campaign` / `id` are deliberately
20
+ * NOT stripped: they are load-bearing on many sites, and dropping them would
21
+ * collapse distinct pages into one — a silent data loss on the merge step.
22
+ * Only the `utm_` prefix and the explicit click-ID list below are removed.
23
+ *
24
+ * This is the shared normalization contract: every writer (web / native / AI)
25
+ * that dedups by URL should key off this function so behavior is identical
26
+ * across surfaces.
27
+ *
28
+ * Returns the original string unchanged if it is not a parseable absolute URL.
29
+ */
30
+ /** Unambiguous click / tracking params (non-`utm_`) safe to strip everywhere. */
31
+ const STRIP_PARAMS = new Set([
32
+ "fbclid",
33
+ "gclid",
34
+ "gbraid",
35
+ "wbraid",
36
+ "dclid",
37
+ "msclkid",
38
+ "yclid",
39
+ "mc_eid",
40
+ "igshid",
41
+ "twclid",
42
+ "ttclid"
43
+ ]);
44
+ function normalizeItemUrl(raw) {
45
+ let u;
46
+ try {
47
+ u = new URL(raw);
48
+ } catch {
49
+ return raw;
50
+ }
51
+ u.hash = "";
52
+ const kept = new URLSearchParams();
53
+ for (const [k, v] of u.searchParams) if (!k.startsWith("utm_") && !STRIP_PARAMS.has(k)) kept.append(k, v);
54
+ u.search = kept.toString();
55
+ u.searchParams.sort();
56
+ return u.toString();
57
+ }
58
+
59
+ //#endregion
60
+ export { normalizeItemUrl };
61
+ //# sourceMappingURL=url-normalize.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"url-normalize.mjs","names":[],"sources":["../src/url-normalize.ts"],"sourcesContent":["/**\n * URL normalization for item dedup (#492).\n *\n * Produces a stable identity key for a saved URL so the same bookmark saved\n * from different surfaces (clean link, shared-with-tracking, different param\n * order, different anchor) collapses to one entry. Normalization is\n * intentionally CONSERVATIVE — it only removes parts that are never part of a\n * page's identity, so two genuinely different pages are never merged:\n *\n * - scheme + host are lower-cased and default ports dropped (the `URL`\n * constructor does this per RFC 3986);\n * - the fragment (`#...`) is dropped — an anchor is a client-side scroll\n * target, never server identity;\n * - the well-known `utm_*` family and unambiguous click IDs (fbclid, gclid, …)\n * are stripped;\n * - remaining params are sorted so order doesn't create phantom duplicates.\n *\n * Ambiguous params like `ref` / `source` / `campaign` / `id` are deliberately\n * NOT stripped: they are load-bearing on many sites, and dropping them would\n * collapse distinct pages into one — a silent data loss on the merge step.\n * Only the `utm_` prefix and the explicit click-ID list below are removed.\n *\n * This is the shared normalization contract: every writer (web / native / AI)\n * that dedups by URL should key off this function so behavior is identical\n * across surfaces.\n *\n * Returns the original string unchanged if it is not a parseable absolute URL.\n */\n\n/** Unambiguous click / tracking params (non-`utm_`) safe to strip everywhere. */\nconst STRIP_PARAMS = new Set([\n \"fbclid\", // Facebook\n \"gclid\", // Google Ads\n \"gbraid\", // Google Ads (iOS)\n \"wbraid\", // Google Ads (web→app)\n \"dclid\", // Google DoubleClick\n \"msclkid\", // Microsoft Ads\n \"yclid\", // Yandex\n \"mc_eid\", // Mailchimp\n \"igshid\", // Instagram\n \"twclid\", // Twitter / X\n \"ttclid\", // TikTok\n]);\n\nexport function normalizeItemUrl(raw: string): string {\n let u: URL;\n try {\n u = new URL(raw);\n } catch {\n return raw;\n }\n // Drop the fragment — an anchor is never part of a bookmark's identity.\n u.hash = \"\";\n const kept = new URLSearchParams();\n for (const [k, v] of u.searchParams) {\n if (!k.startsWith(\"utm_\") && !STRIP_PARAMS.has(k)) {\n // append (not set) so legitimately repeated keys survive intact.\n kept.append(k, v);\n }\n }\n u.search = kept.toString();\n // Sort remaining params so param order doesn't create phantom duplicates.\n u.searchParams.sort();\n return u.toString();\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8BA,MAAM,eAAe,IAAI,IAAI;CAC3B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD,CAAC;AAEF,SAAgB,iBAAiB,KAAqB;CACpD,IAAI;AACJ,KAAI;AACF,MAAI,IAAI,IAAI,IAAI;SACV;AACN,SAAO;;AAGT,GAAE,OAAO;CACT,MAAM,OAAO,IAAI,iBAAiB;AAClC,MAAK,MAAM,CAAC,GAAG,MAAM,EAAE,aACrB,KAAI,CAAC,EAAE,WAAW,OAAO,IAAI,CAAC,aAAa,IAAI,EAAE,CAE/C,MAAK,OAAO,GAAG,EAAE;AAGrB,GAAE,SAAS,KAAK,UAAU;AAE1B,GAAE,aAAa,MAAM;AACrB,QAAO,EAAE,UAAU"}