@fragno-dev/db 0.2.2 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (587) hide show
  1. package/.turbo/turbo-build.log +404 -175
  2. package/CHANGELOG.md +109 -0
  3. package/README.md +54 -9
  4. package/dist/adapters/adapters.d.ts +23 -21
  5. package/dist/adapters/adapters.d.ts.map +1 -1
  6. package/dist/adapters/adapters.js.map +1 -1
  7. package/dist/adapters/generic-sql/driver-config.d.ts +16 -1
  8. package/dist/adapters/generic-sql/driver-config.d.ts.map +1 -1
  9. package/dist/adapters/generic-sql/driver-config.js +23 -1
  10. package/dist/adapters/generic-sql/driver-config.js.map +1 -1
  11. package/dist/adapters/generic-sql/generic-sql-adapter.d.ts +24 -9
  12. package/dist/adapters/generic-sql/generic-sql-adapter.d.ts.map +1 -1
  13. package/dist/adapters/generic-sql/generic-sql-adapter.js +60 -22
  14. package/dist/adapters/generic-sql/generic-sql-adapter.js.map +1 -1
  15. package/dist/adapters/generic-sql/generic-sql-uow-executor.js +169 -3
  16. package/dist/adapters/generic-sql/generic-sql-uow-executor.js.map +1 -1
  17. package/dist/adapters/generic-sql/migration/cold-kysely.js.map +1 -1
  18. package/dist/adapters/generic-sql/migration/dialect/mysql.js +25 -6
  19. package/dist/adapters/generic-sql/migration/dialect/mysql.js.map +1 -1
  20. package/dist/adapters/generic-sql/migration/dialect/postgres.js +7 -6
  21. package/dist/adapters/generic-sql/migration/dialect/postgres.js.map +1 -1
  22. package/dist/adapters/generic-sql/migration/dialect/sqlite.js +193 -16
  23. package/dist/adapters/generic-sql/migration/dialect/sqlite.js.map +1 -1
  24. package/dist/adapters/generic-sql/migration/executor.d.ts.map +1 -1
  25. package/dist/adapters/generic-sql/migration/executor.js +30 -3
  26. package/dist/adapters/generic-sql/migration/executor.js.map +1 -1
  27. package/dist/adapters/generic-sql/migration/prepared-migrations.d.ts.map +1 -1
  28. package/dist/adapters/generic-sql/migration/prepared-migrations.js +9 -9
  29. package/dist/adapters/generic-sql/migration/prepared-migrations.js.map +1 -1
  30. package/dist/adapters/generic-sql/migration/sql-generator.js +75 -52
  31. package/dist/adapters/generic-sql/migration/sql-generator.js.map +1 -1
  32. package/dist/adapters/generic-sql/query/create-sql-query-compiler.js +7 -6
  33. package/dist/adapters/generic-sql/query/create-sql-query-compiler.js.map +1 -1
  34. package/dist/adapters/generic-sql/query/cursor-utils.js +42 -4
  35. package/dist/adapters/generic-sql/query/cursor-utils.js.map +1 -1
  36. package/dist/adapters/generic-sql/query/db-now-sql.js +27 -0
  37. package/dist/adapters/generic-sql/query/db-now-sql.js.map +1 -0
  38. package/dist/adapters/generic-sql/query/generic-sql-uow-operation-compiler.js +32 -21
  39. package/dist/adapters/generic-sql/query/generic-sql-uow-operation-compiler.js.map +1 -1
  40. package/dist/adapters/generic-sql/query/select-builder.js +5 -3
  41. package/dist/adapters/generic-sql/query/select-builder.js.map +1 -1
  42. package/dist/adapters/generic-sql/query/sql-query-compiler.js +49 -18
  43. package/dist/adapters/generic-sql/query/sql-query-compiler.js.map +1 -1
  44. package/dist/adapters/generic-sql/query/where-builder.js +43 -29
  45. package/dist/adapters/generic-sql/query/where-builder.js.map +1 -1
  46. package/dist/adapters/generic-sql/sqlite-storage.d.ts +13 -0
  47. package/dist/adapters/generic-sql/sqlite-storage.d.ts.map +1 -0
  48. package/dist/adapters/generic-sql/sqlite-storage.js +15 -0
  49. package/dist/adapters/generic-sql/sqlite-storage.js.map +1 -0
  50. package/dist/adapters/generic-sql/uow-decoder.js +6 -2
  51. package/dist/adapters/generic-sql/uow-decoder.js.map +1 -1
  52. package/dist/adapters/generic-sql/uow-encoder.js +27 -8
  53. package/dist/adapters/generic-sql/uow-encoder.js.map +1 -1
  54. package/dist/adapters/in-memory/condition-evaluator.js +135 -0
  55. package/dist/adapters/in-memory/condition-evaluator.js.map +1 -0
  56. package/dist/adapters/in-memory/errors.d.ts +13 -0
  57. package/dist/adapters/in-memory/errors.d.ts.map +1 -0
  58. package/dist/adapters/in-memory/errors.js +23 -0
  59. package/dist/adapters/in-memory/errors.js.map +1 -0
  60. package/dist/adapters/in-memory/in-memory-adapter.d.ts +27 -0
  61. package/dist/adapters/in-memory/in-memory-adapter.d.ts.map +1 -0
  62. package/dist/adapters/in-memory/in-memory-adapter.js +196 -0
  63. package/dist/adapters/in-memory/in-memory-adapter.js.map +1 -0
  64. package/dist/adapters/in-memory/in-memory-uow.js +871 -0
  65. package/dist/adapters/in-memory/in-memory-uow.js.map +1 -0
  66. package/dist/adapters/in-memory/index.d.ts +4 -0
  67. package/dist/adapters/in-memory/index.js +4 -0
  68. package/dist/adapters/in-memory/options.d.ts +30 -0
  69. package/dist/adapters/in-memory/options.d.ts.map +1 -0
  70. package/dist/adapters/in-memory/options.js +62 -0
  71. package/dist/adapters/in-memory/options.js.map +1 -0
  72. package/dist/adapters/in-memory/reference-resolution.js +26 -0
  73. package/dist/adapters/in-memory/reference-resolution.js.map +1 -0
  74. package/dist/adapters/in-memory/sorted-array-index.js +129 -0
  75. package/dist/adapters/in-memory/sorted-array-index.js.map +1 -0
  76. package/dist/adapters/in-memory/store.js +71 -0
  77. package/dist/adapters/in-memory/store.js.map +1 -0
  78. package/dist/adapters/in-memory/value-comparison.js +28 -0
  79. package/dist/adapters/in-memory/value-comparison.js.map +1 -0
  80. package/dist/adapters/shared/from-unit-of-work-compiler.js +51 -24
  81. package/dist/adapters/shared/from-unit-of-work-compiler.js.map +1 -1
  82. package/dist/adapters/shared/uow-operation-compiler.js +11 -11
  83. package/dist/adapters/shared/uow-operation-compiler.js.map +1 -1
  84. package/dist/adapters/sql/index.d.ts +5 -0
  85. package/dist/adapters/sql/index.js +4 -0
  86. package/dist/browser/adapters/adapters.d.ts +61 -0
  87. package/dist/browser/adapters/adapters.d.ts.map +1 -0
  88. package/dist/browser/adapters/generic-sql/migration/executor.d.ts +15 -0
  89. package/dist/browser/adapters/generic-sql/migration/executor.d.ts.map +1 -0
  90. package/dist/browser/adapters/generic-sql/migration/prepared-migrations.d.ts +66 -0
  91. package/dist/browser/adapters/generic-sql/migration/prepared-migrations.d.ts.map +1 -0
  92. package/dist/browser/adapters/generic-sql/sqlite-storage.d.ts +11 -0
  93. package/dist/browser/adapters/generic-sql/sqlite-storage.d.ts.map +1 -0
  94. package/dist/browser/adapters/in-memory/in-memory-adapter.d.ts +5 -0
  95. package/dist/browser/adapters/in-memory/index.d.ts +2 -0
  96. package/dist/browser/adapters/in-memory/options.d.ts +1 -0
  97. package/dist/browser/db-fragment-definition-builder.d.ts +237 -0
  98. package/dist/browser/db-fragment-definition-builder.d.ts.map +1 -0
  99. package/dist/browser/durable-hooks.d.ts +3 -0
  100. package/dist/browser/fragments/internal-fragment.d.ts +317 -0
  101. package/dist/browser/fragments/internal-fragment.d.ts.map +1 -0
  102. package/dist/browser/fragments/internal-fragment.schema.d.ts +1 -0
  103. package/dist/browser/hooks/durable-hooks-logger.d.ts +10 -0
  104. package/dist/browser/hooks/durable-hooks-logger.d.ts.map +1 -0
  105. package/dist/browser/hooks/hooks.d.ts +146 -0
  106. package/dist/browser/hooks/hooks.d.ts.map +1 -0
  107. package/dist/browser/id.js +1 -0
  108. package/dist/browser/internal/adapter-registry.d.ts +4 -0
  109. package/dist/browser/internal/outbox-state.d.ts +2 -0
  110. package/dist/browser/mod.d.ts +15 -0
  111. package/dist/browser/mod.d.ts.map +1 -0
  112. package/dist/browser/mod.js +17 -0
  113. package/dist/browser/mod.js.map +1 -0
  114. package/dist/browser/mod2.d.ts +48 -0
  115. package/dist/browser/mod2.d.ts.map +1 -0
  116. package/dist/browser/naming/sql-naming.d.ts +19 -0
  117. package/dist/browser/naming/sql-naming.d.ts.map +1 -0
  118. package/dist/browser/outbox/outbox.d.ts +21 -0
  119. package/dist/browser/outbox/outbox.d.ts.map +1 -0
  120. package/dist/browser/query/column-defaults.js +1 -0
  121. package/dist/browser/query/condition-builder.d.ts +44 -0
  122. package/dist/browser/query/condition-builder.d.ts.map +1 -0
  123. package/dist/browser/query/condition-builder.js +97 -0
  124. package/dist/browser/query/condition-builder.js.map +1 -0
  125. package/dist/browser/query/cursor.d.ts +105 -0
  126. package/dist/browser/query/cursor.d.ts.map +1 -0
  127. package/dist/browser/query/cursor.js +150 -0
  128. package/dist/browser/query/cursor.js.map +1 -0
  129. package/dist/browser/query/db-now.d.ts +22 -0
  130. package/dist/browser/query/db-now.d.ts.map +1 -0
  131. package/dist/browser/query/db-now.js +33 -0
  132. package/dist/browser/query/db-now.js.map +1 -0
  133. package/dist/browser/query/orm/orm.d.ts +18 -0
  134. package/dist/browser/query/orm/orm.d.ts.map +1 -0
  135. package/dist/browser/query/simple-query-interface.d.ts +108 -0
  136. package/dist/browser/query/simple-query-interface.d.ts.map +1 -0
  137. package/dist/browser/query/unit-of-work/execute-unit-of-work.d.ts +423 -0
  138. package/dist/browser/query/unit-of-work/execute-unit-of-work.d.ts.map +1 -0
  139. package/dist/browser/query/unit-of-work/execute-unit-of-work.js +507 -0
  140. package/dist/browser/query/unit-of-work/execute-unit-of-work.js.map +1 -0
  141. package/dist/browser/query/unit-of-work/retry-policy.d.ts +23 -0
  142. package/dist/browser/query/unit-of-work/retry-policy.d.ts.map +1 -0
  143. package/dist/browser/query/unit-of-work/retry-policy.js +40 -0
  144. package/dist/browser/query/unit-of-work/retry-policy.js.map +1 -0
  145. package/dist/browser/query/unit-of-work/unit-of-work.d.ts +703 -0
  146. package/dist/browser/query/unit-of-work/unit-of-work.d.ts.map +1 -0
  147. package/dist/browser/query/unit-of-work/unit-of-work.js +1206 -0
  148. package/dist/browser/query/unit-of-work/unit-of-work.js.map +1 -0
  149. package/dist/browser/query/value-encoding.js +38 -0
  150. package/dist/browser/query/value-encoding.js.map +1 -0
  151. package/dist/browser/schema/create.d.ts +326 -0
  152. package/dist/browser/schema/create.d.ts.map +1 -0
  153. package/dist/browser/schema/create.js +89 -0
  154. package/dist/browser/schema/create.js.map +1 -0
  155. package/dist/browser/schema/generate-id.js +28 -0
  156. package/dist/browser/schema/generate-id.js.map +1 -0
  157. package/dist/browser/shared/providers.d.ts +6 -0
  158. package/dist/browser/shared/providers.d.ts.map +1 -0
  159. package/dist/browser/sql-driver/connection/connection-provider.d.ts +13 -0
  160. package/dist/browser/sql-driver/connection/connection-provider.d.ts.map +1 -0
  161. package/dist/browser/sql-driver/dialect-adapter/dialect-adapter.d.ts +7 -0
  162. package/dist/browser/sql-driver/dialect-adapter/dialect-adapter.d.ts.map +1 -0
  163. package/dist/browser/sql-driver/driver/runtime-driver.d.ts +23 -0
  164. package/dist/browser/sql-driver/driver/runtime-driver.d.ts.map +1 -0
  165. package/dist/browser/sql-driver/query-executor/plugin.d.ts +17 -0
  166. package/dist/browser/sql-driver/query-executor/plugin.d.ts.map +1 -0
  167. package/dist/browser/sql-driver/query-executor/query-executor.d.ts +36 -0
  168. package/dist/browser/sql-driver/query-executor/query-executor.d.ts.map +1 -0
  169. package/dist/browser/sql-driver/sql-driver-adapter.d.ts +29 -0
  170. package/dist/browser/sql-driver/sql-driver-adapter.d.ts.map +1 -0
  171. package/dist/browser/sql-driver/sql-driver.d.ts +38 -0
  172. package/dist/browser/sql-driver/sql-driver.d.ts.map +1 -0
  173. package/dist/browser/sync/commands.d.ts +15 -0
  174. package/dist/browser/sync/commands.d.ts.map +1 -0
  175. package/dist/browser/sync/commands.js +27 -0
  176. package/dist/browser/sync/commands.js.map +1 -0
  177. package/dist/browser/sync/types.d.ts +63 -0
  178. package/dist/browser/sync/types.d.ts.map +1 -0
  179. package/dist/browser/util/types.d.ts +8 -0
  180. package/dist/browser/util/types.d.ts.map +1 -0
  181. package/dist/browser/with-database.d.ts +29 -0
  182. package/dist/browser/with-database.d.ts.map +1 -0
  183. package/dist/client.d.ts +4 -0
  184. package/dist/client.js +5 -0
  185. package/dist/db-fragment-definition-builder.d.ts +101 -33
  186. package/dist/db-fragment-definition-builder.d.ts.map +1 -1
  187. package/dist/db-fragment-definition-builder.js +450 -60
  188. package/dist/db-fragment-definition-builder.js.map +1 -1
  189. package/dist/dispatchers/cloudflare-do/dispatcher.d.ts +20 -0
  190. package/dist/dispatchers/cloudflare-do/dispatcher.d.ts.map +1 -0
  191. package/dist/dispatchers/cloudflare-do/dispatcher.js +147 -0
  192. package/dist/dispatchers/cloudflare-do/dispatcher.js.map +1 -0
  193. package/dist/dispatchers/cloudflare-do/index.d.ts +11 -0
  194. package/dist/dispatchers/cloudflare-do/index.d.ts.map +1 -0
  195. package/dist/dispatchers/cloudflare-do/index.js +31 -0
  196. package/dist/dispatchers/cloudflare-do/index.js.map +1 -0
  197. package/dist/dispatchers/node/dispatcher.d.ts +14 -0
  198. package/dist/dispatchers/node/dispatcher.d.ts.map +1 -0
  199. package/dist/dispatchers/node/dispatcher.js +80 -0
  200. package/dist/dispatchers/node/dispatcher.js.map +1 -0
  201. package/dist/dispatchers/node/index.d.ts +12 -0
  202. package/dist/dispatchers/node/index.d.ts.map +1 -0
  203. package/dist/dispatchers/node/index.js +27 -0
  204. package/dist/dispatchers/node/index.js.map +1 -0
  205. package/dist/durable-hooks.d.ts +31 -0
  206. package/dist/durable-hooks.d.ts.map +1 -0
  207. package/dist/durable-hooks.js +23 -0
  208. package/dist/durable-hooks.js.map +1 -0
  209. package/dist/fragments/internal-fragment.d.ts +186 -8
  210. package/dist/fragments/internal-fragment.d.ts.map +1 -1
  211. package/dist/fragments/internal-fragment.js +203 -38
  212. package/dist/fragments/internal-fragment.js.map +1 -1
  213. package/dist/fragments/internal-fragment.routes.js +164 -0
  214. package/dist/fragments/internal-fragment.routes.js.map +1 -0
  215. package/dist/fragments/internal-fragment.schema.d.ts +15 -0
  216. package/dist/fragments/internal-fragment.schema.d.ts.map +1 -0
  217. package/dist/fragments/internal-fragment.schema.js +39 -0
  218. package/dist/fragments/internal-fragment.schema.js.map +1 -0
  219. package/dist/hooks/durable-hooks-logger.d.ts +10 -0
  220. package/dist/hooks/durable-hooks-logger.d.ts.map +1 -0
  221. package/dist/hooks/durable-hooks-logger.js +75 -0
  222. package/dist/hooks/durable-hooks-logger.js.map +1 -0
  223. package/dist/hooks/durable-hooks-processor.d.ts +1 -0
  224. package/dist/hooks/durable-hooks-processor.js +80 -0
  225. package/dist/hooks/durable-hooks-processor.js.map +1 -0
  226. package/dist/hooks/durable-hooks-runtime.js +44 -0
  227. package/dist/hooks/durable-hooks-runtime.js.map +1 -0
  228. package/dist/hooks/hooks.d.ts +100 -1
  229. package/dist/hooks/hooks.d.ts.map +1 -1
  230. package/dist/hooks/hooks.js +254 -27
  231. package/dist/hooks/hooks.js.map +1 -1
  232. package/dist/id.d.ts +2 -2
  233. package/dist/id.js +2 -2
  234. package/dist/internal/adapter-registry.d.ts +11 -0
  235. package/dist/internal/adapter-registry.d.ts.map +1 -0
  236. package/dist/internal/adapter-registry.js +135 -0
  237. package/dist/internal/adapter-registry.js.map +1 -0
  238. package/dist/internal/outbox-state.d.ts +2 -0
  239. package/dist/internal/outbox-state.js +26 -0
  240. package/dist/internal/outbox-state.js.map +1 -0
  241. package/dist/migration-engine/auto-from-schema.d.ts +33 -0
  242. package/dist/migration-engine/auto-from-schema.d.ts.map +1 -0
  243. package/dist/migration-engine/auto-from-schema.js +223 -37
  244. package/dist/migration-engine/auto-from-schema.js.map +1 -1
  245. package/dist/migration-engine/generation-engine.d.ts +16 -10
  246. package/dist/migration-engine/generation-engine.d.ts.map +1 -1
  247. package/dist/migration-engine/generation-engine.js +86 -35
  248. package/dist/migration-engine/generation-engine.js.map +1 -1
  249. package/dist/migration-engine/shared.d.ts +113 -0
  250. package/dist/migration-engine/shared.d.ts.map +1 -0
  251. package/dist/migration-engine/shared.js.map +1 -1
  252. package/dist/mod.d.ts +20 -12
  253. package/dist/mod.d.ts.map +1 -1
  254. package/dist/mod.js +18 -12
  255. package/dist/mod.js.map +1 -1
  256. package/dist/naming/sql-naming.d.ts +19 -0
  257. package/dist/naming/sql-naming.d.ts.map +1 -0
  258. package/dist/naming/sql-naming.js +116 -0
  259. package/dist/naming/sql-naming.js.map +1 -0
  260. package/dist/outbox/outbox-builder.js +156 -0
  261. package/dist/outbox/outbox-builder.js.map +1 -0
  262. package/dist/outbox/outbox.d.ts +54 -0
  263. package/dist/outbox/outbox.d.ts.map +1 -0
  264. package/dist/outbox/outbox.js +37 -0
  265. package/dist/outbox/outbox.js.map +1 -0
  266. package/dist/query/column-defaults.js +20 -4
  267. package/dist/query/column-defaults.js.map +1 -1
  268. package/dist/query/condition-builder.d.ts +7 -1
  269. package/dist/query/condition-builder.d.ts.map +1 -1
  270. package/dist/query/condition-builder.js +5 -1
  271. package/dist/query/condition-builder.js.map +1 -1
  272. package/dist/query/cursor-client.d.ts +105 -0
  273. package/dist/query/cursor-client.d.ts.map +1 -0
  274. package/dist/query/cursor-client.js +165 -0
  275. package/dist/query/cursor-client.js.map +1 -0
  276. package/dist/query/cursor.d.ts +3 -1
  277. package/dist/query/cursor.d.ts.map +1 -1
  278. package/dist/query/cursor.js +51 -14
  279. package/dist/query/cursor.js.map +1 -1
  280. package/dist/query/db-now.d.ts +22 -0
  281. package/dist/query/db-now.d.ts.map +1 -0
  282. package/dist/query/db-now.js +35 -0
  283. package/dist/query/db-now.js.map +1 -0
  284. package/dist/query/orm/orm.js.map +1 -1
  285. package/dist/query/serialize/create-sql-serializer.js +5 -4
  286. package/dist/query/serialize/create-sql-serializer.js.map +1 -1
  287. package/dist/query/serialize/dialect/mysql-serializer.js +12 -6
  288. package/dist/query/serialize/dialect/mysql-serializer.js.map +1 -1
  289. package/dist/query/serialize/dialect/postgres-serializer.js +25 -7
  290. package/dist/query/serialize/dialect/postgres-serializer.js.map +1 -1
  291. package/dist/query/serialize/dialect/sqlite-serializer.js +60 -12
  292. package/dist/query/serialize/dialect/sqlite-serializer.js.map +1 -1
  293. package/dist/query/serialize/sql-serializer.js +2 -2
  294. package/dist/query/serialize/sql-serializer.js.map +1 -1
  295. package/dist/query/simple-query-interface.d.ts +13 -4
  296. package/dist/query/simple-query-interface.d.ts.map +1 -1
  297. package/dist/query/unit-of-work/execute-unit-of-work.d.ts +37 -2
  298. package/dist/query/unit-of-work/execute-unit-of-work.d.ts.map +1 -1
  299. package/dist/query/unit-of-work/execute-unit-of-work.js +50 -24
  300. package/dist/query/unit-of-work/execute-unit-of-work.js.map +1 -1
  301. package/dist/query/unit-of-work/unit-of-work.d.ts +92 -30
  302. package/dist/query/unit-of-work/unit-of-work.d.ts.map +1 -1
  303. package/dist/query/unit-of-work/unit-of-work.js +136 -11
  304. package/dist/query/unit-of-work/unit-of-work.js.map +1 -1
  305. package/dist/query/value-decoding.js +16 -6
  306. package/dist/query/value-decoding.js.map +1 -1
  307. package/dist/query/value-encoding.js +29 -9
  308. package/dist/query/value-encoding.js.map +1 -1
  309. package/dist/schema/create.d.ts +103 -35
  310. package/dist/schema/create.d.ts.map +1 -1
  311. package/dist/schema/create.js +172 -58
  312. package/dist/schema/create.js.map +1 -1
  313. package/dist/schema/generate-id.js +2 -2
  314. package/dist/schema/generate-id.js.map +1 -1
  315. package/dist/schema/type-conversion/create-sql-type-mapper.js +4 -3
  316. package/dist/schema/type-conversion/create-sql-type-mapper.js.map +1 -1
  317. package/dist/schema/type-conversion/dialect/sqlite.js +9 -0
  318. package/dist/schema/type-conversion/dialect/sqlite.js.map +1 -1
  319. package/dist/schema/validator.d.ts +10 -0
  320. package/dist/schema/validator.d.ts.map +1 -0
  321. package/dist/schema/validator.js +123 -0
  322. package/dist/schema/validator.js.map +1 -0
  323. package/dist/schema-output/drizzle.d.ts +30 -0
  324. package/dist/schema-output/drizzle.d.ts.map +1 -0
  325. package/dist/{adapters/drizzle/generate.js → schema-output/drizzle.js} +88 -60
  326. package/dist/schema-output/drizzle.js.map +1 -0
  327. package/dist/schema-output/prisma.d.ts +17 -0
  328. package/dist/schema-output/prisma.d.ts.map +1 -0
  329. package/dist/schema-output/prisma.js +307 -0
  330. package/dist/schema-output/prisma.js.map +1 -0
  331. package/dist/sql-driver/dialects/durable-object-dialect.js +3 -9
  332. package/dist/sql-driver/dialects/durable-object-dialect.js.map +1 -1
  333. package/dist/sql-driver/query-executor/default-query-executor.js.map +1 -1
  334. package/dist/sql-driver/query-executor/query-executor-base.js.map +1 -1
  335. package/dist/sql-driver/sql-driver-adapter.js.map +1 -1
  336. package/dist/sql-driver/sql.js.map +1 -1
  337. package/dist/sync/commands.d.ts +15 -0
  338. package/dist/sync/commands.d.ts.map +1 -0
  339. package/dist/sync/commands.js +27 -0
  340. package/dist/sync/commands.js.map +1 -0
  341. package/dist/sync/index.d.ts +4 -0
  342. package/dist/sync/index.js +4 -0
  343. package/dist/sync/read-tracking.d.ts +25 -0
  344. package/dist/sync/read-tracking.d.ts.map +1 -0
  345. package/dist/sync/read-tracking.js +148 -0
  346. package/dist/sync/read-tracking.js.map +1 -0
  347. package/dist/sync/submit.js +213 -0
  348. package/dist/sync/submit.js.map +1 -0
  349. package/dist/sync/types.d.ts +63 -0
  350. package/dist/sync/types.d.ts.map +1 -0
  351. package/dist/util/default-database-adapter.js +66 -0
  352. package/dist/util/default-database-adapter.js.map +1 -0
  353. package/dist/with-database.d.ts +3 -6
  354. package/dist/with-database.d.ts.map +1 -1
  355. package/dist/with-database.js +8 -7
  356. package/dist/with-database.js.map +1 -1
  357. package/package.json +62 -55
  358. package/src/adapters/adapters.ts +33 -26
  359. package/src/adapters/drizzle/migrate-drizzle.test.ts +99 -41
  360. package/src/adapters/drizzle/migration-parity-drizzle-kit.test.ts +601 -0
  361. package/src/adapters/drizzle/test-utils.ts +13 -8
  362. package/src/adapters/generic-sql/driver-config.ts +38 -0
  363. package/src/adapters/generic-sql/generic-sql-adapter.test.ts +10 -8
  364. package/src/adapters/generic-sql/generic-sql-adapter.ts +117 -34
  365. package/src/adapters/generic-sql/generic-sql-uow-executor.test.ts +55 -0
  366. package/src/adapters/generic-sql/generic-sql-uow-executor.ts +297 -3
  367. package/src/adapters/generic-sql/migration/adapter-migration-parity.test.ts +120 -0
  368. package/src/adapters/generic-sql/migration/cold-kysely.ts +1 -0
  369. package/src/adapters/generic-sql/migration/dialect/mysql.test.ts +27 -8
  370. package/src/adapters/generic-sql/migration/dialect/mysql.ts +47 -8
  371. package/src/adapters/generic-sql/migration/dialect/postgres.test.ts +28 -9
  372. package/src/adapters/generic-sql/migration/dialect/postgres.ts +9 -4
  373. package/src/adapters/generic-sql/migration/dialect/sqlite.test.ts +839 -8
  374. package/src/adapters/generic-sql/migration/dialect/sqlite.ts +396 -53
  375. package/src/adapters/generic-sql/migration/executor.test.ts +52 -0
  376. package/src/adapters/generic-sql/migration/executor.ts +47 -4
  377. package/src/adapters/generic-sql/migration/prepared-migrations.test.ts +238 -46
  378. package/src/adapters/generic-sql/migration/prepared-migrations.ts +21 -13
  379. package/src/adapters/generic-sql/migration/sql-generator.ts +145 -66
  380. package/src/adapters/generic-sql/query/create-sql-query-compiler.ts +11 -8
  381. package/src/adapters/generic-sql/query/cursor-utils.test.ts +272 -0
  382. package/src/adapters/generic-sql/query/cursor-utils.ts +42 -7
  383. package/src/adapters/generic-sql/query/db-now-sql.ts +49 -0
  384. package/src/adapters/generic-sql/query/generic-sql-uow-operation-compiler.test.ts +171 -35
  385. package/src/adapters/generic-sql/query/generic-sql-uow-operation-compiler.ts +53 -40
  386. package/src/adapters/generic-sql/query/select-builder.test.ts +16 -11
  387. package/src/adapters/generic-sql/query/select-builder.ts +7 -3
  388. package/src/adapters/generic-sql/query/sql-query-compiler.test.ts +75 -6
  389. package/src/adapters/generic-sql/query/sql-query-compiler.ts +129 -24
  390. package/src/adapters/generic-sql/query/where-builder.test.ts +96 -20
  391. package/src/adapters/generic-sql/query/where-builder.ts +112 -41
  392. package/src/adapters/{kysely/kysely-adapter-pglite.test.ts → generic-sql/sql-adapter-pglite-migrations.test.ts} +11 -20
  393. package/src/adapters/generic-sql/sql-adapter-pglite-pagination.test.ts +851 -0
  394. package/src/adapters/{drizzle/drizzle-adapter-pglite.test.ts → generic-sql/sql-adapter-pglite-queries.test.ts} +18 -15
  395. package/src/adapters/generic-sql/{test/generic-drizzle-adapter-sqlite3.test.ts → sql-adapter-sqlite3-driver.test.ts} +282 -14
  396. package/src/adapters/{drizzle/drizzle-adapter-sqlite3.test.ts → generic-sql/sql-adapter-sqlite3-uow.test.ts} +129 -12
  397. package/src/adapters/{kysely/kysely-adapter-sqlocal.test.ts → generic-sql/sql-adapter-sqlocal.test.ts} +9 -7
  398. package/src/adapters/generic-sql/sqlite-storage.ts +20 -0
  399. package/src/adapters/generic-sql/uow-decoder.test.ts +5 -4
  400. package/src/adapters/generic-sql/uow-decoder.ts +23 -5
  401. package/src/adapters/generic-sql/uow-encoder.test.ts +36 -3
  402. package/src/adapters/generic-sql/uow-encoder.ts +48 -13
  403. package/src/adapters/in-memory/condition-evaluator.test.ts +194 -0
  404. package/src/adapters/in-memory/condition-evaluator.ts +280 -0
  405. package/src/adapters/in-memory/errors.ts +20 -0
  406. package/src/adapters/in-memory/in-memory-adapter.ts +388 -0
  407. package/src/adapters/in-memory/in-memory-uow.mutations.test.ts +344 -0
  408. package/src/adapters/in-memory/in-memory-uow.retrieval.test.ts +255 -0
  409. package/src/adapters/in-memory/in-memory-uow.ts +1724 -0
  410. package/src/adapters/in-memory/index.ts +3 -0
  411. package/src/adapters/in-memory/options.test.ts +42 -0
  412. package/src/adapters/in-memory/options.ts +91 -0
  413. package/src/adapters/in-memory/outbox.test.ts +361 -0
  414. package/src/adapters/in-memory/reference-resolution.test.ts +51 -0
  415. package/src/adapters/in-memory/reference-resolution.ts +67 -0
  416. package/src/adapters/in-memory/sorted-array-index.test.ts +124 -0
  417. package/src/adapters/in-memory/sorted-array-index.ts +228 -0
  418. package/src/adapters/in-memory/store.test.ts +69 -0
  419. package/src/adapters/in-memory/store.ts +145 -0
  420. package/src/adapters/in-memory/value-comparison.ts +53 -0
  421. package/src/adapters/in-memory/value-normalization.test.ts +58 -0
  422. package/src/adapters/prisma/prisma-adapter-sqlite3.test.ts +1207 -0
  423. package/src/adapters/shared/from-unit-of-work-compiler.ts +159 -47
  424. package/src/adapters/shared/uow-operation-compiler.ts +28 -18
  425. package/src/adapters/sql/index.ts +12 -0
  426. package/src/browser/mod.ts +64 -0
  427. package/src/client.ts +19 -0
  428. package/src/db-fragment-definition-builder.test.ts +845 -53
  429. package/src/db-fragment-definition-builder.ts +911 -95
  430. package/src/db-fragment-instantiator.test.ts +210 -94
  431. package/src/db-fragment-integration.test.ts +17 -12
  432. package/src/dispatchers/cloudflare-do/dispatcher.ts +204 -0
  433. package/src/dispatchers/cloudflare-do/index.test.ts +206 -0
  434. package/src/dispatchers/cloudflare-do/index.ts +63 -0
  435. package/src/dispatchers/node/dispatcher.ts +112 -0
  436. package/src/dispatchers/node/index.test.ts +120 -0
  437. package/src/dispatchers/node/index.ts +50 -0
  438. package/src/durable-hooks.test.ts +80 -0
  439. package/src/durable-hooks.ts +67 -0
  440. package/src/fragments/internal-fragment.routes.test.ts +570 -0
  441. package/src/fragments/internal-fragment.routes.ts +334 -0
  442. package/src/fragments/internal-fragment.schema.ts +95 -0
  443. package/src/fragments/internal-fragment.test.ts +505 -83
  444. package/src/fragments/internal-fragment.ts +453 -70
  445. package/src/hooks/durable-hooks-logger.ts +126 -0
  446. package/src/hooks/durable-hooks-processor.pglite.test.ts +87 -0
  447. package/src/hooks/durable-hooks-processor.test.ts +282 -0
  448. package/src/hooks/durable-hooks-processor.ts +173 -0
  449. package/src/hooks/durable-hooks-runtime.test.ts +65 -0
  450. package/src/hooks/durable-hooks-runtime.ts +81 -0
  451. package/src/hooks/hooks.test.ts +455 -34
  452. package/src/hooks/hooks.ts +501 -34
  453. package/src/id.test.ts +34 -0
  454. package/src/id.ts +1 -3
  455. package/src/internal/adapter-registry.test.ts +93 -0
  456. package/src/internal/adapter-registry.ts +239 -0
  457. package/src/internal/outbox-state.ts +43 -0
  458. package/src/migration-engine/auto-from-schema.test.ts +107 -14
  459. package/src/migration-engine/auto-from-schema.ts +365 -44
  460. package/src/migration-engine/create.test.ts +4 -3
  461. package/src/migration-engine/create.ts +1 -1
  462. package/src/migration-engine/generation-engine.test.ts +292 -110
  463. package/src/migration-engine/generation-engine.ts +117 -66
  464. package/src/migration-engine/shared.ts +14 -0
  465. package/src/mod.ts +95 -39
  466. package/src/naming/sql-naming.ts +181 -0
  467. package/src/outbox/outbox-builder.ts +241 -0
  468. package/src/outbox/outbox.test.ts +424 -0
  469. package/src/outbox/outbox.ts +139 -0
  470. package/src/query/column-defaults.ts +42 -4
  471. package/src/query/condition-builder.test.ts +18 -3
  472. package/src/query/condition-builder.ts +7 -0
  473. package/src/query/cursor-client.test.ts +70 -0
  474. package/src/query/cursor-client.ts +263 -0
  475. package/src/query/cursor.test.ts +119 -20
  476. package/src/query/cursor.ts +88 -27
  477. package/src/query/db-now.ts +73 -0
  478. package/src/query/orm/orm.ts +2 -2
  479. package/src/query/query-type.test.ts +4 -3
  480. package/src/query/serialize/create-sql-serializer.ts +10 -5
  481. package/src/query/serialize/dialect/mysql-serializer.ts +13 -5
  482. package/src/query/serialize/dialect/postgres-serializer.ts +35 -5
  483. package/src/query/serialize/dialect/sqlite-serializer.test.ts +90 -3
  484. package/src/query/serialize/dialect/sqlite-serializer.ts +108 -12
  485. package/src/query/serialize/sql-serializer.ts +4 -4
  486. package/src/query/simple-query-interface.ts +15 -4
  487. package/src/query/unit-of-work/execute-unit-of-work.test.ts +372 -10
  488. package/src/query/unit-of-work/execute-unit-of-work.ts +87 -27
  489. package/src/query/unit-of-work/retry-policy.test.ts +1 -0
  490. package/src/query/unit-of-work/tx-builder.test.ts +73 -1
  491. package/src/query/unit-of-work/unit-of-work-coordinator.test.ts +17 -16
  492. package/src/query/unit-of-work/unit-of-work-types.test.ts +42 -12
  493. package/src/query/unit-of-work/unit-of-work.test.ts +196 -39
  494. package/src/query/unit-of-work/unit-of-work.ts +309 -38
  495. package/src/query/value-decoding.test.ts +63 -4
  496. package/src/query/value-decoding.ts +32 -6
  497. package/src/query/value-encoding.test.ts +86 -2
  498. package/src/query/value-encoding.ts +56 -6
  499. package/src/schema/create.test.ts +293 -47
  500. package/src/schema/create.ts +406 -70
  501. package/src/schema/generate-id.test.ts +3 -2
  502. package/src/schema/generate-id.ts +2 -2
  503. package/src/schema/serialize.test.ts +18 -5
  504. package/src/schema/type-conversion/create-sql-type-mapper.ts +8 -3
  505. package/src/schema/type-conversion/dialect/sqlite.ts +18 -0
  506. package/src/schema/type-conversion/type-mapping.test.ts +26 -1
  507. package/src/schema/validator.test.ts +199 -0
  508. package/src/schema/validator.ts +232 -0
  509. package/src/{adapters/drizzle/generate.test.ts → schema-output/drizzle.test.ts} +232 -129
  510. package/src/{adapters/drizzle/generate.ts → schema-output/drizzle.ts} +155 -99
  511. package/src/schema-output/prisma.test.ts +694 -0
  512. package/src/schema-output/prisma.ts +593 -0
  513. package/src/sql-driver/better-sqlite3.test.ts +5 -3
  514. package/src/sql-driver/dialects/durable-object-dialect.ts +3 -8
  515. package/src/sql-driver/query-executor/default-query-executor.ts +1 -1
  516. package/src/sql-driver/query-executor/query-executor-base.ts +1 -1
  517. package/src/sql-driver/query-executor/query-executor.ts +1 -1
  518. package/src/sql-driver/sql-driver-adapter.ts +2 -2
  519. package/src/sql-driver/sql.ts +2 -1
  520. package/src/sql-driver/sqlocal.test.ts +4 -2
  521. package/src/sync/commands.test.ts +39 -0
  522. package/src/sync/commands.ts +51 -0
  523. package/src/sync/conflict-checker.test.ts +450 -0
  524. package/src/sync/conflict-checker.ts +248 -0
  525. package/src/sync/index.ts +14 -0
  526. package/src/sync/plan.ts +9 -0
  527. package/src/sync/read-tracking.test.ts +177 -0
  528. package/src/sync/read-tracking.ts +287 -0
  529. package/src/sync/submit.test.ts +205 -0
  530. package/src/sync/submit.ts +328 -0
  531. package/src/sync/types.ts +80 -0
  532. package/src/util/default-database-adapter.ts +119 -0
  533. package/src/with-database.ts +20 -31
  534. package/tsconfig.json +1 -1
  535. package/tsdown.config.ts +38 -24
  536. package/vitest.config.ts +1 -0
  537. package/dist/adapters/drizzle/drizzle-adapter.d.ts +0 -20
  538. package/dist/adapters/drizzle/drizzle-adapter.d.ts.map +0 -1
  539. package/dist/adapters/drizzle/drizzle-adapter.js +0 -27
  540. package/dist/adapters/drizzle/drizzle-adapter.js.map +0 -1
  541. package/dist/adapters/drizzle/generate.d.ts +0 -30
  542. package/dist/adapters/drizzle/generate.d.ts.map +0 -1
  543. package/dist/adapters/drizzle/generate.js.map +0 -1
  544. package/dist/adapters/kysely/kysely-adapter.d.ts +0 -19
  545. package/dist/adapters/kysely/kysely-adapter.d.ts.map +0 -1
  546. package/dist/adapters/kysely/kysely-adapter.js +0 -17
  547. package/dist/adapters/kysely/kysely-adapter.js.map +0 -1
  548. package/dist/adapters/shared/table-name-mapper.d.ts +0 -12
  549. package/dist/adapters/shared/table-name-mapper.d.ts.map +0 -1
  550. package/dist/adapters/shared/table-name-mapper.js +0 -43
  551. package/dist/adapters/shared/table-name-mapper.js.map +0 -1
  552. package/dist/node_modules/.pnpm/rou3@0.7.10/node_modules/rou3/dist/index.js +0 -165
  553. package/dist/node_modules/.pnpm/rou3@0.7.10/node_modules/rou3/dist/index.js.map +0 -1
  554. package/dist/packages/fragno/dist/api/bind-services.js +0 -20
  555. package/dist/packages/fragno/dist/api/bind-services.js.map +0 -1
  556. package/dist/packages/fragno/dist/api/error.js +0 -48
  557. package/dist/packages/fragno/dist/api/error.js.map +0 -1
  558. package/dist/packages/fragno/dist/api/fragment-definition-builder.js +0 -320
  559. package/dist/packages/fragno/dist/api/fragment-definition-builder.js.map +0 -1
  560. package/dist/packages/fragno/dist/api/fragment-instantiator.js +0 -525
  561. package/dist/packages/fragno/dist/api/fragment-instantiator.js.map +0 -1
  562. package/dist/packages/fragno/dist/api/fragno-response.js +0 -73
  563. package/dist/packages/fragno/dist/api/fragno-response.js.map +0 -1
  564. package/dist/packages/fragno/dist/api/internal/response-stream.js +0 -81
  565. package/dist/packages/fragno/dist/api/internal/response-stream.js.map +0 -1
  566. package/dist/packages/fragno/dist/api/internal/route.js +0 -10
  567. package/dist/packages/fragno/dist/api/internal/route.js.map +0 -1
  568. package/dist/packages/fragno/dist/api/mutable-request-state.js +0 -97
  569. package/dist/packages/fragno/dist/api/mutable-request-state.js.map +0 -1
  570. package/dist/packages/fragno/dist/api/request-context-storage.js +0 -43
  571. package/dist/packages/fragno/dist/api/request-context-storage.js.map +0 -1
  572. package/dist/packages/fragno/dist/api/request-input-context.js +0 -118
  573. package/dist/packages/fragno/dist/api/request-input-context.js.map +0 -1
  574. package/dist/packages/fragno/dist/api/request-middleware.js +0 -83
  575. package/dist/packages/fragno/dist/api/request-middleware.js.map +0 -1
  576. package/dist/packages/fragno/dist/api/request-output-context.js +0 -119
  577. package/dist/packages/fragno/dist/api/request-output-context.js.map +0 -1
  578. package/dist/packages/fragno/dist/api/route.js +0 -17
  579. package/dist/packages/fragno/dist/api/route.js.map +0 -1
  580. package/dist/packages/fragno/dist/internal/symbols.js +0 -10
  581. package/dist/packages/fragno/dist/internal/symbols.js.map +0 -1
  582. package/dist/schema-generator/schema-generator.d.ts +0 -15
  583. package/dist/schema-generator/schema-generator.d.ts.map +0 -1
  584. package/src/adapters/drizzle/drizzle-adapter.ts +0 -39
  585. package/src/adapters/kysely/kysely-adapter.ts +0 -27
  586. package/src/adapters/shared/table-name-mapper.ts +0 -50
  587. package/src/schema-generator/schema-generator.ts +0 -12
