anchordb 0.2.0

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 (438) hide show
  1. package/CHANGELOG.md +61 -0
  2. package/LICENSE +21 -0
  3. package/README.md +160 -0
  4. package/dist/cjs/conflict/strategies.d.ts +110 -0
  5. package/dist/cjs/conflict/strategies.d.ts.map +1 -0
  6. package/dist/cjs/conflict/strategies.js +298 -0
  7. package/dist/cjs/conflict/strategies.js.map +1 -0
  8. package/dist/cjs/conflict/types.d.ts +38 -0
  9. package/dist/cjs/conflict/types.d.ts.map +1 -0
  10. package/dist/cjs/conflict/types.js +3 -0
  11. package/dist/cjs/conflict/types.js.map +1 -0
  12. package/dist/cjs/core/anchor-db.d.ts +154 -0
  13. package/dist/cjs/core/anchor-db.d.ts.map +1 -0
  14. package/dist/cjs/core/anchor-db.js +273 -0
  15. package/dist/cjs/core/anchor-db.js.map +1 -0
  16. package/dist/cjs/core/errors.d.ts +125 -0
  17. package/dist/cjs/core/errors.d.ts.map +1 -0
  18. package/dist/cjs/core/errors.js +174 -0
  19. package/dist/cjs/core/errors.js.map +1 -0
  20. package/dist/cjs/core/hex.d.ts +4 -0
  21. package/dist/cjs/core/hex.d.ts.map +1 -0
  22. package/dist/cjs/core/hex.js +41 -0
  23. package/dist/cjs/core/hex.js.map +1 -0
  24. package/dist/cjs/core/hlc.d.ts +96 -0
  25. package/dist/cjs/core/hlc.d.ts.map +1 -0
  26. package/dist/cjs/core/hlc.js +161 -0
  27. package/dist/cjs/core/hlc.js.map +1 -0
  28. package/dist/cjs/core/object-id.d.ts +38 -0
  29. package/dist/cjs/core/object-id.d.ts.map +1 -0
  30. package/dist/cjs/core/object-id.js +167 -0
  31. package/dist/cjs/core/object-id.js.map +1 -0
  32. package/dist/cjs/core/random.d.ts +6 -0
  33. package/dist/cjs/core/random.d.ts.map +1 -0
  34. package/dist/cjs/core/random.js +39 -0
  35. package/dist/cjs/core/random.js.map +1 -0
  36. package/dist/cjs/core/runtime.d.ts +96 -0
  37. package/dist/cjs/core/runtime.d.ts.map +1 -0
  38. package/dist/cjs/core/runtime.js +3 -0
  39. package/dist/cjs/core/runtime.js.map +1 -0
  40. package/dist/cjs/core/uuid.d.ts +16 -0
  41. package/dist/cjs/core/uuid.d.ts.map +1 -0
  42. package/dist/cjs/core/uuid.js +37 -0
  43. package/dist/cjs/core/uuid.js.map +1 -0
  44. package/dist/cjs/decorators/index.d.ts +48 -0
  45. package/dist/cjs/decorators/index.d.ts.map +1 -0
  46. package/dist/cjs/decorators/index.js +295 -0
  47. package/dist/cjs/decorators/index.js.map +1 -0
  48. package/dist/cjs/events/emitter.d.ts +16 -0
  49. package/dist/cjs/events/emitter.d.ts.map +1 -0
  50. package/dist/cjs/events/emitter.js +56 -0
  51. package/dist/cjs/events/emitter.js.map +1 -0
  52. package/dist/cjs/index/keys.d.ts +79 -0
  53. package/dist/cjs/index/keys.d.ts.map +1 -0
  54. package/dist/cjs/index/keys.js +208 -0
  55. package/dist/cjs/index/keys.js.map +1 -0
  56. package/dist/cjs/index.d.ts +81 -0
  57. package/dist/cjs/index.d.ts.map +1 -0
  58. package/dist/cjs/index.js +193 -0
  59. package/dist/cjs/index.js.map +1 -0
  60. package/dist/cjs/inspector/agent.d.ts +75 -0
  61. package/dist/cjs/inspector/agent.d.ts.map +1 -0
  62. package/dist/cjs/inspector/agent.js +520 -0
  63. package/dist/cjs/inspector/agent.js.map +1 -0
  64. package/dist/cjs/inspector/auth.d.ts +49 -0
  65. package/dist/cjs/inspector/auth.d.ts.map +1 -0
  66. package/dist/cjs/inspector/auth.js +234 -0
  67. package/dist/cjs/inspector/auth.js.map +1 -0
  68. package/dist/cjs/inspector/bridge.d.ts +141 -0
  69. package/dist/cjs/inspector/bridge.d.ts.map +1 -0
  70. package/dist/cjs/inspector/bridge.js +190 -0
  71. package/dist/cjs/inspector/bridge.js.map +1 -0
  72. package/dist/cjs/inspector/client.d.ts +111 -0
  73. package/dist/cjs/inspector/client.d.ts.map +1 -0
  74. package/dist/cjs/inspector/client.js +218 -0
  75. package/dist/cjs/inspector/client.js.map +1 -0
  76. package/dist/cjs/inspector/protocol.d.ts +160 -0
  77. package/dist/cjs/inspector/protocol.d.ts.map +1 -0
  78. package/dist/cjs/inspector/protocol.js +53 -0
  79. package/dist/cjs/inspector/protocol.js.map +1 -0
  80. package/dist/cjs/inspector/transports/in-process.d.ts +7 -0
  81. package/dist/cjs/inspector/transports/in-process.d.ts.map +1 -0
  82. package/dist/cjs/inspector/transports/in-process.js +58 -0
  83. package/dist/cjs/inspector/transports/in-process.js.map +1 -0
  84. package/dist/cjs/inspector/transports/websocket.d.ts +39 -0
  85. package/dist/cjs/inspector/transports/websocket.d.ts.map +1 -0
  86. package/dist/cjs/inspector/transports/websocket.js +60 -0
  87. package/dist/cjs/inspector/transports/websocket.js.map +1 -0
  88. package/dist/cjs/interop/csv.d.ts +53 -0
  89. package/dist/cjs/interop/csv.d.ts.map +1 -0
  90. package/dist/cjs/interop/csv.js +230 -0
  91. package/dist/cjs/interop/csv.js.map +1 -0
  92. package/dist/cjs/interop/ejson.d.ts +41 -0
  93. package/dist/cjs/interop/ejson.d.ts.map +1 -0
  94. package/dist/cjs/interop/ejson.js +182 -0
  95. package/dist/cjs/interop/ejson.js.map +1 -0
  96. package/dist/cjs/interop/export-import.d.ts +98 -0
  97. package/dist/cjs/interop/export-import.d.ts.map +1 -0
  98. package/dist/cjs/interop/export-import.js +222 -0
  99. package/dist/cjs/interop/export-import.js.map +1 -0
  100. package/dist/cjs/model/document.d.ts +66 -0
  101. package/dist/cjs/model/document.d.ts.map +1 -0
  102. package/dist/cjs/model/document.js +302 -0
  103. package/dist/cjs/model/document.js.map +1 -0
  104. package/dist/cjs/model/model.d.ts +178 -0
  105. package/dist/cjs/model/model.d.ts.map +1 -0
  106. package/dist/cjs/model/model.js +823 -0
  107. package/dist/cjs/model/model.js.map +1 -0
  108. package/dist/cjs/package.json +3 -0
  109. package/dist/cjs/query/aggregation/expressions.d.ts +34 -0
  110. package/dist/cjs/query/aggregation/expressions.d.ts.map +1 -0
  111. package/dist/cjs/query/aggregation/expressions.js +552 -0
  112. package/dist/cjs/query/aggregation/expressions.js.map +1 -0
  113. package/dist/cjs/query/aggregation/pipeline.d.ts +79 -0
  114. package/dist/cjs/query/aggregation/pipeline.d.ts.map +1 -0
  115. package/dist/cjs/query/aggregation/pipeline.js +597 -0
  116. package/dist/cjs/query/aggregation/pipeline.js.map +1 -0
  117. package/dist/cjs/query/aggregation/source.d.ts +35 -0
  118. package/dist/cjs/query/aggregation/source.d.ts.map +1 -0
  119. package/dist/cjs/query/aggregation/source.js +81 -0
  120. package/dist/cjs/query/aggregation/source.js.map +1 -0
  121. package/dist/cjs/query/builder/query.d.ts +113 -0
  122. package/dist/cjs/query/builder/query.d.ts.map +1 -0
  123. package/dist/cjs/query/builder/query.js +215 -0
  124. package/dist/cjs/query/builder/query.js.map +1 -0
  125. package/dist/cjs/query/filter.d.ts +50 -0
  126. package/dist/cjs/query/filter.d.ts.map +1 -0
  127. package/dist/cjs/query/filter.js +275 -0
  128. package/dist/cjs/query/filter.js.map +1 -0
  129. package/dist/cjs/query/path.d.ts +41 -0
  130. package/dist/cjs/query/path.d.ts.map +1 -0
  131. package/dist/cjs/query/path.js +294 -0
  132. package/dist/cjs/query/path.js.map +1 -0
  133. package/dist/cjs/query/update.d.ts +30 -0
  134. package/dist/cjs/query/update.d.ts.map +1 -0
  135. package/dist/cjs/query/update.js +205 -0
  136. package/dist/cjs/query/update.js.map +1 -0
  137. package/dist/cjs/reactive/live-query.d.ts +41 -0
  138. package/dist/cjs/reactive/live-query.d.ts.map +1 -0
  139. package/dist/cjs/reactive/live-query.js +88 -0
  140. package/dist/cjs/reactive/live-query.js.map +1 -0
  141. package/dist/cjs/schema/cast.d.ts +38 -0
  142. package/dist/cjs/schema/cast.d.ts.map +1 -0
  143. package/dist/cjs/schema/cast.js +280 -0
  144. package/dist/cjs/schema/cast.js.map +1 -0
  145. package/dist/cjs/schema/index.d.ts +5 -0
  146. package/dist/cjs/schema/index.d.ts.map +1 -0
  147. package/dist/cjs/schema/index.js +27 -0
  148. package/dist/cjs/schema/index.js.map +1 -0
  149. package/dist/cjs/schema/schema.d.ts +58 -0
  150. package/dist/cjs/schema/schema.d.ts.map +1 -0
  151. package/dist/cjs/schema/schema.js +363 -0
  152. package/dist/cjs/schema/schema.js.map +1 -0
  153. package/dist/cjs/schema/types.d.ts +144 -0
  154. package/dist/cjs/schema/types.d.ts.map +1 -0
  155. package/dist/cjs/schema/types.js +20 -0
  156. package/dist/cjs/schema/types.js.map +1 -0
  157. package/dist/cjs/schema/validate.d.ts +15 -0
  158. package/dist/cjs/schema/validate.d.ts.map +1 -0
  159. package/dist/cjs/schema/validate.js +101 -0
  160. package/dist/cjs/schema/validate.js.map +1 -0
  161. package/dist/cjs/storage/adapters/capacitor-sqlite.d.ts +67 -0
  162. package/dist/cjs/storage/adapters/capacitor-sqlite.d.ts.map +1 -0
  163. package/dist/cjs/storage/adapters/capacitor-sqlite.js +69 -0
  164. package/dist/cjs/storage/adapters/capacitor-sqlite.js.map +1 -0
  165. package/dist/cjs/storage/adapters/expo-sqlite.d.ts +55 -0
  166. package/dist/cjs/storage/adapters/expo-sqlite.d.ts.map +1 -0
  167. package/dist/cjs/storage/adapters/expo-sqlite.js +53 -0
  168. package/dist/cjs/storage/adapters/expo-sqlite.js.map +1 -0
  169. package/dist/cjs/storage/adapters/indexeddb.d.ts +55 -0
  170. package/dist/cjs/storage/adapters/indexeddb.d.ts.map +1 -0
  171. package/dist/cjs/storage/adapters/indexeddb.js +393 -0
  172. package/dist/cjs/storage/adapters/indexeddb.js.map +1 -0
  173. package/dist/cjs/storage/adapters/memory.d.ts +44 -0
  174. package/dist/cjs/storage/adapters/memory.d.ts.map +1 -0
  175. package/dist/cjs/storage/adapters/memory.js +286 -0
  176. package/dist/cjs/storage/adapters/memory.js.map +1 -0
  177. package/dist/cjs/storage/adapters/node-sqlite.d.ts +59 -0
  178. package/dist/cjs/storage/adapters/node-sqlite.d.ts.map +1 -0
  179. package/dist/cjs/storage/adapters/node-sqlite.js +457 -0
  180. package/dist/cjs/storage/adapters/node-sqlite.js.map +1 -0
  181. package/dist/cjs/storage/adapters/sql-base.d.ts +84 -0
  182. package/dist/cjs/storage/adapters/sql-base.d.ts.map +1 -0
  183. package/dist/cjs/storage/adapters/sql-base.js +393 -0
  184. package/dist/cjs/storage/adapters/sql-base.js.map +1 -0
  185. package/dist/cjs/storage/types.d.ts +131 -0
  186. package/dist/cjs/storage/types.d.ts.map +1 -0
  187. package/dist/cjs/storage/types.js +3 -0
  188. package/dist/cjs/storage/types.js.map +1 -0
  189. package/dist/cjs/sync/adapters/rest.d.ts +31 -0
  190. package/dist/cjs/sync/adapters/rest.d.ts.map +1 -0
  191. package/dist/cjs/sync/adapters/rest.js +75 -0
  192. package/dist/cjs/sync/adapters/rest.js.map +1 -0
  193. package/dist/cjs/sync/attach.d.ts +30 -0
  194. package/dist/cjs/sync/attach.d.ts.map +1 -0
  195. package/dist/cjs/sync/attach.js +104 -0
  196. package/dist/cjs/sync/attach.js.map +1 -0
  197. package/dist/cjs/sync/engine.d.ts +96 -0
  198. package/dist/cjs/sync/engine.d.ts.map +1 -0
  199. package/dist/cjs/sync/engine.js +491 -0
  200. package/dist/cjs/sync/engine.js.map +1 -0
  201. package/dist/cjs/sync/protocol.d.ts +128 -0
  202. package/dist/cjs/sync/protocol.d.ts.map +1 -0
  203. package/dist/cjs/sync/protocol.js +38 -0
  204. package/dist/cjs/sync/protocol.js.map +1 -0
  205. package/dist/cjs/sync/queue.d.ts +77 -0
  206. package/dist/cjs/sync/queue.d.ts.map +1 -0
  207. package/dist/cjs/sync/queue.js +245 -0
  208. package/dist/cjs/sync/queue.js.map +1 -0
  209. package/dist/cjs/sync/server/memory-server.d.ts +65 -0
  210. package/dist/cjs/sync/server/memory-server.d.ts.map +1 -0
  211. package/dist/cjs/sync/server/memory-server.js +193 -0
  212. package/dist/cjs/sync/server/memory-server.js.map +1 -0
  213. package/dist/cjs/timestamps/index.d.ts +47 -0
  214. package/dist/cjs/timestamps/index.d.ts.map +1 -0
  215. package/dist/cjs/timestamps/index.js +88 -0
  216. package/dist/cjs/timestamps/index.js.map +1 -0
  217. package/dist/cjs/timestamps/timezone.d.ts +65 -0
  218. package/dist/cjs/timestamps/timezone.d.ts.map +1 -0
  219. package/dist/cjs/timestamps/timezone.js +208 -0
  220. package/dist/cjs/timestamps/timezone.js.map +1 -0
  221. package/dist/esm/conflict/strategies.d.ts +110 -0
  222. package/dist/esm/conflict/strategies.d.ts.map +1 -0
  223. package/dist/esm/conflict/strategies.js +289 -0
  224. package/dist/esm/conflict/strategies.js.map +1 -0
  225. package/dist/esm/conflict/types.d.ts +38 -0
  226. package/dist/esm/conflict/types.d.ts.map +1 -0
  227. package/dist/esm/conflict/types.js +2 -0
  228. package/dist/esm/conflict/types.js.map +1 -0
  229. package/dist/esm/core/anchor-db.d.ts +154 -0
  230. package/dist/esm/core/anchor-db.d.ts.map +1 -0
  231. package/dist/esm/core/anchor-db.js +269 -0
  232. package/dist/esm/core/anchor-db.js.map +1 -0
  233. package/dist/esm/core/errors.d.ts +125 -0
  234. package/dist/esm/core/errors.d.ts.map +1 -0
  235. package/dist/esm/core/errors.js +161 -0
  236. package/dist/esm/core/errors.js.map +1 -0
  237. package/dist/esm/core/hex.d.ts +4 -0
  238. package/dist/esm/core/hex.d.ts.map +1 -0
  239. package/dist/esm/core/hex.js +37 -0
  240. package/dist/esm/core/hex.js.map +1 -0
  241. package/dist/esm/core/hlc.d.ts +96 -0
  242. package/dist/esm/core/hlc.d.ts.map +1 -0
  243. package/dist/esm/core/hlc.js +153 -0
  244. package/dist/esm/core/hlc.js.map +1 -0
  245. package/dist/esm/core/object-id.d.ts +38 -0
  246. package/dist/esm/core/object-id.d.ts.map +1 -0
  247. package/dist/esm/core/object-id.js +163 -0
  248. package/dist/esm/core/object-id.js.map +1 -0
  249. package/dist/esm/core/random.d.ts +6 -0
  250. package/dist/esm/core/random.d.ts.map +1 -0
  251. package/dist/esm/core/random.js +34 -0
  252. package/dist/esm/core/random.js.map +1 -0
  253. package/dist/esm/core/runtime.d.ts +96 -0
  254. package/dist/esm/core/runtime.d.ts.map +1 -0
  255. package/dist/esm/core/runtime.js +2 -0
  256. package/dist/esm/core/runtime.js.map +1 -0
  257. package/dist/esm/core/uuid.d.ts +16 -0
  258. package/dist/esm/core/uuid.d.ts.map +1 -0
  259. package/dist/esm/core/uuid.js +33 -0
  260. package/dist/esm/core/uuid.js.map +1 -0
  261. package/dist/esm/decorators/index.d.ts +48 -0
  262. package/dist/esm/decorators/index.d.ts.map +1 -0
  263. package/dist/esm/decorators/index.js +286 -0
  264. package/dist/esm/decorators/index.js.map +1 -0
  265. package/dist/esm/events/emitter.d.ts +16 -0
  266. package/dist/esm/events/emitter.d.ts.map +1 -0
  267. package/dist/esm/events/emitter.js +52 -0
  268. package/dist/esm/events/emitter.js.map +1 -0
  269. package/dist/esm/index/keys.d.ts +79 -0
  270. package/dist/esm/index/keys.d.ts.map +1 -0
  271. package/dist/esm/index/keys.js +198 -0
  272. package/dist/esm/index/keys.js.map +1 -0
  273. package/dist/esm/index.d.ts +81 -0
  274. package/dist/esm/index.d.ts.map +1 -0
  275. package/dist/esm/index.js +59 -0
  276. package/dist/esm/index.js.map +1 -0
  277. package/dist/esm/inspector/agent.d.ts +75 -0
  278. package/dist/esm/inspector/agent.d.ts.map +1 -0
  279. package/dist/esm/inspector/agent.js +482 -0
  280. package/dist/esm/inspector/agent.js.map +1 -0
  281. package/dist/esm/inspector/auth.d.ts +49 -0
  282. package/dist/esm/inspector/auth.d.ts.map +1 -0
  283. package/dist/esm/inspector/auth.js +228 -0
  284. package/dist/esm/inspector/auth.js.map +1 -0
  285. package/dist/esm/inspector/bridge.d.ts +141 -0
  286. package/dist/esm/inspector/bridge.d.ts.map +1 -0
  287. package/dist/esm/inspector/bridge.js +182 -0
  288. package/dist/esm/inspector/bridge.js.map +1 -0
  289. package/dist/esm/inspector/client.d.ts +111 -0
  290. package/dist/esm/inspector/client.d.ts.map +1 -0
  291. package/dist/esm/inspector/client.js +213 -0
  292. package/dist/esm/inspector/client.js.map +1 -0
  293. package/dist/esm/inspector/protocol.d.ts +160 -0
  294. package/dist/esm/inspector/protocol.d.ts.map +1 -0
  295. package/dist/esm/inspector/protocol.js +43 -0
  296. package/dist/esm/inspector/protocol.js.map +1 -0
  297. package/dist/esm/inspector/transports/in-process.d.ts +7 -0
  298. package/dist/esm/inspector/transports/in-process.d.ts.map +1 -0
  299. package/dist/esm/inspector/transports/in-process.js +55 -0
  300. package/dist/esm/inspector/transports/in-process.js.map +1 -0
  301. package/dist/esm/inspector/transports/websocket.d.ts +39 -0
  302. package/dist/esm/inspector/transports/websocket.d.ts.map +1 -0
  303. package/dist/esm/inspector/transports/websocket.js +56 -0
  304. package/dist/esm/inspector/transports/websocket.js.map +1 -0
  305. package/dist/esm/interop/csv.d.ts +53 -0
  306. package/dist/esm/interop/csv.d.ts.map +1 -0
  307. package/dist/esm/interop/csv.js +222 -0
  308. package/dist/esm/interop/csv.js.map +1 -0
  309. package/dist/esm/interop/ejson.d.ts +41 -0
  310. package/dist/esm/interop/ejson.d.ts.map +1 -0
  311. package/dist/esm/interop/ejson.js +176 -0
  312. package/dist/esm/interop/ejson.js.map +1 -0
  313. package/dist/esm/interop/export-import.d.ts +98 -0
  314. package/dist/esm/interop/export-import.d.ts.map +1 -0
  315. package/dist/esm/interop/export-import.js +210 -0
  316. package/dist/esm/interop/export-import.js.map +1 -0
  317. package/dist/esm/model/document.d.ts +66 -0
  318. package/dist/esm/model/document.d.ts.map +1 -0
  319. package/dist/esm/model/document.js +297 -0
  320. package/dist/esm/model/document.js.map +1 -0
  321. package/dist/esm/model/model.d.ts +178 -0
  322. package/dist/esm/model/model.d.ts.map +1 -0
  323. package/dist/esm/model/model.js +815 -0
  324. package/dist/esm/model/model.js.map +1 -0
  325. package/dist/esm/package.json +3 -0
  326. package/dist/esm/query/aggregation/expressions.d.ts +34 -0
  327. package/dist/esm/query/aggregation/expressions.d.ts.map +1 -0
  328. package/dist/esm/query/aggregation/expressions.js +545 -0
  329. package/dist/esm/query/aggregation/expressions.js.map +1 -0
  330. package/dist/esm/query/aggregation/pipeline.d.ts +79 -0
  331. package/dist/esm/query/aggregation/pipeline.d.ts.map +1 -0
  332. package/dist/esm/query/aggregation/pipeline.js +591 -0
  333. package/dist/esm/query/aggregation/pipeline.js.map +1 -0
  334. package/dist/esm/query/aggregation/source.d.ts +35 -0
  335. package/dist/esm/query/aggregation/source.d.ts.map +1 -0
  336. package/dist/esm/query/aggregation/source.js +77 -0
  337. package/dist/esm/query/aggregation/source.js.map +1 -0
  338. package/dist/esm/query/builder/query.d.ts +113 -0
  339. package/dist/esm/query/builder/query.d.ts.map +1 -0
  340. package/dist/esm/query/builder/query.js +209 -0
  341. package/dist/esm/query/builder/query.js.map +1 -0
  342. package/dist/esm/query/filter.d.ts +50 -0
  343. package/dist/esm/query/filter.d.ts.map +1 -0
  344. package/dist/esm/query/filter.js +267 -0
  345. package/dist/esm/query/filter.js.map +1 -0
  346. package/dist/esm/query/path.d.ts +41 -0
  347. package/dist/esm/query/path.d.ts.map +1 -0
  348. package/dist/esm/query/path.js +282 -0
  349. package/dist/esm/query/path.js.map +1 -0
  350. package/dist/esm/query/update.d.ts +30 -0
  351. package/dist/esm/query/update.d.ts.map +1 -0
  352. package/dist/esm/query/update.js +198 -0
  353. package/dist/esm/query/update.js.map +1 -0
  354. package/dist/esm/reactive/live-query.d.ts +41 -0
  355. package/dist/esm/reactive/live-query.d.ts.map +1 -0
  356. package/dist/esm/reactive/live-query.js +83 -0
  357. package/dist/esm/reactive/live-query.js.map +1 -0
  358. package/dist/esm/schema/cast.d.ts +38 -0
  359. package/dist/esm/schema/cast.d.ts.map +1 -0
  360. package/dist/esm/schema/cast.js +275 -0
  361. package/dist/esm/schema/cast.js.map +1 -0
  362. package/dist/esm/schema/index.d.ts +5 -0
  363. package/dist/esm/schema/index.d.ts.map +1 -0
  364. package/dist/esm/schema/index.js +5 -0
  365. package/dist/esm/schema/index.js.map +1 -0
  366. package/dist/esm/schema/schema.d.ts +58 -0
  367. package/dist/esm/schema/schema.d.ts.map +1 -0
  368. package/dist/esm/schema/schema.js +358 -0
  369. package/dist/esm/schema/schema.js.map +1 -0
  370. package/dist/esm/schema/types.d.ts +144 -0
  371. package/dist/esm/schema/types.d.ts.map +1 -0
  372. package/dist/esm/schema/types.js +17 -0
  373. package/dist/esm/schema/types.js.map +1 -0
  374. package/dist/esm/schema/validate.d.ts +15 -0
  375. package/dist/esm/schema/validate.d.ts.map +1 -0
  376. package/dist/esm/schema/validate.js +98 -0
  377. package/dist/esm/schema/validate.js.map +1 -0
  378. package/dist/esm/storage/adapters/capacitor-sqlite.d.ts +67 -0
  379. package/dist/esm/storage/adapters/capacitor-sqlite.d.ts.map +1 -0
  380. package/dist/esm/storage/adapters/capacitor-sqlite.js +65 -0
  381. package/dist/esm/storage/adapters/capacitor-sqlite.js.map +1 -0
  382. package/dist/esm/storage/adapters/expo-sqlite.d.ts +55 -0
  383. package/dist/esm/storage/adapters/expo-sqlite.d.ts.map +1 -0
  384. package/dist/esm/storage/adapters/expo-sqlite.js +49 -0
  385. package/dist/esm/storage/adapters/expo-sqlite.js.map +1 -0
  386. package/dist/esm/storage/adapters/indexeddb.d.ts +55 -0
  387. package/dist/esm/storage/adapters/indexeddb.d.ts.map +1 -0
  388. package/dist/esm/storage/adapters/indexeddb.js +389 -0
  389. package/dist/esm/storage/adapters/indexeddb.js.map +1 -0
  390. package/dist/esm/storage/adapters/memory.d.ts +44 -0
  391. package/dist/esm/storage/adapters/memory.d.ts.map +1 -0
  392. package/dist/esm/storage/adapters/memory.js +282 -0
  393. package/dist/esm/storage/adapters/memory.js.map +1 -0
  394. package/dist/esm/storage/adapters/node-sqlite.d.ts +59 -0
  395. package/dist/esm/storage/adapters/node-sqlite.d.ts.map +1 -0
  396. package/dist/esm/storage/adapters/node-sqlite.js +450 -0
  397. package/dist/esm/storage/adapters/node-sqlite.js.map +1 -0
  398. package/dist/esm/storage/adapters/sql-base.d.ts +84 -0
  399. package/dist/esm/storage/adapters/sql-base.d.ts.map +1 -0
  400. package/dist/esm/storage/adapters/sql-base.js +383 -0
  401. package/dist/esm/storage/adapters/sql-base.js.map +1 -0
  402. package/dist/esm/storage/types.d.ts +131 -0
  403. package/dist/esm/storage/types.d.ts.map +1 -0
  404. package/dist/esm/storage/types.js +2 -0
  405. package/dist/esm/storage/types.js.map +1 -0
  406. package/dist/esm/sync/adapters/rest.d.ts +31 -0
  407. package/dist/esm/sync/adapters/rest.d.ts.map +1 -0
  408. package/dist/esm/sync/adapters/rest.js +71 -0
  409. package/dist/esm/sync/adapters/rest.js.map +1 -0
  410. package/dist/esm/sync/attach.d.ts +30 -0
  411. package/dist/esm/sync/attach.d.ts.map +1 -0
  412. package/dist/esm/sync/attach.js +98 -0
  413. package/dist/esm/sync/attach.js.map +1 -0
  414. package/dist/esm/sync/engine.d.ts +96 -0
  415. package/dist/esm/sync/engine.d.ts.map +1 -0
  416. package/dist/esm/sync/engine.js +487 -0
  417. package/dist/esm/sync/engine.js.map +1 -0
  418. package/dist/esm/sync/protocol.d.ts +128 -0
  419. package/dist/esm/sync/protocol.d.ts.map +1 -0
  420. package/dist/esm/sync/protocol.js +33 -0
  421. package/dist/esm/sync/protocol.js.map +1 -0
  422. package/dist/esm/sync/queue.d.ts +77 -0
  423. package/dist/esm/sync/queue.d.ts.map +1 -0
  424. package/dist/esm/sync/queue.js +241 -0
  425. package/dist/esm/sync/queue.js.map +1 -0
  426. package/dist/esm/sync/server/memory-server.d.ts +65 -0
  427. package/dist/esm/sync/server/memory-server.d.ts.map +1 -0
  428. package/dist/esm/sync/server/memory-server.js +189 -0
  429. package/dist/esm/sync/server/memory-server.js.map +1 -0
  430. package/dist/esm/timestamps/index.d.ts +47 -0
  431. package/dist/esm/timestamps/index.d.ts.map +1 -0
  432. package/dist/esm/timestamps/index.js +70 -0
  433. package/dist/esm/timestamps/index.js.map +1 -0
  434. package/dist/esm/timestamps/timezone.d.ts +65 -0
  435. package/dist/esm/timestamps/timezone.d.ts.map +1 -0
  436. package/dist/esm/timestamps/timezone.js +196 -0
  437. package/dist/esm/timestamps/timezone.js.map +1 -0
  438. package/package.json +163 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,61 @@
