@fragno-dev/db 0.2.2 → 0.3.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 (355) hide show
  1. package/.turbo/turbo-build.log +202 -140
  2. package/CHANGELOG.md +35 -0
  3. package/README.md +30 -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 +27 -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 +55 -16
  14. package/dist/adapters/generic-sql/generic-sql-adapter.js.map +1 -1
  15. package/dist/adapters/generic-sql/generic-sql-uow-executor.js +129 -3
  16. package/dist/adapters/generic-sql/generic-sql-uow-executor.js.map +1 -1
  17. package/dist/adapters/generic-sql/migration/dialect/mysql.js +24 -5
  18. package/dist/adapters/generic-sql/migration/dialect/mysql.js.map +1 -1
  19. package/dist/adapters/generic-sql/migration/dialect/postgres.js +6 -5
  20. package/dist/adapters/generic-sql/migration/dialect/postgres.js.map +1 -1
  21. package/dist/adapters/generic-sql/migration/dialect/sqlite.js +21 -10
  22. package/dist/adapters/generic-sql/migration/dialect/sqlite.js.map +1 -1
  23. package/dist/adapters/generic-sql/migration/prepared-migrations.d.ts.map +1 -1
  24. package/dist/adapters/generic-sql/migration/prepared-migrations.js +8 -8
  25. package/dist/adapters/generic-sql/migration/prepared-migrations.js.map +1 -1
  26. package/dist/adapters/generic-sql/migration/sql-generator.js +74 -51
  27. package/dist/adapters/generic-sql/migration/sql-generator.js.map +1 -1
  28. package/dist/adapters/generic-sql/query/create-sql-query-compiler.js +6 -5
  29. package/dist/adapters/generic-sql/query/create-sql-query-compiler.js.map +1 -1
  30. package/dist/adapters/generic-sql/query/cursor-utils.js +42 -4
  31. package/dist/adapters/generic-sql/query/cursor-utils.js.map +1 -1
  32. package/dist/adapters/generic-sql/query/generic-sql-uow-operation-compiler.js +25 -17
  33. package/dist/adapters/generic-sql/query/generic-sql-uow-operation-compiler.js.map +1 -1
  34. package/dist/adapters/generic-sql/query/select-builder.js +5 -3
  35. package/dist/adapters/generic-sql/query/select-builder.js.map +1 -1
  36. package/dist/adapters/generic-sql/query/sql-query-compiler.js +15 -12
  37. package/dist/adapters/generic-sql/query/sql-query-compiler.js.map +1 -1
  38. package/dist/adapters/generic-sql/query/where-builder.js +39 -29
  39. package/dist/adapters/generic-sql/query/where-builder.js.map +1 -1
  40. package/dist/adapters/generic-sql/sqlite-storage.d.ts +13 -0
  41. package/dist/adapters/generic-sql/sqlite-storage.d.ts.map +1 -0
  42. package/dist/adapters/generic-sql/sqlite-storage.js +15 -0
  43. package/dist/adapters/generic-sql/sqlite-storage.js.map +1 -0
  44. package/dist/adapters/generic-sql/uow-decoder.js +7 -3
  45. package/dist/adapters/generic-sql/uow-decoder.js.map +1 -1
  46. package/dist/adapters/generic-sql/uow-encoder.js +28 -8
  47. package/dist/adapters/generic-sql/uow-encoder.js.map +1 -1
  48. package/dist/adapters/in-memory/condition-evaluator.js +131 -0
  49. package/dist/adapters/in-memory/condition-evaluator.js.map +1 -0
  50. package/dist/adapters/in-memory/errors.d.ts +13 -0
  51. package/dist/adapters/in-memory/errors.d.ts.map +1 -0
  52. package/dist/adapters/in-memory/errors.js +23 -0
  53. package/dist/adapters/in-memory/errors.js.map +1 -0
  54. package/dist/adapters/in-memory/in-memory-adapter.d.ts +27 -0
  55. package/dist/adapters/in-memory/in-memory-adapter.d.ts.map +1 -0
  56. package/dist/adapters/in-memory/in-memory-adapter.js +176 -0
  57. package/dist/adapters/in-memory/in-memory-adapter.js.map +1 -0
  58. package/dist/adapters/in-memory/in-memory-uow.js +648 -0
  59. package/dist/adapters/in-memory/in-memory-uow.js.map +1 -0
  60. package/dist/adapters/in-memory/index.d.ts +4 -0
  61. package/dist/adapters/in-memory/index.js +4 -0
  62. package/dist/adapters/in-memory/options.d.ts +28 -0
  63. package/dist/adapters/in-memory/options.d.ts.map +1 -0
  64. package/dist/adapters/in-memory/options.js +61 -0
  65. package/dist/adapters/in-memory/options.js.map +1 -0
  66. package/dist/adapters/in-memory/reference-resolution.js +26 -0
  67. package/dist/adapters/in-memory/reference-resolution.js.map +1 -0
  68. package/dist/adapters/in-memory/sorted-array-index.js +129 -0
  69. package/dist/adapters/in-memory/sorted-array-index.js.map +1 -0
  70. package/dist/adapters/in-memory/store.js +71 -0
  71. package/dist/adapters/in-memory/store.js.map +1 -0
  72. package/dist/adapters/in-memory/value-comparison.js +28 -0
  73. package/dist/adapters/in-memory/value-comparison.js.map +1 -0
  74. package/dist/adapters/shared/from-unit-of-work-compiler.js.map +1 -1
  75. package/dist/adapters/shared/uow-operation-compiler.js +11 -11
  76. package/dist/adapters/shared/uow-operation-compiler.js.map +1 -1
  77. package/dist/adapters/sql/index.d.ts +5 -0
  78. package/dist/adapters/sql/index.js +4 -0
  79. package/dist/db-fragment-definition-builder.d.ts +18 -7
  80. package/dist/db-fragment-definition-builder.d.ts.map +1 -1
  81. package/dist/db-fragment-definition-builder.js +116 -54
  82. package/dist/db-fragment-definition-builder.js.map +1 -1
  83. package/dist/dispatchers/cloudflare-do/index.d.ts +26 -0
  84. package/dist/dispatchers/cloudflare-do/index.d.ts.map +1 -0
  85. package/dist/dispatchers/cloudflare-do/index.js +63 -0
  86. package/dist/dispatchers/cloudflare-do/index.js.map +1 -0
  87. package/dist/dispatchers/node/index.d.ts +17 -0
  88. package/dist/dispatchers/node/index.d.ts.map +1 -0
  89. package/dist/dispatchers/node/index.js +59 -0
  90. package/dist/dispatchers/node/index.js.map +1 -0
  91. package/dist/fragments/internal-fragment.d.ts +79 -2
  92. package/dist/fragments/internal-fragment.d.ts.map +1 -1
  93. package/dist/fragments/internal-fragment.js +150 -32
  94. package/dist/fragments/internal-fragment.js.map +1 -1
  95. package/dist/fragments/internal-fragment.routes.js +29 -0
  96. package/dist/fragments/internal-fragment.routes.js.map +1 -0
  97. package/dist/fragments/internal-fragment.schema.d.ts +9 -0
  98. package/dist/fragments/internal-fragment.schema.d.ts.map +1 -0
  99. package/dist/fragments/internal-fragment.schema.js +22 -0
  100. package/dist/fragments/internal-fragment.schema.js.map +1 -0
  101. package/dist/hooks/durable-hooks-processor.d.ts +14 -0
  102. package/dist/hooks/durable-hooks-processor.d.ts.map +1 -0
  103. package/dist/hooks/durable-hooks-processor.js +32 -0
  104. package/dist/hooks/durable-hooks-processor.js.map +1 -0
  105. package/dist/hooks/hooks.d.ts +42 -1
  106. package/dist/hooks/hooks.d.ts.map +1 -1
  107. package/dist/hooks/hooks.js +72 -6
  108. package/dist/hooks/hooks.js.map +1 -1
  109. package/dist/migration-engine/auto-from-schema.js +14 -11
  110. package/dist/migration-engine/auto-from-schema.js.map +1 -1
  111. package/dist/migration-engine/generation-engine.d.ts +16 -10
  112. package/dist/migration-engine/generation-engine.d.ts.map +1 -1
  113. package/dist/migration-engine/generation-engine.js +72 -33
  114. package/dist/migration-engine/generation-engine.js.map +1 -1
  115. package/dist/migration-engine/shared.js.map +1 -1
  116. package/dist/mod.d.ts +15 -8
  117. package/dist/mod.d.ts.map +1 -1
  118. package/dist/mod.js +14 -8
  119. package/dist/mod.js.map +1 -1
  120. package/dist/naming/sql-naming.d.ts +19 -0
  121. package/dist/naming/sql-naming.d.ts.map +1 -0
  122. package/dist/naming/sql-naming.js +116 -0
  123. package/dist/naming/sql-naming.js.map +1 -0
  124. package/dist/node_modules/.pnpm/{rou3@0.7.10 → rou3@0.7.12}/node_modules/rou3/dist/index.js +8 -5
  125. package/dist/node_modules/.pnpm/rou3@0.7.12/node_modules/rou3/dist/index.js.map +1 -0
  126. package/dist/outbox/outbox-builder.js +156 -0
  127. package/dist/outbox/outbox-builder.js.map +1 -0
  128. package/dist/outbox/outbox.d.ts +52 -0
  129. package/dist/outbox/outbox.d.ts.map +1 -0
  130. package/dist/outbox/outbox.js +37 -0
  131. package/dist/outbox/outbox.js.map +1 -0
  132. package/dist/packages/fragno/dist/api/fragment-definition-builder.js +3 -2
  133. package/dist/packages/fragno/dist/api/fragment-definition-builder.js.map +1 -1
  134. package/dist/packages/fragno/dist/api/fragment-instantiator.js +164 -20
  135. package/dist/packages/fragno/dist/api/fragment-instantiator.js.map +1 -1
  136. package/dist/packages/fragno/dist/api/request-input-context.js +67 -0
  137. package/dist/packages/fragno/dist/api/request-input-context.js.map +1 -1
  138. package/dist/packages/fragno/dist/api/route.js +14 -1
  139. package/dist/packages/fragno/dist/api/route.js.map +1 -1
  140. package/dist/packages/fragno/dist/internal/trace-context.js +12 -0
  141. package/dist/packages/fragno/dist/internal/trace-context.js.map +1 -0
  142. package/dist/query/column-defaults.js +20 -4
  143. package/dist/query/column-defaults.js.map +1 -1
  144. package/dist/query/cursor.d.ts +3 -1
  145. package/dist/query/cursor.d.ts.map +1 -1
  146. package/dist/query/cursor.js +45 -14
  147. package/dist/query/cursor.js.map +1 -1
  148. package/dist/query/db-now.d.ts +8 -0
  149. package/dist/query/db-now.d.ts.map +1 -0
  150. package/dist/query/db-now.js +7 -0
  151. package/dist/query/db-now.js.map +1 -0
  152. package/dist/query/serialize/create-sql-serializer.js +3 -2
  153. package/dist/query/serialize/create-sql-serializer.js.map +1 -1
  154. package/dist/query/serialize/dialect/mysql-serializer.js +12 -6
  155. package/dist/query/serialize/dialect/mysql-serializer.js.map +1 -1
  156. package/dist/query/serialize/dialect/postgres-serializer.js +25 -7
  157. package/dist/query/serialize/dialect/postgres-serializer.js.map +1 -1
  158. package/dist/query/serialize/dialect/sqlite-serializer.js +55 -11
  159. package/dist/query/serialize/dialect/sqlite-serializer.js.map +1 -1
  160. package/dist/query/serialize/sql-serializer.js +2 -2
  161. package/dist/query/serialize/sql-serializer.js.map +1 -1
  162. package/dist/query/simple-query-interface.d.ts +6 -1
  163. package/dist/query/simple-query-interface.d.ts.map +1 -1
  164. package/dist/query/unit-of-work/execute-unit-of-work.d.ts.map +1 -1
  165. package/dist/query/unit-of-work/execute-unit-of-work.js +11 -6
  166. package/dist/query/unit-of-work/execute-unit-of-work.js.map +1 -1
  167. package/dist/query/unit-of-work/unit-of-work.d.ts +50 -14
  168. package/dist/query/unit-of-work/unit-of-work.d.ts.map +1 -1
  169. package/dist/query/unit-of-work/unit-of-work.js +86 -5
  170. package/dist/query/unit-of-work/unit-of-work.js.map +1 -1
  171. package/dist/query/value-decoding.js +9 -6
  172. package/dist/query/value-decoding.js.map +1 -1
  173. package/dist/query/value-encoding.js +29 -9
  174. package/dist/query/value-encoding.js.map +1 -1
  175. package/dist/schema/create.d.ts +38 -14
  176. package/dist/schema/create.d.ts.map +1 -1
  177. package/dist/schema/create.js +81 -42
  178. package/dist/schema/create.js.map +1 -1
  179. package/dist/schema/generate-id.js +2 -2
  180. package/dist/schema/generate-id.js.map +1 -1
  181. package/dist/schema/type-conversion/create-sql-type-mapper.js +3 -2
  182. package/dist/schema/type-conversion/create-sql-type-mapper.js.map +1 -1
  183. package/dist/schema/type-conversion/dialect/sqlite.js +9 -0
  184. package/dist/schema/type-conversion/dialect/sqlite.js.map +1 -1
  185. package/dist/schema/validator.d.ts +10 -0
  186. package/dist/schema/validator.d.ts.map +1 -0
  187. package/dist/schema/validator.js +123 -0
  188. package/dist/schema/validator.js.map +1 -0
  189. package/dist/schema-output/drizzle.d.ts +30 -0
  190. package/dist/schema-output/drizzle.d.ts.map +1 -0
  191. package/dist/{adapters/drizzle/generate.js → schema-output/drizzle.js} +82 -56
  192. package/dist/schema-output/drizzle.js.map +1 -0
  193. package/dist/schema-output/prisma.d.ts +17 -0
  194. package/dist/schema-output/prisma.d.ts.map +1 -0
  195. package/dist/schema-output/prisma.js +296 -0
  196. package/dist/schema-output/prisma.js.map +1 -0
  197. package/dist/util/default-database-adapter.js +61 -0
  198. package/dist/util/default-database-adapter.js.map +1 -0
  199. package/dist/with-database.d.ts +1 -1
  200. package/dist/with-database.d.ts.map +1 -1
  201. package/dist/with-database.js +12 -3
  202. package/dist/with-database.js.map +1 -1
  203. package/package.json +43 -28
  204. package/src/adapters/adapters.ts +30 -24
  205. package/src/adapters/drizzle/migrate-drizzle.test.ts +54 -33
  206. package/src/adapters/drizzle/migration-parity-drizzle-kit.test.ts +599 -0
  207. package/src/adapters/drizzle/test-utils.ts +12 -8
  208. package/src/adapters/generic-sql/driver-config.ts +38 -0
  209. package/src/adapters/generic-sql/generic-sql-adapter.test.ts +5 -5
  210. package/src/adapters/generic-sql/generic-sql-adapter.ts +110 -24
  211. package/src/adapters/generic-sql/generic-sql-uow-executor.test.ts +54 -0
  212. package/src/adapters/generic-sql/generic-sql-uow-executor.ts +231 -3
  213. package/src/adapters/generic-sql/migration/adapter-migration-parity.test.ts +118 -0
  214. package/src/adapters/generic-sql/migration/dialect/mysql.test.ts +26 -8
  215. package/src/adapters/generic-sql/migration/dialect/mysql.ts +46 -8
  216. package/src/adapters/generic-sql/migration/dialect/postgres.test.ts +25 -7
  217. package/src/adapters/generic-sql/migration/dialect/postgres.ts +8 -4
  218. package/src/adapters/generic-sql/migration/dialect/sqlite.test.ts +47 -8
  219. package/src/adapters/generic-sql/migration/dialect/sqlite.ts +27 -12
  220. package/src/adapters/generic-sql/migration/prepared-migrations.test.ts +128 -39
  221. package/src/adapters/generic-sql/migration/prepared-migrations.ts +15 -8
  222. package/src/adapters/generic-sql/migration/sql-generator.ts +142 -65
  223. package/src/adapters/generic-sql/query/create-sql-query-compiler.ts +9 -6
  224. package/src/adapters/generic-sql/query/cursor-utils.test.ts +271 -0
  225. package/src/adapters/generic-sql/query/cursor-utils.ts +41 -6
  226. package/src/adapters/generic-sql/query/generic-sql-uow-operation-compiler.test.ts +27 -27
  227. package/src/adapters/generic-sql/query/generic-sql-uow-operation-compiler.ts +38 -24
  228. package/src/adapters/generic-sql/query/select-builder.test.ts +15 -11
  229. package/src/adapters/generic-sql/query/select-builder.ts +6 -2
  230. package/src/adapters/generic-sql/query/sql-query-compiler.test.ts +52 -2
  231. package/src/adapters/generic-sql/query/sql-query-compiler.ts +50 -15
  232. package/src/adapters/generic-sql/query/where-builder.test.ts +91 -17
  233. package/src/adapters/generic-sql/query/where-builder.ts +90 -38
  234. package/src/adapters/{kysely/kysely-adapter-pglite.test.ts → generic-sql/sql-adapter-pglite-migrations.test.ts} +6 -6
  235. package/src/adapters/generic-sql/sql-adapter-pglite-pagination.test.ts +806 -0
  236. package/src/adapters/{drizzle/drizzle-adapter-pglite.test.ts → generic-sql/sql-adapter-pglite-queries.test.ts} +11 -11
  237. package/src/adapters/generic-sql/{test/generic-drizzle-adapter-sqlite3.test.ts → sql-adapter-sqlite3-driver.test.ts} +10 -10
  238. package/src/adapters/{drizzle/drizzle-adapter-sqlite3.test.ts → generic-sql/sql-adapter-sqlite3-uow.test.ts} +7 -7
  239. package/src/adapters/{kysely/kysely-adapter-sqlocal.test.ts → generic-sql/sql-adapter-sqlocal.test.ts} +6 -6
  240. package/src/adapters/generic-sql/sqlite-storage.ts +20 -0
  241. package/src/adapters/generic-sql/uow-decoder.test.ts +1 -1
  242. package/src/adapters/generic-sql/uow-decoder.ts +21 -3
  243. package/src/adapters/generic-sql/uow-encoder.test.ts +33 -2
  244. package/src/adapters/generic-sql/uow-encoder.ts +50 -11
  245. package/src/adapters/in-memory/condition-evaluator.test.ts +193 -0
  246. package/src/adapters/in-memory/condition-evaluator.ts +275 -0
  247. package/src/adapters/in-memory/errors.ts +20 -0
  248. package/src/adapters/in-memory/in-memory-adapter.ts +277 -0
  249. package/src/adapters/in-memory/in-memory-uow.mutations.test.ts +296 -0
  250. package/src/adapters/in-memory/in-memory-uow.retrieval.test.ts +100 -0
  251. package/src/adapters/in-memory/in-memory-uow.ts +1348 -0
  252. package/src/adapters/in-memory/index.ts +3 -0
  253. package/src/adapters/in-memory/options.test.ts +41 -0
  254. package/src/adapters/in-memory/options.ts +87 -0
  255. package/src/adapters/in-memory/reference-resolution.test.ts +50 -0
  256. package/src/adapters/in-memory/reference-resolution.ts +67 -0
  257. package/src/adapters/in-memory/sorted-array-index.test.ts +123 -0
  258. package/src/adapters/in-memory/sorted-array-index.ts +228 -0
  259. package/src/adapters/in-memory/store.test.ts +68 -0
  260. package/src/adapters/in-memory/store.ts +145 -0
  261. package/src/adapters/in-memory/value-comparison.ts +53 -0
  262. package/src/adapters/in-memory/value-normalization.test.ts +57 -0
  263. package/src/adapters/prisma/prisma-adapter-sqlite3.test.ts +1163 -0
  264. package/src/adapters/shared/from-unit-of-work-compiler.ts +3 -1
  265. package/src/adapters/shared/uow-operation-compiler.ts +26 -16
  266. package/src/adapters/sql/index.ts +12 -0
  267. package/src/db-fragment-definition-builder.test.ts +30 -12
  268. package/src/db-fragment-definition-builder.ts +142 -73
  269. package/src/db-fragment-instantiator.test.ts +105 -13
  270. package/src/db-fragment-integration.test.ts +9 -7
  271. package/src/dispatchers/cloudflare-do/index.test.ts +73 -0
  272. package/src/dispatchers/cloudflare-do/index.ts +104 -0
  273. package/src/dispatchers/node/index.test.ts +91 -0
  274. package/src/dispatchers/node/index.ts +87 -0
  275. package/src/fragments/internal-fragment.routes.ts +42 -0
  276. package/src/fragments/internal-fragment.schema.ts +51 -0
  277. package/src/fragments/internal-fragment.test.ts +458 -8
  278. package/src/fragments/internal-fragment.ts +322 -63
  279. package/src/hooks/durable-hooks-processor.test.ts +117 -0
  280. package/src/hooks/durable-hooks-processor.ts +67 -0
  281. package/src/hooks/hooks.test.ts +165 -5
  282. package/src/hooks/hooks.ts +197 -9
  283. package/src/migration-engine/auto-from-schema.test.ts +14 -14
  284. package/src/migration-engine/auto-from-schema.ts +5 -2
  285. package/src/migration-engine/create.test.ts +2 -2
  286. package/src/migration-engine/generation-engine.test.ts +229 -104
  287. package/src/migration-engine/generation-engine.ts +94 -64
  288. package/src/migration-engine/shared.ts +1 -0
  289. package/src/mod.ts +64 -26
  290. package/src/naming/sql-naming.ts +180 -0
  291. package/src/outbox/outbox-builder.ts +241 -0
  292. package/src/outbox/outbox.test.ts +253 -0
  293. package/src/outbox/outbox.ts +137 -0
  294. package/src/query/column-defaults.ts +41 -3
  295. package/src/query/condition-builder.test.ts +3 -3
  296. package/src/query/cursor.test.ts +116 -18
  297. package/src/query/cursor.ts +75 -26
  298. package/src/query/db-now.ts +6 -0
  299. package/src/query/query-type.test.ts +2 -2
  300. package/src/query/serialize/create-sql-serializer.ts +7 -2
  301. package/src/query/serialize/dialect/mysql-serializer.ts +12 -4
  302. package/src/query/serialize/dialect/postgres-serializer.ts +34 -4
  303. package/src/query/serialize/dialect/sqlite-serializer.test.ts +51 -1
  304. package/src/query/serialize/dialect/sqlite-serializer.ts +92 -9
  305. package/src/query/serialize/sql-serializer.ts +4 -4
  306. package/src/query/simple-query-interface.ts +5 -0
  307. package/src/query/unit-of-work/execute-unit-of-work.test.ts +25 -1
  308. package/src/query/unit-of-work/execute-unit-of-work.ts +25 -8
  309. package/src/query/unit-of-work/unit-of-work-coordinator.test.ts +12 -12
  310. package/src/query/unit-of-work/unit-of-work-types.test.ts +1 -1
  311. package/src/query/unit-of-work/unit-of-work.test.ts +168 -37
  312. package/src/query/unit-of-work/unit-of-work.ts +203 -18
  313. package/src/query/value-decoding.test.ts +13 -2
  314. package/src/query/value-decoding.ts +17 -4
  315. package/src/query/value-encoding.test.ts +85 -2
  316. package/src/query/value-encoding.ts +56 -6
  317. package/src/schema/create.test.ts +129 -42
  318. package/src/schema/create.ts +185 -47
  319. package/src/schema/generate-id.test.ts +2 -2
  320. package/src/schema/generate-id.ts +2 -2
  321. package/src/schema/serialize.test.ts +14 -2
  322. package/src/schema/type-conversion/create-sql-type-mapper.ts +7 -2
  323. package/src/schema/type-conversion/dialect/sqlite.ts +18 -0
  324. package/src/schema/type-conversion/type-mapping.test.ts +25 -1
  325. package/src/schema/validator.test.ts +197 -0
  326. package/src/schema/validator.ts +231 -0
  327. package/src/{adapters/drizzle/generate.test.ts → schema-output/drizzle.test.ts} +179 -129
  328. package/src/{adapters/drizzle/generate.ts → schema-output/drizzle.ts} +143 -93
  329. package/src/schema-output/prisma.test.ts +536 -0
  330. package/src/schema-output/prisma.ts +573 -0
  331. package/src/util/default-database-adapter.ts +106 -0
  332. package/src/with-database.ts +22 -3
  333. package/tsdown.config.ts +6 -4
  334. package/dist/adapters/drizzle/drizzle-adapter.d.ts +0 -20
  335. package/dist/adapters/drizzle/drizzle-adapter.d.ts.map +0 -1
  336. package/dist/adapters/drizzle/drizzle-adapter.js +0 -27
  337. package/dist/adapters/drizzle/drizzle-adapter.js.map +0 -1
  338. package/dist/adapters/drizzle/generate.d.ts +0 -30
  339. package/dist/adapters/drizzle/generate.d.ts.map +0 -1
  340. package/dist/adapters/drizzle/generate.js.map +0 -1
  341. package/dist/adapters/kysely/kysely-adapter.d.ts +0 -19
  342. package/dist/adapters/kysely/kysely-adapter.d.ts.map +0 -1
  343. package/dist/adapters/kysely/kysely-adapter.js +0 -17
  344. package/dist/adapters/kysely/kysely-adapter.js.map +0 -1
  345. package/dist/adapters/shared/table-name-mapper.d.ts +0 -12
  346. package/dist/adapters/shared/table-name-mapper.d.ts.map +0 -1
  347. package/dist/adapters/shared/table-name-mapper.js +0 -43
  348. package/dist/adapters/shared/table-name-mapper.js.map +0 -1
  349. package/dist/node_modules/.pnpm/rou3@0.7.10/node_modules/rou3/dist/index.js.map +0 -1
  350. package/dist/schema-generator/schema-generator.d.ts +0 -15
  351. package/dist/schema-generator/schema-generator.d.ts.map +0 -1
  352. package/src/adapters/drizzle/drizzle-adapter.ts +0 -39
  353. package/src/adapters/kysely/kysely-adapter.ts +0 -27
  354. package/src/adapters/shared/table-name-mapper.ts +0 -50
  355. package/src/schema-generator/schema-generator.ts +0 -12