@@ -1,21 +1,38 @@
1
+ import { beforeAll, describe, expect, it } from "vitest";
2
+
1
3
  import SQLite from "better-sqlite3";
2
4
  import { SqliteDialect } from "kysely";
3
- import { beforeAll, describe, expect, it } from "vitest";
5
+
4
6
  import { instantiate } from "@fragno-dev/core";
5
- import { internalFragmentDef, internalSchema, SETTINGS_NAMESPACE } from "./internal-fragment";
6
- import type { FragnoPublicConfigWithDatabase } from "../db-fragment-definition-builder";
7
- import { DrizzleAdapter } from "../adapters/drizzle/drizzle-adapter";
7
+
8
8
  import { BetterSQLite3DriverConfig } from "../adapters/generic-sql/driver-config";
9
+ import { SqlAdapter } from "../adapters/generic-sql/generic-sql-adapter";
10
+ import type { FragnoPublicConfigWithDatabase } from "../db-fragment-definition-builder";
11
+ import { getRegistryForAdapterSync } from "../internal/adapter-registry";
12
+ import { dbNow } from "../query/db-now";
9
13
  import { ExponentialBackoffRetryPolicy, NoRetryPolicy } from "../query/unit-of-work/retry-policy";
10
14
  import type { FragnoId } from "../schema/create";
