@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 +1 @@
1
- {"version":3,"file":"db-fragment-definition-builder.js","names":["#baseBuilder","#schema","#namespace","#hooksFactory","implicitDeps: ImplicitDatabaseDependencies<TSchema>","serviceContext: DatabaseServiceContext<THooks>"],"sources":["../src/db-fragment-definition-builder.ts"],"sourcesContent":["import type { AnySchema } from \"./schema/create\";\nimport type { SimpleQueryInterface } from \"./query/simple-query-interface\";\nimport type { DatabaseAdapter } from \"./adapters/adapters\";\nimport type { IUnitOfWork } from \"./query/unit-of-work/unit-of-work\";\nimport type {\n RequestThisContext,\n FragnoPublicConfig,\n AnyFragnoInstantiatedFragment,\n} from \"@fragno-dev/core\";\nimport {\n FragmentDefinitionBuilder,\n type FragmentDefinition,\n type ServiceConstructorFn,\n} from \"@fragno-dev/core\";\nimport {\n createServiceTxBuilder,\n createHandlerTxBuilder,\n ServiceTxBuilder,\n HandlerTxBuilder,\n type ExecuteTxOptions,\n} from \"./query/unit-of-work/execute-unit-of-work\";\nimport {\n prepareHookMutations,\n processHooks,\n type HooksMap,\n type HookFn,\n type HookContext,\n} from \"./hooks/hooks\";\nimport type { InternalFragmentInstance } from \"./fragments/internal-fragment\";\n\n/**\n * Extended FragnoPublicConfig that includes a database adapter.\n * Use this type when creating fragments with database support.\n */\nexport type FragnoPublicConfigWithDatabase = FragnoPublicConfig & {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n databaseAdapter: DatabaseAdapter<any>;\n};\n\n/**\n * Implicit dependencies that database fragments get automatically.\n * These are injected without requiring explicit configuration.\n */\nexport type ImplicitDatabaseDependencies<TSchema extends AnySchema> = {\n /**\n * Database query engine for the fragment's schema.\n */\n db: SimpleQueryInterface<TSchema>;\n /**\n * The schema definition for this fragment.\n */\n schema: TSchema;\n /**\n * The database namespace for this fragment.\n */\n namespace: string;\n /**\n * Create a new Unit of Work for database operations.\n */\n createUnitOfWork: () => IUnitOfWork;\n};\n\n/**\n * Service context for database fragments - provides restricted UOW access without execute methods.\n */\nexport type DatabaseServiceContext<THooks extends HooksMap> = RequestThisContext & {\n /**\n * Create a service-level transaction builder using the fluent API.\n * Returns a builder that can be chained with withServiceCalls, retrieve,\n * transformRetrieve, mutate, transform, and build.\n *\n * @example\n * ```ts\n * return this.serviceTx(schema)\n * .withServiceCalls(() => [otherService.getData()])\n * .retrieve((uow) => uow.find(\"users\", ...))\n * .transformRetrieve(([users]) => users[0])\n * .mutate(({ uow, retrieveResult, serviceIntermediateResult }) =>\n * uow.create(\"records\", { ... })\n * )\n * .transform(({ mutateResult, serviceResult }) => ({ id: mutateResult }))\n * .build();\n * ```\n */\n serviceTx<TSchema extends AnySchema>(\n schema: TSchema,\n ): ServiceTxBuilder<\n TSchema,\n readonly [],\n [],\n [],\n unknown,\n unknown,\n false,\n false,\n false,\n false,\n THooks\n >;\n};\n\n/**\n * Handler context for database fragments - provides UOW execution with automatic retry support.\n */\nexport type DatabaseHandlerContext<THooks extends HooksMap = {}> = RequestThisContext & {\n /**\n * Create a handler-level transaction builder using the fluent API.\n * Returns a builder that can be chained with withServiceCalls, retrieve,\n * transformRetrieve, mutate, transform, and execute.\n *\n * @example\n * ```ts\n * const result = await this.handlerTx()\n * .withServiceCalls(() => [userService.getUser(id)])\n * .mutate(({ forSchema, idempotencyKey, currentAttempt, serviceIntermediateResult }) => {\n * return forSchema(ordersSchema).create(\"orders\", { ... });\n * })\n * .transform(({ mutateResult, serviceResult }) => ({ ... }))\n * .execute();\n * ```\n */\n handlerTx(\n options?: Omit<ExecuteTxOptions, \"createUnitOfWork\">,\n ): HandlerTxBuilder<readonly [], [], [], unknown, unknown, false, false, false, false, THooks>;\n};\n\n/**\n * Database fragment context provided to user callbacks.\n */\nexport type DatabaseFragmentContext<TSchema extends AnySchema> = {\n /**\n * Database adapter instance.\n */\n databaseAdapter: DatabaseAdapter<any>; // eslint-disable-line @typescript-eslint/no-explicit-any\n /**\n * ORM query engine for the fragment's schema.\n */\n db: SimpleQueryInterface<TSchema>;\n};\n\n/**\n * Create database context from options.\n * This extracts the database adapter and creates the ORM instance.\n */\nfunction createDatabaseContext<TSchema extends AnySchema>(\n options: FragnoPublicConfigWithDatabase,\n schema: TSchema,\n namespace: string,\n): DatabaseFragmentContext<TSchema> {\n const databaseAdapter = options.databaseAdapter;\n\n if (!databaseAdapter) {\n throw new Error(\n \"Database fragment requires a database adapter to be provided in options.databaseAdapter\",\n );\n }\n\n const db = databaseAdapter.createQueryEngine(schema, namespace);\n\n return { databaseAdapter, db };\n}\n\n/**\n * Storage type for database fragments - stores the Unit of Work.\n */\nexport type DatabaseRequestStorage = {\n uow: IUnitOfWork;\n};\n\n/**\n * Builder for database fragments that wraps the core fragment builder\n * and provides database-specific functionality.\n *\n * Database fragments always require FragnoPublicConfigWithDatabase (which includes databaseAdapter).\n */\nexport class DatabaseFragmentDefinitionBuilder<\n TSchema extends AnySchema,\n TConfig,\n TDeps,\n TBaseServices,\n TServices,\n TServiceDependencies,\n TPrivateServices,\n THooks extends HooksMap = {},\n TServiceThisContext extends RequestThisContext = DatabaseHandlerContext,\n THandlerThisContext extends RequestThisContext = DatabaseHandlerContext,\n TLinkedFragments extends Record<string, AnyFragnoInstantiatedFragment> = {},\n> {\n // Store the base builder - we'll replace its storage and context setup when building\n #baseBuilder: FragmentDefinitionBuilder<\n TConfig,\n FragnoPublicConfigWithDatabase,\n TDeps,\n TBaseServices,\n TServices,\n TServiceDependencies,\n TPrivateServices,\n TServiceThisContext,\n THandlerThisContext,\n DatabaseRequestStorage,\n TLinkedFragments\n >;\n #schema: TSchema;\n #namespace: string;\n #hooksFactory?: (context: { config: TConfig; options: FragnoPublicConfigWithDatabase }) => THooks;\n\n constructor(\n baseBuilder: FragmentDefinitionBuilder<\n TConfig,\n FragnoPublicConfigWithDatabase,\n TDeps,\n TBaseServices,\n TServices,\n TServiceDependencies,\n TPrivateServices,\n TServiceThisContext,\n THandlerThisContext,\n DatabaseRequestStorage,\n TLinkedFragments\n >,\n schema: TSchema,\n namespace?: string,\n hooksFactory?: (context: {\n config: TConfig;\n options: FragnoPublicConfigWithDatabase;\n }) => THooks,\n ) {\n this.#baseBuilder = baseBuilder;\n this.#schema = schema;\n this.#namespace = namespace ?? baseBuilder.name;\n this.#hooksFactory = hooksFactory;\n }\n\n /**\n * Define dependencies for this database fragment.\n * The context includes database adapter and ORM instance.\n */\n withDependencies<TNewDeps>(\n fn: (context: {\n config: TConfig;\n options: FragnoPublicConfigWithDatabase;\n db: SimpleQueryInterface<TSchema>;\n databaseAdapter: DatabaseAdapter<any>; // eslint-disable-line @typescript-eslint/no-explicit-any\n }) => TNewDeps,\n ): DatabaseFragmentDefinitionBuilder<\n TSchema,\n TConfig,\n TNewDeps & ImplicitDatabaseDependencies<TSchema>,\n {},\n {},\n TServiceDependencies,\n {},\n THooks,\n TServiceThisContext,\n THandlerThisContext,\n TLinkedFragments\n > {\n // Wrap user function to inject DB context\n const wrappedFn = (context: { config: TConfig; options: FragnoPublicConfigWithDatabase }) => {\n const dbContext = createDatabaseContext(context.options, this.#schema, this.#namespace);\n\n // Call user function with enriched context\n const userDeps = fn({\n config: context.config,\n options: context.options,\n db: dbContext.db,\n databaseAdapter: dbContext.databaseAdapter,\n });\n\n // Create implicit dependencies\n const createUow = () => dbContext.db.createUnitOfWork();\n const implicitDeps: ImplicitDatabaseDependencies<TSchema> = {\n db: dbContext.db,\n schema: this.#schema,\n namespace: this.#namespace,\n createUnitOfWork: createUow,\n };\n\n return {\n ...userDeps,\n ...implicitDeps,\n };\n };\n\n // Create new base builder with wrapped function\n const newBaseBuilder = this.#baseBuilder.withDependencies(wrappedFn);\n\n return new DatabaseFragmentDefinitionBuilder(\n newBaseBuilder,\n this.#schema,\n this.#namespace,\n this.#hooksFactory,\n );\n }\n\n providesBaseService<TNewService>(\n fn: ServiceConstructorFn<\n TConfig,\n FragnoPublicConfigWithDatabase,\n TDeps,\n TServiceDependencies,\n TPrivateServices,\n TNewService,\n TServiceThisContext\n >,\n ): DatabaseFragmentDefinitionBuilder<\n TSchema,\n TConfig,\n TDeps,\n TNewService,\n TServices,\n TServiceDependencies,\n TPrivateServices,\n THooks,\n TServiceThisContext,\n THandlerThisContext,\n TLinkedFragments\n > {\n const newBaseBuilder = this.#baseBuilder.providesBaseService<TNewService>(fn);\n\n return new DatabaseFragmentDefinitionBuilder(\n newBaseBuilder,\n this.#schema,\n this.#namespace,\n this.#hooksFactory,\n );\n }\n\n providesService<TServiceName extends string, TService>(\n serviceName: TServiceName,\n fn: ServiceConstructorFn<\n TConfig,\n FragnoPublicConfigWithDatabase,\n TDeps,\n TServiceDependencies,\n TPrivateServices,\n TService,\n TServiceThisContext\n >,\n ): DatabaseFragmentDefinitionBuilder<\n TSchema,\n TConfig,\n TDeps,\n TBaseServices,\n TServices & { [K in TServiceName]: TService },\n TServiceDependencies,\n TPrivateServices,\n THooks,\n TServiceThisContext,\n THandlerThisContext,\n TLinkedFragments\n > {\n const newBaseBuilder = this.#baseBuilder.providesService<TServiceName, TService>(\n serviceName,\n fn,\n );\n\n return new DatabaseFragmentDefinitionBuilder(\n newBaseBuilder,\n this.#schema,\n this.#namespace,\n this.#hooksFactory,\n );\n }\n\n /**\n * Provide a private service that is only accessible to the fragment author.\n * Private services are NOT exposed on the fragment instance, but can be used\n * when defining other services (baseServices, namedServices, and other privateServices).\n * Private services are instantiated in order, so earlier private services are available\n * to later ones.\n */\n providesPrivateService<TServiceName extends string, TService>(\n serviceName: TServiceName,\n fn: ServiceConstructorFn<\n TConfig,\n FragnoPublicConfigWithDatabase,\n TDeps,\n TServiceDependencies,\n TPrivateServices,\n TService,\n TServiceThisContext\n >,\n ): DatabaseFragmentDefinitionBuilder<\n TSchema,\n TConfig,\n TDeps,\n TBaseServices,\n TServices,\n TServiceDependencies,\n TPrivateServices & { [K in TServiceName]: TService },\n THooks,\n TServiceThisContext,\n THandlerThisContext,\n TLinkedFragments\n > {\n const newBaseBuilder = this.#baseBuilder.providesPrivateService<TServiceName, TService>(\n serviceName,\n fn,\n );\n\n return new DatabaseFragmentDefinitionBuilder(\n newBaseBuilder,\n this.#schema,\n this.#namespace,\n this.#hooksFactory,\n );\n }\n\n /**\n * Define durable hooks for this fragment.\n * Hooks are automatically persisted and retried on failure.\n *\n * @param fn - Function that receives defineHook helper and returns a hooks map\n * @returns Builder with hooks type set\n *\n * @example\n * ```ts\n * .provideHooks(({ defineHook, config }) => ({\n * onSubscribe: defineHook(async function (payload: { email: string }) {\n * // 'this' context available (HookServiceContext with idempotencyKey)\n * await config.onSubscribe?.(payload.email);\n * }),\n * }))\n * ```\n */\n provideHooks<TNewHooks extends HooksMap>(\n fn: (context: {\n config: TConfig;\n options: FragnoPublicConfigWithDatabase;\n defineHook: <TPayload>(\n hook: (this: HookContext, payload: TPayload) => void | Promise<void>,\n ) => HookFn<TPayload>;\n }) => TNewHooks,\n ): DatabaseFragmentDefinitionBuilder<\n TSchema,\n TConfig,\n TDeps,\n TBaseServices,\n TServices,\n TServiceDependencies,\n TPrivateServices,\n TNewHooks,\n DatabaseServiceContext<TNewHooks>,\n THandlerThisContext,\n TLinkedFragments\n > {\n const defineHook = <TPayload>(\n hook: (this: HookContext, payload: TPayload) => void | Promise<void>,\n ): HookFn<TPayload> => {\n return hook;\n };\n\n // Store the hooks factory - it will be called in build() with config/options\n const hooksFactory = (context: {\n config: TConfig;\n options: FragnoPublicConfigWithDatabase;\n }) => {\n return fn({\n config: context.config,\n options: context.options,\n defineHook,\n });\n };\n\n // Create new builder with hooks factory stored\n // Cast is safe: we're only changing THooks and TServiceThisContext type parameters\n const newBuilder = new DatabaseFragmentDefinitionBuilder(\n this.#baseBuilder,\n this.#schema,\n this.#namespace,\n ) as unknown as DatabaseFragmentDefinitionBuilder<\n TSchema,\n TConfig,\n TDeps,\n TBaseServices,\n TServices,\n TServiceDependencies,\n TPrivateServices,\n TNewHooks,\n DatabaseServiceContext<TNewHooks>,\n THandlerThisContext,\n TLinkedFragments\n >;\n\n newBuilder.#hooksFactory = hooksFactory;\n\n return newBuilder;\n }\n\n /**\n * Declare that this fragment uses a required service provided by the runtime.\n * Delegates to the base builder.\n */\n usesService<TServiceName extends string, TService>(\n serviceName: TServiceName,\n ): DatabaseFragmentDefinitionBuilder<\n TSchema,\n TConfig,\n TDeps,\n TBaseServices,\n TServices,\n TServiceDependencies & { [K in TServiceName]: TService },\n TPrivateServices,\n THooks,\n TServiceThisContext,\n THandlerThisContext,\n TLinkedFragments\n > {\n const newBaseBuilder = this.#baseBuilder.usesService<TServiceName, TService>(serviceName);\n\n return new DatabaseFragmentDefinitionBuilder(\n newBaseBuilder,\n this.#schema,\n this.#namespace,\n this.#hooksFactory,\n );\n }\n\n /**\n * Declare that this fragment uses an optional service provided by the runtime.\n * Delegates to the base builder.\n */\n usesOptionalService<TServiceName extends string, TService>(\n serviceName: TServiceName,\n ): DatabaseFragmentDefinitionBuilder<\n TSchema,\n TConfig,\n TDeps,\n TBaseServices,\n TServices,\n TServiceDependencies & { [K in TServiceName]: TService | undefined },\n TPrivateServices,\n THooks,\n TServiceThisContext,\n THandlerThisContext,\n TLinkedFragments\n > {\n const newBaseBuilder = this.#baseBuilder.usesOptionalService<TServiceName, TService>(\n serviceName,\n );\n\n return new DatabaseFragmentDefinitionBuilder(\n newBaseBuilder,\n this.#schema,\n this.#namespace,\n this.#hooksFactory,\n );\n }\n\n /**\n * Build the final database fragment definition.\n * This includes the request context setup for UnitOfWork management.\n * Note: TDeps already includes ImplicitDatabaseDependencies from withDatabase().\n */\n build(): FragmentDefinition<\n TConfig,\n FragnoPublicConfigWithDatabase,\n TDeps,\n TBaseServices,\n TServices,\n TServiceDependencies,\n TPrivateServices,\n DatabaseServiceContext<THooks>,\n DatabaseHandlerContext<THooks>,\n DatabaseRequestStorage,\n TLinkedFragments\n > {\n const baseDef = this.#baseBuilder.build();\n\n // Ensure dependencies callback always exists for database fragments\n // If no user dependencies were defined, create a minimal one that only adds implicit deps\n const dependencies = (context: {\n config: TConfig;\n options: FragnoPublicConfigWithDatabase;\n }): TDeps => {\n // In dry run mode, allow user deps to fail gracefully.\n // This is critical for database fragments because the CLI needs access to the schema\n // even when user dependencies (like API clients) can't be initialized.\n // Without this, if user deps fail, we'd lose the implicit database dependencies\n // (including schema), and the CLI couldn't extract schema information.\n let userDeps;\n try {\n userDeps = baseDef.dependencies?.(context);\n } catch (error) {\n if (process.env[\"FRAGNO_INIT_DRY_RUN\"] === \"true\") {\n console.warn(\n \"Warning: Failed to initialize user dependencies in dry run mode:\",\n error instanceof Error ? error.message : String(error),\n );\n userDeps = {};\n } else {\n throw error;\n }\n }\n\n const { db } = createDatabaseContext(context.options, this.#schema, this.#namespace);\n\n const implicitDeps: ImplicitDatabaseDependencies<TSchema> = {\n db,\n schema: this.#schema,\n namespace: this.#namespace,\n createUnitOfWork: () => db.createUnitOfWork(),\n };\n\n return {\n ...userDeps,\n ...implicitDeps,\n } as TDeps;\n };\n\n // Use the adapter's shared context storage (all fragments using the same adapter share this storage)\n const builderWithExternalStorage = this.#baseBuilder.withExternalRequestStorage(\n ({ options }) => {\n const dbContext = createDatabaseContext(options, this.#schema, this.#namespace);\n return dbContext.databaseAdapter.contextStorage;\n },\n );\n\n // Set up request storage to initialize the Unit of Work\n const builderWithStorage = builderWithExternalStorage.withRequestStorage(\n ({ options }): DatabaseRequestStorage => {\n // Create database context - needed here to create the UOW\n const dbContextForStorage = createDatabaseContext(options, this.#schema, this.#namespace);\n\n // Create a new Unit of Work for this request\n const uow: IUnitOfWork = dbContextForStorage.db.createUnitOfWork();\n\n return { uow };\n },\n );\n\n // Get the internal fragment factory from linked fragments (added by withDatabase)\n // Cast is safe: withDatabase() guarantees this fragment exists and has the correct type\n const internalFragmentFactory = baseDef.linkedFragments?.[\"_fragno_internal\"] as (context: {\n config: TConfig;\n options: FragnoPublicConfigWithDatabase;\n }) => InternalFragmentInstance;\n\n const builderWithContext = builderWithStorage.withThisContext<\n DatabaseServiceContext<THooks>,\n DatabaseHandlerContext<THooks>\n >(({ storage, config, options }) => {\n // Create hooks config if hooks factory is defined\n const hooksConfig = this.#hooksFactory\n ? {\n hooks: this.#hooksFactory({ config, options }),\n namespace: this.#namespace,\n internalFragment: internalFragmentFactory({ config, options }),\n }\n : undefined;\n\n // Builder API: serviceTx using createServiceTxBuilder\n function serviceTx<TSchema extends AnySchema>(schema: TSchema) {\n const uow = storage.getStore()?.uow;\n if (!uow) {\n throw new Error(\n \"No UnitOfWork in context. Service must be called within a route handler OR using `withUnitOfWork`.\",\n );\n }\n return createServiceTxBuilder<TSchema, THooks>(schema, uow, hooksConfig?.hooks);\n }\n\n const serviceContext: DatabaseServiceContext<THooks> = {\n serviceTx,\n };\n\n // Builder API: handlerTx using createHandlerTxBuilder\n function handlerTx(execOptions?: Omit<ExecuteTxOptions, \"createUnitOfWork\">) {\n const currentStorage = storage.getStore();\n if (!currentStorage) {\n throw new Error(\n \"No storage in context. Handler must be called within a request context.\",\n );\n }\n\n const userOnBeforeMutate = execOptions?.onBeforeMutate;\n const userOnAfterMutate = execOptions?.onAfterMutate;\n\n return createHandlerTxBuilder<THooks>({\n ...execOptions,\n createUnitOfWork: () => {\n currentStorage.uow.reset();\n if (hooksConfig) {\n currentStorage.uow.registerSchema(\n hooksConfig.internalFragment.$internal.deps.schema,\n hooksConfig.internalFragment.$internal.deps.namespace,\n );\n }\n return currentStorage.uow;\n },\n onBeforeMutate: (uow) => {\n if (hooksConfig) {\n prepareHookMutations(uow, hooksConfig);\n }\n if (userOnBeforeMutate) {\n userOnBeforeMutate(uow);\n }\n },\n onAfterMutate: async (uow) => {\n if (hooksConfig) {\n await processHooks(hooksConfig);\n }\n if (userOnAfterMutate) {\n await userOnAfterMutate(uow);\n }\n },\n });\n }\n\n const handlerContext: DatabaseHandlerContext<THooks> = {\n handlerTx,\n };\n\n return { serviceContext, handlerContext };\n });\n\n // Build the final definition\n const finalDef = builderWithContext.build();\n\n // Return the complete definition with proper typing and dependencies\n return {\n ...finalDef,\n dependencies,\n };\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"db-fragment-definition-builder.js","names":["logContext: Record<string, unknown>","notifyContext: HookNotifyContext","#baseBuilder","#schema","#hooksFactory","#syncRegistry","#registryResolver","implicitDeps: ImplicitDatabaseDependencies<TSchema>","isInternalFragment","hooksConfig: HookProcessorConfig<THooks>","storageRef: DatabaseContextStorage | null","serviceContext: DatabaseServiceContext<THooks>"],"sources":["../src/db-fragment-definition-builder.ts"],"sourcesContent":["import { FragnoApiError } from \"@fragno-dev/core/api\";\n\nimport type {\n RequestThisContext,\n FragnoPublicConfig,\n AnyRouteOrFactory,\n FragnoRouteConfig,\n BoundServices,\n} from \"@fragno-dev/core\";\nimport {\n FragmentDefinitionBuilder,\n type FragmentDefinition,\n type ServiceConstructorFn,\n} from \"@fragno-dev/core\";\n\nimport type { DatabaseAdapter, DatabaseContextStorage } from \"./adapters/adapters\";\nimport type { InternalFragmentInstance } from \"./fragments/internal-fragment\";\nimport { DurableHooksLogger } from \"./hooks/durable-hooks-logger\";\nimport {\n getDurableHooksRuntimeByConfig,\n getDurableHooksRuntimeByNamespace,\n registerDurableHooksRuntime,\n} from \"./hooks/durable-hooks-runtime\";\nimport {\n prepareHookMutations,\n type HooksMap,\n type HookFn,\n type HookContext,\n type HookProcessorConfig,\n type HookNotifier,\n type HookNotifyContext,\n type DurableHooksProcessingOptions,\n createDurableHooksRunner,\n} from \"./hooks/hooks\";\nimport { sanitizeNamespace } from \"./naming/sql-naming\";\nimport type { SimpleQueryInterface } from \"./query/simple-query-interface\";\nimport {\n createServiceTxBuilder,\n createHandlerTxBuilder,\n ServiceTxBuilder,\n HandlerTxBuilder,\n type AwaitedPromisesInObject,\n type ExtractServiceFinalResults,\n type ExecuteTxOptions,\n type TxResult,\n} from \"./query/unit-of-work/execute-unit-of-work\";\nimport type { IUnitOfWork } from \"./query/unit-of-work/unit-of-work\";\nimport type { AnySchema } from \"./schema/create\";\nimport type { SyncCommandRegistry, SyncCommandTargetRegistration } from \"./sync/types\";\nimport { resolveDatabaseAdapter } from \"./util/default-database-adapter\";\ntype RegistrySchemaInfo = {\n name: string;\n namespace: string | null;\n version: number;\n tables: string[];\n};\n\ntype RegistryFragmentMeta = {\n name: string;\n mountRoute: string;\n};\n\ntype ExtractServiceFinalResultOrSingle<T> = T extends readonly (\n | TxResult<unknown, unknown>\n | undefined\n)[]\n ? AwaitedPromisesInObject<ExtractServiceFinalResults<T>>\n : T extends undefined\n ? undefined\n : AwaitedPromisesInObject<ExtractServiceFinalResults<readonly [T]>>[0];\n\ntype RegistryResolver = {\n getRegistryForAdapterSync: <TUOWConfig>(adapter: DatabaseAdapter<TUOWConfig>) => {\n registerSchema: (\n schema: RegistrySchemaInfo,\n fragment: RegistryFragmentMeta,\n options?: { outboxEnabled?: boolean },\n ) => void;\n registerSyncCommands: (registration: SyncCommandTargetRegistration) => void;\n };\n getInternalFragment: <TUOWConfig>(\n adapter: DatabaseAdapter<TUOWConfig>,\n ) => InternalFragmentInstance;\n};\n\ntype HooksFactoryContext<TConfig> = {\n config: TConfig;\n options: FragnoPublicConfigWithDatabase;\n deps: unknown;\n services: unknown;\n serviceDeps: unknown;\n};\n\ntype AnyHttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\" | \"HEAD\" | \"OPTIONS\";\n\ntype AnyFragnoRouteConfig = FragnoRouteConfig<\n AnyHttpMethod,\n string,\n undefined,\n undefined,\n string,\n string,\n RequestThisContext\n>;\n\n/**\n * Extended FragnoPublicConfig for database fragments.\n * If databaseAdapter is omitted and better-sqlite3 is available, a default SQLite adapter is used.\n */\nexport type FragnoPublicConfigWithDatabase = FragnoPublicConfig & {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n databaseAdapter?: DatabaseAdapter<any>;\n /**\n * Optional guard to limit database roundtrips per request (primarily for tests).\n * When enabled, retrieve-only and mutate-only handlerTx().execute() calls are\n * counted separately (one of each by default).\n * Applied only for route handlers (not inContext).\n */\n dbRoundtripGuard?: boolean | DbRoundtripGuardConfig;\n /**\n * Optional outbox configuration for this fragment.\n */\n outbox?: {\n enabled?: boolean;\n };\n /**\n * Optional durable hooks processing configuration.\n */\n durableHooks?: DurableHooksProcessingOptions;\n /**\n * Optional override for database namespace. If provided (including null), it is used as-is\n * without sanitization — the caller is responsible for providing a valid namespace.\n * When omitted, defaults to a sanitized version of schema.name.\n */\n databaseNamespace?: string | null;\n};\n\n/**\n * Configuration for limiting database roundtrips per request.\n */\nexport type DbRoundtripGuardConfig = {\n /**\n * Maximum allowed retrieve-only and mutate-only handlerTx().execute() calls per request.\n * Each type is tracked separately.\n * Defaults to 1 when the guard is enabled.\n */\n maxRoundtrips?: number;\n};\n\n/**\n * Implicit dependencies that database fragments get automatically.\n * These are injected without requiring explicit configuration.\n */\nexport type ImplicitDatabaseDependencies<TSchema extends AnySchema> = {\n /**\n * Database adapter instance.\n */\n databaseAdapter: DatabaseAdapter<any>; // eslint-disable-line @typescript-eslint/no-explicit-any\n /**\n * The schema definition for this fragment.\n */\n schema: TSchema;\n /**\n * The database namespace for this fragment.\n */\n namespace: string | null;\n /**\n * Create a new Unit of Work for database operations.\n */\n createUnitOfWork: () => IUnitOfWork;\n};\n\n/**\n * Service context for database fragments - provides restricted UOW access without execute methods.\n */\nexport type DatabaseServiceContext<THooks extends HooksMap> = RequestThisContext & {\n /**\n * Create a service-level transaction builder using the fluent API.\n * Returns a builder that can be chained with withServiceCalls, retrieve,\n * transformRetrieve, mutate, transform, and build.\n *\n * @example\n * ```ts\n * return this.serviceTx(schema)\n * .withServiceCalls(() => [otherService.getData()])\n * .retrieve((uow) => uow.find(\"users\", ...))\n * .transformRetrieve(([users]) => users[0])\n * .mutate(({ uow, retrieveResult, serviceIntermediateResult }) =>\n * uow.create(\"records\", { ... })\n * )\n * .transform(({ mutateResult, serviceResult }) => ({ id: mutateResult }))\n * .build();\n * ```\n */\n serviceTx<TSchema extends AnySchema>(\n schema: TSchema,\n ): ServiceTxBuilder<\n TSchema,\n readonly [],\n [],\n [],\n unknown,\n unknown,\n false,\n false,\n false,\n false,\n THooks\n >;\n};\n\n/**\n * Handler context for database fragments - provides UOW execution with automatic retry support.\n */\nexport type DatabaseHandlerContext<THooks extends HooksMap = {}> = RequestThisContext & {\n /**\n * Create a handler-level transaction builder using the fluent API.\n * Returns a builder that can be chained with withServiceCalls, retrieve,\n * transformRetrieve, mutate, transform, and execute.\n *\n * @example\n * ```ts\n * const result = await this.handlerTx()\n * .withServiceCalls(() => [userService.getUser(id)])\n * .mutate(({ forSchema, idempotencyKey, currentAttempt, serviceIntermediateResult }) => {\n * return forSchema(ordersSchema).create(\"orders\", { ... });\n * })\n * .transform(({ mutateResult, serviceResult }) => ({ ... }))\n * .execute();\n * ```\n */\n handlerTx(\n options?: Omit<ExecuteTxOptions, \"createUnitOfWork\">,\n ): HandlerTxBuilder<readonly [], [], [], unknown, unknown, false, false, false, false, THooks>;\n\n /**\n * Execute multiple service calls in a handler context and return their final results.\n */\n callServices<\n TServiceCalls extends\n | TxResult<unknown, unknown>\n | undefined\n | readonly (TxResult<unknown, unknown> | undefined)[],\n >(\n /**\n * Factory to create service calls inside the active context.\n */\n serviceCalls: () => TServiceCalls,\n ): Promise<ExtractServiceFinalResultOrSingle<TServiceCalls>>;\n};\n\n/**\n * Database fragment context provided to user callbacks.\n */\nexport type DatabaseFragmentContext = {\n /**\n * Database adapter instance.\n */\n databaseAdapter: DatabaseAdapter<any>; // eslint-disable-line @typescript-eslint/no-explicit-any\n};\n\ntype DatabaseFragmentContextInternal<TSchema extends AnySchema> = DatabaseFragmentContext & {\n db: SimpleQueryInterface<TSchema>;\n};\n\n/**\n * Create database context from options.\n * This extracts the database adapter and creates the ORM instance.\n */\nfunction createDatabaseContext<TSchema extends AnySchema>(\n options: FragnoPublicConfigWithDatabase,\n schema: TSchema,\n): DatabaseFragmentContextInternal<TSchema> {\n const databaseAdapter = resolveDatabaseAdapter(options, schema);\n\n const namespace = resolveDatabaseNamespace(options, schema);\n const db = databaseAdapter.createQueryEngine(schema, namespace);\n\n return { databaseAdapter, db };\n}\n\nfunction resolveDatabaseNamespace<TSchema extends AnySchema>(\n options: FragnoPublicConfigWithDatabase,\n schema: TSchema,\n): string | null {\n const hasOverride = options.databaseNamespace !== undefined;\n return hasOverride ? (options.databaseNamespace ?? null) : sanitizeNamespace(schema.name);\n}\n\nfunction resolveMountRoute(name: string, mountRoute?: string): string {\n const resolved = mountRoute ?? `/api/${name}`;\n return resolved.endsWith(\"/\") ? resolved.slice(0, -1) : resolved;\n}\n\nconst dbRoundtripGuardStateSymbol = Symbol(\"fragno-db-roundtrip-guard\");\nconst requestSourceSymbol = Symbol.for(\"fragno-request-source\");\nconst requestRouteSymbol = Symbol.for(\"fragno-request-route\");\nconst requestWaitUntilSymbol = Symbol.for(\"fragno-request-wait-until\");\nconst roundtripGuardDocsUrl = \"https://fragno.dev/docs/fragno/for-library-authors/rules-of-fragno\";\n\ntype DbRoundtripGuardState = {\n retrieveCount: number;\n mutateCount: number;\n maxRoundtrips: number;\n};\n\ntype DurableHooksLogContext = HookNotifyContext;\n\ntype AnyHandlerTxBuilder = HandlerTxBuilder<\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n any,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n any,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n any,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n any,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n any,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n any,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n any,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n any,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n any,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n any\n>;\n\nfunction wrapHandlerTxBuilderWithRoundtripGuard<\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n TBuilder extends HandlerTxBuilder<any, any, any, any, any, any, any, any, any, any>,\n>(builder: TBuilder, onExecute: () => void): TBuilder {\n const wrappedBuilders = new WeakSet<AnyHandlerTxBuilder>();\n\n const applyExecuteGuard = (target: TBuilder): TBuilder => {\n if (wrappedBuilders.has(target)) {\n return target;\n }\n wrappedBuilders.add(target);\n const execute = target.execute.bind(target);\n target.execute = () => {\n onExecute();\n return execute();\n };\n return target;\n };\n\n const wrap = (target: TBuilder): TBuilder => {\n const guarded = applyExecuteGuard(target);\n return new Proxy(guarded, {\n get(obj, prop, receiver) {\n const value = Reflect.get(obj, prop, receiver);\n if (typeof value !== \"function\") {\n return value;\n }\n if (prop === \"execute\") {\n return value;\n }\n return (...args: unknown[]) => {\n const result = value.apply(obj, args);\n if (result instanceof HandlerTxBuilder) {\n return wrap(result as TBuilder);\n }\n return result;\n };\n },\n }) as TBuilder;\n };\n\n return wrap(builder);\n}\n\nfunction buildDurableHooksLogContext(context?: DurableHooksLogContext) {\n const logContext: Record<string, unknown> = {};\n if (context?.route !== undefined) {\n logContext[\"route\"] = context.route;\n }\n if (context?.source !== undefined) {\n logContext[\"source\"] = context.source;\n }\n return logContext;\n}\n\nfunction notifyDurableHooks(\n notifier: HookNotifier,\n namespace: string,\n notifyContext: HookNotifyContext,\n logContextFields: Record<string, unknown>,\n options?: { crossNamespace?: boolean },\n) {\n const crossNamespace = options?.crossNamespace ?? false;\n const suffix = crossNamespace ? \" (cross-namespace)\" : \"\";\n const notifyStart = Date.now();\n DurableHooksLogger.debug(`Durable hooks notify requested${suffix}`, {\n namespace,\n fields: logContextFields,\n });\n const notifyPromise = Promise.resolve()\n .then(() => notifier.notify(notifyContext))\n .then((processed) => {\n DurableHooksLogger.debug(`Durable hooks notify completed${suffix}`, {\n namespace,\n fields: {\n result: processed === undefined ? null : processed,\n ms: Date.now() - notifyStart,\n ...logContextFields,\n },\n });\n })\n .catch((error) => {\n DurableHooksLogger.error(`Durable hooks notify failed${suffix}`, {\n namespace,\n fields: {\n error: DurableHooksLogger.toErrorMessage(error),\n ...logContextFields,\n },\n });\n });\n\n if (notifyContext.waitUntil) {\n notifyContext.waitUntil(notifyPromise);\n return;\n }\n void notifyPromise;\n}\n\nfunction notifyDurableHooksAfterMutate<THooks extends HooksMap>({\n uow,\n hooksConfig,\n internalFragment,\n autoSchedule,\n planMode,\n logContext,\n}: {\n uow: IUnitOfWork;\n hooksConfig?: HookProcessorConfig<THooks>;\n internalFragment?: InternalFragmentInstance;\n autoSchedule: boolean;\n planMode: boolean;\n logContext?: DurableHooksLogContext;\n}) {\n if (planMode) {\n return;\n }\n\n const notifyContext: HookNotifyContext = {\n source: logContext?.source ?? \"request\",\n route: logContext?.route,\n waitUntil: logContext?.waitUntil,\n };\n\n const logContextFields = buildDurableHooksLogContext(logContext);\n const triggeredHooks = uow.getTriggeredHooks();\n const ownNamespaceTriggeredCount = hooksConfig\n ? triggeredHooks.filter((hook) => hook.namespace === hooksConfig.namespace).length\n : 0;\n\n if (hooksConfig?.notifier && autoSchedule && ownNamespaceTriggeredCount > 0) {\n notifyDurableHooks(\n hooksConfig.notifier,\n hooksConfig.namespace,\n notifyContext,\n logContextFields,\n );\n } else if (hooksConfig && !autoSchedule && ownNamespaceTriggeredCount > 0) {\n DurableHooksLogger.debug(\"Durable hooks notify skipped (autoSchedule=false)\", {\n namespace: hooksConfig.namespace,\n fields: {\n queued: ownNamespaceTriggeredCount,\n ...logContextFields,\n },\n });\n } else if (hooksConfig && !hooksConfig.notifier && ownNamespaceTriggeredCount > 0) {\n DurableHooksLogger.debug(\"Durable hooks notify skipped (notifier missing)\", {\n namespace: hooksConfig.namespace,\n fields: {\n queued: ownNamespaceTriggeredCount,\n ...logContextFields,\n },\n });\n }\n\n if (triggeredHooks.length === 0) {\n return;\n }\n\n const namespaces = new Set<string>();\n const triggeredCountByNamespace = new Map<string, number>();\n for (const hook of triggeredHooks) {\n namespaces.add(hook.namespace);\n triggeredCountByNamespace.set(\n hook.namespace,\n (triggeredCountByNamespace.get(hook.namespace) ?? 0) + 1,\n );\n }\n if (hooksConfig) {\n namespaces.delete(hooksConfig.namespace);\n }\n\n for (const namespace of namespaces) {\n if (!internalFragment) {\n DurableHooksLogger.debug(\"Durable hooks notifier missing scope for namespace\", {\n namespace,\n fields: logContextFields,\n });\n continue;\n }\n\n const runtime = getDurableHooksRuntimeByNamespace(namespace, internalFragment);\n if (!runtime) {\n DurableHooksLogger.debug(\"Durable hooks notifier missing for namespace\", {\n namespace,\n fields: logContextFields,\n });\n continue;\n }\n if (runtime.config.autoSchedule === false) {\n DurableHooksLogger.debug(\"Durable hooks notify skipped (autoSchedule=false)\", {\n namespace,\n fields: {\n queued: triggeredCountByNamespace.get(namespace) ?? 0,\n ...logContextFields,\n },\n });\n continue;\n }\n const notifier = runtime.config.notifier;\n if (!notifier) {\n DurableHooksLogger.debug(\"Durable hooks notifier missing for namespace\", {\n namespace,\n fields: logContextFields,\n });\n continue;\n }\n notifyDurableHooks(notifier, namespace, notifyContext, logContextFields, {\n crossNamespace: true,\n });\n }\n}\n\nfunction resolveDbRoundtripGuard(\n options: FragnoPublicConfigWithDatabase,\n): DbRoundtripGuardState | null {\n const guard = options.dbRoundtripGuard;\n if (!guard) {\n return null;\n }\n\n if (guard === true) {\n return { retrieveCount: 0, mutateCount: 0, maxRoundtrips: 1 };\n }\n\n return { retrieveCount: 0, mutateCount: 0, maxRoundtrips: guard.maxRoundtrips ?? 1 };\n}\n\nfunction getDbRoundtripGuardState(\n storage: DatabaseContextStorage,\n guard: DbRoundtripGuardState,\n): DbRoundtripGuardState {\n const storageWithGuard = storage as DatabaseContextStorage & {\n [dbRoundtripGuardStateSymbol]?: DbRoundtripGuardState;\n };\n if (!storageWithGuard[dbRoundtripGuardStateSymbol]) {\n storageWithGuard[dbRoundtripGuardStateSymbol] = { ...guard };\n } else {\n storageWithGuard[dbRoundtripGuardStateSymbol]!.maxRoundtrips = guard.maxRoundtrips;\n }\n return storageWithGuard[dbRoundtripGuardStateSymbol]!;\n}\n\nfunction isRouteRequest(storage: DatabaseContextStorage): boolean {\n const source = (storage as Record<symbol, unknown>)[requestSourceSymbol];\n return source === \"route\";\n}\n\n/**\n * Storage type for database fragments - stores the Unit of Work.\n */\nexport type DatabaseRequestStorage = {\n uow: IUnitOfWork;\n};\n\n/**\n * Builder for database fragments that wraps the core fragment builder\n * and provides database-specific functionality.\n *\n * Database fragments use FragnoPublicConfigWithDatabase and default the adapter when possible.\n */\nexport class DatabaseFragmentDefinitionBuilder<\n TSchema extends AnySchema,\n TConfig,\n TDeps,\n TBaseServices,\n TServices,\n TServiceDependencies,\n TPrivateServices,\n THooks extends HooksMap = {},\n TServiceThisContext extends RequestThisContext = DatabaseHandlerContext,\n THandlerThisContext extends RequestThisContext = DatabaseHandlerContext,\n TInternalRoutes extends readonly AnyRouteOrFactory[] = readonly [],\n> {\n // Store the base builder - we'll replace its storage and context setup when building\n #baseBuilder: FragmentDefinitionBuilder<\n TConfig,\n FragnoPublicConfigWithDatabase,\n TDeps,\n TBaseServices,\n TServices,\n TServiceDependencies,\n TPrivateServices,\n TServiceThisContext,\n THandlerThisContext,\n DatabaseRequestStorage,\n TInternalRoutes\n >;\n #schema: TSchema;\n #hooksFactory?: (context: HooksFactoryContext<TConfig>) => THooks;\n #syncRegistry?: SyncCommandRegistry;\n #registryResolver?: RegistryResolver;\n\n constructor(\n baseBuilder: FragmentDefinitionBuilder<\n TConfig,\n FragnoPublicConfigWithDatabase,\n TDeps,\n TBaseServices,\n TServices,\n TServiceDependencies,\n TPrivateServices,\n TServiceThisContext,\n THandlerThisContext,\n DatabaseRequestStorage,\n TInternalRoutes\n >,\n schema: TSchema,\n hooksFactory?: (context: HooksFactoryContext<TConfig>) => THooks,\n syncRegistry?: SyncCommandRegistry,\n registryResolver?: RegistryResolver,\n ) {\n this.#baseBuilder = baseBuilder;\n this.#schema = schema;\n this.#hooksFactory = hooksFactory;\n this.#syncRegistry = syncRegistry;\n this.#registryResolver = registryResolver;\n }\n\n /**\n * Define dependencies for this database fragment.\n * The context includes the database adapter.\n */\n withDependencies<TNewDeps>(\n fn: (context: {\n config: TConfig;\n options: FragnoPublicConfigWithDatabase;\n databaseAdapter: DatabaseAdapter<any>; // eslint-disable-line @typescript-eslint/no-explicit-any\n }) => TNewDeps,\n ): DatabaseFragmentDefinitionBuilder<\n TSchema,\n TConfig,\n TNewDeps & ImplicitDatabaseDependencies<TSchema>,\n {},\n {},\n TServiceDependencies,\n {},\n THooks,\n TServiceThisContext,\n THandlerThisContext,\n TInternalRoutes\n > {\n // Wrap user function to inject DB context\n const wrappedFn = (context: { config: TConfig; options: FragnoPublicConfigWithDatabase }) => {\n const dbContext = createDatabaseContext(context.options, this.#schema);\n const namespace = resolveDatabaseNamespace(context.options, this.#schema);\n\n // Call user function with enriched context\n const userDeps = fn({\n config: context.config,\n options: context.options,\n databaseAdapter: dbContext.databaseAdapter,\n });\n\n // Create implicit dependencies\n const createUow = () => dbContext.db.createUnitOfWork();\n const implicitDeps: ImplicitDatabaseDependencies<TSchema> = {\n databaseAdapter: dbContext.databaseAdapter,\n schema: this.#schema,\n namespace,\n createUnitOfWork: createUow,\n };\n\n return {\n ...userDeps,\n ...implicitDeps,\n };\n };\n\n // Create new base builder with wrapped function\n const newBaseBuilder = this.#baseBuilder.withDependencies(wrappedFn);\n\n return new DatabaseFragmentDefinitionBuilder(\n newBaseBuilder,\n this.#schema,\n this.#hooksFactory,\n this.#syncRegistry,\n this.#registryResolver,\n );\n }\n\n providesBaseService<TNewService>(\n fn: ServiceConstructorFn<\n TConfig,\n FragnoPublicConfigWithDatabase,\n TDeps,\n TServiceDependencies,\n TPrivateServices,\n TNewService,\n TServiceThisContext\n >,\n ): DatabaseFragmentDefinitionBuilder<\n TSchema,\n TConfig,\n TDeps,\n TNewService,\n TServices,\n TServiceDependencies,\n TPrivateServices,\n THooks,\n TServiceThisContext,\n THandlerThisContext,\n TInternalRoutes\n > {\n const newBaseBuilder = this.#baseBuilder.providesBaseService<TNewService>(fn);\n\n return new DatabaseFragmentDefinitionBuilder(\n newBaseBuilder,\n this.#schema,\n this.#hooksFactory,\n this.#syncRegistry,\n this.#registryResolver,\n );\n }\n\n providesService<TServiceName extends string, TService>(\n serviceName: TServiceName,\n fn: ServiceConstructorFn<\n TConfig,\n FragnoPublicConfigWithDatabase,\n TDeps,\n TServiceDependencies,\n TPrivateServices,\n TService,\n TServiceThisContext\n >,\n ): DatabaseFragmentDefinitionBuilder<\n TSchema,\n TConfig,\n TDeps,\n TBaseServices,\n TServices & { [K in TServiceName]: TService },\n TServiceDependencies,\n TPrivateServices,\n THooks,\n TServiceThisContext,\n THandlerThisContext,\n TInternalRoutes\n > {\n const newBaseBuilder = this.#baseBuilder.providesService<TServiceName, TService>(\n serviceName,\n fn,\n );\n\n return new DatabaseFragmentDefinitionBuilder(\n newBaseBuilder,\n this.#schema,\n this.#hooksFactory,\n this.#syncRegistry,\n this.#registryResolver,\n );\n }\n\n /**\n * Provide a private service that is only accessible to the fragment author.\n * Private services are NOT exposed on the fragment instance, but can be used\n * when defining other services (baseServices, namedServices, and other privateServices).\n * Private services are instantiated in order, so earlier private services are available\n * to later ones.\n */\n providesPrivateService<TServiceName extends string, TService>(\n serviceName: TServiceName,\n fn: ServiceConstructorFn<\n TConfig,\n FragnoPublicConfigWithDatabase,\n TDeps,\n TServiceDependencies,\n TPrivateServices,\n TService,\n TServiceThisContext\n >,\n ): DatabaseFragmentDefinitionBuilder<\n TSchema,\n TConfig,\n TDeps,\n TBaseServices,\n TServices,\n TServiceDependencies,\n TPrivateServices & { [K in TServiceName]: TService },\n THooks,\n TServiceThisContext,\n THandlerThisContext,\n TInternalRoutes\n > {\n const newBaseBuilder = this.#baseBuilder.providesPrivateService<TServiceName, TService>(\n serviceName,\n fn,\n );\n\n return new DatabaseFragmentDefinitionBuilder(\n newBaseBuilder,\n this.#schema,\n this.#hooksFactory,\n this.#syncRegistry,\n this.#registryResolver,\n );\n }\n\n /**\n * Define durable hooks for this fragment.\n * Hooks are automatically persisted and retried on failure.\n *\n * @param fn - Function that receives defineHook helper and returns a hooks map\n * @returns Builder with hooks type set\n *\n * @example\n * ```ts\n * .provideHooks(({ defineHook, config }) => ({\n * onSubscribe: defineHook(async function (payload: { email: string }) {\n * // 'this' context available (HookServiceContext with idempotencyKey)\n * await config.onSubscribe?.(payload.email);\n * }),\n * }))\n * ```\n */\n provideHooks<TNewHooks extends HooksMap>(\n fn: (context: {\n config: TConfig;\n options: FragnoPublicConfigWithDatabase;\n deps: TDeps;\n services: BoundServices<TBaseServices & TServices>;\n serviceDeps: TServiceDependencies;\n defineHook: <TPayload>(\n hook: (this: HookContext, payload: TPayload) => void | Promise<void>,\n ) => HookFn<TPayload>;\n }) => TNewHooks,\n ): DatabaseFragmentDefinitionBuilder<\n TSchema,\n TConfig,\n TDeps,\n TBaseServices,\n TServices,\n TServiceDependencies,\n TPrivateServices,\n TNewHooks,\n DatabaseServiceContext<TNewHooks>,\n THandlerThisContext,\n TInternalRoutes\n > {\n const defineHook = <TPayload>(\n hook: (this: HookContext, payload: TPayload) => void | Promise<void>,\n ): HookFn<TPayload> => {\n return hook;\n };\n\n // Store the hooks factory - it will be called in build() with config/options\n const hooksFactory = (context: HooksFactoryContext<TConfig>) => {\n return fn({\n config: context.config,\n options: context.options,\n deps: context.deps as TDeps,\n services: context.services as BoundServices<TBaseServices & TServices>,\n serviceDeps: context.serviceDeps as TServiceDependencies,\n defineHook,\n });\n };\n\n // Create new builder with hooks factory stored\n // Cast is safe: we're only changing THooks and TServiceThisContext type parameters\n const newBuilder = new DatabaseFragmentDefinitionBuilder(\n this.#baseBuilder,\n this.#schema,\n this.#hooksFactory,\n this.#syncRegistry,\n this.#registryResolver,\n ) as unknown as DatabaseFragmentDefinitionBuilder<\n TSchema,\n TConfig,\n TDeps,\n TBaseServices,\n TServices,\n TServiceDependencies,\n TPrivateServices,\n TNewHooks,\n DatabaseServiceContext<TNewHooks>,\n THandlerThisContext,\n TInternalRoutes\n >;\n\n newBuilder.#hooksFactory = hooksFactory;\n\n return newBuilder;\n }\n\n /**\n * Register sync command definitions for this fragment.\n */\n withSyncCommands(\n registry: SyncCommandRegistry,\n ): DatabaseFragmentDefinitionBuilder<\n TSchema,\n TConfig,\n TDeps,\n TBaseServices,\n TServices,\n TServiceDependencies,\n TPrivateServices,\n THooks,\n TServiceThisContext,\n THandlerThisContext,\n TInternalRoutes\n > {\n if (registry.schemaName !== this.#schema.name) {\n throw new Error(\n `Sync command registry schema name \"${registry.schemaName}\" does not match fragment schema \"${this.#schema.name}\".`,\n );\n }\n\n return new DatabaseFragmentDefinitionBuilder(\n this.#baseBuilder,\n this.#schema,\n this.#hooksFactory,\n registry,\n this.#registryResolver,\n );\n }\n\n /**\n * Declare that this fragment uses a required service provided by the runtime.\n * Delegates to the base builder.\n */\n usesService<TServiceName extends string, TService>(\n serviceName: TServiceName,\n ): DatabaseFragmentDefinitionBuilder<\n TSchema,\n TConfig,\n TDeps,\n TBaseServices,\n TServices,\n TServiceDependencies & { [K in TServiceName]: TService },\n TPrivateServices,\n THooks,\n TServiceThisContext,\n THandlerThisContext,\n TInternalRoutes\n > {\n const newBaseBuilder = this.#baseBuilder.usesService<TServiceName, TService>(serviceName);\n\n return new DatabaseFragmentDefinitionBuilder(\n newBaseBuilder,\n this.#schema,\n this.#hooksFactory,\n this.#syncRegistry,\n this.#registryResolver,\n );\n }\n\n /**\n * Declare that this fragment uses an optional service provided by the runtime.\n * Delegates to the base builder.\n */\n usesOptionalService<TServiceName extends string, TService>(\n serviceName: TServiceName,\n ): DatabaseFragmentDefinitionBuilder<\n TSchema,\n TConfig,\n TDeps,\n TBaseServices,\n TServices,\n TServiceDependencies & { [K in TServiceName]: TService | undefined },\n TPrivateServices,\n THooks,\n TServiceThisContext,\n THandlerThisContext,\n TInternalRoutes\n > {\n const newBaseBuilder = this.#baseBuilder.usesOptionalService<TServiceName, TService>(\n serviceName,\n );\n\n return new DatabaseFragmentDefinitionBuilder(\n newBaseBuilder,\n this.#schema,\n this.#hooksFactory,\n this.#syncRegistry,\n this.#registryResolver,\n );\n }\n\n /**\n * Build the final database fragment definition.\n * This includes the request context setup for UnitOfWork management.\n * Note: TDeps already includes ImplicitDatabaseDependencies from withDatabase().\n */\n build(): FragmentDefinition<\n TConfig,\n FragnoPublicConfigWithDatabase,\n TDeps,\n TBaseServices,\n TServices,\n TServiceDependencies,\n TPrivateServices,\n DatabaseServiceContext<THooks>,\n DatabaseHandlerContext<THooks>,\n DatabaseRequestStorage,\n TInternalRoutes\n > {\n const baseDef = this.#baseBuilder.build();\n\n // Ensure dependencies callback always exists for database fragments\n // If no user dependencies were defined, create a minimal one that only adds implicit deps\n const dependencies = (context: {\n config: TConfig;\n options: FragnoPublicConfigWithDatabase;\n }): TDeps => {\n // In dry run mode, allow user deps to fail gracefully.\n // This is critical for database fragments because the CLI needs access to the schema\n // even when user dependencies (like API clients) can't be initialized.\n // Without this, if user deps fail, we'd lose the implicit database dependencies\n // (including schema), and the CLI couldn't extract schema information.\n let userDeps;\n try {\n userDeps = baseDef.dependencies?.(context);\n } catch (error) {\n if (process.env[\"FRAGNO_INIT_DRY_RUN\"] === \"true\") {\n console.warn(\n \"Warning: Failed to initialize user dependencies in dry run mode:\",\n error instanceof Error ? error.message : String(error),\n );\n userDeps = {};\n } else {\n throw error;\n }\n }\n\n const dbContext = createDatabaseContext(context.options, this.#schema);\n const { db } = dbContext;\n const namespace = resolveDatabaseNamespace(context.options, this.#schema);\n const dryRun = process.env[\"FRAGNO_INIT_DRY_RUN\"] === \"true\";\n const isInternalFragment = baseDef.name === \"$fragno-internal-fragment\";\n\n if (!dryRun && !isInternalFragment && this.#registryResolver) {\n const registry = this.#registryResolver.getRegistryForAdapterSync(\n dbContext.databaseAdapter,\n );\n const outboxEnabled = context.options.outbox?.enabled ?? false;\n registry.registerSchema(\n {\n name: this.#schema.name,\n namespace,\n version: this.#schema.version,\n tables: Object.keys(this.#schema.tables).sort(),\n },\n {\n name: baseDef.name,\n mountRoute: resolveMountRoute(baseDef.name, context.options.mountRoute),\n },\n { outboxEnabled },\n );\n if (this.#syncRegistry) {\n registry.registerSyncCommands({\n fragmentName: baseDef.name,\n schemaName: this.#syncRegistry.schemaName,\n namespace,\n commands: this.#syncRegistry.commands,\n });\n }\n }\n\n const implicitDeps: ImplicitDatabaseDependencies<TSchema> = {\n databaseAdapter: dbContext.databaseAdapter,\n schema: this.#schema,\n namespace,\n createUnitOfWork: () => db.createUnitOfWork(),\n };\n\n return {\n ...userDeps,\n ...implicitDeps,\n } as TDeps;\n };\n\n // Use the adapter's shared context storage (all fragments using the same adapter share this storage)\n const builderWithExternalStorage = this.#baseBuilder.withExternalRequestStorage(\n ({ options }) => {\n const dbContext = createDatabaseContext(options, this.#schema);\n return dbContext.databaseAdapter.contextStorage;\n },\n );\n\n // Set up request storage to initialize the Unit of Work\n const builderWithStorage = builderWithExternalStorage.withRequestStorage(\n ({ options }): DatabaseRequestStorage => {\n // Create database context - needed here to create the UOW\n const dbContextForStorage = createDatabaseContext(options, this.#schema);\n\n const uow = dbContextForStorage.db.createBaseUnitOfWork();\n\n return { uow };\n },\n );\n\n // Cache per instantiated fragment (deps object is unique per instantiation).\n const hooksConfigCache = new WeakMap<object, HookProcessorConfig<THooks>>();\n\n const createHooksConfig = (context: {\n config: TConfig;\n options: FragnoPublicConfigWithDatabase;\n deps: TDeps;\n services?: BoundServices<TBaseServices & TServices>;\n serviceDeps?: TServiceDependencies;\n }) => {\n if (!this.#hooksFactory) {\n return undefined;\n }\n const depsKey =\n typeof context.deps === \"object\" && context.deps !== null\n ? (context.deps as object)\n : undefined;\n const namespace = resolveDatabaseNamespace(context.options, this.#schema);\n const namespaceKey = namespace ?? this.#schema.name;\n const durableHooksOptions = context.options.durableHooks;\n DurableHooksLogger.configure(durableHooksOptions?.logging, namespaceKey);\n const cachedHooksConfig = depsKey ? hooksConfigCache.get(depsKey) : undefined;\n if (cachedHooksConfig) {\n if (!cachedHooksConfig.hooks && context.services) {\n cachedHooksConfig.hooks = this.#hooksFactory({\n config: context.config,\n options: context.options,\n deps: context.deps,\n services: context.services,\n serviceDeps: context.serviceDeps ?? ({} as TServiceDependencies),\n });\n }\n return cachedHooksConfig;\n }\n\n const autoSchedule = durableHooksOptions?.autoSchedule !== false;\n const baseAdapter = resolveDatabaseAdapter(context.options, this.#schema);\n const hookAdapter = baseAdapter.getHookProcessingAdapter?.() ?? baseAdapter;\n const hookOptions =\n hookAdapter === baseAdapter\n ? context.options\n : { ...context.options, databaseAdapter: hookAdapter };\n const registryResolver = this.#registryResolver;\n if (!registryResolver) {\n throw new Error(\"Adapter registry resolver is missing for durable hooks.\");\n }\n const dbContextForHooks = createDatabaseContext(hookOptions, this.#schema);\n const hookContextStorage = dbContextForHooks.databaseAdapter.contextStorage;\n const hooksConfig: HookProcessorConfig<THooks> = {\n hooks: context.services\n ? this.#hooksFactory({\n config: context.config,\n options: context.options,\n deps: context.deps,\n services: context.services,\n serviceDeps: context.serviceDeps ?? ({} as TServiceDependencies),\n })\n : undefined,\n namespace: namespaceKey,\n internalFragment: registryResolver.getInternalFragment(hookAdapter),\n autoSchedule,\n handlerTx: (execOptions?: Omit<ExecuteTxOptions, \"createUnitOfWork\">) => {\n const userOnBeforeMutate = execOptions?.onBeforeMutate;\n const userOnAfterMutate = execOptions?.onAfterMutate;\n const planMode = execOptions?.planMode ?? false;\n let storageRef: DatabaseContextStorage | null = null;\n const getHookWaitUntil = () => {\n if (!hookContextStorage.hasStore()) {\n return undefined;\n }\n return (\n hookContextStorage.getStore() as DatabaseContextStorage & {\n [requestWaitUntilSymbol]?: (promise: Promise<unknown>) => void;\n }\n )[requestWaitUntilSymbol];\n };\n return createHandlerTxBuilder<THooks>(\n {\n ...execOptions,\n createUnitOfWork: () => {\n const baseUow = dbContextForHooks.db.createBaseUnitOfWork();\n baseUow.registerSchema(\n hooksConfig.internalFragment.$internal.deps.schema,\n hooksConfig.internalFragment.$internal.deps.namespace,\n );\n if (storageRef) {\n storageRef.uow = baseUow;\n }\n return baseUow;\n },\n onBeforeMutate: (uow) => {\n if (!planMode) {\n prepareHookMutations(\n uow,\n hooksConfig.internalFragment,\n hooksConfig.defaultRetryPolicy,\n );\n }\n if (userOnBeforeMutate) {\n userOnBeforeMutate(uow);\n }\n },\n onAfterMutate: async (uow) => {\n notifyDurableHooksAfterMutate({\n uow,\n hooksConfig,\n internalFragment: hooksConfig.internalFragment,\n autoSchedule,\n planMode,\n logContext: { source: \"hook\", waitUntil: getHookWaitUntil() },\n });\n if (userOnAfterMutate) {\n await userOnAfterMutate(uow);\n }\n },\n },\n undefined,\n (run) =>\n hookContextStorage.runWithInitializer(() => {\n const inheritedWaitUntil = getHookWaitUntil();\n storageRef = { uow: null as unknown as DatabaseContextStorage[\"uow\"] };\n if (inheritedWaitUntil) {\n (\n storageRef as DatabaseContextStorage & {\n [requestWaitUntilSymbol]?: (promise: Promise<unknown>) => void;\n }\n )[requestWaitUntilSymbol] = inheritedWaitUntil;\n }\n return storageRef;\n }, run),\n );\n },\n stuckProcessingTimeoutMinutes: durableHooksOptions?.stuckProcessingTimeoutMinutes,\n onStuckProcessingHooks: durableHooksOptions?.onStuckProcessingHooks,\n };\n hooksConfig.runner = createDurableHooksRunner(hooksConfig);\n registerDurableHooksRuntime(hooksConfig);\n if (depsKey) {\n hooksConfigCache.set(depsKey, hooksConfig);\n }\n return hooksConfig;\n };\n\n const isInternalFragment = baseDef.name === \"$fragno-internal-fragment\";\n\n const builderWithContext = builderWithStorage.withThisContext<\n DatabaseServiceContext<THooks>,\n DatabaseHandlerContext<THooks>\n >(({ storage, config, options, deps }) => {\n // Create hooks config if hooks factory is defined\n const hooksConfig = createHooksConfig({ config, options, deps });\n const autoSchedule = options.durableHooks?.autoSchedule !== false;\n const registryResolver = this.#registryResolver;\n const databaseAdapter =\n (deps as ImplicitDatabaseDependencies<TSchema>).databaseAdapter ??\n resolveDatabaseAdapter(options, this.#schema);\n const internalFragment = isInternalFragment\n ? undefined\n : (hooksConfig?.internalFragment ?? registryResolver?.getInternalFragment(databaseAdapter));\n\n // Builder API: serviceTx using createServiceTxBuilder\n function serviceTx<TSchema extends AnySchema>(schema: TSchema) {\n const uow = storage.getStore()?.uow;\n if (!uow) {\n throw new Error(\n \"No UnitOfWork in context. Service must be called within a route handler OR using `withUnitOfWork`.\",\n );\n }\n return createServiceTxBuilder<TSchema, THooks>(schema, uow, hooksConfig?.hooks);\n }\n\n const serviceContext: DatabaseServiceContext<THooks> = {\n serviceTx,\n };\n\n // Builder API: handlerTx using createHandlerTxBuilder\n function handlerTx(execOptions?: Omit<ExecuteTxOptions, \"createUnitOfWork\">) {\n const currentStorage = storage.getStore();\n if (!currentStorage) {\n throw new Error(\n \"No storage in context. Handler must be called within a request context.\",\n );\n }\n\n const userOnBeforeMutate = execOptions?.onBeforeMutate;\n const userOnAfterMutate = execOptions?.onAfterMutate;\n const userOnAfterRetrieve = execOptions?.onAfterRetrieve;\n const planMode = execOptions?.planMode ?? false;\n const roundtripGuard = isRouteRequest(currentStorage)\n ? resolveDbRoundtripGuard(options)\n : null;\n const roundtripState = roundtripGuard\n ? getDbRoundtripGuardState(currentStorage, roundtripGuard)\n : null;\n const routeInfo = (\n currentStorage as DatabaseContextStorage & {\n [requestRouteSymbol]?: { method?: string; path?: string };\n }\n )[requestRouteSymbol];\n const routeWaitUntil = (\n currentStorage as DatabaseContextStorage & {\n [requestWaitUntilSymbol]?: (promise: Promise<unknown>) => void;\n }\n )[requestWaitUntilSymbol];\n const routeLabel =\n routeInfo && routeInfo.method && routeInfo.path\n ? `${routeInfo.method} ${routeInfo.path}`\n : null;\n const routeSuffix = routeLabel ? ` (route: ${routeLabel})` : \"\";\n const buildRoundtripError = (kind: \"retrieve\" | \"mutate\") =>\n new FragnoApiError(\n {\n message:\n `[fragno-db] Fragment \"${baseDef.name}\" executed more than ` +\n `${roundtripState?.maxRoundtrips ?? 1} ${kind} ` +\n `database roundtrip(s) in a single request${routeSuffix}. ` +\n \"Combine reads/writes into one handlerTx() or increase dbRoundtripGuard. \" +\n `See ${roundtripGuardDocsUrl}`,\n code: \"DB_ROUNDTRIP_LIMIT_EXCEEDED\",\n },\n 500,\n );\n const roundtripExecutionState = roundtripState\n ? { countedRetrieve: false, countedMutate: false }\n : null;\n\n const resetRoundtripExecutionState = () => {\n if (!roundtripExecutionState) {\n return;\n }\n roundtripExecutionState.countedRetrieve = false;\n roundtripExecutionState.countedMutate = false;\n };\n\n const guardOnAfterRetrieve = roundtripState\n ? async (uow: IUnitOfWork, results: unknown[]) => {\n if (\n roundtripExecutionState &&\n !roundtripExecutionState.countedRetrieve &&\n uow.getRetrievalOperations().length > 0\n ) {\n roundtripExecutionState.countedRetrieve = true;\n roundtripState.retrieveCount += 1;\n if (roundtripState.retrieveCount > roundtripState.maxRoundtrips) {\n throw buildRoundtripError(\"retrieve\");\n }\n }\n\n if (userOnAfterRetrieve) {\n await userOnAfterRetrieve(uow, results);\n }\n }\n : userOnAfterRetrieve;\n\n const builder = createHandlerTxBuilder<THooks>({\n ...execOptions,\n createUnitOfWork: () => {\n currentStorage.uow.reset();\n if (internalFragment) {\n currentStorage.uow.registerSchema(\n internalFragment.$internal.deps.schema,\n internalFragment.$internal.deps.namespace,\n );\n }\n return currentStorage.uow;\n },\n onBeforeMutate: (uow) => {\n if (internalFragment && !planMode) {\n prepareHookMutations(uow, internalFragment, hooksConfig?.defaultRetryPolicy);\n }\n if (userOnBeforeMutate) {\n userOnBeforeMutate(uow);\n }\n if (\n roundtripState &&\n roundtripExecutionState &&\n !roundtripExecutionState.countedMutate &&\n uow.getMutationOperations().length > 0\n ) {\n roundtripExecutionState.countedMutate = true;\n roundtripState.mutateCount += 1;\n if (roundtripState.mutateCount > roundtripState.maxRoundtrips) {\n throw buildRoundtripError(\"mutate\");\n }\n }\n },\n onAfterRetrieve: guardOnAfterRetrieve,\n onAfterMutate: async (uow) => {\n notifyDurableHooksAfterMutate({\n uow,\n hooksConfig,\n internalFragment,\n autoSchedule,\n planMode,\n logContext: { route: routeLabel, source: \"request\", waitUntil: routeWaitUntil },\n });\n if (hooksConfig && !planMode) {\n const runtimeState = getDurableHooksRuntimeByConfig(hooksConfig);\n if (\n runtimeState &&\n !runtimeState.dispatcherRegistered &&\n !runtimeState.dispatcherWarningEmitted\n ) {\n const hasHooks = uow\n .getTriggeredHooks()\n .some((hook) => hook.namespace === hooksConfig.namespace);\n if (hasHooks) {\n runtimeState.dispatcherWarningEmitted = true;\n DurableHooksLogger.warn(\"Durable hooks dispatcher not configured for fragment\", {\n namespace: hooksConfig.namespace,\n fields: {\n guidance:\n \"Hooks will only run during requests; scheduled/retry hooks may stall. \" +\n \"Create a dispatcher with createDurableHooksProcessor([...]) from \" +\n \"`@fragno-dev/db/dispatchers/node` or `@fragno-dev/db/dispatchers/cloudflare-do`.\",\n },\n });\n }\n }\n }\n if (userOnAfterMutate) {\n await userOnAfterMutate(uow);\n }\n },\n });\n\n if (roundtripState) {\n const guardedBuilder = wrapHandlerTxBuilderWithRoundtripGuard(\n builder,\n resetRoundtripExecutionState,\n );\n return guardedBuilder;\n }\n\n return builder;\n }\n\n function callServices<\n TServiceCalls extends\n | TxResult<unknown, unknown>\n | undefined\n | readonly (TxResult<unknown, unknown> | undefined)[],\n >(\n serviceCalls: () => TServiceCalls,\n ): Promise<ExtractServiceFinalResultOrSingle<TServiceCalls>> {\n let callWasArray = false;\n const resultPromise = handlerTx()\n .withServiceCalls(() => {\n const calls = serviceCalls();\n callWasArray = Array.isArray(calls);\n return (callWasArray ? calls : [calls]) as readonly (\n | TxResult<unknown, unknown>\n | undefined\n )[];\n })\n .execute();\n\n return resultPromise.then((result) =>\n callWasArray\n ? (result as ExtractServiceFinalResultOrSingle<TServiceCalls>)\n : (\n result as AwaitedPromisesInObject<\n ExtractServiceFinalResults<readonly [TServiceCalls]>\n >\n )[0],\n ) as Promise<ExtractServiceFinalResultOrSingle<TServiceCalls>>;\n }\n\n const handlerContext: DatabaseHandlerContext<THooks> = {\n handlerTx,\n callServices,\n };\n\n return { serviceContext, handlerContext };\n });\n\n // Build the final definition\n const finalDef = builderWithContext.build();\n if (this.#hooksFactory) {\n finalDef.internalDataFactory = ({ config, options, deps, services, serviceDeps }) => {\n const hooksConfig = createHooksConfig({\n config: config as TConfig,\n options: options as FragnoPublicConfigWithDatabase,\n deps: deps as TDeps,\n services: services as BoundServices<TBaseServices & TServices>,\n serviceDeps: serviceDeps as TServiceDependencies,\n });\n if (!hooksConfig) {\n return {};\n }\n return {\n durableHooksToken: registerDurableHooksRuntime(hooksConfig),\n };\n };\n }\n if (this.#registryResolver) {\n const registryInternalRoutes = ({ deps }: { deps: TDeps }) => {\n const databaseAdapter = (deps as ImplicitDatabaseDependencies<TSchema>).databaseAdapter;\n if (!databaseAdapter) {\n throw new Error(\"Database adapter is missing for internal routes.\");\n }\n const internalFragment = this.#registryResolver!.getInternalFragment(databaseAdapter);\n if (!internalFragment) {\n return [];\n }\n return (internalFragment.routes ?? []) as readonly AnyFragnoRouteConfig[];\n };\n const mergedInternalRoutes = [\n ...(finalDef.internalRoutes ?? []),\n registryInternalRoutes,\n ] as readonly AnyRouteOrFactory[];\n finalDef.internalRoutes = mergedInternalRoutes as TInternalRoutes;\n }\n\n // Return the complete definition with proper typing and dependencies\n return {\n ...finalDef,\n dependencies,\n };\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ import { HookNotifyContext } from "../../hooks/hooks.js";
2
+ import "../../hooks/durable-hooks-processor.js";
3
+
4
+ //#region src/dispatchers/cloudflare-do/dispatcher.d.ts
5
+ type AlarmStorage = {
6
+ setAlarm?: (timestamp: number | Date) => Promise<void>;
7
+ deleteAlarm?: () => Promise<void>;
8
+ };
9
+ type DurableHooksDispatcherDurableObjectState = {
10
+ readonly storage: AlarmStorage;
11
+ };
12
+ type DurableHooksDispatcherDurableObjectHandler = {
13
+ fetch?: (request: Request) => Promise<Response>;
14
+ notify?: (context: HookNotifyContext) => void | Promise<void>;
15
+ alarm?: () => Promise<void>;
16
+ };
17
+ type DurableHooksDispatcherDurableObjectFactory<TEnv = unknown> = (state: DurableHooksDispatcherDurableObjectState, env: TEnv) => DurableHooksDispatcherDurableObjectHandler;
18
+ //#endregion
19
+ export { DurableHooksDispatcherDurableObjectFactory, DurableHooksDispatcherDurableObjectHandler, DurableHooksDispatcherDurableObjectState };
20
+ //# sourceMappingURL=dispatcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dispatcher.d.ts","names":[],"sources":["../../../src/dispatchers/cloudflare-do/dispatcher.ts"],"sourcesContent":[],"mappings":";;;;KAIK,YAAA;kCAC6B,SAAS;EADtC,WAAA,CAAA,EAAA,GAAY,GAEK,OAFL,CAAA,IAAA,CAAA;CACiB;AAAS,KAI/B,wCAAA,GAJ+B;EACrB,SAAA,OAAA,EAIF,YAJE;CAAO;AAGjB,KAIA,0CAAA,GAJwC;EAIxC,KAAA,CAAA,EAAA,CAAA,OAAA,EACQ,OADR,EAAA,GACoB,OADpB,CAC4B,QADc,CAAA;EAClC,MAAA,CAAA,EAAA,CAAA,OAAA,EACC,iBADD,EAAA,GAAA,IAAA,GAC8B,OAD9B,CAAA,IAAA,CAAA;EAAoB,KAAA,CAAA,EAAA,GAAA,GAExB,OAFwB,CAAA,IAAA,CAAA;CAAR;AACX,KAIT,0CAJS,CAAA,OAAA,OAAA,CAAA,GAAA,CAAA,KAAA,EAKZ,wCALY,EAAA,GAAA,EAMd,IANc,EAAA,GAOhB,0CAPgB"}
@@ -0,0 +1,147 @@
1
+ import { DurableHooksLogger } from "../../hooks/durable-hooks-logger.js";
2
+
3
+ //#region src/dispatchers/cloudflare-do/dispatcher.ts
4
+ function createDurableHooksDispatcherDurableObject(options) {
5
+ return (state, env) => {
6
+ const processor = options.createProcessor({
7
+ state,
8
+ env
9
+ });
10
+ const onProcessError = options.onProcessError ?? ((error) => {
11
+ DurableHooksLogger.error("Durable hooks dispatcher error", {
12
+ namespace: processor.namespace,
13
+ fields: { error: DurableHooksLogger.toErrorMessage(error) }
14
+ });
15
+ });
16
+ const safeOnProcessError = (error) => {
17
+ Promise.resolve().then(() => onProcessError(error)).catch((callbackError) => {
18
+ DurableHooksLogger.error("Durable hooks dispatcher onProcessError callback failed", {
19
+ namespace: processor.namespace,
20
+ fields: { error: DurableHooksLogger.toErrorMessage(callbackError) }
21
+ });
22
+ });
23
+ };
24
+ const rawSetAlarm = state.storage.setAlarm;
25
+ const rawDeleteAlarm = state.storage.deleteAlarm;
26
+ if (!rawSetAlarm) throw new Error("Durable hooks dispatcher requires state.storage.setAlarm to schedule alarms.");
27
+ const setAlarm = rawSetAlarm.bind(state.storage);
28
+ const deleteAlarm = rawDeleteAlarm?.bind(state.storage);
29
+ let processing = false;
30
+ let queued = false;
31
+ let currentPromise;
32
+ let alarmRefreshQueued = false;
33
+ let alarmRefreshPromise;
34
+ let latestAlarmRefreshSource = "request";
35
+ const runProcess = () => {
36
+ if (processing) {
37
+ queued = true;
38
+ return currentPromise ?? Promise.resolve();
39
+ }
40
+ processing = true;
41
+ currentPromise = (async () => {
42
+ try {
43
+ do {
44
+ queued = false;
45
+ try {
46
+ const startedAt = Date.now();
47
+ DurableHooksLogger.debug("Durable hooks alarm start", { namespace: processor.namespace });
48
+ const processed = await processor.processDue();
49
+ DurableHooksLogger.debug("Durable hooks alarm processed", {
50
+ namespace: processor.namespace,
51
+ fields: {
52
+ processed,
53
+ ms: Date.now() - startedAt
54
+ }
55
+ });
56
+ } catch (error) {
57
+ DurableHooksLogger.error("Durable hooks alarm failed", {
58
+ namespace: processor.namespace,
59
+ fields: { error: DurableHooksLogger.toErrorMessage(error) }
60
+ });
61
+ safeOnProcessError(error);
62
+ }
63
+ } while (queued);
64
+ } finally {
65
+ processing = false;
66
+ currentPromise = void 0;
67
+ }
68
+ })();
69
+ return currentPromise;
70
+ };
71
+ const scheduleNextAlarm = async (source) => {
72
+ DurableHooksLogger.debug("Durable hooks alarm schedule requested", {
73
+ namespace: processor.namespace,
74
+ fields: { source }
75
+ });
76
+ const nextWakeAt = await processor.getNextWakeAt();
77
+ if (!nextWakeAt) {
78
+ await deleteAlarm?.();
79
+ DurableHooksLogger.debug("Durable hooks alarm cleared", {
80
+ namespace: processor.namespace,
81
+ fields: { source }
82
+ });
83
+ return;
84
+ }
85
+ const now = Date.now();
86
+ const scheduledAt = new Date(Math.max(nextWakeAt.getTime(), now));
87
+ await setAlarm(scheduledAt);
88
+ DurableHooksLogger.debug("Durable hooks alarm scheduled", {
89
+ namespace: processor.namespace,
90
+ fields: {
91
+ source,
92
+ nextWakeAt: nextWakeAt.toISOString(),
93
+ scheduledAt: scheduledAt.toISOString()
94
+ }
95
+ });
96
+ };
97
+ const refreshAlarm = (source) => {
98
+ latestAlarmRefreshSource = source;
99
+ if (alarmRefreshPromise) {
100
+ alarmRefreshQueued = true;
101
+ return alarmRefreshPromise;
102
+ }
103
+ alarmRefreshPromise = (async () => {
104
+ do {
105
+ alarmRefreshQueued = false;
106
+ await scheduleNextAlarm(latestAlarmRefreshSource);
107
+ } while (alarmRefreshQueued);
108
+ })().finally(() => {
109
+ alarmRefreshPromise = void 0;
110
+ });
111
+ return alarmRefreshPromise;
112
+ };
113
+ DurableHooksLogger.debug("Durable hooks dispatcher init", { namespace: processor.namespace });
114
+ refreshAlarm("alarm").catch((error) => {
115
+ DurableHooksLogger.error("Durable hooks alarm schedule failed", {
116
+ namespace: processor.namespace,
117
+ fields: { error: DurableHooksLogger.toErrorMessage(error) }
118
+ });
119
+ safeOnProcessError(error);
120
+ });
121
+ return {
122
+ notify: (context) => {
123
+ const handledPromise = refreshAlarm(context.source).catch((error) => {
124
+ DurableHooksLogger.error("Durable hooks alarm schedule failed", {
125
+ namespace: processor.namespace,
126
+ fields: { error: DurableHooksLogger.toErrorMessage(error) }
127
+ });
128
+ safeOnProcessError(error);
129
+ });
130
+ if (context.waitUntil) context.waitUntil(handledPromise);
131
+ return handledPromise;
132
+ },
133
+ alarm: async () => {
134
+ try {
135
+ await runProcess();
136
+ await refreshAlarm("alarm");
137
+ } catch (error) {
138
+ safeOnProcessError(error);
139
+ }
140
+ }
141
+ };
142
+ };
143
+ }
144
+
145
+ //#endregion
146
+ export { createDurableHooksDispatcherDurableObject };
147
+ //# sourceMappingURL=dispatcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dispatcher.js","names":["currentPromise: Promise<void> | undefined","alarmRefreshPromise: Promise<void> | undefined","latestAlarmRefreshSource: HookNotifySource"],"sources":["../../../src/dispatchers/cloudflare-do/dispatcher.ts"],"sourcesContent":["import { DurableHooksLogger } from \"../../hooks/durable-hooks-logger\";\nimport type { DurableHooksProcessor } from \"../../hooks/durable-hooks-processor\";\nimport type { HookNotifyContext, HookNotifySource } from \"../../hooks/hooks\";\n\ntype AlarmStorage = {\n setAlarm?: (timestamp: number | Date) => Promise<void>;\n deleteAlarm?: () => Promise<void>;\n};\n\nexport type DurableHooksDispatcherDurableObjectState = {\n readonly storage: AlarmStorage;\n};\n\nexport type DurableHooksDispatcherDurableObjectHandler = {\n fetch?: (request: Request) => Promise<Response>;\n notify?: (context: HookNotifyContext) => void | Promise<void>;\n alarm?: () => Promise<void>;\n};\n\nexport type DurableHooksDispatcherDurableObjectFactory<TEnv = unknown> = (\n state: DurableHooksDispatcherDurableObjectState,\n env: TEnv,\n) => DurableHooksDispatcherDurableObjectHandler;\n\nexport type DurableHooksDispatcherDurableObjectOptions<TEnv = unknown> = {\n createProcessor: (context: {\n state: DurableHooksDispatcherDurableObjectState;\n env: TEnv;\n }) => DurableHooksProcessor;\n onProcessError?: (error: unknown) => void;\n};\n\nexport function createDurableHooksDispatcherDurableObject<TEnv>(\n options: DurableHooksDispatcherDurableObjectOptions<TEnv>,\n): DurableHooksDispatcherDurableObjectFactory<TEnv> {\n return (state, env) => {\n const processor = options.createProcessor({ state, env });\n const onProcessError =\n options.onProcessError ??\n ((error: unknown) => {\n DurableHooksLogger.error(\"Durable hooks dispatcher error\", {\n namespace: processor.namespace,\n fields: { error: DurableHooksLogger.toErrorMessage(error) },\n });\n });\n const safeOnProcessError = (error: unknown) => {\n void Promise.resolve()\n .then(() => onProcessError(error))\n .catch((callbackError) => {\n DurableHooksLogger.error(\"Durable hooks dispatcher onProcessError callback failed\", {\n namespace: processor.namespace,\n fields: { error: DurableHooksLogger.toErrorMessage(callbackError) },\n });\n });\n };\n const rawSetAlarm = state.storage.setAlarm;\n const rawDeleteAlarm = state.storage.deleteAlarm;\n\n if (!rawSetAlarm) {\n throw new Error(\n \"Durable hooks dispatcher requires state.storage.setAlarm to schedule alarms.\",\n );\n }\n const setAlarm = rawSetAlarm.bind(state.storage);\n const deleteAlarm = rawDeleteAlarm?.bind(state.storage);\n\n let processing = false;\n let queued = false;\n let currentPromise: Promise<void> | undefined;\n let alarmRefreshQueued = false;\n let alarmRefreshPromise: Promise<void> | undefined;\n let latestAlarmRefreshSource: HookNotifySource = \"request\";\n\n const runProcess = () => {\n if (processing) {\n queued = true;\n return currentPromise ?? Promise.resolve();\n }\n\n processing = true;\n currentPromise = (async () => {\n try {\n do {\n queued = false;\n try {\n const startedAt = Date.now();\n DurableHooksLogger.debug(\"Durable hooks alarm start\", {\n namespace: processor.namespace,\n });\n const processed = await processor.processDue();\n DurableHooksLogger.debug(\"Durable hooks alarm processed\", {\n namespace: processor.namespace,\n fields: {\n processed,\n ms: Date.now() - startedAt,\n },\n });\n } catch (error) {\n DurableHooksLogger.error(\"Durable hooks alarm failed\", {\n namespace: processor.namespace,\n fields: { error: DurableHooksLogger.toErrorMessage(error) },\n });\n safeOnProcessError(error);\n }\n } while (queued);\n } finally {\n processing = false;\n currentPromise = undefined;\n }\n })();\n\n return currentPromise;\n };\n\n const scheduleNextAlarm = async (source: HookNotifySource) => {\n DurableHooksLogger.debug(\"Durable hooks alarm schedule requested\", {\n namespace: processor.namespace,\n fields: {\n source,\n },\n });\n const nextWakeAt = await processor.getNextWakeAt();\n if (!nextWakeAt) {\n await deleteAlarm?.();\n DurableHooksLogger.debug(\"Durable hooks alarm cleared\", {\n namespace: processor.namespace,\n fields: {\n source,\n },\n });\n return;\n }\n\n const now = Date.now();\n const scheduledAt = new Date(Math.max(nextWakeAt.getTime(), now));\n await setAlarm(scheduledAt);\n DurableHooksLogger.debug(\"Durable hooks alarm scheduled\", {\n namespace: processor.namespace,\n fields: {\n source,\n nextWakeAt: nextWakeAt.toISOString(),\n scheduledAt: scheduledAt.toISOString(),\n },\n });\n };\n\n const refreshAlarm = (source: HookNotifySource): Promise<void> => {\n latestAlarmRefreshSource = source;\n if (alarmRefreshPromise) {\n alarmRefreshQueued = true;\n return alarmRefreshPromise;\n }\n\n alarmRefreshPromise = (async () => {\n do {\n alarmRefreshQueued = false;\n await scheduleNextAlarm(latestAlarmRefreshSource);\n } while (alarmRefreshQueued);\n })().finally(() => {\n alarmRefreshPromise = undefined;\n });\n\n return alarmRefreshPromise;\n };\n\n DurableHooksLogger.debug(\"Durable hooks dispatcher init\", {\n namespace: processor.namespace,\n });\n void refreshAlarm(\"alarm\").catch((error) => {\n DurableHooksLogger.error(\"Durable hooks alarm schedule failed\", {\n namespace: processor.namespace,\n fields: { error: DurableHooksLogger.toErrorMessage(error) },\n });\n safeOnProcessError(error);\n });\n\n return {\n notify: (context) => {\n const schedulePromise = refreshAlarm(context.source);\n const handledPromise = schedulePromise.catch((error) => {\n DurableHooksLogger.error(\"Durable hooks alarm schedule failed\", {\n namespace: processor.namespace,\n fields: { error: DurableHooksLogger.toErrorMessage(error) },\n });\n safeOnProcessError(error);\n });\n if (context.waitUntil) {\n context.waitUntil(handledPromise);\n } else {\n void handledPromise;\n }\n return handledPromise;\n },\n alarm: async () => {\n try {\n await runProcess();\n await refreshAlarm(\"alarm\");\n } catch (error) {\n safeOnProcessError(error);\n }\n },\n };\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import { AnyFragnoInstantiatedDatabaseFragment } from "../../mod.js";
2
+ import { DurableHooksDispatcherDurableObjectFactory, DurableHooksDispatcherDurableObjectHandler, DurableHooksDispatcherDurableObjectState } from "./dispatcher.js";
3
+
4
+ //#region src/dispatchers/cloudflare-do/index.d.ts
5
+ type DurableHooksProcessorOptions = {
6
+ onProcessError?: (error: unknown) => void;
7
+ };
8
+ declare function createDurableHooksProcessor<TEnv>(fragments: readonly AnyFragnoInstantiatedDatabaseFragment[], options?: DurableHooksProcessorOptions): DurableHooksDispatcherDurableObjectFactory<TEnv>;
9
+ //#endregion
10
+ export { type DurableHooksDispatcherDurableObjectFactory, type DurableHooksDispatcherDurableObjectHandler, type DurableHooksDispatcherDurableObjectState, DurableHooksProcessorOptions, createDurableHooksProcessor };
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/dispatchers/cloudflare-do/index.ts"],"sourcesContent":[],"mappings":";;;;KAUY,4BAAA;;AAAZ,CAAA;AAesB,iBADN,2BACM,CAAA,IAAA,CAAA,CAAA,SAAA,EAAA,SAAA,qCAAA,EAAA,EAAA,OAAA,CAAA,EACX,4BADW,CAAA,EAEnB,0CAFmB,CAEwB,IAFxB,CAAA"}
@@ -0,0 +1,31 @@
1
+ import { getDurableHooksRuntimeByToken } from "../../hooks/durable-hooks-runtime.js";
2
+ import { createDurableHooksProcessorGroup } from "../../hooks/durable-hooks-processor.js";
3
+ import { createDurableHooksDispatcherDurableObject } from "./dispatcher.js";
4
+
5
+ //#region src/dispatchers/cloudflare-do/index.ts
6
+ function createDurableHooksProcessor(fragments, options = {}) {
7
+ const processor = createDurableHooksProcessorGroup(fragments, { onError: options.onProcessError });
8
+ const factory = createDurableHooksDispatcherDurableObject({
9
+ createProcessor: () => processor,
10
+ onProcessError: options.onProcessError
11
+ });
12
+ return (state, env) => {
13
+ const handler = factory(state, env);
14
+ const notifier = { notify: (context) => {
15
+ if (!handler.notify) return;
16
+ return handler.notify(context);
17
+ } };
18
+ for (const fragment of fragments) {
19
+ const durableHooksToken = fragment.$internal?.durableHooksToken;
20
+ if (!durableHooksToken) continue;
21
+ const runtime = getDurableHooksRuntimeByToken(durableHooksToken);
22
+ if (!runtime) continue;
23
+ runtime.config.notifier = notifier;
24
+ }
25
+ return handler;
26
+ };
27
+ }
28
+
29
+ //#endregion
30
+ export { createDurableHooksProcessor };
31
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/dispatchers/cloudflare-do/index.ts"],"sourcesContent":["import { createDurableHooksProcessorGroup } from \"../../hooks/durable-hooks-processor\";\nimport { getDurableHooksRuntimeByToken } from \"../../hooks/durable-hooks-runtime\";\nimport type { AnyFragnoInstantiatedDatabaseFragment } from \"../../mod\";\nimport {\n createDurableHooksDispatcherDurableObject,\n type DurableHooksDispatcherDurableObjectFactory,\n type DurableHooksDispatcherDurableObjectHandler,\n type DurableHooksDispatcherDurableObjectState,\n} from \"./dispatcher\";\n\nexport type DurableHooksProcessorOptions = {\n onProcessError?: (error: unknown) => void;\n};\n\nexport type {\n DurableHooksDispatcherDurableObjectFactory,\n DurableHooksDispatcherDurableObjectHandler,\n DurableHooksDispatcherDurableObjectState,\n};\n\ntype DurableHooksInternal = {\n durableHooksToken?: object;\n};\n\nexport function createDurableHooksProcessor<TEnv>(\n fragments: readonly AnyFragnoInstantiatedDatabaseFragment[],\n options: DurableHooksProcessorOptions = {},\n): DurableHooksDispatcherDurableObjectFactory<TEnv> {\n const processor = createDurableHooksProcessorGroup(fragments, {\n onError: options.onProcessError,\n });\n const factory = createDurableHooksDispatcherDurableObject<TEnv>({\n createProcessor: () => processor,\n onProcessError: options.onProcessError,\n });\n\n return (state, env) => {\n const handler = factory(state, env);\n const notifier = {\n notify: (context: Parameters<NonNullable<typeof handler.notify>>[0]) => {\n if (!handler.notify) {\n return;\n }\n return handler.notify(context);\n },\n };\n\n for (const fragment of fragments) {\n const internal = fragment.$internal as DurableHooksInternal | undefined;\n const durableHooksToken = internal?.durableHooksToken;\n if (!durableHooksToken) {\n continue;\n }\n const runtime = getDurableHooksRuntimeByToken(durableHooksToken);\n if (!runtime) {\n continue;\n }\n runtime.config.notifier = notifier;\n }\n\n return handler;\n };\n}\n"],"mappings":";;;;;AAwBA,SAAgB,4BACd,WACA,UAAwC,EAAE,EACQ;CAClD,MAAM,YAAY,iCAAiC,WAAW,EAC5D,SAAS,QAAQ,gBAClB,CAAC;CACF,MAAM,UAAU,0CAAgD;EAC9D,uBAAuB;EACvB,gBAAgB,QAAQ;EACzB,CAAC;AAEF,SAAQ,OAAO,QAAQ;EACrB,MAAM,UAAU,QAAQ,OAAO,IAAI;EACnC,MAAM,WAAW,EACf,SAAS,YAA+D;AACtE,OAAI,CAAC,QAAQ,OACX;AAEF,UAAO,QAAQ,OAAO,QAAQ;KAEjC;AAED,OAAK,MAAM,YAAY,WAAW;GAEhC,MAAM,oBADW,SAAS,WACU;AACpC,OAAI,CAAC,kBACH;GAEF,MAAM,UAAU,8BAA8B,kBAAkB;AAChE,OAAI,CAAC,QACH;AAEF,WAAQ,OAAO,WAAW;;AAG5B,SAAO"}
@@ -0,0 +1,14 @@
1
+ import { HookNotifyContext } from "../../hooks/hooks.js";
2
+ import "../../hooks/durable-hooks-processor.js";
3
+
4
+ //#region src/dispatchers/node/dispatcher.d.ts
5
+ type DurableHooksDispatcher = {
6
+ notify: (context: HookNotifyContext) => void;
7
+ wake: () => Promise<void>;
8
+ drain: () => Promise<void>;
9
+ startPolling: () => void;
10
+ stopPolling: () => void;
11
+ };
12
+ //#endregion
13
+ export { DurableHooksDispatcher };
14
+ //# sourceMappingURL=dispatcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dispatcher.d.ts","names":[],"sources":["../../../src/dispatchers/node/dispatcher.ts"],"sourcesContent":[],"mappings":";;;;KAIY,sBAAA;oBACQ;EADR,IAAA,EAAA,GAAA,GAEE,OAFF,CAAA,IAAA,CAAsB;EACd,KAAA,EAAA,GAAA,GAEL,OAFK,CAAA,IAAA,CAAA;EACN,YAAA,EAAA,GAAA,GAAA,IAAA;EACC,WAAA,EAAA,GAAA,GAAA,IAAA;CAAO"}
@@ -0,0 +1,80 @@
1
+ import { DurableHooksLogger } from "../../hooks/durable-hooks-logger.js";
2
+
3
+ //#region src/dispatchers/node/dispatcher.ts
4
+ function createDurableHooksDispatcher(options) {
5
+ const pollIntervalMs = options.pollIntervalMs ?? 5e3;
6
+ const onError = options.onError ?? ((error) => {
7
+ DurableHooksLogger.error("Durable hooks dispatcher error", {
8
+ namespace: options.processor.namespace,
9
+ fields: { error: DurableHooksLogger.toErrorMessage(error) }
10
+ });
11
+ });
12
+ let timer;
13
+ let processing = false;
14
+ let queued = false;
15
+ let notifyQueued = false;
16
+ let currentPromise;
17
+ const runProcess = () => {
18
+ if (processing) {
19
+ queued = true;
20
+ return currentPromise ?? Promise.resolve();
21
+ }
22
+ processing = true;
23
+ currentPromise = (async () => {
24
+ do {
25
+ queued = false;
26
+ try {
27
+ await options.processor.processDue();
28
+ } catch (error) {
29
+ onError(error);
30
+ }
31
+ } while (queued);
32
+ processing = false;
33
+ })();
34
+ return currentPromise;
35
+ };
36
+ const poll = async () => {
37
+ try {
38
+ const nextWakeAt = await options.processor.getNextWakeAt();
39
+ if (!nextWakeAt) return;
40
+ if (Date.now() >= nextWakeAt.getTime()) await runProcess();
41
+ } catch (error) {
42
+ onError(error);
43
+ }
44
+ };
45
+ return {
46
+ notify: (_context) => {
47
+ if (notifyQueued) return;
48
+ notifyQueued = true;
49
+ setTimeout(() => {
50
+ notifyQueued = false;
51
+ runProcess();
52
+ }, 0);
53
+ },
54
+ wake: async () => {
55
+ await runProcess();
56
+ },
57
+ drain: async () => {
58
+ try {
59
+ await options.processor.drain();
60
+ } catch (error) {
61
+ onError(error);
62
+ }
63
+ },
64
+ startPolling: () => {
65
+ if (timer) return;
66
+ timer = setInterval(() => {
67
+ poll();
68
+ }, pollIntervalMs);
69
+ },
70
+ stopPolling: () => {
71
+ if (!timer) return;
72
+ clearInterval(timer);
73
+ timer = void 0;
74
+ }
75
+ };
76
+ }
77
+
78
+ //#endregion
79
+ export { createDurableHooksDispatcher };
80
+ //# sourceMappingURL=dispatcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dispatcher.js","names":["timer: ReturnType<typeof setInterval> | undefined","currentPromise: Promise<void> | undefined"],"sources":["../../../src/dispatchers/node/dispatcher.ts"],"sourcesContent":["import { DurableHooksLogger } from \"../../hooks/durable-hooks-logger\";\nimport type { DurableHooksProcessor } from \"../../hooks/durable-hooks-processor\";\nimport type { HookNotifyContext } from \"../../hooks/hooks\";\n\nexport type DurableHooksDispatcher = {\n notify: (context: HookNotifyContext) => void;\n wake: () => Promise<void>;\n drain: () => Promise<void>;\n startPolling: () => void;\n stopPolling: () => void;\n};\n\nexport type DurableHooksDispatcherOptions = {\n processor: DurableHooksProcessor;\n pollIntervalMs?: number;\n onError?: (error: unknown) => void;\n};\n\nexport function createDurableHooksDispatcher(\n options: DurableHooksDispatcherOptions,\n): DurableHooksDispatcher {\n const pollIntervalMs = options.pollIntervalMs ?? 5000;\n const onError =\n options.onError ??\n ((error: unknown) => {\n DurableHooksLogger.error(\"Durable hooks dispatcher error\", {\n namespace: options.processor.namespace,\n fields: { error: DurableHooksLogger.toErrorMessage(error) },\n });\n });\n let timer: ReturnType<typeof setInterval> | undefined;\n let processing = false;\n let queued = false;\n let notifyQueued = false;\n let currentPromise: Promise<void> | undefined;\n\n const runProcess = () => {\n if (processing) {\n queued = true;\n return currentPromise ?? Promise.resolve();\n }\n\n processing = true;\n currentPromise = (async () => {\n do {\n queued = false;\n try {\n await options.processor.processDue();\n } catch (error) {\n onError(error);\n }\n } while (queued);\n processing = false;\n })();\n\n return currentPromise;\n };\n\n const poll = async () => {\n try {\n const nextWakeAt = await options.processor.getNextWakeAt();\n if (!nextWakeAt) {\n return;\n }\n if (Date.now() >= nextWakeAt.getTime()) {\n await runProcess();\n }\n } catch (error) {\n onError(error);\n }\n };\n\n return {\n notify: (_context) => {\n if (notifyQueued) {\n return;\n }\n notifyQueued = true;\n setTimeout(() => {\n notifyQueued = false;\n void runProcess();\n }, 0);\n },\n wake: async () => {\n await runProcess();\n },\n drain: async () => {\n try {\n await options.processor.drain();\n } catch (error) {\n onError(error);\n }\n },\n startPolling: () => {\n if (timer) {\n return;\n }\n\n timer = setInterval(() => {\n void poll();\n }, pollIntervalMs);\n },\n stopPolling: () => {\n if (!timer) {\n return;\n }\n\n clearInterval(timer);\n timer = undefined;\n },\n };\n}\n"],"mappings":";;;AAkBA,SAAgB,6BACd,SACwB;CACxB,MAAM,iBAAiB,QAAQ,kBAAkB;CACjD,MAAM,UACJ,QAAQ,aACN,UAAmB;AACnB,qBAAmB,MAAM,kCAAkC;GACzD,WAAW,QAAQ,UAAU;GAC7B,QAAQ,EAAE,OAAO,mBAAmB,eAAe,MAAM,EAAE;GAC5D,CAAC;;CAEN,IAAIA;CACJ,IAAI,aAAa;CACjB,IAAI,SAAS;CACb,IAAI,eAAe;CACnB,IAAIC;CAEJ,MAAM,mBAAmB;AACvB,MAAI,YAAY;AACd,YAAS;AACT,UAAO,kBAAkB,QAAQ,SAAS;;AAG5C,eAAa;AACb,oBAAkB,YAAY;AAC5B,MAAG;AACD,aAAS;AACT,QAAI;AACF,WAAM,QAAQ,UAAU,YAAY;aAC7B,OAAO;AACd,aAAQ,MAAM;;YAET;AACT,gBAAa;MACX;AAEJ,SAAO;;CAGT,MAAM,OAAO,YAAY;AACvB,MAAI;GACF,MAAM,aAAa,MAAM,QAAQ,UAAU,eAAe;AAC1D,OAAI,CAAC,WACH;AAEF,OAAI,KAAK,KAAK,IAAI,WAAW,SAAS,CACpC,OAAM,YAAY;WAEb,OAAO;AACd,WAAQ,MAAM;;;AAIlB,QAAO;EACL,SAAS,aAAa;AACpB,OAAI,aACF;AAEF,kBAAe;AACf,oBAAiB;AACf,mBAAe;AACf,IAAK,YAAY;MAChB,EAAE;;EAEP,MAAM,YAAY;AAChB,SAAM,YAAY;;EAEpB,OAAO,YAAY;AACjB,OAAI;AACF,UAAM,QAAQ,UAAU,OAAO;YACxB,OAAO;AACd,YAAQ,MAAM;;;EAGlB,oBAAoB;AAClB,OAAI,MACF;AAGF,WAAQ,kBAAkB;AACxB,IAAK,MAAM;MACV,eAAe;;EAEpB,mBAAmB;AACjB,OAAI,CAAC,MACH;AAGF,iBAAc,MAAM;AACpB,WAAQ;;EAEX"}
@@ -0,0 +1,12 @@
1
+ import { AnyFragnoInstantiatedDatabaseFragment } from "../../mod.js";
2
+ import { DurableHooksDispatcher } from "./dispatcher.js";
3
+
4
+ //#region src/dispatchers/node/index.d.ts
5
+ type DurableHooksProcessorOptions = {
6
+ pollIntervalMs?: number;
7
+ onError?: (error: unknown) => void;
8
+ };
9
+ declare function createDurableHooksProcessor(fragments: readonly AnyFragnoInstantiatedDatabaseFragment[], options?: DurableHooksProcessorOptions): DurableHooksDispatcher;
10
+ //#endregion
11
+ export { type DurableHooksDispatcher, DurableHooksProcessorOptions, createDurableHooksProcessor };
12
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/dispatchers/node/index.ts"],"sourcesContent":[],"mappings":";;;;KAKY,4BAAA;;EAAA,OAAA,CAAA,EAAA,CAAA,KAAA,EAAA,OAAA,EAAA,GAAA,IAA4B;AAWxC,CAAA;AAEW,iBAFK,2BAAA,CAEL,SAAA,EAAA,SADW,qCACX,EAAA,EAAA,OAAA,CAAA,EAAA,4BAAA,CAAA,EACR,sBADQ"}
@@ -0,0 +1,27 @@
1
+ import { getDurableHooksRuntimeByToken } from "../../hooks/durable-hooks-runtime.js";
2
+ import { createDurableHooksProcessorGroup } from "../../hooks/durable-hooks-processor.js";
3
+ import { createDurableHooksDispatcher } from "./dispatcher.js";
4
+
5
+ //#region src/dispatchers/node/index.ts
6
+ function createDurableHooksProcessor(fragments, options = {}) {
7
+ const dispatcher = createDurableHooksDispatcher({
8
+ processor: createDurableHooksProcessorGroup(fragments, { onError: options.onError }),
9
+ pollIntervalMs: options.pollIntervalMs,
10
+ onError: options.onError
11
+ });
12
+ const notifier = { notify: (context) => {
13
+ dispatcher.notify(context);
14
+ } };
15
+ for (const fragment of fragments) {
16
+ const durableHooksToken = fragment.$internal?.durableHooksToken;
17
+ if (!durableHooksToken) continue;
18
+ const runtime = getDurableHooksRuntimeByToken(durableHooksToken);
19
+ if (!runtime) continue;
20
+ runtime.config.notifier = notifier;
21
+ }
22
+ return dispatcher;
23
+ }
24
+
25
+ //#endregion
26
+ export { createDurableHooksProcessor };
27
+ //# sourceMappingURL=index.js.map