@@ -5,6 +5,7 @@ import type {
5
5
  UOWCompiler,
6
6
  UOWDecoder,
7
7
  UOWExecutor,
8
+ UOWInstrumentation,
8
9
  ValidIndexName,
9
10
  } from "../../query/unit-of-work/unit-of-work";
10
11
  import { UnitOfWork } from "../../query/unit-of-work/unit-of-work";
@@ -25,6 +26,7 @@ export interface UnitOfWorkConfig {
25
26
  * since those have to be manually executed.
26
27
  */
27
28
  dryRun?: boolean;
29
+ instrumentation?: UOWInstrumentation;
28
30
  }
29
31
 
30
32
  /**
@@ -50,7 +52,7 @@ export interface UnitOfWorkFactory {
50
52
  /**
51
53
  * Optional WeakMap for schema-to-namespace lookups
52
54
  */
53
- schemaNamespaceMap?: WeakMap<AnySchema, string>;
55
+ schemaNamespaceMap?: WeakMap<AnySchema, string | null>;
54
56
  }
55
57
 
56
58
  /**
@@ -8,7 +8,7 @@ import type {
8
8
  } from "../../query/unit-of-work/unit-of-work";
9
9
  import { Cursor } from "../../query/cursor";
10
10
  import type { DriverConfig } from "../generic-sql/driver-config";
11
- import { createTableNameMapper, type TableNameMapper } from "./table-name-mapper";
11
+ import { createNamingResolver, type NamingResolver } from "../../naming/sql-naming";
12
12
 
13
13
  /**
14
14
  * Options for compiling a find operation with cursor pagination
@@ -55,24 +55,24 @@ export interface CursorConditionResult {
55
55
  */