15
+ import {
16
+ internalFragmentDef,
17
+ internalSchema,
18
+ SETTINGS_NAMESPACE,
19
+ getSchemaVersionFromDatabase,
20
+ } from "./internal-fragment";
21
+
22
+ type OptionsWithAdapter = FragnoPublicConfigWithDatabase & {
23
+ databaseAdapter: SqlAdapter;
24
+ };
11
25
 
12
26
  describe("Internal Fragment", () => {
13
27
  let sqliteDatabase: SQLite.Database;
14
- let adapter: DrizzleAdapter;
28
+ let adapter: SqlAdapter;
15
29
  let fragment: ReturnType<typeof instantiateFragment>;
16
30
 
17
- function instantiateFragment(options: FragnoPublicConfigWithDatabase) {
18
- return instantiate(internalFragmentDef).withConfig({}).withOptions(options).build();
31
+ function instantiateFragment(options: OptionsWithAdapter) {
32
+ return instantiate(internalFragmentDef)
33
+ .withConfig({ registry: getRegistryForAdapterSync(options.databaseAdapter) })
34
+ .withOptions(options)
35
+ .build();
19
36
  }
20
37
 
21
38
  beforeAll(async () => {
@@ -25,19 +42,20 @@ describe("Internal Fragment", () => {
25
42
  database: sqliteDatabase,
26
43
  });
27
44
 
28
- adapter = new DrizzleAdapter({
45
+ adapter = new SqlAdapter({
29
46
  dialect,
30
47
  driverConfig: new BetterSQLite3DriverConfig(),
31
48
  });
32
49
 
33
50
  {
34
- const migrations = adapter.prepareMigrations(internalSchema, "");
51
+ const migrations = adapter.prepareMigrations(internalSchema, null);
35
52
  await migrations.executeWithDriver(adapter.driver, 0);
36
53
  }
37
54
 
38
55
  // Instantiate fragment with shared database adapter
39
- const options: FragnoPublicConfigWithDatabase = {
56
+ const options: OptionsWithAdapter = {
40
57
  databaseAdapter: adapter,
58
+ databaseNamespace: null,
41
59
  };
42
60
 
43
61
  fragment = instantiateFragment(options);
@@ -151,11 +169,14 @@ describe("Internal Fragment", () => {
151
169
 
152
170
  describe("Hook Service", () => {
153
171
  let sqliteDatabase: SQLite.Database;
154
- let adapter: DrizzleAdapter;
172
+ let adapter: SqlAdapter;
155
173
  let fragment: ReturnType<typeof instantiateFragment>;
156
174
 
157
- function instantiateFragment(options: FragnoPublicConfigWithDatabase) {
158
- return instantiate(internalFragmentDef).withConfig({}).withOptions(options).build();
175
+ function instantiateFragment(options: OptionsWithAdapter) {
176
+ return instantiate(internalFragmentDef)
177
+ .withConfig({ registry: getRegistryForAdapterSync(options.databaseAdapter) })
178
+ .withOptions(options)
179
+ .build();
159
180
  }
160
181
 
161
182
  beforeAll(async () => {
@@ -165,18 +186,19 @@ describe("Hook Service", () => {
165
186
  database: sqliteDatabase,
166
187
  });
167
188
 
168
- adapter = new DrizzleAdapter({
189
+ adapter = new SqlAdapter({
169
190
  dialect,
170
191
  driverConfig: new BetterSQLite3DriverConfig(),
171
192
  });
172
193
 
173
194
  {
174
- const migrations = adapter.prepareMigrations(internalSchema, "");
195
+ const migrations = adapter.prepareMigrations(internalSchema, null);
175
196
  await migrations.executeWithDriver(adapter.driver, 0);
176
197
  }
177
198
 
178
- const options: FragnoPublicConfigWithDatabase = {
199
+ const options: OptionsWithAdapter = {
179
200
  databaseAdapter: adapter,
201
+ databaseNamespace: null,
180
202
  };
181
203
 
182
204
  fragment = instantiateFragment(options);
@@ -224,62 +246,119 @@ describe("Hook Service", () => {
224
246
  const events = await fragment.inContext(async function () {
225
247
  return await this.handlerTx()
226
248
  .withServiceCalls(
227
- () => [fragment.services.hookService.getPendingHookEvents("test-namespace")] as const,
249
+ () => [fragment.services.hookService.getHooksByNamespace("test-namespace")] as const,
228
250
  )
229
251
  .transform(({ serviceResult: [result] }) => result)
230
252
  .execute();
231
253
  });
232
254
 
233
- expect(events).toHaveLength(1);
234
- expect(events[0]).toMatchObject({
255
+ const event = events.find((entry) => entry.hookName === "onTest" && entry.status === "pending");
256
+ expect(event).toBeDefined();
257
+ expect(event).toMatchObject({
235
258
  hookName: "onTest",
236
259
  payload: { test: "data" },
237
260
  attempts: 0,
238
261
  maxAttempts: 5,
239
- idempotencyKey: nonce,
262
+ status: "pending",
263
+ nonce,
240
264
  });
241
265
  });
242
266
 
243
- it("should mark a hook event as completed", async () => {
244
- const nonce = "test-nonce-2";
245
- let eventId: FragnoId;
267
+ it("should paginate hooks by namespace with a cursor", async () => {
268
+ const namespace = "page-cursor";
269
+ const createdAt1 = new Date("2024-01-01T00:00:00.000Z");
270
+ const createdAt2 = new Date("2024-01-02T00:00:00.000Z");
271
+ const createdAt3 = new Date("2024-01-03T00:00:00.000Z");
272
+
273
+ let id1!: FragnoId;
274
+ let id2!: FragnoId;
275
+ let id3!: FragnoId;
246
276
 
247
277
  await fragment.inContext(async function () {
248
278
  await this.handlerTx()
249
279
  .mutate(({ forSchema }) => {
250
280
  const uow = forSchema(internalSchema);
251
- eventId = uow.create("fragno_hooks", {
252
- namespace: "test-namespace",
253
- hookName: "onComplete",
254
- payload: { test: "data" },
281
+ id1 = uow.create("fragno_hooks", {
282
+ namespace,
283
+ hookName: "onPage1",
284
+ payload: { test: "page-1" },
255
285
  status: "pending",
256
286
  attempts: 0,
257
287
  maxAttempts: 5,
258
288
  lastAttemptAt: null,
259
289
  nextRetryAt: null,
260
290
  error: null,
261
- nonce,
291
+ nonce: "test-nonce-page-1",
292
+ createdAt: createdAt1,
293
+ });
294
+ id2 = uow.create("fragno_hooks", {
295
+ namespace,
296
+ hookName: "onPage2",
297
+ payload: { test: "page-2" },
298
+ status: "pending",
299
+ attempts: 0,
300
+ maxAttempts: 5,
301
+ lastAttemptAt: null,
302
+ nextRetryAt: null,
303
+ error: null,
304
+ nonce: "test-nonce-page-2",
305
+ createdAt: createdAt2,
306
+ });
307
+ id3 = uow.create("fragno_hooks", {
308
+ namespace,
309
+ hookName: "onPage3",
310
+ payload: { test: "page-3" },
311
+ status: "pending",
312
+ attempts: 0,
313
+ maxAttempts: 5,
314
+ lastAttemptAt: null,
315
+ nextRetryAt: null,
316
+ error: null,
317
+ nonce: "test-nonce-page-3",
318
+ createdAt: createdAt3,
262
319
  });
263
320
  })
264
321
  .execute();
265
322
  });
266
323
 
267
- await fragment.inContext(async function () {
268
- await this.handlerTx()
269
- .withServiceCalls(() => [fragment.services.hookService.markHookCompleted(eventId)] as const)
324
+ const firstPage = await fragment.inContext(async function () {
325
+ return await this.handlerTx()
326
+ .withServiceCalls(
327
+ () =>
328
+ [
329
+ fragment.services.hookService.getHooksByNamespacePage(namespace, { pageSize: 2 }),
330
+ ] as const,
331
+ )
332
+ .transform(({ serviceResult: [result] }) => result)
270
333
  .execute();
271
334
  });
272
335
 
273
- const result = await fragment.inContext(async function () {
336
+ expect(firstPage.items).toHaveLength(2);
337
+ expect(firstPage.hasNextPage).toBe(true);
338
+ expect(firstPage.cursor).toBeDefined();
339
+ expect(firstPage.items.map((event) => event.id.externalId)).toEqual([
340
+ id3.externalId,
341
+ id2.externalId,
342
+ ]);
343
+
344
+ const secondPage = await fragment.inContext(async function () {
274
345
  return await this.handlerTx()
275
- .withServiceCalls(() => [fragment.services.hookService.getHookById(eventId)] as const)
276
- .transform(({ serviceResult: [event] }) => event)
346
+ .withServiceCalls(
347
+ () =>
348
+ [
349
+ fragment.services.hookService.getHooksByNamespacePage(namespace, {
350
+ cursor: firstPage.cursor ?? undefined,
351
+ pageSize: 2,
352
+ }),
353
+ ] as const,
354
+ )
355
+ .transform(({ serviceResult: [result] }) => result)
277
356
  .execute();
278
357
  });
279
358
 
280
- expect(result).toBeDefined();
281
- expect(result?.status).toBe("completed");
282
- expect(result?.lastAttemptAt).toBeInstanceOf(Date);
359
+ expect(secondPage.items).toHaveLength(1);
360
+ expect(secondPage.hasNextPage).toBe(false);
361
+ expect(secondPage.items[0]?.id.externalId).toBe(id1.externalId);
283
362
  });
284
363
 
285
364
  it("should mark a hook event as processing", async () => {
@@ -435,121 +514,464 @@ describe("Hook Service", () => {
435
514
  expect(result?.error).toBe("Max attempts reached");
436
515
  });
437
516
 
438
- it("should retrieve stale events ready for retry", async () => {
439
- const nonce = "test-nonce-6";
440
- let eventId: FragnoId;
441
-
517
+ it("should claim only ready pending events and mark them processing", async () => {
518
+ const namespace = "claim-ready";
442
519
  const pastTime = new Date(Date.now() - 10000);
520
+ const futureTime = new Date(Date.now() + 60000);
521
+
522
+ let nullRetryId!: FragnoId;
523
+ let pastRetryId!: FragnoId;
524
+ let futureRetryId!: FragnoId;
525
+ let otherNamespaceId!: FragnoId;
443
526
 
444
527
  await fragment.inContext(async function () {
445
- const createdId = await this.handlerTx()
528
+ await this.handlerTx()
446
529
  .mutate(({ forSchema }) => {
447
530
  const uow = forSchema(internalSchema);
448
- return uow.create("fragno_hooks", {
449
- namespace: "test-namespace",
450
- hookName: "onStale",
451
- payload: { test: "stale" },
531
+ nullRetryId = uow.create("fragno_hooks", {
532
+ namespace,
533
+ hookName: "onNullRetry",
534
+ payload: { test: "null" },
535
+ status: "pending",
536
+ attempts: 0,
537
+ maxAttempts: 5,
538
+ lastAttemptAt: null,
539
+ nextRetryAt: null,
540
+ error: null,
541
+ nonce: "test-nonce-claim-null",
542
+ });
543
+ pastRetryId = uow.create("fragno_hooks", {
544
+ namespace,
545
+ hookName: "onPastRetry",
546
+ payload: { test: "past" },
452
547
  status: "pending",
453
548
  attempts: 1,
454
549
  maxAttempts: 5,
455
550
  lastAttemptAt: pastTime,
456
551
  nextRetryAt: pastTime,
457
552
  error: "Previous error",
553
+ nonce: "test-nonce-claim-past",
554
+ });
555
+ futureRetryId = uow.create("fragno_hooks", {
556
+ namespace,
557
+ hookName: "onFutureRetry",
558
+ payload: { test: "future" },
559
+ status: "pending",
560
+ attempts: 1,
561
+ maxAttempts: 5,
562
+ lastAttemptAt: new Date(),
563
+ nextRetryAt: futureTime,
564
+ error: "Previous error",
565
+ nonce: "test-nonce-claim-future",
566
+ });
567
+ otherNamespaceId = uow.create("fragno_hooks", {
568
+ namespace: "other-namespace",
569
+ hookName: "onOtherNamespace",
570
+ payload: { test: "other" },
571
+ status: "pending",
572
+ attempts: 0,
573
+ maxAttempts: 5,
574
+ lastAttemptAt: null,
575
+ nextRetryAt: null,
576
+ error: null,
577
+ nonce: "test-nonce-claim-other",
578
+ });
579
+ })
580
+ .execute();
581
+ });
582
+
583
+ const claimed = await fragment.inContext(async function () {
584
+ return await this.handlerTx()
585
+ .withServiceCalls(
586
+ () => [fragment.services.hookService.claimPendingHookEvents(namespace)] as const,
587
+ )
588
+ .transform(({ serviceResult: [result] }) => result)
589
+ .execute();
590
+ });
591
+
592
+ expect(claimed).toHaveLength(2);
593
+ const claimedIds = new Set(claimed.map((event) => event.id.externalId));
594
+ expect(claimedIds.has(nullRetryId.externalId)).toBe(true);
595
+ expect(claimedIds.has(pastRetryId.externalId)).toBe(true);
596
+ expect(claimedIds.has(futureRetryId.externalId)).toBe(false);
597
+ expect(claimedIds.has(otherNamespaceId.externalId)).toBe(false);
598
+
599
+ const [nullEvent, pastEvent, futureEvent, otherEvent] = await fragment.inContext(
600
+ async function () {
601
+ return await this.handlerTx()
602
+ .withServiceCalls(
603
+ () =>
604
+ [
605
+ fragment.services.hookService.getHookById(nullRetryId),
606
+ fragment.services.hookService.getHookById(pastRetryId),
607
+ fragment.services.hookService.getHookById(futureRetryId),
608
+ fragment.services.hookService.getHookById(otherNamespaceId),
609
+ ] as const,
610
+ )
611
+ .transform(({ serviceResult: [nullResult, pastResult, futureResult, otherResult] }) => [
612
+ nullResult,
613
+ pastResult,
614
+ futureResult,
615
+ otherResult,
616
+ ])
617
+ .execute();
618
+ },
619
+ );
620
+
621
+ expect(nullEvent?.status).toBe("processing");
622
+ expect(nullEvent?.lastAttemptAt).toBeInstanceOf(Date);
623
+ expect(pastEvent?.status).toBe("processing");
624
+ expect(pastEvent?.lastAttemptAt).toBeInstanceOf(Date);
625
+ expect(futureEvent?.status).toBe("pending");
626
+ expect(otherEvent?.status).toBe("pending");
627
+ });
628
+
629
+ it("should return claimed ids with incremented versions", async () => {
630
+ const namespace = "claim-version";
631
+ const nonce = "test-nonce-claim-version";
632
+ let createdId!: FragnoId;
633
+
634
+ await fragment.inContext(async function () {
635
+ createdId = await this.handlerTx()
636
+ .mutate(({ forSchema }) => {
637
+ const uow = forSchema(internalSchema);
638
+ return uow.create("fragno_hooks", {
639
+ namespace,
640
+ hookName: "onClaimVersion",
641
+ payload: { test: "version" },
642
+ status: "pending",
643
+ attempts: 0,
644
+ maxAttempts: 5,
645
+ lastAttemptAt: null,
646
+ nextRetryAt: null,
647
+ error: null,
458
648
  nonce,
459
649
  });
460
650
  })
461
651
  .execute();
462
- eventId = createdId;
463
652
  });
464
653
 
465
- const events = await fragment.inContext(async function () {
654
+ const claimed = await fragment.inContext(async function () {
466
655
  return await this.handlerTx()
467
656
  .withServiceCalls(
468
- () => [fragment.services.hookService.getPendingHookEvents("test-namespace")] as const,
657
+ () => [fragment.services.hookService.claimPendingHookEvents(namespace)] as const,
469
658
  )
470
659
  .transform(({ serviceResult: [result] }) => result)
471
660
  .execute();
472
661
  });
473
662
 
474
- const staleEvent = events.find((e) => e.id.externalId === eventId.externalId);
475
- expect(staleEvent).toBeDefined();
476
- expect(staleEvent?.hookName).toBe("onStale");
477
- expect(staleEvent?.attempts).toBe(1);
663
+ expect(claimed).toHaveLength(1);
664
+ expect(claimed[0]?.id.externalId).toBe(createdId.externalId);
665
+ expect(claimed[0]?.id.version).toBe(createdId.version + 1);
478
666
  });
479
667
 
480
- it("should not retrieve events from different namespace", async () => {
481
- const nonce = "test-nonce-7";
668
+ it("should claim stale processing events and return stuck metadata", async () => {
669
+ const namespace = "claim-stuck";
670
+ const staleBefore = dbNow().plus({ minutes: -1 });
671
+ const staleLastAttemptAt = new Date(Date.now() - 5 * 60_000);
672
+ const freshLastAttemptAt = new Date(Date.now() - 10_000);
673
+ const staleNextRetryAt = new Date(Date.now() + 60_000);
674
+
675
+ let staleId!: FragnoId;
676
+ let freshId!: FragnoId;
677
+
678
+ await fragment.inContext(async function () {
679
+ await this.handlerTx()
680
+ .mutate(({ forSchema }) => {
681
+ const uow = forSchema(internalSchema);
682
+ staleId = uow.create("fragno_hooks", {
683
+ namespace,
684
+ hookName: "onStuck",
685
+ payload: { test: "stuck" },
686
+ status: "processing",
687
+ attempts: 1,
688
+ maxAttempts: 5,
689
+ lastAttemptAt: staleLastAttemptAt,
690
+ nextRetryAt: staleNextRetryAt,
691
+ error: null,
692
+ nonce: "test-nonce-stuck",
693
+ });
694
+ freshId = uow.create("fragno_hooks", {
695
+ namespace,
696
+ hookName: "onFresh",
697
+ payload: { test: "fresh" },
698
+ status: "processing",
699
+ attempts: 0,
700
+ maxAttempts: 5,
701
+ lastAttemptAt: freshLastAttemptAt,
702
+ nextRetryAt: null,
703
+ error: null,
704
+ nonce: "test-nonce-fresh",
705
+ });
706
+ })
707
+ .execute();
708
+ });
709
+
710
+ const claimResult = await fragment.inContext(async function () {
711
+ return await this.handlerTx()
712
+ .withServiceCalls(
713
+ () =>
714
+ [
715
+ fragment.services.hookService.claimStuckProcessingHookEvents(namespace, staleBefore),
716
+ ] as const,
717
+ )
718
+ .transform(({ serviceResult: [result] }) => result)
719
+ .execute();
720
+ });
721
+
722
+ expect(claimResult.events).toHaveLength(1);
723
+ expect(claimResult.events[0]?.hookName).toBe("onStuck");
724
+ expect(claimResult.events[0]?.id.version).toBe(staleId.version + 1);
725
+
726
+ expect(claimResult.stuckEvents).toHaveLength(1);
727
+ expect(claimResult.stuckEvents[0]?.hookName).toBe("onStuck");
728
+ expect(claimResult.stuckEvents[0]?.id.externalId).toBe(staleId.externalId);
729
+ expect(claimResult.stuckEvents[0]?.id.version).toBe(staleId.version);
730
+ expect(claimResult.stuckEvents[0]?.lastAttemptAt?.getTime()).toBe(staleLastAttemptAt.getTime());
731
+ expect(claimResult.stuckEvents[0]?.nextRetryAt?.getTime()).toBe(staleNextRetryAt.getTime());
732
+
733
+ const [staleEvent, freshEvent] = await fragment.inContext(async function () {
734
+ return await this.handlerTx()
735
+ .withServiceCalls(
736
+ () =>
737
+ [
738
+ fragment.services.hookService.getHookById(staleId),
739
+ fragment.services.hookService.getHookById(freshId),
740
+ ] as const,
741
+ )
742
+ .transform(({ serviceResult: [staleResult, freshResult] }) => [staleResult, freshResult])
743
+ .execute();
744
+ });
745
+
746
+ expect(staleEvent?.status).toBe("processing");
747
+ expect(staleEvent?.nextRetryAt).toBeNull();
748
+ expect(staleEvent?.lastAttemptAt).toBeInstanceOf(Date);
749
+ expect(staleEvent?.lastAttemptAt?.getTime()).toBeGreaterThan(staleLastAttemptAt.getTime());
750
+ expect(freshEvent?.lastAttemptAt).toBeInstanceOf(Date);
751
+ expect(
752
+ Math.abs((freshEvent?.lastAttemptAt?.getTime() ?? 0) - freshLastAttemptAt.getTime()),
753
+ ).toBeLessThan(2000);
754
+ });
755
+
756
+ it("should return now when pending hooks have no nextRetryAt", async () => {
757
+ const namespace = "wake-now";
482
758
 
483
759
  await fragment.inContext(async function () {
484
760
  await this.handlerTx()
485
761
  .mutate(({ forSchema }) => {
486
762
  const uow = forSchema(internalSchema);
487
763
  uow.create("fragno_hooks", {
488
- namespace: "other-namespace",
489
- hookName: "onOther",
490
- payload: { test: "other" },
764
+ namespace,
765
+ hookName: "onImmediate",
766
+ payload: { test: "now" },
491
767
  status: "pending",
492
768
  attempts: 0,
493
769
  maxAttempts: 5,
494
770
  lastAttemptAt: null,
495
771
  nextRetryAt: null,
496
772
  error: null,
497
- nonce,
773
+ nonce: "test-nonce-now",
498
774
  });
499
775
  })
500
776
  .execute();
501
777
  });
502
778
 
503
- const events = await fragment.inContext(async function () {
779
+ const wakeAt = await fragment.inContext(async function () {
504
780
  return await this.handlerTx()
505
781
  .withServiceCalls(
506
- () => [fragment.services.hookService.getPendingHookEvents("test-namespace")] as const,
782
+ () => [fragment.services.hookService.getNextHookWakeAt(namespace)] as const,
507
783
  )
508
784
  .transform(({ serviceResult: [result] }) => result)
509
785
  .execute();
510
786
  });
511
787
 
512
- const otherEvent = events.find((e) => e.hookName === "onOther");
513
- expect(otherEvent).toBeUndefined();
788
+ expect(wakeAt).toBeInstanceOf(Date);
789
+ expect(Math.abs((wakeAt as Date).getTime() - Date.now())).toBeLessThan(5000);
514
790
  });
515
791
 
516
- it("should not retrieve events not yet ready for retry", async () => {
517
- const nonce = "test-nonce-8";
518
- let eventId: FragnoId;
519
-
520
- const futureTime = new Date(Date.now() + 60000);
792
+ it("should return earliest scheduled hook time", async () => {
793
+ const namespace = "wake-future";
794
+ const soon = new Date(Date.now() + 10000);
795
+ const later = new Date(Date.now() + 60000);
521
796
 
522
797
  await fragment.inContext(async function () {
523
- const createdId = await this.handlerTx()
798
+ await this.handlerTx()
524
799
  .mutate(({ forSchema }) => {
525
800
  const uow = forSchema(internalSchema);
526
- return uow.create("fragno_hooks", {
527
- namespace: "test-namespace",
528
- hookName: "onFuture",
529
- payload: { test: "future" },
801
+ uow.create("fragno_hooks", {
802
+ namespace,
803
+ hookName: "onSoon",
804
+ payload: { test: "soon" },
530
805
  status: "pending",
531
- attempts: 1,
806
+ attempts: 0,
532
807
  maxAttempts: 5,
533
- lastAttemptAt: new Date(),
534
- nextRetryAt: futureTime,
535
- error: "Previous error",
536
- nonce,
808
+ lastAttemptAt: null,
809
+ nextRetryAt: soon,
810
+ error: null,
811
+ nonce: "test-nonce-soon",
812
+ });
813
+ uow.create("fragno_hooks", {
814
+ namespace,
815
+ hookName: "onLater",
816
+ payload: { test: "later" },
817
+ status: "pending",
818
+ attempts: 0,
819
+ maxAttempts: 5,
820
+ lastAttemptAt: null,
821
+ nextRetryAt: later,
822
+ error: null,
823
+ nonce: "test-nonce-later",
537
824
  });
538
825
  })
539
826
  .execute();
540
- eventId = createdId;
541
827
  });
542
828
 
543
- const events = await fragment.inContext(async function () {
829
+ const wakeAt = await fragment.inContext(async function () {
544
830
  return await this.handlerTx()
545
831
  .withServiceCalls(
546
- () => [fragment.services.hookService.getPendingHookEvents("test-namespace")] as const,
832
+ () => [fragment.services.hookService.getNextHookWakeAt(namespace)] as const,
547
833
  )
548
834
  .transform(({ serviceResult: [result] }) => result)
549
835
  .execute();
550
836
  });
551
837
 
552
- const futureEvent = events.find((e) => e.id.externalId === eventId.externalId);
553
- expect(futureEvent).toBeUndefined();
838
+ expect(wakeAt).toEqual(soon);
839
+ });
840
+
841
+ it("should return null when no pending hooks exist", async () => {
842
+ const namespace = "wake-none";
843
+ const wakeAt = await fragment.inContext(async function () {
844
+ return await this.handlerTx()
845
+ .withServiceCalls(
846
+ () => [fragment.services.hookService.getNextHookWakeAt(namespace)] as const,
847
+ )
848
+ .transform(({ serviceResult: [result] }) => result)
849
+ .execute();
850
+ });
851
+
852
+ expect(wakeAt).toBeNull();
853
+ });
854
+ });
855
+
856
+ describe("getSchemaVersionFromDatabase", () => {
857
+ function createTestSetup() {
858
+ const sqliteDatabase = new SQLite(":memory:");
859
+ const dialect = new SqliteDialect({ database: sqliteDatabase });
860
+ const adapter = new SqlAdapter({
861
+ dialect,
862
+ driverConfig: new BetterSQLite3DriverConfig(),
863
+ });
864
+
865
+ function instantiateFragment(options: FragnoPublicConfigWithDatabase) {
866
+ return instantiate(internalFragmentDef).withConfig({}).withOptions(options).build();
867
+ }
868
+
869
+ return { sqliteDatabase, adapter, instantiateFragment };
870
+ }
871
+
872
+ async function setupAndMigrate() {
873
+ const { sqliteDatabase, adapter, instantiateFragment } = createTestSetup();
874
+ // Create tables without writing a version record, so tests control version state
875
+ const migrations = adapter.prepareMigrations(internalSchema, "");
876
+ await migrations.executeWithDriver(adapter.driver, 0, undefined, {
877
+ updateVersionInMigration: false,
878
+ });
879
+ const fragment = instantiateFragment({
880
+ databaseAdapter: adapter,
881
+ databaseNamespace: null,
882
+ });
883
+ return { sqliteDatabase, adapter, fragment };
884
+ }
885
+
886
+ it("should return 0 when no version exists", async () => {
887
+ const { fragment } = await setupAndMigrate();
888
+
889
+ const version = await getSchemaVersionFromDatabase(fragment, "nonexistent");
890
+ expect(version).toBe(0);
891
+ });
892
+
893
+ it("should find version stored under empty-string namespace", async () => {
894
+ const { fragment } = await setupAndMigrate();
895
+
896
+ // Write version under empty-string namespace (key = ".schema_version")
897
+ await fragment.inContext(async function () {
898
+ await this.handlerTx()
899
+ .withServiceCalls(() => [fragment.services.settingsService.set("", "schema_version", "5")])
900
+ .execute();
901
+ });
902
+
903
+ const version = await getSchemaVersionFromDatabase(fragment, "");
904
+ expect(version).toBe(5);
905
+ });
906
+
907
+ it("should find version via back-compat when stored under internalSchema.name but read with empty string", async () => {
908
+ const { fragment } = await setupAndMigrate();
909
+
910
+ // Write version under "fragno_internal" namespace (legacy key from buggy code)
911
+ await fragment.inContext(async function () {
912
+ await this.handlerTx()
913
+ .withServiceCalls(() => [
914
+ fragment.services.settingsService.set(internalSchema.name, "schema_version", "3"),
915
+ ])
916
+ .execute();
917
+ });
918
+
919
+ // Reading with "" should find it via back-compat fallback
920
+ const version = await getSchemaVersionFromDatabase(fragment, "");
921
+ expect(version).toBe(3);
922
+ });
923
+
924
+ it("should find version via back-compat when stored under empty string but read with internalSchema.name", async () => {
925
+ const { fragment } = await setupAndMigrate();
926
+
927
+ // Write version under empty-string namespace
928
+ await fragment.inContext(async function () {
929
+ await this.handlerTx()
930
+ .withServiceCalls(() => [fragment.services.settingsService.set("", "schema_version", "7")])
931
+ .execute();
932
+ });
933
+
934
+ // Reading with internalSchema.name should find it via back-compat fallback
935
+ const version = await getSchemaVersionFromDatabase(fragment, internalSchema.name);
936
+ expect(version).toBe(7);
937
+ });
938
+
939
+ it("should prefer primary namespace over back-compat fallback", async () => {
940
+ const { fragment } = await setupAndMigrate();
941
+
942
+ // Write version under BOTH namespaces with different values
943
+ await fragment.inContext(async function () {
944
+ await this.handlerTx()
945
+ .withServiceCalls(() => [
946
+ fragment.services.settingsService.set("", "schema_version", "10"),
947
+ fragment.services.settingsService.set(internalSchema.name, "schema_version", "20"),
948
+ ])
949
+ .execute();
950
+ });
951
+
952
+ // Reading with "" should find 10 (primary), not 20 (back-compat)
953
+ const versionEmpty = await getSchemaVersionFromDatabase(fragment, "");
954
+ expect(versionEmpty).toBe(10);
955
+
956
+ // Reading with internalSchema.name should find 20 (primary), not 10 (back-compat)
957
+ const versionNamed = await getSchemaVersionFromDatabase(fragment, internalSchema.name);
958
+ expect(versionNamed).toBe(20);
959
+ });
960
+
961
+ it("should not use back-compat for non-internal namespaces", async () => {
962
+ const { fragment } = await setupAndMigrate();
963
+
964
+ // Write version under "some-fragment"
965
+ await fragment.inContext(async function () {
966
+ await this.handlerTx()
967
+ .withServiceCalls(() => [
968
+ fragment.services.settingsService.set("some-fragment", "schema_version", "4"),
969
+ ])
970
+ .execute();
971
+ });
972
+
973
+ // Reading with a different non-internal namespace should NOT find it
974
+ const version = await getSchemaVersionFromDatabase(fragment, "other-fragment");
975
+ expect(version).toBe(0);
554
976
  });
555
977
  });