1
+ # Changelog
2
+
3
+ All notable changes to the `anchordb` packages.
4
+
5
+ This project follows [semantic versioning](https://semver.org/). While the version is `0.x`, minor
6
+ releases may contain breaking changes.
7
+
8
+ ## 0.1.0 — unreleased
9
+
10
+ First release. Five packages, published together.
11
+
12
+ ### `anchordb`
13
+
14
+ - **Local-first database** with a Mongoose-shaped API. No `sync` block means a purely local
15
+ database: no mutation queue, no network code, no sync metadata, hard deletes.
16
+ - **Mongoose parity**: `Schema`, `model()`, documents with `.save()`/`.isModified()`, virtuals,
17
+ methods, statics, `pre`/`post` hooks, `ValidationError`/`CastError` shapes, and `code: 11000`.
18
+ - **Decorators** (`anchordb/decorators`) matching `@nestjs/mongoose` — `@Schema`, `@Prop`,
19
+ `SchemaFactory`, `raw()` — so one decorated class can be shared with a NestJS backend.
20
+ Metadata is optional: explicit `@Prop(String)` works with `emitDecoratorMetadata` off.
21
+ - **Real MongoDB ObjectId**, generated on-device, cross-validated byte-for-byte against `bson`.
22
+ - **Indexes** — single, compound, multikey, `unique`, `sparse`, `partialFilterExpression`, TTL —
23
+ with unique violations enforced at the storage layer and reported as `E11000`.
24
+ - **Lazy chainable query builder**: `.populate().sort().skip().limit().select().exec()`, thenable,
25
+ async-iterable, with `explain()`.
26
+ - **Aggregation pipeline** with streaming execution, index pushdown, and a `mongoCompatible` strict
27
+ mode that rejects non-portable constructs at development time.
28
+ - **UTC-canonical timestamps** with IANA timezone support, validated at construction.
29
+ - **Extended JSON v2 interop** — `export()` feeds `mongoimport`; `mongoexport` output imports back.
30
+ - **Offline mutation queue** and sync engine with five conflict strategies
31
+ (`last-write-wins`, `server-wins`, `client-wins`, `field-level`, `custom`).
32
+ - **Inspector protocol v1** with pairing, sessions, and live change events.
33
+ - **Five storage adapters**: Memory, Node SQLite, IndexedDB, Expo SQLite, Capacitor SQLite.
34
+
35
+ ### `anchordb-sync-server`
36
+
37
+ - Framework-agnostic protocol engine over a pluggable `ServerStore`.
38
+ - Express, NestJS and Next.js adapters, all held to one conformance suite.
39
+ - `MemoryStore` (default) and `MongooseStore`.
40
+
41
+ ### `anchordb-react`
42
+
43
+ - `useFind`, `useFindOne`, `useCount`, `useAggregate`, `useSyncStatus`, `useAnchorEvent`.
44
+
45
+ ### `anchordb-angular`
46
+
47
+ - `AnchorModule.forRoot`/`forFeature`, `getModelToken`, `AnchorService` with RxJS-compatible
48
+ observables. Angular and RxJS are optional peers and are never imported.
49
+
50
+ ### `anchordb-relay`
51
+
52
+ - Development-only WebSocket relay plus the `anchor-relay` CLI.
53
+
54
+ ### Known limitations
55
+
56
+ - **Expo SQLite and Capacitor SQLite are unverified** — written and typechecked, never executed on
57
+ a device. Test before production use.
58
+ - The REST sync transport and `MongooseStore` have no live-server tests.
59
+ - Not supported in v1: discriminators, `refPath`, transactions, server-side change streams,
60
+ text/geo/hashed indexes, collation, and the `$graphLookup`/`$geoNear`/`$search`/`$merge`/`$out`/
61
+ `$unionWith` aggregation stages.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 AnchorDB contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,160 @@
1
+ # anchordb
2
+
3
+ **MongoDB + Mongoose, for mobile apps.** A local, persistent document database with a
4
+ Mongoose-shaped API that works completely offline — and *optionally* synchronises with a backend.
5
+
6
+ ```bash
7
+ npm install anchordb
8
+ ```
9
+
10
+ ## Quick start — no backend required
11
+
12
+ ```ts
13
+ import { AnchorDB, Schema } from "anchordb";
14
+
15
+ const db = new AnchorDB({ name: "my-app" }); // no sync block → purely local
16
+
17
+ const userSchema = new Schema({
18
+ name: { type: String, required: true, trim: true },
19
+ email: { type: String, required: true, unique: true, lowercase: true },
20
+ age: { type: Number, min: 0, max: 150 },
21
+ role: { type: String, enum: ["admin", "user"], default: "user" },
22
+ }, { timestamps: true });
23
+
24
+ const User = db.model("User", userSchema);
25
+
26
+ await User.create({ name: "Nisala", age: 28, email: "n@example.com" });
27
+
28
+ const adults = await User.find({ age: { $gte: 18 } })
29
+ .sort("-createdAt")
30
+ .limit(10);
31
+ ```
32
+
33
+ That is Mongoose code. It runs on a phone, offline, with no server anywhere.
34
+
35
+ ## Two principles
36
+
37
+ **1. Zero re-learning.** If you know MongoDB and Mongoose on the backend, you already know this:
38
+ the same `Schema`, `model()`, query builder, `populate`, `ObjectId`, index options and error codes
39
+ (`err.code === 11000`, `err.errors[path].kind`). Anything Mongoose does that AnchorDB does not is
40
+ written down, never silently reinterpreted.
41
+
42
+ **2. Sync is optional.** An app with no backend is the default case, not a degraded one. With no
43
+ `sync` block there is no mutation queue, no network code, no sync metadata and no tombstones.
44
+ Adding sync later requires no changes to your CRUD code.
45
+
46
+ ## Decorators (optional)
47
+
48
+ Identical in shape to `@nestjs/mongoose`, so the same decorated class can be shared between an
49
+ Ionic/Angular app and a NestJS backend:
50
+
51
+ ```ts
52
+ import { Schema, Prop, SchemaFactory } from "anchordb/decorators";
53
+
54
+ @Schema({ timestamps: true })
55
+ export class User {
56
+ @Prop({ required: true }) name!: string;
57
+ @Prop(String) nickname!: string;
58
+ @Prop([String]) tags!: string[];
59
+ }
60
+ export const UserSchema = SchemaFactory.createForClass(User);
61
+ ```
62
+
63
+ Requires `experimentalDecorators` + `emitDecoratorMetadata` for type inference — or pass the type
64
+ explicitly (`@Prop(String)`) and no metadata is needed at all.
65
+
66
+ ## Storage adapters
67
+
68
+ | Adapter | Import | Platform | Verified here |
69
+ | --- | --- | --- | --- |
70
+ | Memory | `MemoryAdapter` from `anchordb` | any | yes — conformance suite |
71
+ | Node SQLite | `anchordb/storage/node-sqlite` | Node 22.5+ (built in, no native deps) | yes — conformance suite |
72
+ | IndexedDB | `anchordb/storage/indexeddb` | browser, PWA, `ionic serve` | yes — conformance suite |
73
+ | Expo SQLite | `anchordb/storage/expo-sqlite` | React Native, iOS/Android | **no — see below** |
74
+ | Capacitor SQLite | `anchordb/storage/capacitor-sqlite` | Ionic native | **no — see below** |
75
+
76
+ All adapters sit behind one `DatabaseAdapter` interface, and the three verified ones are held to a
77
+ single 70-test conformance suite, so unique-index semantics, null handling and write atomicity
78
+ cannot drift between them.
79
+
80
+ ## Interchange with MongoDB
81
+
82
+ Export and import speak what `mongoexport` writes and `mongoimport` reads, in both directions and
83
+ in both formats:
84
+
85
+ ```ts
86
+ // Extended JSON — lossless. NDJSON by default, which mongoimport reads with no extra flag.
87
+ const file = await Model.export({ mode: "canonical" });
88
+
89
+ // Only what a filter matches, run as a real query so it is cast and indexed like any other.
90
+ const page = await Model.export({ filter: { status: "active" } });
91
+
92
+ // CSV — for spreadsheets, and for mongoimport --type=csv --headerline.
93
+ const csv = await Model.export({ format: "csv" });
94
+
95
+ // Import auto-detects a JSON array, NDJSON or CSV.
96
+ await db.import(text, { mode: "upsert" });
97
+ ```
98
+
99
+ `mongoimportCommand()` prints the exact command that ingests the result.
100
+
101
+ CSV carries no types, so on import values are inferred conservatively and then **cast through the
102
+ collection's schema** — a declared `Number` comes back a number rather than the text the file held.
103
+ Two things CSV genuinely cannot round-trip, stated rather than hidden: `null` and a missing field
104
+ are both an empty cell (read back as missing, matching `mongoimport --ignoreBlanks`), and nested
105
+ fields travel as dotted paths.
106
+
107
+ Extended JSON has three modes, matching the ones MongoDB Compass offers: `canonical` (lossless),
108
+ `relaxed` (readable), and `default` (relaxed, except integers past 2^53 which are marked
109
+ `$numberLong` so they do not silently become doubles).
110
+
111
+ ## Status
112
+
113
+ **0.2.0 — early, and 0.x means breaking changes are expected.**
114
+
115
+ **631 tests across 17 files.** Implemented and covered: the local database, Mongoose-shaped schema
116
+ and validation, decorators, indexes with real `E11000` enforcement, the lazy query builder,
117
+ `populate`, documents with `.save()`, aggregation, UTC timestamps and timezones, MongoDB Extended
118
+ JSON and CSV interop, the offline mutation queue, the sync engine with all five conflict strategies,
119
+ and the inspector protocol.
120
+
121
+ ### New in 0.2.0
122
+
123
+ - **`updateMany` and `deleteMany` on the inspector protocol**, behind a new `documents:bulk`
124
+ capability. Both route through the ordinary Model API, so a bulk write from Anchor Lens validates,
125
+ stamps and queues exactly like an app write. An empty filter is refused unless explicitly
126
+ acknowledged — an inspector that can empty a collection on a mis-tap is worse than one that asks
127
+ twice. The capability is negotiated, so an older agent and a newer Lens still connect.
128
+ - **CSV export and import**, and a `filter` on export.
129
+ - **A MongoDB bridge protocol** (`MongoBridgeClient`), so Anchor Lens can pull collections from a
130
+ real MongoDB or push a device into one. The driver runs in `anchordb-relay` — React
131
+ Native has no TCP sockets — and both directions carry the same Extended JSON as the file export.
132
+ - **`default` Extended JSON mode.**
133
+ - **A no-op update is now matched but not modified**, as in MongoDB: `modifiedCount` excludes
134
+ documents the update did not change, and their `updatedAt` and version key are left alone. It
135
+ previously counted every match, because the timestamp was stamped before the comparison. Beyond
136
+ correctness this matters for bulk writes — setting a field over 10,000 documents no longer queues
137
+ 10,000 mutations when only a few hundred needed changing.
138
+
139
+ ### What is NOT verified
140
+
141
+ Stated plainly rather than left to be discovered:
142
+
143
+ - **Expo SQLite and Capacitor SQLite have never been executed.** They are written against the
144
+ documented APIs and typechecked, but this package is developed on a machine with no simulator or
145
+ device. All of their query, index and unique-enforcement logic is inherited from a shared base
146
+ that *is* covered by the conformance suite; the unverified surface is roughly forty lines of
147
+ driver plumbing each. **Test on a device before relying on them in production.**
148
+ - **The REST sync transport** is typechecked but has no live-HTTP test. The protocol it speaks is
149
+ covered end to end through an in-process transport.
150
+ - **`MongooseStore`** in `anchordb-sync-server` has not run against a live MongoDB here.
151
+
152
+ ### Not supported in v1
153
+
154
+ Documented rather than silently absent: discriminators, `refPath`, transactions/sessions,
155
+ server-side change streams, text/`2dsphere`/hashed indexes, collation, and the
156
+ `$graphLookup`/`$geoNear`/`$search`/`$merge`/`$out`/`$unionWith` aggregation stages.
157
+
158
+ ## License
159
+
160
+ MIT
@@ -0,0 +1,110 @@
1
+ import type { ConflictContext, ConflictResolutionConfig, ConflictStrategyName, Resolution } from "./types.js";
2
+ /**
3
+ * The five conflict strategies, behind one interface.
4
+ *
5
+ * The sync engine knows only `resolve(context) -> Resolution`. No strategy-specific branching leaks
6
+ * into the engine, which is what makes switching strategy a pure configuration change (§19) and
7
+ * makes a sixth strategy a matter of registering one more object.
8
+ */
9
+ export interface ConflictStrategyHandler<T extends Record<string, unknown> = Record<string, unknown>> {
10
+ readonly name: ConflictStrategyName | string;
11
+ resolve(context: ConflictContext<T>): Promise<Resolution<T>> | Resolution<T>;
12
+ }
13
+ /**
14
+ * Last write wins — the default.
15
+ *
16
+ * "Latest" is decided by the hybrid logical clock, never by raw device wall-clock strings. The
17
+ * comparison order is documented in SYNC_PROTOCOL.md:
18
+ *
19
+ * 1. HLC physical time (already skew-corrected against the server)
20
+ * 2. HLC logical counter, for writes inside the same millisecond
21
+ * 3. clientId, lexicographically
22
+ *
23
+ * Step 3 is what makes this a *total* order. Without it two devices could produce genuinely equal
24
+ * stamps and the winner would depend on evaluation order — different devices would converge to
25
+ * different documents, which is precisely the failure LWW is supposed to prevent.
26
+ *
27
+ * On an exact tie the server wins, because the server's copy is the one everyone else has already
28
+ * observed; preferring the client would make convergence depend on who pushed last.
29
+ */
30
+ export declare class LastWriteWinsStrategy<T extends Record<string, unknown>> implements ConflictStrategyHandler<T> {
31
+ readonly name = "last-write-wins";
32
+ resolve(ctx: ConflictContext<T>): Resolution<T>;
33
+ }
34
+ /**
35
+ * Server wins — the local change is discarded and the server's document adopted.
36
+ *
37
+ * `pushBack: false` matters: re-pushing a document the server just gave us would create an endless
38
+ * echo between the two.
39
+ */
40
+ export declare class ServerWinsStrategy<T extends Record<string, unknown>> implements ConflictStrategyHandler<T> {
41
+ readonly name = "server-wins";
42
+ resolve(ctx: ConflictContext<T>): Resolution<T>;
43
+ }
44
+ /**
45
+ * Client wins — the local change overwrites the server's.
46
+ *
47
+ * The loop hazard is real and is handled by the engine rather than here: the re-push carries
48
+ * `baseVersion = remoteVersion` (the version we just observed), so the server's optimistic check
49
+ * now passes instead of conflicting again forever. The engine also caps `conflictAttempts`.
50
+ */
51
+ export declare class ClientWinsStrategy<T extends Record<string, unknown>> implements ConflictStrategyHandler<T> {
52
+ readonly name = "client-wins";
53
+ resolve(ctx: ConflictContext<T>): Resolution<T>;
54
+ }
55
+ declare const DELETED: unique symbol;
56
+ /**
57
+ * Field-level three-way merge.
58
+ *
59
+ * Compares local and remote against their common ancestor (`base`, the last server-confirmed
60
+ * document kept in the shadow table). Paths only one side touched merge silently; paths both sides
61
+ * touched are a genuine conflict and fall to `fieldPolicy`.
62
+ *
63
+ * Documented edge cases, each with a test:
64
+ *
65
+ * - **No base.** Without an ancestor we cannot tell an edit from an insert, so a merge would be a
66
+ * guess. Falls back to last-write-wins rather than inventing a result.
67
+ * - **Arrays are atomic by default.** Element-wise merging of two concurrently reordered arrays
68
+ * has no correct answer in general. `arrayStrategy: "union-by-id"` opts into merging arrays of
69
+ * objects that carry `_id`/`id`.
70
+ * - **Deleted fields.** "Deleted on one side" is distinguished from "absent on both" by diffing
71
+ * against base — otherwise a deletion would be silently undone by the other side's copy.
72
+ * - **Type changes** (string -> object) are treated as an ordinary same-path conflict.
73
+ * - **Object replacement.** An edit at `a` conflicts with an edit at `a.b`: parent/child overlap is
74
+ * detected explicitly, because treating them as unrelated paths would resurrect a replaced object.
75
+ */
76
+ export declare class FieldLevelStrategy<T extends Record<string, unknown>> implements ConflictStrategyHandler<T> {
77
+ readonly name = "field-level";
78
+ private readonly policy;
79
+ private readonly arrayStrategy;
80
+ private readonly fallback;
81
+ constructor(config?: ConflictResolutionConfig<T>);
82
+ resolve(ctx: ConflictContext<T>): Resolution<T>;
83
+ private decide;
84
+ /** Opt-in array merging for arrays of objects with a stable identity. */
85
+ private mergeArraysById;
86
+ }
87
+ /**
88
+ * Custom resolver.
89
+ *
90
+ * The developer's function may return either a bare document (treated as the resolved value) or a
91
+ * full `Resolution` when it needs to control `pushBack`. A throwing resolver is *not* caught here —
92
+ * the engine parks the mutation and keeps draining the queue, so one bad resolver cannot wedge sync
93
+ * for every other document.
94
+ */
95
+ export declare class CustomStrategy<T extends Record<string, unknown>> implements ConflictStrategyHandler<T> {
96
+ readonly name = "custom";
97
+ private readonly resolver;
98
+ constructor(config: ConflictResolutionConfig<T>);
99
+ resolve(ctx: ConflictContext<T>): Promise<Resolution<T>>;
100
+ }
101
+ /** Registry — open for user-defined strategies (§11). */
102
+ export declare class ConflictStrategyRegistry<T extends Record<string, unknown> = Record<string, unknown>> {
103
+ private readonly strategies;
104
+ constructor(config?: ConflictResolutionConfig<T>);
105
+ register(strategy: ConflictStrategyHandler<T>): void;
106
+ get(name: string): ConflictStrategyHandler<T>;
107
+ names(): string[];
108
+ }
109
+ export { DELETED as FIELD_DELETED };
110
+ //# sourceMappingURL=strategies.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"strategies.d.ts","sourceRoot":"","sources":["../../../src/conflict/strategies.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,eAAe,EACf,wBAAwB,EACxB,oBAAoB,EAEpB,UAAU,EACX,MAAM,YAAY,CAAC;AAEpB;;;;;;GAMG;AACH,MAAM,WAAW,uBAAuB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAClG,QAAQ,CAAC,IAAI,EAAE,oBAAoB,GAAG,MAAM,CAAC;IAC7C,OAAO,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;CAC9E;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,qBAAqB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAE,YAAW,uBAAuB,CAAC,CAAC,CAAC;IACzG,QAAQ,CAAC,IAAI,qBAAqB;IAElC,OAAO,CAAC,GAAG,EAAE,eAAe,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC;CAKhD;AAED;;;;;GAKG;AACH,qBAAa,kBAAkB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAE,YAAW,uBAAuB,CAAC,CAAC,CAAC;IACtG,QAAQ,CAAC,IAAI,iBAAiB;IAE9B,OAAO,CAAC,GAAG,EAAE,eAAe,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC;CAGhD;AAED;;;;;;GAMG;AACH,qBAAa,kBAAkB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAE,YAAW,uBAAuB,CAAC,CAAC,CAAC;IACtG,QAAQ,CAAC,IAAI,iBAAiB;IAE9B,OAAO,CAAC,GAAG,EAAE,eAAe,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC;CAGhD;AAED,QAAA,MAAM,OAAO,eAAiC,CAAC;AAE/C;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,kBAAkB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAE,YAAW,uBAAuB,CAAC,CAAC,CAAC;IACtG,QAAQ,CAAC,IAAI,iBAAiB;IAC9B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA6C;IACpE,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA2B;IACzD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAkC;gBAE/C,MAAM,GAAE,wBAAwB,CAAC,CAAC,CAAM;IAKpD,OAAO,CAAC,GAAG,EAAE,eAAe,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC;IAsD/C,OAAO,CAAC,MAAM;IAMd,yEAAyE;IACzE,OAAO,CAAC,eAAe;CA+BxB;AAED;;;;;;;GAOG;AACH,qBAAa,cAAc,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAE,YAAW,uBAAuB,CAAC,CAAC,CAAC;IAClG,QAAQ,CAAC,IAAI,YAAY;IACzB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAuD;gBAEpE,MAAM,EAAE,wBAAwB,CAAC,CAAC,CAAC;IAUzC,OAAO,CAAC,GAAG,EAAE,eAAe,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;CAc/D;AAED,yDAAyD;AACzD,qBAAa,wBAAwB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAC/F,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAiD;gBAEhE,MAAM,GAAE,wBAAwB,CAAC,CAAC,CAAM;IAUpD,QAAQ,CAAC,QAAQ,EAAE,uBAAuB,CAAC,CAAC,CAAC,GAAG,IAAI;IAIpD,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,uBAAuB,CAAC,CAAC,CAAC;IAU7C,KAAK,IAAI,MAAM,EAAE;CAGlB;AAmED,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,CAAC"}
@@ -0,0 +1,298 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FIELD_DELETED = exports.ConflictStrategyRegistry = exports.CustomStrategy = exports.FieldLevelStrategy = exports.ClientWinsStrategy = exports.ServerWinsStrategy = exports.LastWriteWinsStrategy = void 0;
4
+ const hlc_ts_1 = require("../core/hlc.js");
5
+ const path_ts_1 = require("../query/path.js");
6
+ /**
7
+ * Last write wins — the default.
8
+ *
9
+ * "Latest" is decided by the hybrid logical clock, never by raw device wall-clock strings. The
10
+ * comparison order is documented in SYNC_PROTOCOL.md:
11
+ *
12
+ * 1. HLC physical time (already skew-corrected against the server)
13
+ * 2. HLC logical counter, for writes inside the same millisecond
14
+ * 3. clientId, lexicographically
15
+ *
16
+ * Step 3 is what makes this a *total* order. Without it two devices could produce genuinely equal
17
+ * stamps and the winner would depend on evaluation order — different devices would converge to
18
+ * different documents, which is precisely the failure LWW is supposed to prevent.
19
+ *
20
+ * On an exact tie the server wins, because the server's copy is the one everyone else has already
21
+ * observed; preferring the client would make convergence depend on who pushed last.
22
+ */
23
+ class LastWriteWinsStrategy {
24
+ constructor() {
25
+ this.name = "last-write-wins";
26
+ }
27
+ resolve(ctx) {
28
+ const cmp = (0, hlc_ts_1.compareHlcStamps)(ctx.localHlc, ctx.remoteHlc);
29
+ if (cmp > 0)
30
+ return { winner: "local", document: ctx.local, pushBack: true };
31
+ return { winner: "remote", document: ctx.remote, pushBack: false };
32
+ }
33
+ }
34
+ exports.LastWriteWinsStrategy = LastWriteWinsStrategy;
35
+ /**
36
+ * Server wins — the local change is discarded and the server's document adopted.
37
+ *
38
+ * `pushBack: false` matters: re-pushing a document the server just gave us would create an endless
39
+ * echo between the two.
40
+ */
41
+ class ServerWinsStrategy {
42
+ constructor() {
43
+ this.name = "server-wins";
44
+ }
45
+ resolve(ctx) {
46
+ return { winner: "remote", document: ctx.remote, pushBack: false };
47
+ }
48
+ }
49
+ exports.ServerWinsStrategy = ServerWinsStrategy;
50
+ /**
51
+ * Client wins — the local change overwrites the server's.
52
+ *
53
+ * The loop hazard is real and is handled by the engine rather than here: the re-push carries
54
+ * `baseVersion = remoteVersion` (the version we just observed), so the server's optimistic check
55
+ * now passes instead of conflicting again forever. The engine also caps `conflictAttempts`.
56
+ */
57
+ class ClientWinsStrategy {
58
+ constructor() {
59
+ this.name = "client-wins";
60
+ }
61
+ resolve(ctx) {
62
+ return { winner: "local", document: ctx.local, pushBack: true };
63
+ }
64
+ }
65
+ exports.ClientWinsStrategy = ClientWinsStrategy;
66
+ const DELETED = Symbol("anchor.field.deleted");
67
+ exports.FIELD_DELETED = DELETED;
68
+ /**
69
+ * Field-level three-way merge.
70
+ *
71
+ * Compares local and remote against their common ancestor (`base`, the last server-confirmed
72
+ * document kept in the shadow table). Paths only one side touched merge silently; paths both sides
73
+ * touched are a genuine conflict and fall to `fieldPolicy`.
74
+ *
75
+ * Documented edge cases, each with a test:
76
+ *
77
+ * - **No base.** Without an ancestor we cannot tell an edit from an insert, so a merge would be a
78
+ * guess. Falls back to last-write-wins rather than inventing a result.
79
+ * - **Arrays are atomic by default.** Element-wise merging of two concurrently reordered arrays
80
+ * has no correct answer in general. `arrayStrategy: "union-by-id"` opts into merging arrays of
81
+ * objects that carry `_id`/`id`.
82
+ * - **Deleted fields.** "Deleted on one side" is distinguished from "absent on both" by diffing
83
+ * against base — otherwise a deletion would be silently undone by the other side's copy.
84
+ * - **Type changes** (string -> object) are treated as an ordinary same-path conflict.
85
+ * - **Object replacement.** An edit at `a` conflicts with an edit at `a.b`: parent/child overlap is
86
+ * detected explicitly, because treating them as unrelated paths would resurrect a replaced object.
87
+ */
88
+ class FieldLevelStrategy {
89
+ constructor(config = {}) {
90
+ this.name = "field-level";
91
+ this.fallback = new LastWriteWinsStrategy();
92
+ this.policy = config.fieldPolicy ?? "lww";
93
+ this.arrayStrategy = config.arrayStrategy ?? "atomic";
94
+ }
95
+ resolve(ctx) {
96
+ if (!ctx.base) {
97
+ // Honest degradation: a "merge" without an ancestor is a guess dressed up as a decision.
98
+ return this.fallback.resolve(ctx);
99
+ }
100
+ const base = ctx.base;
101
+ const local = ctx.local;
102
+ const remote = ctx.remote;
103
+ const localChanges = diff(base, local);
104
+ const remoteChanges = diff(base, remote);
105
+ const merged = (0, path_ts_1.deepClone)(remote);
106
+ const conflicts = [];
107
+ let tookLocal = false;
108
+ for (const [path, localValue] of localChanges) {
109
+ const remoteValue = remoteChanges.get(path);
110
+ const overlaps = remoteChanges.has(path) || hasAncestorOrDescendant(path, remoteChanges);
111
+ if (!overlaps) {
112
+ // Only the client touched this path — apply it on top of the server document.
113
+ applyChange(merged, path, localValue);
114
+ tookLocal = true;
115
+ continue;
116
+ }
117
+ if (remoteChanges.has(path) && (0, path_ts_1.valuesEqual)(localValue, remoteValue)) {
118
+ continue; // both sides made the same edit; nothing to decide
119
+ }
120
+ conflicts.push(path);
121
+ const decision = this.decide(path, ctx);
122
+ if (decision === "client") {
123
+ applyChange(merged, path, localValue);
124
+ tookLocal = true;
125
+ }
126
+ // "server" needs no action: `merged` started as the remote document.
127
+ }
128
+ if (this.arrayStrategy === "union-by-id") {
129
+ this.mergeArraysById(base, local, remote, merged);
130
+ }
131
+ return {
132
+ winner: tookLocal ? "merged" : "remote",
133
+ document: merged,
134
+ // Only push back when the merge actually contains something the server has not seen.
135
+ pushBack: tookLocal,
136
+ ...(conflicts.length > 0 ? { conflictedPaths: conflicts } : {}),
137
+ };
138
+ }
139
+ decide(path, ctx) {
140
+ const policy = typeof this.policy === "function" ? this.policy(path, ctx) : (this.policy ?? "lww");
141
+ if (policy !== "lww")
142
+ return policy;
143
+ return (0, hlc_ts_1.compareHlcStamps)(ctx.localHlc, ctx.remoteHlc) > 0 ? "client" : "server";
144
+ }
145
+ /** Opt-in array merging for arrays of objects with a stable identity. */
146
+ mergeArraysById(base, local, remote, merged) {
147
+ for (const key of new Set([...Object.keys(local), ...Object.keys(remote)])) {
148
+ const l = local[key];
149
+ const r = remote[key];
150
+ if (!Array.isArray(l) || !Array.isArray(r))
151
+ continue;
152
+ if (!l.every(hasIdentity) || !r.every(hasIdentity))
153
+ continue;
154
+ const baseArr = Array.isArray(base[key]) ? base[key] : [];
155
+ const baseIds = new Set(baseArr.map(identityOf));
156
+ const byId = new Map();
157
+ for (const item of r)
158
+ byId.set(identityOf(item), item);
159
+ for (const item of l) {
160
+ const id = identityOf(item);
161
+ // Added locally, or edited locally — local wins for that element.
162
+ if (!baseIds.has(id) || !(0, path_ts_1.valuesEqual)(item, baseArr.find((b) => identityOf(b) === id))) {
163
+ byId.set(id, item);
164
+ }
165
+ }
166
+ // Removed on either side stays removed.
167
+ const removedLocally = baseArr.filter((b) => !l.some((x) => identityOf(x) === identityOf(b)));
168
+ for (const gone of removedLocally)
169
+ byId.delete(identityOf(gone));
170
+ merged[key] = [...byId.values()];
171
+ }
172
+ }
173
+ }
174
+ exports.FieldLevelStrategy = FieldLevelStrategy;
175
+ /**
176
+ * Custom resolver.
177
+ *
178
+ * The developer's function may return either a bare document (treated as the resolved value) or a
179
+ * full `Resolution` when it needs to control `pushBack`. A throwing resolver is *not* caught here —
180
+ * the engine parks the mutation and keeps draining the queue, so one bad resolver cannot wedge sync
181
+ * for every other document.
182
+ */
183
+ class CustomStrategy {
184
+ constructor(config) {
185
+ this.name = "custom";
186
+ if (!config.resolver) {
187
+ throw new Error('conflictResolution.strategy is "custom" but no `resolver` was provided. ' +
188
+ "Pass resolver: async ({ local, remote, base }) => {...}");
189
+ }
190
+ this.resolver = config.resolver;
191
+ }
192
+ async resolve(ctx) {
193
+ const result = await this.resolver(ctx);
194
+ if (result && typeof result === "object" && "winner" in result && "document" in result) {
195
+ return result;
196
+ }
197
+ const document = result;
198
+ // Infer the winner so events and Lens can report something meaningful.
199
+ const winner = (0, path_ts_1.valuesEqual)(document, ctx.remote)
200
+ ? "remote"
201
+ : (0, path_ts_1.valuesEqual)(document, ctx.local)
202
+ ? "local"
203
+ : "merged";
204
+ return { winner, document, pushBack: winner !== "remote" };
205
+ }
206
+ }
207
+ exports.CustomStrategy = CustomStrategy;
208
+ /** Registry — open for user-defined strategies (§11). */
209
+ class ConflictStrategyRegistry {
210
+ constructor(config = {}) {
211
+ this.strategies = new Map();
212
+ this.register(new LastWriteWinsStrategy());
213
+ this.register(new ServerWinsStrategy());
214
+ this.register(new ClientWinsStrategy());
215
+ this.register(new FieldLevelStrategy(config));
216
+ if (config.strategy === "custom" || config.resolver) {
217
+ this.register(new CustomStrategy(config));
218
+ }
219
+ }
220
+ register(strategy) {
221
+ this.strategies.set(strategy.name, strategy);
222
+ }
223
+ get(name) {
224
+ const found = this.strategies.get(name);
225
+ if (!found) {
226
+ throw new Error(`Unknown conflict strategy "${name}". Available: ${[...this.strategies.keys()].join(", ")}.`);
227
+ }
228
+ return found;
229
+ }
230
+ names() {
231
+ return [...this.strategies.keys()];
232
+ }
233
+ }
234
+ exports.ConflictStrategyRegistry = ConflictStrategyRegistry;
235
+ // ---- diffing helpers -------------------------------------------------------
236
+ /**
237
+ * Leaf-path diff of `next` against `prev`.
238
+ *
239
+ * Deletions are recorded explicitly with a sentinel rather than omitted, because "absent from the
240
+ * diff" and "deleted by this side" must not be confused — conflating them silently undoes deletions.
241
+ */
242
+ function diff(prev, next) {
243
+ const out = new Map();
244
+ const prevPaths = (0, path_ts_1.flattenPaths)(prev);
245
+ const nextPaths = (0, path_ts_1.flattenPaths)(next);
246
+ for (const [path, value] of nextPaths) {
247
+ if (isInternal(path))
248
+ continue;
249
+ if (!prevPaths.has(path) || !(0, path_ts_1.valuesEqual)(prevPaths.get(path), value))
250
+ out.set(path, value);
251
+ }
252
+ for (const [path] of prevPaths) {
253
+ if (isInternal(path))
254
+ continue;
255
+ if (!nextPaths.has(path))
256
+ out.set(path, DELETED);
257
+ }
258
+ return out;
259
+ }
260
+ /** `updatedAt` and the version key always differ; treating them as edits would conflict every time. */
261
+ function isInternal(path) {
262
+ const head = path.split(".")[0];
263
+ return head === "_id" || head === "updatedAt" || head === "__v" || head === "_sync";
264
+ }
265
+ function applyChange(target, path, value) {
266
+ if (value === DELETED) {
267
+ const parts = path.split(".");
268
+ const last = parts.pop();
269
+ const parent = parts.length ? (0, path_ts_1.getPath)(target, parts.join(".")) : target;
270
+ if (parent && typeof parent === "object")
271
+ delete parent[last];
272
+ return;
273
+ }
274
+ (0, path_ts_1.setPath)(target, path, value);
275
+ }
276
+ /** `a` conflicts with `a.b`: replacing an object and editing inside it are not independent. */
277
+ function hasAncestorOrDescendant(path, others) {
278
+ for (const other of others.keys()) {
279
+ if (other === path)
280
+ continue;
281
+ if (other.startsWith(`${path}.`) || path.startsWith(`${other}.`))
282
+ return true;
283
+ }
284
+ return false;
285
+ }
286
+ function hasIdentity(item) {
287
+ return (item !== null &&
288
+ typeof item === "object" &&
289
+ !Array.isArray(item) &&
290
+ (("_id" in item) || ("id" in item)));
291
+ }
292
+ function identityOf(item) {
293
+ if (item === null || typeof item !== "object")
294
+ return item;
295
+ const rec = item;
296
+ return String(rec._id ?? rec.id);
297
+ }
298
+ //# sourceMappingURL=strategies.js.map