56
56
  export abstract class UOWOperationCompiler<TCompiledQuery> {
57
57
  #driverConfig: DriverConfig;
58
- #mapperFactory?: (namespace: string | undefined) => TableNameMapper | undefined;
58
+ #resolverFactory?: (schema: AnySchema, namespace: string | null) => NamingResolver;
59
59
 
60
60
  constructor(
61
61
  driverConfig: DriverConfig,
62
- mapperFactory?: (namespace: string | undefined) => TableNameMapper | undefined,
62
+ resolverFactory?: (schema: AnySchema, namespace: string | null) => NamingResolver,
63
63
  ) {
64
64
  this.#driverConfig = driverConfig;
65
- this.#mapperFactory = mapperFactory;
65
+ this.#resolverFactory = resolverFactory;
66
66
  }
67
67
 
68
68
  protected get driverConfig(): DriverConfig {
69
69
  return this.#driverConfig;
70
70
  }
71
71
 
72
- protected get mapperFactory():
73
- | ((namespace: string | undefined) => TableNameMapper | undefined)
72
+ protected get resolverFactory():
73
+ | ((schema: AnySchema, namespace: string | null) => NamingResolver)
74
74
  | undefined {
75
- return this.#mapperFactory;
75
+ return this.#resolverFactory;
76
76
  }
77
77
 
78
78
  abstract compileCount(
@@ -105,12 +105,18 @@ export abstract class UOWOperationCompiler<TCompiledQuery> {
105
105
  /**
106
106
  * Get the mapper for a specific operation based on its namespace
107
107
  */
108
- protected getMapperForOperation(namespace: string | undefined): TableNameMapper | undefined {
109
- return this.#mapperFactory
110
- ? this.#mapperFactory(namespace)
111
- : namespace
112
- ? createTableNameMapper(namespace)
113
- : undefined;
108
+ protected getNamingResolver(
109
+ schema: AnySchema,
110
+ namespace: string | null | undefined,
111
+ ): NamingResolver {
112
+ if (this.#resolverFactory) {
113
+ return this.#resolverFactory(schema, namespace ?? null);
114
+ }
115
+ return createNamingResolver(
116
+ schema,
117
+ namespace ?? null,
118
+ this.#driverConfig.defaultNamingStrategy,
119
+ );
114
120
  }
115
121
 
116
122
  /**
@@ -154,9 +160,13 @@ export abstract class UOWOperationCompiler<TCompiledQuery> {
154
160
  /**
155
161
  * Get the physical table name for an operation, applying namespace mapping if needed
156
162
  */
157
- protected getPhysicalTableName(logicalName: string, namespace: string | undefined): string {
158
- const mapper = this.getMapperForOperation(namespace);
159
- return mapper ? mapper.toPhysical(logicalName) : logicalName;
163
+ protected getPhysicalTableName(
164
+ schema: AnySchema,
165
+ logicalName: string,
166
+ namespace: string | undefined,
167
+ ): string {
168
+ const resolver = this.getNamingResolver(schema, namespace ?? null);
169
+ return resolver.getTableName(logicalName);
160
170
  }
161
171
  }
162
172
 
@@ -0,0 +1,12 @@
1
+ export {
2
+ SqlAdapter,
3
+ type SqlAdapterOptions,
4
+ type UnitOfWorkConfig,
5
+ type OutboxConfig,
6
+ sqliteProfiles,
7
+ sqliteStorageDefault,
8
+ sqliteStoragePrisma,
9
+ type SQLiteStorageMode,
10
+ } from "../generic-sql/generic-sql-adapter";
11
+
12
+ export type { SQLiteProfile } from "../adapters";
@@ -1,3 +1,6 @@
1
+ import fs from "node:fs";
2
+ import os from "node:os";
3
+ import path from "node:path";
1
4
  import { describe, it, expect, vi, expectTypeOf } from "vitest";
2
5
  import { defineFragment } from "@fragno-dev/core";
3
6
  import {
@@ -9,9 +12,11 @@ import { schema, column, idColumn } from "./schema/create";
9
12
  import type { SimpleQueryInterface } from "./query/simple-query-interface";
10
13
  import type { DatabaseAdapter } from "./adapters/adapters";
11
14
  import * as executeUnitOfWork from "./query/unit-of-work/execute-unit-of-work";
15
+ import { RequestContextStorage } from "@fragno-dev/core/internal/request-context-storage";
16
+ import { suffixNamingStrategy } from "./naming/sql-naming";
12
17
 
13
18
  // Create a test schema
14
- const testSchema = schema((s) => {
19
+ const testSchema = schema("test", (s) => {
15
20
  return s.addTable("users", (t) => {
16
21
  return t
17
22
  .addColumn("id", idColumn())
@@ -29,13 +34,17 @@ function createMockAdapter(): DatabaseAdapter {
29
34
  forSchema: vi.fn(),
30
35
  executeRetrieve: vi.fn(),
31
36
  executeMutations: vi.fn(),
37
+ registerSchema: vi.fn(),
38
+ reset: vi.fn(),
32
39
  })),
33
40
  } as unknown as SimpleQueryInterface<TestSchema>;
34
41
 
35
42
  return {
36
43
  createQueryEngine: vi.fn(() => mockdb),
37
- migrate: vi.fn(),
44
+ getSchemaVersion: vi.fn(async () => undefined),
38
45
  close: vi.fn(),
46
+ contextStorage: new RequestContextStorage(),
47
+ namingStrategy: suffixNamingStrategy,
39
48
  } as unknown as DatabaseAdapter;
40
49
  }
41
50
 
@@ -735,10 +744,7 @@ describe("DatabaseFragmentDefinitionBuilder", () => {
735
744
 
736
745
  const mockAdapter = createMockAdapter();
737
746
 
738
- const definition = withDatabase(
739
- testSchema,
740
- "my-namespace",
741
- )(defineFragment<Config>("complex-db-frag"))
747
+ const definition = withDatabase(testSchema)(defineFragment<Config>("complex-db-frag"))
742
748
  .withDependencies(({ config }) => ({
743
749
  connectionString: config.dbConnectionString,
744
750
  debug: config.debug,
@@ -806,17 +812,29 @@ describe("DatabaseFragmentDefinitionBuilder", () => {
806
812
  });
807
813
  });
808
814
 
809
- describe("error handling", () => {
810
- it("should throw error if database adapter is missing", () => {
815
+ describe("default adapter", () => {
816
+ it("should default to sqlite adapter when database adapter is missing", () => {
817
+ const previous = process.env["FRAGNO_DATA_DIR"];
818
+ const dataDir = fs.mkdtempSync(path.join(os.tmpdir(), "fragno-db-default-"));
819
+ process.env["FRAGNO_DATA_DIR"] = dataDir;
820
+
811
821
  const definition = withDatabase(testSchema)(defineFragment("db-frag")).build();
812
822
 
813
- expect(() => {
814
- definition.dependencies!({
823
+ try {
824
+ const deps = definition.dependencies!({
815
825
  config: {},
816
- // @ts-expect-error No databaseAdapter - intentionally invalid for runtime error test
817
826
  options: {},
818
827
  });
819
- }).toThrow("Database fragment requires a database adapter");
828
+
829
+ expect(deps.db).toBeDefined();
830
+ expect(deps.createUnitOfWork).toBeDefined();
831
+ } finally {
832
+ if (previous === undefined) {
833
+ delete process.env["FRAGNO_DATA_DIR"];
834
+ } else {
835
+ process.env["FRAGNO_DATA_DIR"] = previous;
836
+ }
837
+ }
820
838
  });
821
839
  });
822
840
 
@@ -21,20 +21,34 @@ import {
21
21
  } from "./query/unit-of-work/execute-unit-of-work";
22
22
  import {
23
23
  prepareHookMutations,
24
- processHooks,
25
24
  type HooksMap,
26
25
  type HookFn,
27
26
  type HookContext,
27
+ type HookProcessorConfig,
28
+ type DurableHooksProcessingOptions,
29
+ createHookScheduler,
28
30
  } from "./hooks/hooks";
29
31
  import type { InternalFragmentInstance } from "./fragments/internal-fragment";
32
+ import { resolveDatabaseAdapter } from "./util/default-database-adapter";
33
+ import { sanitizeNamespace } from "./naming/sql-naming";
30
34
 
31
35
  /**
32
- * Extended FragnoPublicConfig that includes a database adapter.
33
- * Use this type when creating fragments with database support.
36
+ * Extended FragnoPublicConfig for database fragments.
37
+ * If databaseAdapter is omitted and better-sqlite3 is available, a default SQLite adapter is used.
34
38
  */
35
39
  export type FragnoPublicConfigWithDatabase = FragnoPublicConfig & {
36
40
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
37
- databaseAdapter: DatabaseAdapter<any>;
41
+ databaseAdapter?: DatabaseAdapter<any>;
42
+ /**
43
+ * Optional durable hooks processing configuration.
44
+ */
45
+ durableHooks?: DurableHooksProcessingOptions;
46
+ /**
47
+ * Optional override for database namespace. If provided (including null), it is used as-is
48
+ * without sanitization — the caller is responsible for providing a valid namespace.
49
+ * When omitted, defaults to a sanitized version of schema.name.
50
+ */
51
+ databaseNamespace?: string | null;
38
52
  };
39
53
 
40
54
  /**
@@ -44,6 +58,7 @@ export type FragnoPublicConfigWithDatabase = FragnoPublicConfig & {
44
58
  export type ImplicitDatabaseDependencies<TSchema extends AnySchema> = {
45
59
  /**
46
60
  * Database query engine for the fragment's schema.
61
+ * @deprecated Prefer handlerTx/serviceTx instead of direct db usage.
47
62
  */
48
63
  db: SimpleQueryInterface<TSchema>;
49
64
  /**
@@ -53,7 +68,7 @@ export type ImplicitDatabaseDependencies<TSchema extends AnySchema> = {
53
68
  /**
54
69
  * The database namespace for this fragment.
55
70
  */
56
- namespace: string;
71
+ namespace: string | null;
57
72
  /**
58
73
  * Create a new Unit of Work for database operations.
59
74
  */
@@ -145,21 +160,23 @@ export type DatabaseFragmentContext<TSchema extends AnySchema> = {
145
160
  function createDatabaseContext<TSchema extends AnySchema>(
146
161
  options: FragnoPublicConfigWithDatabase,
147
162
  schema: TSchema,
148
- namespace: string,
149
163
  ): DatabaseFragmentContext<TSchema> {
150
- const databaseAdapter = options.databaseAdapter;
151
-
152
- if (!databaseAdapter) {
153
- throw new Error(
154
- "Database fragment requires a database adapter to be provided in options.databaseAdapter",
155
- );
156
- }
164
+ const databaseAdapter = resolveDatabaseAdapter(options, schema);
157
165
 
166
+ const namespace = resolveDatabaseNamespace(options, schema);
158
167
  const db = databaseAdapter.createQueryEngine(schema, namespace);
159
168
 
160
169
  return { databaseAdapter, db };
161
170
  }
162
171
 
172
+ function resolveDatabaseNamespace<TSchema extends AnySchema>(
173
+ options: FragnoPublicConfigWithDatabase,
174
+ schema: TSchema,
175
+ ): string | null {
176
+ const hasOverride = options.databaseNamespace !== undefined;
177
+ return hasOverride ? (options.databaseNamespace ?? null) : sanitizeNamespace(schema.name);
178
+ }
179
+
163
180
  /**
164
181
  * Storage type for database fragments - stores the Unit of Work.
165
182
  */
@@ -171,7 +188,7 @@ export type DatabaseRequestStorage = {
171
188
  * Builder for database fragments that wraps the core fragment builder
172
189
  * and provides database-specific functionality.
173
190
  *
174
- * Database fragments always require FragnoPublicConfigWithDatabase (which includes databaseAdapter).
191
+ * Database fragments use FragnoPublicConfigWithDatabase and default the adapter when possible.
175
192
  */
176
193
  export class DatabaseFragmentDefinitionBuilder<
177
194
  TSchema extends AnySchema,
@@ -201,7 +218,6 @@ export class DatabaseFragmentDefinitionBuilder<
201
218
  TLinkedFragments
202
219
  >;
203
220
  #schema: TSchema;
204
- #namespace: string;
205
221
  #hooksFactory?: (context: { config: TConfig; options: FragnoPublicConfigWithDatabase }) => THooks;
206
222
 
207
223
  constructor(
@@ -219,7 +235,6 @@ export class DatabaseFragmentDefinitionBuilder<
219
235
  TLinkedFragments
220
236
  >,
221
237
  schema: TSchema,
222
- namespace?: string,
223
238
  hooksFactory?: (context: {
224
239
  config: TConfig;
225
240
  options: FragnoPublicConfigWithDatabase;
@@ -227,7 +242,6 @@ export class DatabaseFragmentDefinitionBuilder<
227
242
  ) {
228
243
  this.#baseBuilder = baseBuilder;
229
244
  this.#schema = schema;
230
- this.#namespace = namespace ?? baseBuilder.name;
231
245
  this.#hooksFactory = hooksFactory;
232
246
  }
233
247
 
@@ -257,7 +271,8 @@ export class DatabaseFragmentDefinitionBuilder<
257
271
  > {
258
272
  // Wrap user function to inject DB context
259
273
  const wrappedFn = (context: { config: TConfig; options: FragnoPublicConfigWithDatabase }) => {
260
- const dbContext = createDatabaseContext(context.options, this.#schema, this.#namespace);
274
+ const dbContext = createDatabaseContext(context.options, this.#schema);
275
+ const namespace = resolveDatabaseNamespace(context.options, this.#schema);
261
276
 
262
277
  // Call user function with enriched context
263
278
  const userDeps = fn({
@@ -272,7 +287,7 @@ export class DatabaseFragmentDefinitionBuilder<
272
287
  const implicitDeps: ImplicitDatabaseDependencies<TSchema> = {
273
288
  db: dbContext.db,
274
289
  schema: this.#schema,
275
- namespace: this.#namespace,
290
+ namespace,
276
291
  createUnitOfWork: createUow,
277
292
  };
278
293
 
@@ -285,12 +300,7 @@ export class DatabaseFragmentDefinitionBuilder<
285
300
  // Create new base builder with wrapped function
286
301
  const newBaseBuilder = this.#baseBuilder.withDependencies(wrappedFn);
287
302
 
288
- return new DatabaseFragmentDefinitionBuilder(
289
- newBaseBuilder,
290
- this.#schema,
291
- this.#namespace,
292
- this.#hooksFactory,
293
- );
303
+ return new DatabaseFragmentDefinitionBuilder(newBaseBuilder, this.#schema, this.#hooksFactory);
294
304
  }
295
305
 
296
306
  providesBaseService<TNewService>(
@@ -318,12 +328,7 @@ export class DatabaseFragmentDefinitionBuilder<
318
328
  > {
319
329
  const newBaseBuilder = this.#baseBuilder.providesBaseService<TNewService>(fn);
320
330
 
321
- return new DatabaseFragmentDefinitionBuilder(
322
- newBaseBuilder,
323
- this.#schema,
324
- this.#namespace,
325
- this.#hooksFactory,
326
- );
331
+ return new DatabaseFragmentDefinitionBuilder(newBaseBuilder, this.#schema, this.#hooksFactory);
327
332
  }
328
333
 
329
334
  providesService<TServiceName extends string, TService>(
@@ -355,12 +360,7 @@ export class DatabaseFragmentDefinitionBuilder<
355
360
  fn,
356
361
  );
357
362
 
358
- return new DatabaseFragmentDefinitionBuilder(
359
- newBaseBuilder,
360
- this.#schema,
361
- this.#namespace,
362
- this.#hooksFactory,
363
- );
363
+ return new DatabaseFragmentDefinitionBuilder(newBaseBuilder, this.#schema, this.#hooksFactory);
364
364
  }
365
365
 
366
366
  /**
@@ -399,12 +399,7 @@ export class DatabaseFragmentDefinitionBuilder<
399
399
  fn,
400
400
  );
401
401
 
402
- return new DatabaseFragmentDefinitionBuilder(
403
- newBaseBuilder,
404
- this.#schema,
405
- this.#namespace,
406
- this.#hooksFactory,
407
- );
402
+ return new DatabaseFragmentDefinitionBuilder(newBaseBuilder, this.#schema, this.#hooksFactory);
408
403
  }
409
404
 
410
405
  /**
@@ -468,7 +463,6 @@ export class DatabaseFragmentDefinitionBuilder<
468
463
  const newBuilder = new DatabaseFragmentDefinitionBuilder(
469
464
  this.#baseBuilder,
470
465
  this.#schema,
471
- this.#namespace,
472
466
  ) as unknown as DatabaseFragmentDefinitionBuilder<
473
467
  TSchema,
474
468
  TConfig,
@@ -509,12 +503,7 @@ export class DatabaseFragmentDefinitionBuilder<
509
503
  > {
510
504
  const newBaseBuilder = this.#baseBuilder.usesService<TServiceName, TService>(serviceName);
511
505
 
512
- return new DatabaseFragmentDefinitionBuilder(
513
- newBaseBuilder,
514
- this.#schema,
515
- this.#namespace,
516
- this.#hooksFactory,
517
- );
506
+ return new DatabaseFragmentDefinitionBuilder(newBaseBuilder, this.#schema, this.#hooksFactory);
518
507
  }
519
508
 
520
509
  /**
@@ -540,12 +529,7 @@ export class DatabaseFragmentDefinitionBuilder<
540
529
  serviceName,
541
530
  );
542
531
 
543
- return new DatabaseFragmentDefinitionBuilder(
544
- newBaseBuilder,
545
- this.#schema,
546
- this.#namespace,
547
- this.#hooksFactory,
548
- );
532
+ return new DatabaseFragmentDefinitionBuilder(newBaseBuilder, this.#schema, this.#hooksFactory);
549
533
  }
550
534
 
551
535
  /**
@@ -594,12 +578,13 @@ export class DatabaseFragmentDefinitionBuilder<
594
578
  }
595
579
  }
596
580
 
597
- const { db } = createDatabaseContext(context.options, this.#schema, this.#namespace);
581
+ const { db } = createDatabaseContext(context.options, this.#schema);
582
+ const namespace = resolveDatabaseNamespace(context.options, this.#schema);
598
583
 
599
584
  const implicitDeps: ImplicitDatabaseDependencies<TSchema> = {
600
585
  db,
601
586
  schema: this.#schema,
602
- namespace: this.#namespace,
587
+ namespace,
603
588
  createUnitOfWork: () => db.createUnitOfWork(),
604
589
  };
605
590
 
@@ -612,7 +597,7 @@ export class DatabaseFragmentDefinitionBuilder<
612
597
  // Use the adapter's shared context storage (all fragments using the same adapter share this storage)
613
598
  const builderWithExternalStorage = this.#baseBuilder.withExternalRequestStorage(
614
599
  ({ options }) => {
615
- const dbContext = createDatabaseContext(options, this.#schema, this.#namespace);
600
+ const dbContext = createDatabaseContext(options, this.#schema);
616
601
  return dbContext.databaseAdapter.contextStorage;
617
602
  },
618
603
  );
@@ -621,7 +606,7 @@ export class DatabaseFragmentDefinitionBuilder<
621
606
  const builderWithStorage = builderWithExternalStorage.withRequestStorage(
622
607
  ({ options }): DatabaseRequestStorage => {
623
608
  // Create database context - needed here to create the UOW
624
- const dbContextForStorage = createDatabaseContext(options, this.#schema, this.#namespace);
609
+ const dbContextForStorage = createDatabaseContext(options, this.#schema);
625
610
 
626
611
  // Create a new Unit of Work for this request
627
612
  const uow: IUnitOfWork = dbContextForStorage.db.createUnitOfWork();
@@ -637,18 +622,91 @@ export class DatabaseFragmentDefinitionBuilder<
637
622
  options: FragnoPublicConfigWithDatabase;
638
623
  }) => InternalFragmentInstance;
639
624
 
625
+ // Cache per instantiated fragment (deps object is unique per instantiation).
626
+ const hooksConfigCache = new WeakMap<object, HookProcessorConfig<THooks>>();
627
+
628
+ const createHooksConfig = (context: {
629
+ config: TConfig;
630
+ options: FragnoPublicConfigWithDatabase;
631
+ deps: TDeps;
632
+ }) => {
633
+ if (!this.#hooksFactory) {
634
+ return undefined;
635
+ }
636
+ const depsKey =
637
+ typeof context.deps === "object" && context.deps !== null
638
+ ? (context.deps as object)
639
+ : undefined;
640
+ const cachedHooksConfig = depsKey ? hooksConfigCache.get(depsKey) : undefined;
641
+ if (cachedHooksConfig) {
642
+ return cachedHooksConfig;
643
+ }
644
+
645
+ const namespace = resolveDatabaseNamespace(context.options, this.#schema);
646
+ const namespaceKey = namespace ?? this.#schema.name;
647
+ const durableHooksOptions = context.options.durableHooks;
648
+ const baseAdapter = resolveDatabaseAdapter(context.options, this.#schema);
649
+ const hookAdapter = baseAdapter.getHookProcessingAdapter?.() ?? baseAdapter;
650
+ const hookOptions =
651
+ hookAdapter === baseAdapter
652
+ ? context.options
653
+ : { ...context.options, databaseAdapter: hookAdapter };
654
+ const dbContextForHooks = createDatabaseContext(hookOptions, this.#schema);
655
+ const hooksConfig: HookProcessorConfig<THooks> = {
656
+ hooks: this.#hooksFactory(context),
657
+ namespace: namespaceKey,
658
+ internalFragment: internalFragmentFactory({
659
+ config: context.config,
660
+ options: hookOptions,
661
+ }),
662
+ handlerTx: (execOptions?: Omit<ExecuteTxOptions, "createUnitOfWork">) => {
663
+ const userOnBeforeMutate = execOptions?.onBeforeMutate;
664
+ const userOnAfterMutate = execOptions?.onAfterMutate;
665
+ return createHandlerTxBuilder<THooks>({
666
+ ...execOptions,
667
+ createUnitOfWork: () => {
668
+ const uow = dbContextForHooks.db.createUnitOfWork();
669
+ uow.registerSchema(
670
+ hooksConfig.internalFragment.$internal.deps.schema,
671
+ hooksConfig.internalFragment.$internal.deps.namespace,
672
+ );
673
+ return uow;
674
+ },
675
+ onBeforeMutate: (uow) => {
676
+ prepareHookMutations(uow, hooksConfig);
677
+ if (userOnBeforeMutate) {
678
+ userOnBeforeMutate(uow);
679
+ }
680
+ },
681
+ onAfterMutate: async (uow) => {
682
+ void hooksConfig.scheduler?.schedule().catch((error) => {
683
+ console.error("Durable hooks processing failed", error);
684
+ });
685
+ if (userOnAfterMutate) {
686
+ await userOnAfterMutate(uow);
687
+ }
688
+ },
689
+ });
690
+ },
691
+ stuckProcessingTimeoutMinutes: durableHooksOptions?.stuckProcessingTimeoutMinutes,
692
+ onStuckProcessingHooks: durableHooksOptions?.onStuckProcessingHooks,
693
+ };
694
+ hooksConfig.scheduler = createHookScheduler(hooksConfig);
695
+ if (depsKey) {
696
+ hooksConfigCache.set(depsKey, hooksConfig);
697
+ }
698
+ return hooksConfig;
699
+ };
700
+
640
701
  const builderWithContext = builderWithStorage.withThisContext<
641
702
  DatabaseServiceContext<THooks>,
642
703
  DatabaseHandlerContext<THooks>
643
- >(({ storage, config, options }) => {
704
+ >(({ storage, config, options, deps }) => {
644
705
  // Create hooks config if hooks factory is defined
645
- const hooksConfig = this.#hooksFactory
646
- ? {
647
- hooks: this.#hooksFactory({ config, options }),
648
- namespace: this.#namespace,
649
- internalFragment: internalFragmentFactory({ config, options }),
650
- }
651
- : undefined;
706
+ const hooksConfig = createHooksConfig({ config, options, deps });
707
+ const internalFragment =
708
+ hooksConfig?.internalFragment ??
709
+ (internalFragmentFactory ? internalFragmentFactory({ config, options }) : undefined);
652
710
 
653
711
  // Builder API: serviceTx using createServiceTxBuilder
654
712
  function serviceTx<TSchema extends AnySchema>(schema: TSchema) {
@@ -681,10 +739,10 @@ export class DatabaseFragmentDefinitionBuilder<
681
739
  ...execOptions,
682
740
  createUnitOfWork: () => {
683
741
  currentStorage.uow.reset();
684
- if (hooksConfig) {
742
+ if (internalFragment) {
685
743
  currentStorage.uow.registerSchema(
686
- hooksConfig.internalFragment.$internal.deps.schema,
687
- hooksConfig.internalFragment.$internal.deps.namespace,
744
+ internalFragment.$internal.deps.schema,
745
+ internalFragment.$internal.deps.namespace,
688
746
  );
689
747
  }
690
748
  return currentStorage.uow;
@@ -698,8 +756,10 @@ export class DatabaseFragmentDefinitionBuilder<
698
756
  }
699
757
  },
700
758
  onAfterMutate: async (uow) => {
701
- if (hooksConfig) {
702
- await processHooks(hooksConfig);
759
+ if (hooksConfig?.scheduler) {
760
+ void hooksConfig.scheduler.schedule().catch((error) => {
761
+ console.error("Durable hooks processing failed", error);
762
+ });
703
763
  }
704
764
  if (userOnAfterMutate) {
705
765
  await userOnAfterMutate(uow);
@@ -717,6 +777,15 @@ export class DatabaseFragmentDefinitionBuilder<
717
777
 
718
778
  // Build the final definition
719
779
  const finalDef = builderWithContext.build();
780
+ if (this.#hooksFactory) {
781
+ finalDef.internalDataFactory = ({ config, options, deps }) => ({
782
+ durableHooks: createHooksConfig({
783
+ config: config as TConfig,
784
+ options: options as FragnoPublicConfigWithDatabase,
785
+ deps: deps as TDeps,
786
+ }),
787
+ });
788
+ }
720
789
 
721
790
  // Return the complete definition with proper typing and dependencies
722
791
  return {