@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,22 +1,37 @@
1
- import { FragmentDefinitionBuilder } from "../packages/fragno/dist/api/fragment-definition-builder.js";
1
+ import { dbNow } from "../query/db-now.js";
2
+ import { FragnoId } from "../schema/create.js";
3
+ import { isHookStatus } from "../hooks/hooks.js";
4
+ import { SETTINGS_NAMESPACE, SETTINGS_TABLE_NAME, internalSchema } from "./internal-fragment.schema.js";
2
5
  import { DatabaseFragmentDefinitionBuilder } from "../db-fragment-definition-builder.js";
3
- import { column, idColumn, schema } from "../schema/create.js";
6
+ import { FragmentDefinitionBuilder } from "@fragno-dev/core";
4
7
 
5
8
  //#region src/fragments/internal-fragment.ts
6
- const SETTINGS_TABLE_NAME = "fragno_db_settings";
7
- const SETTINGS_NAMESPACE = "fragno-db-settings";
8
- const internalSchema = schema((s) => {
9
- return s.addTable(SETTINGS_TABLE_NAME, (t) => {
10
- return t.addColumn("id", idColumn()).addColumn("key", column("string")).addColumn("value", column("string")).createIndex("unique_key", ["key"], { unique: true });
11
- }).addTable("fragno_hooks", (t) => {
12
- return t.addColumn("id", idColumn()).addColumn("namespace", column("string")).addColumn("hookName", column("string")).addColumn("payload", column("json")).addColumn("status", column("string")).addColumn("attempts", column("integer").defaultTo(0)).addColumn("maxAttempts", column("integer").defaultTo(5)).addColumn("lastAttemptAt", column("timestamp").nullable()).addColumn("nextRetryAt", column("timestamp").nullable()).addColumn("error", column("string").nullable()).addColumn("createdAt", column("timestamp").defaultTo((b) => b.now())).addColumn("nonce", column("string")).createIndex("idx_namespace_status_retry", [
13
- "namespace",
14
- "status",
15
- "nextRetryAt"
16
- ]).createIndex("idx_nonce", ["nonce"]);
17
- });
18
- });
19
- const internalFragmentDef = new DatabaseFragmentDefinitionBuilder(new FragmentDefinitionBuilder("$fragno-internal-fragment"), internalSchema, "").providesService("settingsService", ({ defineService }) => {
9
+ var SchemaRegistryCollisionError = class extends Error {
10
+ code = "SCHEMA_REGISTRY_COLLISION";
11
+ namespaceKey;
12
+ existing;
13
+ attempted;
14
+ constructor({ namespaceKey, existing, attempted }) {
15
+ super(`Schema namespace "${namespaceKey}" is already owned by "${existing.name}" (${existing.namespace ?? "null"}).`);
16
+ this.name = "SchemaRegistryCollisionError";
17
+ this.namespaceKey = namespaceKey;
18
+ this.existing = existing;
19
+ this.attempted = attempted;
20
+ }
21
+ };
22
+ const INTERNAL_SCHEMA_MIN_VERSION = 4;
23
+ if (internalSchema.version < INTERNAL_SCHEMA_MIN_VERSION) internalSchema.version = INTERNAL_SCHEMA_MIN_VERSION;
24
+ const describeHookStatusSource = (event) => `fragno_hooks id=${event.id} hook=${event.hookName}`;
25
+ const coerceHookStatus = (status, context) => {
26
+ if (isHookStatus(status)) return status;
27
+ throw new Error(`Invalid hook status from database (${context}): ${status}`);
28
+ };
29
+ const DEFAULT_HOOKS_PAGE_SIZE = 50;
30
+ const resolveHookPageSize = (pageSize) => {
31
+ if (typeof pageSize !== "number" || !Number.isInteger(pageSize) || pageSize <= 0) return DEFAULT_HOOKS_PAGE_SIZE;
32
+ return pageSize;
33
+ };
34
+ const internalFragmentDef = new DatabaseFragmentDefinitionBuilder(new FragmentDefinitionBuilder("$fragno-internal-fragment"), internalSchema).providesService("settingsService", ({ defineService }) => {
20
35
  return defineService({
21
36
  get(namespace, key) {
22
37
  const fullKey = `${namespace}.${key}`;
@@ -32,6 +47,16 @@ const internalFragmentDef = new DatabaseFragmentDefinitionBuilder(new FragmentDe
32
47
  });
33
48
  }).build();
34
49
  },
50
+ setIfMissing(namespace, key, value) {
51
+ const fullKey = `${namespace}.${key}`;
52
+ return this.serviceTx(internalSchema).retrieve((uow) => uow.findFirst(SETTINGS_TABLE_NAME, (b) => b.whereIndex("unique_key", (eb) => eb("key", "=", fullKey)))).transformRetrieve(([result]) => result).mutate(({ uow, retrieveResult }) => {
53
+ if (retrieveResult) return;
54
+ uow.create(SETTINGS_TABLE_NAME, {
55
+ key: fullKey,
56
+ value
57
+ });
58
+ }).build();
59
+ },
35
60
  delete(id) {
36
61
  return this.serviceTx(internalSchema).mutate(({ uow }) => uow.delete(SETTINGS_TABLE_NAME, id)).build();
37
62
  }
@@ -39,45 +64,136 @@ const internalFragmentDef = new DatabaseFragmentDefinitionBuilder(new FragmentDe
39
64
  }).providesService("hookService", ({ defineService }) => {
40
65
  return defineService({
41
66
  getPendingHookEvents(namespace) {
42
- return this.serviceTx(internalSchema).retrieve((uow) => uow.find("fragno_hooks", (b) => b.whereIndex("idx_namespace_status_retry", (eb) => eb.and(eb("namespace", "=", namespace), eb("status", "=", "pending"))))).transformRetrieve(([events]) => {
43
- const now = /* @__PURE__ */ new Date();
44
- return events.filter((event) => {
45
- if (!event.nextRetryAt) return true;
46
- return event.nextRetryAt <= now;
47
- }).map((event) => ({
67
+ const now = dbNow();
68
+ return this.serviceTx(internalSchema).retrieve((uow) => uow.find("fragno_hooks", (b) => b.whereIndex("idx_namespace_status_retry", (eb) => eb.and(eb("namespace", "=", namespace), eb("status", "=", "pending"), eb.or(eb.isNull("nextRetryAt"), eb("nextRetryAt", "<=", now)))))).transformRetrieve(([events]) => {
69
+ return events.map((event) => ({
48
70
  id: event.id,
49
71
  hookName: event.hookName,
50
72
  payload: event.payload,
73
+ status: coerceHookStatus(event.status, describeHookStatusSource(event)),
51
74
  attempts: event.attempts,
52
75
  maxAttempts: event.maxAttempts,
76
+ lastAttemptAt: event.lastAttemptAt,
77
+ nextRetryAt: event.nextRetryAt,
78
+ createdAt: event.createdAt,
53
79
  idempotencyKey: event.nonce
54
80
  }));
55
81
  }).build();
56
82
  },
57
- markHookCompleted(eventId) {
58
- return this.serviceTx(internalSchema).mutate(({ uow }) => uow.update("fragno_hooks", eventId, (b) => b.set({
59
- status: "completed",
60
- lastAttemptAt: /* @__PURE__ */ new Date()
61
- }).check())).build();
83
+ claimPendingHookEvents(namespace) {
84
+ const now = dbNow();
85
+ return this.serviceTx(internalSchema).retrieve((uow) => uow.find("fragno_hooks", (b) => b.whereIndex("idx_namespace_status_retry", (eb) => eb.and(eb("namespace", "=", namespace), eb("status", "=", "pending"), eb.or(eb.isNull("nextRetryAt"), eb("nextRetryAt", "<=", now)))))).transformRetrieve(([events]) => {
86
+ return events.map((event) => ({
87
+ id: event.id,
88
+ hookName: event.hookName,
89
+ payload: event.payload,
90
+ status: coerceHookStatus(event.status, describeHookStatusSource(event)),
91
+ attempts: event.attempts,
92
+ maxAttempts: event.maxAttempts,
93
+ lastAttemptAt: event.lastAttemptAt,
94
+ nextRetryAt: event.nextRetryAt,
95
+ createdAt: event.createdAt,
96
+ idempotencyKey: event.nonce
97
+ }));
98
+ }).mutate(({ uow, retrieveResult }) => {
99
+ if (retrieveResult.length === 0) return;
100
+ for (const event of retrieveResult) uow.update("fragno_hooks", event.id, (b) => b.set({
101
+ status: "processing",
102
+ lastAttemptAt: now
103
+ }).check());
104
+ }).transform(({ retrieveResult }) => retrieveResult.map((event) => ({
105
+ ...event,
106
+ status: "processing",
107
+ id: new FragnoId({
108
+ externalId: event.id.externalId,
109
+ internalId: event.id.internalId,
110
+ version: event.id.version + 1
111
+ })
112
+ }))).build();
113
+ },
114
+ claimStuckProcessingHookEvents(namespace, staleBefore) {
115
+ const now = dbNow();
116
+ return this.serviceTx(internalSchema).retrieve((uow) => uow.find("fragno_hooks", (b) => b.whereIndex("idx_namespace_status_last_attempt", (eb) => eb.and(eb("namespace", "=", namespace), eb("status", "=", "processing"), eb.or(eb.isNull("lastAttemptAt"), eb("lastAttemptAt", "<=", staleBefore)))))).transformRetrieve(([events]) => {
117
+ return events.map((event) => ({
118
+ id: event.id,
119
+ hookName: event.hookName,
120
+ payload: event.payload,
121
+ status: coerceHookStatus(event.status, describeHookStatusSource(event)),
122
+ attempts: event.attempts,
123
+ maxAttempts: event.maxAttempts,
124
+ idempotencyKey: event.nonce,
125
+ lastAttemptAt: event.lastAttemptAt,
126
+ nextRetryAt: event.nextRetryAt,
127
+ createdAt: event.createdAt
128
+ }));
129
+ }).mutate(({ uow, retrieveResult }) => {
130
+ if (retrieveResult.length === 0) return;
131
+ for (const event of retrieveResult) uow.update("fragno_hooks", event.id, (b) => b.set({
132
+ status: "processing",
133
+ lastAttemptAt: now,
134
+ nextRetryAt: null
135
+ }).check());
136
+ }).transform(({ retrieveResult }) => {
137
+ return {
138
+ events: retrieveResult.map((event) => ({
139
+ ...event,
140
+ id: new FragnoId({
141
+ externalId: event.id.externalId,
142
+ internalId: event.id.internalId,
143
+ version: event.id.version + 1
144
+ })
145
+ })),
146
+ stuckEvents: retrieveResult.map((event) => ({
147
+ id: event.id,
148
+ hookName: event.hookName,
149
+ attempts: event.attempts,
150
+ maxAttempts: event.maxAttempts,
151
+ lastAttemptAt: event.lastAttemptAt,
152
+ nextRetryAt: event.nextRetryAt
153
+ }))
154
+ };
155
+ }).build();
156
+ },
157
+ getNextHookWakeAt(namespace, timeoutMinutes) {
158
+ const timeoutMinutesValue = typeof timeoutMinutes === "number" && timeoutMinutes > 0 ? timeoutMinutes : 0;
159
+ const includeProcessing = timeoutMinutesValue > 0;
160
+ const now = dbNow();
161
+ const timeoutMs = timeoutMinutesValue * 6e4;
162
+ const processingStatus = includeProcessing ? "processing" : "__disabled__";
163
+ const staleBefore = now.plus({ minutes: -timeoutMinutesValue });
164
+ return this.serviceTx(internalSchema).retrieve((uow) => uow.forSchema(internalSchema).find("fragno_hooks", (b) => b.whereIndex("idx_namespace_status_retry", (eb) => eb.and(eb("namespace", "=", namespace), eb("status", "=", "pending"), eb.or(eb.isNull("nextRetryAt"), eb("nextRetryAt", "<=", now)))).pageSize(1)).find("fragno_hooks", (b) => b.whereIndex("idx_namespace_status_retry", (eb) => eb.and(eb("namespace", "=", namespace), eb("status", "=", "pending"), eb.isNotNull("nextRetryAt"), eb("nextRetryAt", ">", now))).orderByIndex("idx_namespace_status_retry", "asc").pageSize(1).select(["nextRetryAt"])).find("fragno_hooks", (b) => b.whereIndex("idx_namespace_status_last_attempt", (eb) => eb.and(eb("namespace", "=", namespace), eb("status", "=", processingStatus), eb.or(eb.isNull("lastAttemptAt"), eb("lastAttemptAt", "<=", staleBefore)))).pageSize(1)).find("fragno_hooks", (b) => b.whereIndex("idx_namespace_status_last_attempt", (eb) => eb.and(eb("namespace", "=", namespace), eb("status", "=", processingStatus), eb.isNotNull("lastAttemptAt"), eb("lastAttemptAt", ">", staleBefore))).orderByIndex("idx_namespace_status_last_attempt", "asc").pageSize(1).select(["lastAttemptAt"]))).transformRetrieve(([pendingImmediate, pendingNext, processingImmediate, processingNext]) => {
165
+ const hasProcessingImmediate = includeProcessing && processingImmediate.length > 0;
166
+ if (pendingImmediate.length > 0 || hasProcessingImmediate) return /* @__PURE__ */ new Date();
167
+ const pendingNextAt = pendingNext[0]?.nextRetryAt ?? null;
168
+ let processingNextAt = null;
169
+ if (includeProcessing) {
170
+ const lastAttemptAt = processingNext[0]?.lastAttemptAt;
171
+ if (lastAttemptAt) processingNextAt = new Date(lastAttemptAt.getTime() + timeoutMs);
172
+ }
173
+ if (!pendingNextAt) return processingNextAt ?? null;
174
+ if (!processingNextAt) return pendingNextAt;
175
+ return pendingNextAt <= processingNextAt ? pendingNextAt : processingNextAt;
176
+ }).build();
62
177
  },
63
178
  markHookFailed(eventId, error, attempts, retryPolicy) {
64
179
  const newAttempts = attempts + 1;
65
180
  const shouldRetry = retryPolicy.shouldRetry(newAttempts - 1);
181
+ const now = dbNow();
66
182
  return this.serviceTx(internalSchema).mutate(({ uow }) => {
67
183
  if (shouldRetry) {
68
184
  const delayMs = retryPolicy.getDelayMs(newAttempts - 1);
69
- const nextRetryAt = new Date(Date.now() + delayMs);
185
+ const nextRetryAt = now.plus({ ms: delayMs });
70
186
  uow.update("fragno_hooks", eventId, (b) => b.set({
71
187
  status: "pending",
72
188
  attempts: newAttempts,
73
- lastAttemptAt: /* @__PURE__ */ new Date(),
189
+ lastAttemptAt: now,
74
190
  nextRetryAt,
75
191
  error
76
192
  }).check());
77
193
  } else uow.update("fragno_hooks", eventId, (b) => b.set({
78
194
  status: "failed",
79
195
  attempts: newAttempts,
80
- lastAttemptAt: /* @__PURE__ */ new Date(),
196
+ lastAttemptAt: now,
81
197
  error
82
198
  }).check());
83
199
  }).build();
@@ -85,28 +201,77 @@ const internalFragmentDef = new DatabaseFragmentDefinitionBuilder(new FragmentDe
85
201
  markHookProcessing(eventId) {
86
202
  return this.serviceTx(internalSchema).mutate(({ uow }) => uow.update("fragno_hooks", eventId, (b) => b.set({
87
203
  status: "processing",
88
- lastAttemptAt: /* @__PURE__ */ new Date()
204
+ lastAttemptAt: dbNow()
89
205
  }).check())).build();
90
206
  },
91
207
  getHookById(eventId) {
92
- return this.serviceTx(internalSchema).retrieve((uow) => uow.findFirst("fragno_hooks", (b) => b.whereIndex("primary", (eb) => eb("id", "=", eventId)))).transformRetrieve(([result]) => result ?? void 0).build();
208
+ return this.serviceTx(internalSchema).retrieve((uow) => uow.findFirst("fragno_hooks", (b) => b.whereIndex("primary", (eb) => eb("id", "=", eventId)))).transformRetrieve(([result]) => result ? {
209
+ ...result,
210
+ status: coerceHookStatus(result.status, describeHookStatusSource(result))
211
+ } : void 0).build();
212
+ },
213
+ getHooksByNamespacePage(namespace, options = {}) {
214
+ const pageSize = resolveHookPageSize(options.pageSize);
215
+ return this.serviceTx(internalSchema).retrieve((uow) => uow.findWithCursor("fragno_hooks", (b) => {
216
+ const query = b.whereIndex("idx_namespace_created_at", (eb) => eb("namespace", "=", namespace)).orderByIndex("idx_namespace_created_at", "desc").pageSize(pageSize);
217
+ return options.cursor ? query.after(options.cursor) : query;
218
+ })).transformRetrieve(([page]) => ({
219
+ items: page.items.map((event) => ({
220
+ ...event,
221
+ status: coerceHookStatus(event.status, describeHookStatusSource(event))
222
+ })),
223
+ cursor: page.cursor,
224
+ hasNextPage: page.hasNextPage
225
+ })).build();
93
226
  },
94
227
  getHooksByNamespace(namespace) {
95
- return this.serviceTx(internalSchema).retrieve((uow) => uow.find("fragno_hooks", (b) => b.whereIndex("idx_namespace_status_retry", (eb) => eb("namespace", "=", namespace)))).transformRetrieve(([events]) => events).build();
228
+ return this.serviceTx(internalSchema).retrieve((uow) => uow.find("fragno_hooks", (b) => b.whereIndex("idx_namespace_status_retry", (eb) => eb("namespace", "=", namespace)))).transformRetrieve(([events]) => events.map((event) => ({
229
+ ...event,
230
+ status: coerceHookStatus(event.status, describeHookStatusSource(event))
231
+ }))).build();
96
232
  }
97
233
  });
234
+ }).providesService("outboxService", ({ defineService }) => {
235
+ return defineService({ list({ afterVersionstamp, limit } = {}) {
236
+ const afterValue = afterVersionstamp?.toLowerCase();
237
+ return this.serviceTx(internalSchema).retrieve((uow) => uow.find("fragno_db_outbox", (b) => {
238
+ let builder = afterValue ? b.whereIndex("idx_outbox_versionstamp", (eb) => eb("versionstamp", ">", afterValue)) : b.whereIndex("idx_outbox_versionstamp");
239
+ builder = builder.orderByIndex("idx_outbox_versionstamp", "asc");
240
+ if (limit !== void 0) builder = builder.pageSize(limit);
241
+ return builder;
242
+ })).transformRetrieve(([entries]) => entries.map((entry) => ({
243
+ id: entry.id,
244
+ versionstamp: entry.versionstamp,
245
+ uowId: entry.uowId,
246
+ payload: entry.payload,
247
+ refMap: entry.refMap ?? void 0,
248
+ createdAt: entry.createdAt
249
+ }))).build();
250
+ } });
98
251
  }).build();
99
252
  async function getSchemaVersionFromDatabase(fragment, namespace) {
100
253
  try {
101
- const setting = await fragment.inContext(async function() {
102
- return await this.handlerTx().withServiceCalls(() => [fragment.services.settingsService.get(namespace, "schema_version")]).transform(({ serviceResult: [result] }) => result).execute();
103
- });
104
- return setting ? parseInt(setting.value, 10) : 0;
254
+ const readSchemaVersion = async (targetNamespace) => {
255
+ const setting = await fragment.inContext(async function() {
256
+ return await this.handlerTx().withServiceCalls(() => [fragment.services.settingsService.get(targetNamespace, "schema_version")]).transform(({ serviceResult: [result] }) => result).execute();
257
+ });
258
+ if (!setting) return;
259
+ const parsed = parseInt(setting.value, 10);
260
+ return Number.isNaN(parsed) ? void 0 : parsed;
261
+ };
262
+ const primary = await readSchemaVersion(namespace);
263
+ if (primary !== void 0) return primary;
264
+ const legacyNamespace = namespace === "" ? internalSchema.name : namespace === internalSchema.name ? "" : null;
265
+ if (legacyNamespace !== null) {
266
+ const legacy = await readSchemaVersion(legacyNamespace);
267
+ if (legacy !== void 0) return legacy;
268
+ }
269
+ return 0;
105
270
  } catch {
106
271
  return 0;
107
272
  }
108
273
  }
109
274
 
110
275
  //#endregion
111
- export { SETTINGS_NAMESPACE, SETTINGS_TABLE_NAME, getSchemaVersionFromDatabase, internalFragmentDef, internalSchema };
276
+ export { SchemaRegistryCollisionError, getSchemaVersionFromDatabase, internalFragmentDef };
112
277
  //# sourceMappingURL=internal-fragment.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"internal-fragment.js","names":[],"sources":["../../src/fragments/internal-fragment.ts"],"sourcesContent":["import { FragmentDefinitionBuilder } from \"@fragno-dev/core\";\nimport type { InstantiatedFragmentFromDefinition } from \"@fragno-dev/core\";\nimport {\n DatabaseFragmentDefinitionBuilder,\n type DatabaseHandlerContext,\n type DatabaseRequestStorage,\n type DatabaseServiceContext,\n type FragnoPublicConfigWithDatabase,\n type ImplicitDatabaseDependencies,\n} from \"../db-fragment-definition-builder\";\nimport type { FragnoId } from \"../schema/create\";\nimport { schema, idColumn, column } from \"../schema/create\";\nimport type { RetryPolicy } from \"../query/unit-of-work/retry-policy\";\n\n// Constants for Fragno's internal settings table\nexport const SETTINGS_TABLE_NAME = \"fragno_db_settings\" as const;\n// FIXME: In some places we simply use empty string \"\" as namespace, which is not correct.\nexport const SETTINGS_NAMESPACE = \"fragno-db-settings\" as const;\n\nexport const internalSchema = schema((s) => {\n return s\n .addTable(SETTINGS_TABLE_NAME, (t) => {\n return t\n .addColumn(\"id\", idColumn())\n .addColumn(\"key\", column(\"string\"))\n .addColumn(\"value\", column(\"string\"))\n .createIndex(\"unique_key\", [\"key\"], { unique: true });\n })\n .addTable(\"fragno_hooks\", (t) => {\n return t\n .addColumn(\"id\", idColumn())\n .addColumn(\"namespace\", column(\"string\"))\n .addColumn(\"hookName\", column(\"string\"))\n .addColumn(\"payload\", column(\"json\"))\n .addColumn(\"status\", column(\"string\")) // \"pending\" | \"processing\" | \"completed\" | \"failed\"\n .addColumn(\"attempts\", column(\"integer\").defaultTo(0))\n .addColumn(\"maxAttempts\", column(\"integer\").defaultTo(5))\n .addColumn(\"lastAttemptAt\", column(\"timestamp\").nullable())\n .addColumn(\"nextRetryAt\", column(\"timestamp\").nullable())\n .addColumn(\"error\", column(\"string\").nullable())\n .addColumn(\n \"createdAt\",\n column(\"timestamp\").defaultTo((b) => b.now()),\n )\n .addColumn(\"nonce\", column(\"string\"))\n .createIndex(\"idx_namespace_status_retry\", [\"namespace\", \"status\", \"nextRetryAt\"])\n .createIndex(\"idx_nonce\", [\"nonce\"]);\n });\n});\n\n// This uses DatabaseFragmentDefinitionBuilder directly\n// to avoid circular dependency (it doesn't need to link to itself)\nexport const internalFragmentDef = new DatabaseFragmentDefinitionBuilder(\n new FragmentDefinitionBuilder<\n {},\n FragnoPublicConfigWithDatabase,\n ImplicitDatabaseDependencies<typeof internalSchema>,\n {},\n {},\n {},\n {},\n DatabaseServiceContext<{}>,\n DatabaseHandlerContext,\n DatabaseRequestStorage\n >(\"$fragno-internal-fragment\"),\n internalSchema,\n \"\", // intentionally blank namespace so there is no prefix\n)\n .providesService(\"settingsService\", ({ defineService }) => {\n return defineService({\n /**\n * Get a setting by namespace and key.\n */\n get(namespace: string, key: string) {\n const fullKey = `${namespace}.${key}`;\n return this.serviceTx(internalSchema)\n .retrieve((uow) =>\n uow.findFirst(SETTINGS_TABLE_NAME, (b) =>\n b.whereIndex(\"unique_key\", (eb) => eb(\"key\", \"=\", fullKey)),\n ),\n )\n .transformRetrieve(\n ([result]): { id: FragnoId; key: string; value: string } | undefined =>\n result ?? undefined,\n )\n .build();\n },\n\n /**\n * Set a setting value by namespace and key.\n */\n set(namespace: string, key: string, value: string) {\n const fullKey = `${namespace}.${key}`;\n return this.serviceTx(internalSchema)\n .retrieve((uow) =>\n uow.findFirst(SETTINGS_TABLE_NAME, (b) =>\n b.whereIndex(\"unique_key\", (eb) => eb(\"key\", \"=\", fullKey)),\n ),\n )\n .transformRetrieve(([result]) => result)\n .mutate(({ uow, retrieveResult }) => {\n if (retrieveResult) {\n uow.update(SETTINGS_TABLE_NAME, retrieveResult.id, (b) => b.set({ value }).check());\n } else {\n uow.create(SETTINGS_TABLE_NAME, {\n key: fullKey,\n value,\n });\n }\n })\n .build();\n },\n\n /**\n * Delete a setting by ID.\n */\n delete(id: FragnoId) {\n return this.serviceTx(internalSchema)\n .mutate(({ uow }) => uow.delete(SETTINGS_TABLE_NAME, id))\n .build();\n },\n });\n })\n .providesService(\"hookService\", ({ defineService }) => {\n return defineService({\n /**\n * Get pending hook events for processing.\n * Returns all pending events for the given namespace that are ready to be processed.\n */\n getPendingHookEvents(namespace: string) {\n return this.serviceTx(internalSchema)\n .retrieve((uow) =>\n uow.find(\"fragno_hooks\", (b) =>\n b.whereIndex(\"idx_namespace_status_retry\", (eb) =>\n eb.and(eb(\"namespace\", \"=\", namespace), eb(\"status\", \"=\", \"pending\")),\n ),\n ),\n )\n .transformRetrieve(([events]) => {\n const now = new Date();\n // FIXME(Wilco): this should be handled by the database query, but there seems to be an issue.\n const ready = events.filter((event) => {\n if (!event.nextRetryAt) {\n return true; // Newly created events (nextRetryAt = null) are ready\n }\n return event.nextRetryAt <= now; // Only include if retry time has passed\n });\n\n return ready.map((event) => ({\n id: event.id,\n hookName: event.hookName,\n payload: event.payload as unknown,\n attempts: event.attempts,\n maxAttempts: event.maxAttempts,\n idempotencyKey: event.nonce,\n }));\n })\n .build();\n },\n\n /**\n * Mark a hook event as completed.\n */\n markHookCompleted(eventId: FragnoId) {\n return this.serviceTx(internalSchema)\n .mutate(({ uow }) =>\n uow.update(\"fragno_hooks\", eventId, (b) =>\n b.set({ status: \"completed\", lastAttemptAt: new Date() }).check(),\n ),\n )\n .build();\n },\n\n /**\n * Mark a hook event as failed and schedule next retry.\n */\n markHookFailed(eventId: FragnoId, error: string, attempts: number, retryPolicy: RetryPolicy) {\n const newAttempts = attempts + 1;\n const shouldRetry = retryPolicy.shouldRetry(newAttempts - 1);\n\n return this.serviceTx(internalSchema)\n .mutate(({ uow }) => {\n if (shouldRetry) {\n const delayMs = retryPolicy.getDelayMs(newAttempts - 1);\n const nextRetryAt = new Date(Date.now() + delayMs);\n uow.update(\"fragno_hooks\", eventId, (b) =>\n b\n .set({\n status: \"pending\",\n attempts: newAttempts,\n lastAttemptAt: new Date(),\n nextRetryAt,\n error,\n })\n .check(),\n );\n } else {\n uow.update(\"fragno_hooks\", eventId, (b) =>\n b\n .set({\n status: \"failed\",\n attempts: newAttempts,\n lastAttemptAt: new Date(),\n error,\n })\n .check(),\n );\n }\n })\n .build();\n },\n\n /**\n * Mark a hook event as processing (to prevent concurrent execution).\n */\n markHookProcessing(eventId: FragnoId) {\n return this.serviceTx(internalSchema)\n .mutate(({ uow }) =>\n uow.update(\"fragno_hooks\", eventId, (b) =>\n b.set({ status: \"processing\", lastAttemptAt: new Date() }).check(),\n ),\n )\n .build();\n },\n\n /**\n * Get a hook event by ID (for testing/verification purposes).\n */\n getHookById(eventId: FragnoId) {\n return this.serviceTx(internalSchema)\n .retrieve((uow) =>\n uow.findFirst(\"fragno_hooks\", (b) =>\n b.whereIndex(\"primary\", (eb) => eb(\"id\", \"=\", eventId)),\n ),\n )\n .transformRetrieve(([result]) => result ?? undefined)\n .build();\n },\n\n /**\n * Get all hook events for a namespace (for testing/verification purposes).\n */\n getHooksByNamespace(namespace: string) {\n return this.serviceTx(internalSchema)\n .retrieve((uow) =>\n uow.find(\"fragno_hooks\", (b) =>\n b.whereIndex(\"idx_namespace_status_retry\", (eb) => eb(\"namespace\", \"=\", namespace)),\n ),\n )\n .transformRetrieve(([events]) => events)\n .build();\n },\n });\n })\n .build();\n\n/**\n * Type representing an instantiated internal fragment.\n * This is the fragment that manages Fragno's internal settings table.\n */\nexport type InternalFragmentInstance = InstantiatedFragmentFromDefinition<\n typeof internalFragmentDef\n>;\n\nexport async function getSchemaVersionFromDatabase(\n fragment: InternalFragmentInstance,\n namespace: string,\n): Promise<number> {\n try {\n const setting = await fragment.inContext(async function () {\n return await this.handlerTx()\n .withServiceCalls(\n () => [fragment.services.settingsService.get(namespace, \"schema_version\")] as const,\n )\n .transform(({ serviceResult: [result] }) => result)\n .execute();\n });\n return setting ? parseInt(setting.value, 10) : 0;\n } catch {\n return 0;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"internal-fragment.js","names":["processingNextAt: Date | null"],"sources":["../../src/fragments/internal-fragment.ts"],"sourcesContent":["import { FragmentDefinitionBuilder } from \"@fragno-dev/core\";\nimport type { InstantiatedFragmentFromDefinition } from \"@fragno-dev/core\";\n\nimport {\n DatabaseFragmentDefinitionBuilder,\n type DatabaseHandlerContext,\n type DatabaseRequestStorage,\n type DatabaseServiceContext,\n type FragnoPublicConfigWithDatabase,\n type ImplicitDatabaseDependencies,\n} from \"../db-fragment-definition-builder\";\nimport { isHookStatus, type HookStatus } from \"../hooks/hooks\";\nimport type { Cursor } from \"../query/cursor\";\nimport { dbNow, type DbNow } from \"../query/db-now\";\nimport type { RetryPolicy } from \"../query/unit-of-work/retry-policy\";\nimport { FragnoId } from \"../schema/create\";\nimport {\n internalSchema,\n SETTINGS_NAMESPACE,\n SETTINGS_TABLE_NAME,\n} from \"./internal-fragment.schema\";\n\ntype AdapterRegistry = {\n listSchemas: () => Array<{\n name: string;\n namespace: string | null;\n version: number;\n tables: string[];\n }>;\n listOutboxFragments: () => Array<{ name: string; mountRoute: string }>;\n isOutboxEnabled: () => boolean;\n resolveSyncCommand: (\n fragmentName: string,\n schemaName: string,\n commandName: string,\n ) => { command: unknown; namespace: string | null } | undefined;\n};\n\nexport class SchemaRegistryCollisionError extends Error {\n readonly code = \"SCHEMA_REGISTRY_COLLISION\" as const;\n readonly namespaceKey: string;\n readonly existing: { name: string; namespace: string | null };\n readonly attempted: { name: string; namespace: string | null };\n\n constructor({\n namespaceKey,\n existing,\n attempted,\n }: {\n namespaceKey: string;\n existing: { name: string; namespace: string | null };\n attempted: { name: string; namespace: string | null };\n }) {\n super(\n `Schema namespace \"${namespaceKey}\" is already owned by \"${existing.name}\" (${existing.namespace ?? \"null\"}).`,\n );\n this.name = \"SchemaRegistryCollisionError\";\n this.namespaceKey = namespaceKey;\n this.existing = existing;\n this.attempted = attempted;\n }\n}\n\nexport type InternalFragmentConfig = {\n registry?: AdapterRegistry;\n};\n\nexport { internalSchema, SETTINGS_NAMESPACE, SETTINGS_TABLE_NAME };\n\nconst INTERNAL_SCHEMA_MIN_VERSION = 4;\nif (internalSchema.version < INTERNAL_SCHEMA_MIN_VERSION) {\n // Keep the internal schema version monotonic after removing fragno_db_schemas.\n internalSchema.version = INTERNAL_SCHEMA_MIN_VERSION;\n}\n\nconst describeHookStatusSource = (event: { id: FragnoId; hookName: string }) =>\n `fragno_hooks id=${event.id} hook=${event.hookName}`;\n\nconst coerceHookStatus = (status: string, context: string): HookStatus => {\n if (isHookStatus(status)) {\n return status;\n }\n throw new Error(`Invalid hook status from database (${context}): ${status}`);\n};\n\nconst DEFAULT_HOOKS_PAGE_SIZE = 50;\n\nconst resolveHookPageSize = (pageSize?: number): number => {\n if (typeof pageSize !== \"number\" || !Number.isInteger(pageSize) || pageSize <= 0) {\n return DEFAULT_HOOKS_PAGE_SIZE;\n }\n return pageSize;\n};\n\n// This uses DatabaseFragmentDefinitionBuilder directly\n// to avoid circular dependency (it doesn't need to link to itself)\nexport const internalFragmentDef = new DatabaseFragmentDefinitionBuilder(\n new FragmentDefinitionBuilder<\n InternalFragmentConfig,\n FragnoPublicConfigWithDatabase,\n ImplicitDatabaseDependencies<typeof internalSchema>,\n {},\n {},\n {},\n {},\n DatabaseServiceContext<{}>,\n DatabaseHandlerContext,\n DatabaseRequestStorage\n >(\"$fragno-internal-fragment\"),\n internalSchema,\n)\n .providesService(\"settingsService\", ({ defineService }) => {\n return defineService({\n /**\n * Get a setting by namespace and key.\n */\n get(namespace: string, key: string) {\n const fullKey = `${namespace}.${key}`;\n return this.serviceTx(internalSchema)\n .retrieve((uow) =>\n uow.findFirst(SETTINGS_TABLE_NAME, (b) =>\n b.whereIndex(\"unique_key\", (eb) => eb(\"key\", \"=\", fullKey)),\n ),\n )\n .transformRetrieve(\n ([result]): { id: FragnoId; key: string; value: string } | undefined =>\n result ?? undefined,\n )\n .build();\n },\n\n /**\n * Set a setting value by namespace and key.\n */\n set(namespace: string, key: string, value: string) {\n const fullKey = `${namespace}.${key}`;\n return this.serviceTx(internalSchema)\n .retrieve((uow) =>\n uow.findFirst(SETTINGS_TABLE_NAME, (b) =>\n b.whereIndex(\"unique_key\", (eb) => eb(\"key\", \"=\", fullKey)),\n ),\n )\n .transformRetrieve(([result]) => result)\n .mutate(({ uow, retrieveResult }) => {\n if (retrieveResult) {\n uow.update(SETTINGS_TABLE_NAME, retrieveResult.id, (b) => b.set({ value }).check());\n } else {\n uow.create(SETTINGS_TABLE_NAME, {\n key: fullKey,\n value,\n });\n }\n })\n .build();\n },\n\n /**\n * Set a setting value only if it does not already exist.\n */\n setIfMissing(namespace: string, key: string, value: string) {\n const fullKey = `${namespace}.${key}`;\n return this.serviceTx(internalSchema)\n .retrieve((uow) =>\n uow.findFirst(SETTINGS_TABLE_NAME, (b) =>\n b.whereIndex(\"unique_key\", (eb) => eb(\"key\", \"=\", fullKey)),\n ),\n )\n .transformRetrieve(([result]) => result)\n .mutate(({ uow, retrieveResult }) => {\n if (retrieveResult) {\n return;\n }\n uow.create(SETTINGS_TABLE_NAME, {\n key: fullKey,\n value,\n });\n })\n .build();\n },\n\n /**\n * Delete a setting by ID.\n */\n delete(id: FragnoId) {\n return this.serviceTx(internalSchema)\n .mutate(({ uow }) => uow.delete(SETTINGS_TABLE_NAME, id))\n .build();\n },\n });\n })\n .providesService(\"hookService\", ({ defineService }) => {\n return defineService({\n /**\n * Get pending hook events for processing.\n * Returns all pending events for the given namespace that are ready to be processed.\n */\n getPendingHookEvents(namespace: string) {\n const now = dbNow();\n return this.serviceTx(internalSchema)\n .retrieve((uow) =>\n uow.find(\"fragno_hooks\", (b) =>\n b.whereIndex(\"idx_namespace_status_retry\", (eb) =>\n eb.and(\n eb(\"namespace\", \"=\", namespace),\n eb(\"status\", \"=\", \"pending\"),\n eb.or(eb.isNull(\"nextRetryAt\"), eb(\"nextRetryAt\", \"<=\", now)),\n ),\n ),\n ),\n )\n .transformRetrieve(([events]) => {\n return events.map((event) => ({\n id: event.id,\n hookName: event.hookName,\n payload: event.payload as unknown,\n status: coerceHookStatus(event.status, describeHookStatusSource(event)),\n attempts: event.attempts,\n maxAttempts: event.maxAttempts,\n lastAttemptAt: event.lastAttemptAt,\n nextRetryAt: event.nextRetryAt,\n createdAt: event.createdAt,\n idempotencyKey: event.nonce,\n }));\n })\n .build();\n },\n\n /**\n * Claim pending hook events for processing.\n * Returns ready events and marks them as processing in the same transaction.\n */\n claimPendingHookEvents(namespace: string) {\n const now = dbNow();\n return this.serviceTx(internalSchema)\n .retrieve((uow) =>\n uow.find(\"fragno_hooks\", (b) =>\n b.whereIndex(\"idx_namespace_status_retry\", (eb) =>\n eb.and(\n eb(\"namespace\", \"=\", namespace),\n eb(\"status\", \"=\", \"pending\"),\n eb.or(eb.isNull(\"nextRetryAt\"), eb(\"nextRetryAt\", \"<=\", now)),\n ),\n ),\n ),\n )\n .transformRetrieve(([events]) => {\n return events.map((event) => ({\n id: event.id,\n hookName: event.hookName,\n payload: event.payload,\n status: coerceHookStatus(event.status, describeHookStatusSource(event)),\n attempts: event.attempts,\n maxAttempts: event.maxAttempts,\n lastAttemptAt: event.lastAttemptAt,\n nextRetryAt: event.nextRetryAt,\n createdAt: event.createdAt,\n idempotencyKey: event.nonce,\n }));\n })\n .mutate(({ uow, retrieveResult }) => {\n if (retrieveResult.length === 0) {\n return;\n }\n for (const event of retrieveResult) {\n uow.update(\"fragno_hooks\", event.id, (b) =>\n b.set({ status: \"processing\", lastAttemptAt: now }).check(),\n );\n }\n })\n .transform(({ retrieveResult }) =>\n retrieveResult.map((event) => ({\n ...event,\n status: \"processing\" as const,\n id: new FragnoId({\n externalId: event.id.externalId,\n internalId: event.id.internalId,\n version: event.id.version + 1,\n }),\n })),\n )\n .build();\n },\n\n /**\n * Claim stale processing hook events for processing.\n * Returns ready events and marks them as processing in the same transaction.\n */\n claimStuckProcessingHookEvents(namespace: string, staleBefore: DbNow) {\n const now = dbNow();\n\n return this.serviceTx(internalSchema)\n .retrieve((uow) =>\n uow.find(\"fragno_hooks\", (b) =>\n b.whereIndex(\"idx_namespace_status_last_attempt\", (eb) =>\n eb.and(\n eb(\"namespace\", \"=\", namespace),\n eb(\"status\", \"=\", \"processing\"),\n eb.or(eb.isNull(\"lastAttemptAt\"), eb(\"lastAttemptAt\", \"<=\", staleBefore)),\n ),\n ),\n ),\n )\n .transformRetrieve(([events]) => {\n return events.map((event) => ({\n id: event.id,\n hookName: event.hookName,\n payload: event.payload as unknown,\n status: coerceHookStatus(event.status, describeHookStatusSource(event)),\n attempts: event.attempts,\n maxAttempts: event.maxAttempts,\n idempotencyKey: event.nonce,\n lastAttemptAt: event.lastAttemptAt,\n nextRetryAt: event.nextRetryAt,\n createdAt: event.createdAt,\n }));\n })\n .mutate(({ uow, retrieveResult }) => {\n if (retrieveResult.length === 0) {\n return;\n }\n\n for (const event of retrieveResult) {\n uow.update(\"fragno_hooks\", event.id, (b) =>\n b.set({ status: \"processing\", lastAttemptAt: now, nextRetryAt: null }).check(),\n );\n }\n })\n .transform(({ retrieveResult }) => {\n return {\n events: retrieveResult.map((event) => ({\n ...event,\n id: new FragnoId({\n externalId: event.id.externalId,\n internalId: event.id.internalId,\n version: event.id.version + 1,\n }),\n })),\n stuckEvents: retrieveResult.map((event) => ({\n id: event.id,\n hookName: event.hookName,\n attempts: event.attempts,\n maxAttempts: event.maxAttempts,\n lastAttemptAt: event.lastAttemptAt,\n nextRetryAt: event.nextRetryAt,\n })),\n };\n })\n .build();\n },\n\n /**\n * Get the earliest pending hook wake time for a namespace.\n * Optionally considers processing hooks becoming stale when timeoutMinutes is provided.\n */\n getNextHookWakeAt(namespace: string, timeoutMinutes?: number | false) {\n const timeoutMinutesValue =\n typeof timeoutMinutes === \"number\" && timeoutMinutes > 0 ? timeoutMinutes : 0;\n const includeProcessing = timeoutMinutesValue > 0;\n const now = dbNow();\n const timeoutMs = timeoutMinutesValue * 60_000;\n // Sentinel to keep query shape stable when processing checks are disabled.\n const processingStatus = includeProcessing ? \"processing\" : \"__disabled__\";\n const staleBefore = now.plus({ minutes: -timeoutMinutesValue });\n\n return this.serviceTx(internalSchema)\n .retrieve((uow) =>\n uow\n .forSchema(internalSchema)\n .find(\"fragno_hooks\", (b) =>\n b\n .whereIndex(\"idx_namespace_status_retry\", (eb) =>\n eb.and(\n eb(\"namespace\", \"=\", namespace),\n eb(\"status\", \"=\", \"pending\"),\n eb.or(eb.isNull(\"nextRetryAt\"), eb(\"nextRetryAt\", \"<=\", now)),\n ),\n )\n .pageSize(1),\n )\n .find(\"fragno_hooks\", (b) =>\n b\n .whereIndex(\"idx_namespace_status_retry\", (eb) =>\n eb.and(\n eb(\"namespace\", \"=\", namespace),\n eb(\"status\", \"=\", \"pending\"),\n eb.isNotNull(\"nextRetryAt\"),\n eb(\"nextRetryAt\", \">\", now),\n ),\n )\n .orderByIndex(\"idx_namespace_status_retry\", \"asc\")\n .pageSize(1)\n .select([\"nextRetryAt\"]),\n )\n .find(\"fragno_hooks\", (b) =>\n b\n .whereIndex(\"idx_namespace_status_last_attempt\", (eb) =>\n eb.and(\n eb(\"namespace\", \"=\", namespace),\n eb(\"status\", \"=\", processingStatus),\n eb.or(eb.isNull(\"lastAttemptAt\"), eb(\"lastAttemptAt\", \"<=\", staleBefore)),\n ),\n )\n .pageSize(1),\n )\n .find(\"fragno_hooks\", (b) =>\n b\n .whereIndex(\"idx_namespace_status_last_attempt\", (eb) =>\n eb.and(\n eb(\"namespace\", \"=\", namespace),\n eb(\"status\", \"=\", processingStatus),\n eb.isNotNull(\"lastAttemptAt\"),\n eb(\"lastAttemptAt\", \">\", staleBefore),\n ),\n )\n .orderByIndex(\"idx_namespace_status_last_attempt\", \"asc\")\n .pageSize(1)\n .select([\"lastAttemptAt\"]),\n ),\n )\n .transformRetrieve(\n ([pendingImmediate, pendingNext, processingImmediate, processingNext]) => {\n const hasProcessingImmediate = includeProcessing && processingImmediate.length > 0;\n\n if (pendingImmediate.length > 0 || hasProcessingImmediate) {\n return new Date();\n }\n\n const pendingNextAt = pendingNext[0]?.nextRetryAt ?? null;\n let processingNextAt: Date | null = null;\n\n if (includeProcessing) {\n const lastAttemptAt = processingNext[0]?.lastAttemptAt;\n if (lastAttemptAt) {\n processingNextAt = new Date(lastAttemptAt.getTime() + timeoutMs);\n }\n }\n\n if (!pendingNextAt) {\n return processingNextAt ?? null;\n }\n if (!processingNextAt) {\n return pendingNextAt;\n }\n return pendingNextAt <= processingNextAt ? pendingNextAt : processingNextAt;\n },\n )\n .build();\n },\n\n /**\n * Mark a hook event as failed and schedule next retry.\n */\n markHookFailed(eventId: FragnoId, error: string, attempts: number, retryPolicy: RetryPolicy) {\n const newAttempts = attempts + 1;\n const shouldRetry = retryPolicy.shouldRetry(newAttempts - 1);\n const now = dbNow();\n\n return this.serviceTx(internalSchema)\n .mutate(({ uow }) => {\n if (shouldRetry) {\n const delayMs = retryPolicy.getDelayMs(newAttempts - 1);\n const nextRetryAt = now.plus({ ms: delayMs });\n uow.update(\"fragno_hooks\", eventId, (b) =>\n b\n .set({\n status: \"pending\",\n attempts: newAttempts,\n lastAttemptAt: now,\n nextRetryAt,\n error,\n })\n .check(),\n );\n } else {\n uow.update(\"fragno_hooks\", eventId, (b) =>\n b\n .set({\n status: \"failed\",\n attempts: newAttempts,\n lastAttemptAt: now,\n error,\n })\n .check(),\n );\n }\n })\n .build();\n },\n\n /**\n * Mark a hook event as processing (to prevent concurrent execution).\n */\n markHookProcessing(eventId: FragnoId) {\n return this.serviceTx(internalSchema)\n .mutate(({ uow }) =>\n uow.update(\"fragno_hooks\", eventId, (b) =>\n b.set({ status: \"processing\", lastAttemptAt: dbNow() }).check(),\n ),\n )\n .build();\n },\n\n /**\n * Get a hook event by ID (for testing/verification purposes).\n */\n getHookById(eventId: FragnoId) {\n return this.serviceTx(internalSchema)\n .retrieve((uow) =>\n uow.findFirst(\"fragno_hooks\", (b) =>\n b.whereIndex(\"primary\", (eb) => eb(\"id\", \"=\", eventId)),\n ),\n )\n .transformRetrieve(([result]) =>\n result\n ? {\n ...result,\n status: coerceHookStatus(result.status, describeHookStatusSource(result)),\n }\n : undefined,\n )\n .build();\n },\n\n /**\n * Get hook events for a namespace in newest-first order with pagination.\n */\n getHooksByNamespacePage(\n namespace: string,\n options: { cursor?: Cursor | string; pageSize?: number } = {},\n ) {\n const pageSize = resolveHookPageSize(options.pageSize);\n\n return this.serviceTx(internalSchema)\n .retrieve((uow) =>\n uow.findWithCursor(\"fragno_hooks\", (b) => {\n const query = b\n .whereIndex(\"idx_namespace_created_at\", (eb) => eb(\"namespace\", \"=\", namespace))\n .orderByIndex(\"idx_namespace_created_at\", \"desc\")\n .pageSize(pageSize);\n\n return options.cursor ? query.after(options.cursor) : query;\n }),\n )\n .transformRetrieve(([page]) => ({\n items: page.items.map((event) => ({\n ...event,\n status: coerceHookStatus(event.status, describeHookStatusSource(event)),\n })),\n cursor: page.cursor,\n hasNextPage: page.hasNextPage,\n }))\n .build();\n },\n\n /**\n * Get all hook events for a namespace (for testing/verification purposes).\n */\n getHooksByNamespace(namespace: string) {\n return this.serviceTx(internalSchema)\n .retrieve((uow) =>\n uow.find(\"fragno_hooks\", (b) =>\n b.whereIndex(\"idx_namespace_status_retry\", (eb) => eb(\"namespace\", \"=\", namespace)),\n ),\n )\n .transformRetrieve(([events]) =>\n events.map((event) => ({\n ...event,\n status: coerceHookStatus(event.status, describeHookStatusSource(event)),\n })),\n )\n .build();\n },\n });\n })\n .providesService(\"outboxService\", ({ defineService }) => {\n return defineService({\n /**\n * List outbox entries ordered by versionstamp (ascending).\n */\n list({ afterVersionstamp, limit }: { afterVersionstamp?: string; limit?: number } = {}) {\n const afterValue = afterVersionstamp?.toLowerCase();\n\n return this.serviceTx(internalSchema)\n .retrieve((uow) =>\n uow.find(\"fragno_db_outbox\", (b) => {\n let builder = afterValue\n ? b.whereIndex(\"idx_outbox_versionstamp\", (eb) =>\n eb(\"versionstamp\", \">\", afterValue),\n )\n : b.whereIndex(\"idx_outbox_versionstamp\");\n\n builder = builder.orderByIndex(\"idx_outbox_versionstamp\", \"asc\");\n if (limit !== undefined) {\n builder = builder.pageSize(limit);\n }\n return builder;\n }),\n )\n .transformRetrieve(([entries]) =>\n entries.map((entry) => ({\n id: entry.id,\n versionstamp: entry.versionstamp,\n uowId: entry.uowId,\n payload: entry.payload,\n refMap: entry.refMap ?? undefined,\n createdAt: entry.createdAt,\n })),\n )\n .build();\n },\n });\n })\n .build();\n\n/**\n * Type representing an instantiated internal fragment.\n * This is the fragment that manages Fragno's internal settings table.\n */\nexport type InternalFragmentInstance = InstantiatedFragmentFromDefinition<\n typeof internalFragmentDef\n>;\n\nexport async function getSchemaVersionFromDatabase(\n fragment: InternalFragmentInstance,\n namespace: string,\n): Promise<number> {\n try {\n const readSchemaVersion = async (targetNamespace: string): Promise<number | undefined> => {\n const setting = await fragment.inContext(async function () {\n return await this.handlerTx()\n .withServiceCalls(\n () =>\n [fragment.services.settingsService.get(targetNamespace, \"schema_version\")] as const,\n )\n .transform(({ serviceResult: [result] }) => result)\n .execute();\n });\n if (!setting) {\n return undefined;\n }\n const parsed = parseInt(setting.value, 10);\n return Number.isNaN(parsed) ? undefined : parsed;\n };\n\n const primary = await readSchemaVersion(namespace);\n if (primary !== undefined) {\n return primary;\n }\n\n // Back-compat: some installs stored internal schema version under a different namespace.\n // Check the alternate key (empty string ↔ schema name) so we find the version either way.\n const legacyNamespace =\n namespace === \"\" ? internalSchema.name : namespace === internalSchema.name ? \"\" : null;\n if (legacyNamespace !== null) {\n const legacy = await readSchemaVersion(legacyNamespace);\n if (legacy !== undefined) {\n return legacy;\n }\n }\n\n return 0;\n } catch {\n return 0;\n }\n}\n"],"mappings":";;;;;;;;AAsCA,IAAa,+BAAb,cAAkD,MAAM;CACtD,AAAS,OAAO;CAChB,AAAS;CACT,AAAS;CACT,AAAS;CAET,YAAY,EACV,cACA,UACA,aAKC;AACD,QACE,qBAAqB,aAAa,yBAAyB,SAAS,KAAK,KAAK,SAAS,aAAa,OAAO,IAC5G;AACD,OAAK,OAAO;AACZ,OAAK,eAAe;AACpB,OAAK,WAAW;AAChB,OAAK,YAAY;;;AAUrB,MAAM,8BAA8B;AACpC,IAAI,eAAe,UAAU,4BAE3B,gBAAe,UAAU;AAG3B,MAAM,4BAA4B,UAChC,mBAAmB,MAAM,GAAG,QAAQ,MAAM;AAE5C,MAAM,oBAAoB,QAAgB,YAAgC;AACxE,KAAI,aAAa,OAAO,CACtB,QAAO;AAET,OAAM,IAAI,MAAM,sCAAsC,QAAQ,KAAK,SAAS;;AAG9E,MAAM,0BAA0B;AAEhC,MAAM,uBAAuB,aAA8B;AACzD,KAAI,OAAO,aAAa,YAAY,CAAC,OAAO,UAAU,SAAS,IAAI,YAAY,EAC7E,QAAO;AAET,QAAO;;AAKT,MAAa,sBAAsB,IAAI,kCACrC,IAAI,0BAWF,4BAA4B,EAC9B,eACD,CACE,gBAAgB,oBAAoB,EAAE,oBAAoB;AACzD,QAAO,cAAc;EAInB,IAAI,WAAmB,KAAa;GAClC,MAAM,UAAU,GAAG,UAAU,GAAG;AAChC,UAAO,KAAK,UAAU,eAAe,CAClC,UAAU,QACT,IAAI,UAAU,sBAAsB,MAClC,EAAE,WAAW,eAAe,OAAO,GAAG,OAAO,KAAK,QAAQ,CAAC,CAC5D,CACF,CACA,mBACE,CAAC,YACA,UAAU,OACb,CACA,OAAO;;EAMZ,IAAI,WAAmB,KAAa,OAAe;GACjD,MAAM,UAAU,GAAG,UAAU,GAAG;AAChC,UAAO,KAAK,UAAU,eAAe,CAClC,UAAU,QACT,IAAI,UAAU,sBAAsB,MAClC,EAAE,WAAW,eAAe,OAAO,GAAG,OAAO,KAAK,QAAQ,CAAC,CAC5D,CACF,CACA,mBAAmB,CAAC,YAAY,OAAO,CACvC,QAAQ,EAAE,KAAK,qBAAqB;AACnC,QAAI,eACF,KAAI,OAAO,qBAAqB,eAAe,KAAK,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,OAAO,CAAC;QAEnF,KAAI,OAAO,qBAAqB;KAC9B,KAAK;KACL;KACD,CAAC;KAEJ,CACD,OAAO;;EAMZ,aAAa,WAAmB,KAAa,OAAe;GAC1D,MAAM,UAAU,GAAG,UAAU,GAAG;AAChC,UAAO,KAAK,UAAU,eAAe,CAClC,UAAU,QACT,IAAI,UAAU,sBAAsB,MAClC,EAAE,WAAW,eAAe,OAAO,GAAG,OAAO,KAAK,QAAQ,CAAC,CAC5D,CACF,CACA,mBAAmB,CAAC,YAAY,OAAO,CACvC,QAAQ,EAAE,KAAK,qBAAqB;AACnC,QAAI,eACF;AAEF,QAAI,OAAO,qBAAqB;KAC9B,KAAK;KACL;KACD,CAAC;KACF,CACD,OAAO;;EAMZ,OAAO,IAAc;AACnB,UAAO,KAAK,UAAU,eAAe,CAClC,QAAQ,EAAE,UAAU,IAAI,OAAO,qBAAqB,GAAG,CAAC,CACxD,OAAO;;EAEb,CAAC;EACF,CACD,gBAAgB,gBAAgB,EAAE,oBAAoB;AACrD,QAAO,cAAc;EAKnB,qBAAqB,WAAmB;GACtC,MAAM,MAAM,OAAO;AACnB,UAAO,KAAK,UAAU,eAAe,CAClC,UAAU,QACT,IAAI,KAAK,iBAAiB,MACxB,EAAE,WAAW,+BAA+B,OAC1C,GAAG,IACD,GAAG,aAAa,KAAK,UAAU,EAC/B,GAAG,UAAU,KAAK,UAAU,EAC5B,GAAG,GAAG,GAAG,OAAO,cAAc,EAAE,GAAG,eAAe,MAAM,IAAI,CAAC,CAC9D,CACF,CACF,CACF,CACA,mBAAmB,CAAC,YAAY;AAC/B,WAAO,OAAO,KAAK,WAAW;KAC5B,IAAI,MAAM;KACV,UAAU,MAAM;KAChB,SAAS,MAAM;KACf,QAAQ,iBAAiB,MAAM,QAAQ,yBAAyB,MAAM,CAAC;KACvE,UAAU,MAAM;KAChB,aAAa,MAAM;KACnB,eAAe,MAAM;KACrB,aAAa,MAAM;KACnB,WAAW,MAAM;KACjB,gBAAgB,MAAM;KACvB,EAAE;KACH,CACD,OAAO;;EAOZ,uBAAuB,WAAmB;GACxC,MAAM,MAAM,OAAO;AACnB,UAAO,KAAK,UAAU,eAAe,CAClC,UAAU,QACT,IAAI,KAAK,iBAAiB,MACxB,EAAE,WAAW,+BAA+B,OAC1C,GAAG,IACD,GAAG,aAAa,KAAK,UAAU,EAC/B,GAAG,UAAU,KAAK,UAAU,EAC5B,GAAG,GAAG,GAAG,OAAO,cAAc,EAAE,GAAG,eAAe,MAAM,IAAI,CAAC,CAC9D,CACF,CACF,CACF,CACA,mBAAmB,CAAC,YAAY;AAC/B,WAAO,OAAO,KAAK,WAAW;KAC5B,IAAI,MAAM;KACV,UAAU,MAAM;KAChB,SAAS,MAAM;KACf,QAAQ,iBAAiB,MAAM,QAAQ,yBAAyB,MAAM,CAAC;KACvE,UAAU,MAAM;KAChB,aAAa,MAAM;KACnB,eAAe,MAAM;KACrB,aAAa,MAAM;KACnB,WAAW,MAAM;KACjB,gBAAgB,MAAM;KACvB,EAAE;KACH,CACD,QAAQ,EAAE,KAAK,qBAAqB;AACnC,QAAI,eAAe,WAAW,EAC5B;AAEF,SAAK,MAAM,SAAS,eAClB,KAAI,OAAO,gBAAgB,MAAM,KAAK,MACpC,EAAE,IAAI;KAAE,QAAQ;KAAc,eAAe;KAAK,CAAC,CAAC,OAAO,CAC5D;KAEH,CACD,WAAW,EAAE,qBACZ,eAAe,KAAK,WAAW;IAC7B,GAAG;IACH,QAAQ;IACR,IAAI,IAAI,SAAS;KACf,YAAY,MAAM,GAAG;KACrB,YAAY,MAAM,GAAG;KACrB,SAAS,MAAM,GAAG,UAAU;KAC7B,CAAC;IACH,EAAE,CACJ,CACA,OAAO;;EAOZ,+BAA+B,WAAmB,aAAoB;GACpE,MAAM,MAAM,OAAO;AAEnB,UAAO,KAAK,UAAU,eAAe,CAClC,UAAU,QACT,IAAI,KAAK,iBAAiB,MACxB,EAAE,WAAW,sCAAsC,OACjD,GAAG,IACD,GAAG,aAAa,KAAK,UAAU,EAC/B,GAAG,UAAU,KAAK,aAAa,EAC/B,GAAG,GAAG,GAAG,OAAO,gBAAgB,EAAE,GAAG,iBAAiB,MAAM,YAAY,CAAC,CAC1E,CACF,CACF,CACF,CACA,mBAAmB,CAAC,YAAY;AAC/B,WAAO,OAAO,KAAK,WAAW;KAC5B,IAAI,MAAM;KACV,UAAU,MAAM;KAChB,SAAS,MAAM;KACf,QAAQ,iBAAiB,MAAM,QAAQ,yBAAyB,MAAM,CAAC;KACvE,UAAU,MAAM;KAChB,aAAa,MAAM;KACnB,gBAAgB,MAAM;KACtB,eAAe,MAAM;KACrB,aAAa,MAAM;KACnB,WAAW,MAAM;KAClB,EAAE;KACH,CACD,QAAQ,EAAE,KAAK,qBAAqB;AACnC,QAAI,eAAe,WAAW,EAC5B;AAGF,SAAK,MAAM,SAAS,eAClB,KAAI,OAAO,gBAAgB,MAAM,KAAK,MACpC,EAAE,IAAI;KAAE,QAAQ;KAAc,eAAe;KAAK,aAAa;KAAM,CAAC,CAAC,OAAO,CAC/E;KAEH,CACD,WAAW,EAAE,qBAAqB;AACjC,WAAO;KACL,QAAQ,eAAe,KAAK,WAAW;MACrC,GAAG;MACH,IAAI,IAAI,SAAS;OACf,YAAY,MAAM,GAAG;OACrB,YAAY,MAAM,GAAG;OACrB,SAAS,MAAM,GAAG,UAAU;OAC7B,CAAC;MACH,EAAE;KACH,aAAa,eAAe,KAAK,WAAW;MAC1C,IAAI,MAAM;MACV,UAAU,MAAM;MAChB,UAAU,MAAM;MAChB,aAAa,MAAM;MACnB,eAAe,MAAM;MACrB,aAAa,MAAM;MACpB,EAAE;KACJ;KACD,CACD,OAAO;;EAOZ,kBAAkB,WAAmB,gBAAiC;GACpE,MAAM,sBACJ,OAAO,mBAAmB,YAAY,iBAAiB,IAAI,iBAAiB;GAC9E,MAAM,oBAAoB,sBAAsB;GAChD,MAAM,MAAM,OAAO;GACnB,MAAM,YAAY,sBAAsB;GAExC,MAAM,mBAAmB,oBAAoB,eAAe;GAC5D,MAAM,cAAc,IAAI,KAAK,EAAE,SAAS,CAAC,qBAAqB,CAAC;AAE/D,UAAO,KAAK,UAAU,eAAe,CAClC,UAAU,QACT,IACG,UAAU,eAAe,CACzB,KAAK,iBAAiB,MACrB,EACG,WAAW,+BAA+B,OACzC,GAAG,IACD,GAAG,aAAa,KAAK,UAAU,EAC/B,GAAG,UAAU,KAAK,UAAU,EAC5B,GAAG,GAAG,GAAG,OAAO,cAAc,EAAE,GAAG,eAAe,MAAM,IAAI,CAAC,CAC9D,CACF,CACA,SAAS,EAAE,CACf,CACA,KAAK,iBAAiB,MACrB,EACG,WAAW,+BAA+B,OACzC,GAAG,IACD,GAAG,aAAa,KAAK,UAAU,EAC/B,GAAG,UAAU,KAAK,UAAU,EAC5B,GAAG,UAAU,cAAc,EAC3B,GAAG,eAAe,KAAK,IAAI,CAC5B,CACF,CACA,aAAa,8BAA8B,MAAM,CACjD,SAAS,EAAE,CACX,OAAO,CAAC,cAAc,CAAC,CAC3B,CACA,KAAK,iBAAiB,MACrB,EACG,WAAW,sCAAsC,OAChD,GAAG,IACD,GAAG,aAAa,KAAK,UAAU,EAC/B,GAAG,UAAU,KAAK,iBAAiB,EACnC,GAAG,GAAG,GAAG,OAAO,gBAAgB,EAAE,GAAG,iBAAiB,MAAM,YAAY,CAAC,CAC1E,CACF,CACA,SAAS,EAAE,CACf,CACA,KAAK,iBAAiB,MACrB,EACG,WAAW,sCAAsC,OAChD,GAAG,IACD,GAAG,aAAa,KAAK,UAAU,EAC/B,GAAG,UAAU,KAAK,iBAAiB,EACnC,GAAG,UAAU,gBAAgB,EAC7B,GAAG,iBAAiB,KAAK,YAAY,CACtC,CACF,CACA,aAAa,qCAAqC,MAAM,CACxD,SAAS,EAAE,CACX,OAAO,CAAC,gBAAgB,CAAC,CAC7B,CACJ,CACA,mBACE,CAAC,kBAAkB,aAAa,qBAAqB,oBAAoB;IACxE,MAAM,yBAAyB,qBAAqB,oBAAoB,SAAS;AAEjF,QAAI,iBAAiB,SAAS,KAAK,uBACjC,wBAAO,IAAI,MAAM;IAGnB,MAAM,gBAAgB,YAAY,IAAI,eAAe;IACrD,IAAIA,mBAAgC;AAEpC,QAAI,mBAAmB;KACrB,MAAM,gBAAgB,eAAe,IAAI;AACzC,SAAI,cACF,oBAAmB,IAAI,KAAK,cAAc,SAAS,GAAG,UAAU;;AAIpE,QAAI,CAAC,cACH,QAAO,oBAAoB;AAE7B,QAAI,CAAC,iBACH,QAAO;AAET,WAAO,iBAAiB,mBAAmB,gBAAgB;KAE9D,CACA,OAAO;;EAMZ,eAAe,SAAmB,OAAe,UAAkB,aAA0B;GAC3F,MAAM,cAAc,WAAW;GAC/B,MAAM,cAAc,YAAY,YAAY,cAAc,EAAE;GAC5D,MAAM,MAAM,OAAO;AAEnB,UAAO,KAAK,UAAU,eAAe,CAClC,QAAQ,EAAE,UAAU;AACnB,QAAI,aAAa;KACf,MAAM,UAAU,YAAY,WAAW,cAAc,EAAE;KACvD,MAAM,cAAc,IAAI,KAAK,EAAE,IAAI,SAAS,CAAC;AAC7C,SAAI,OAAO,gBAAgB,UAAU,MACnC,EACG,IAAI;MACH,QAAQ;MACR,UAAU;MACV,eAAe;MACf;MACA;MACD,CAAC,CACD,OAAO,CACX;UAED,KAAI,OAAO,gBAAgB,UAAU,MACnC,EACG,IAAI;KACH,QAAQ;KACR,UAAU;KACV,eAAe;KACf;KACD,CAAC,CACD,OAAO,CACX;KAEH,CACD,OAAO;;EAMZ,mBAAmB,SAAmB;AACpC,UAAO,KAAK,UAAU,eAAe,CAClC,QAAQ,EAAE,UACT,IAAI,OAAO,gBAAgB,UAAU,MACnC,EAAE,IAAI;IAAE,QAAQ;IAAc,eAAe,OAAO;IAAE,CAAC,CAAC,OAAO,CAChE,CACF,CACA,OAAO;;EAMZ,YAAY,SAAmB;AAC7B,UAAO,KAAK,UAAU,eAAe,CAClC,UAAU,QACT,IAAI,UAAU,iBAAiB,MAC7B,EAAE,WAAW,YAAY,OAAO,GAAG,MAAM,KAAK,QAAQ,CAAC,CACxD,CACF,CACA,mBAAmB,CAAC,YACnB,SACI;IACE,GAAG;IACH,QAAQ,iBAAiB,OAAO,QAAQ,yBAAyB,OAAO,CAAC;IAC1E,GACD,OACL,CACA,OAAO;;EAMZ,wBACE,WACA,UAA2D,EAAE,EAC7D;GACA,MAAM,WAAW,oBAAoB,QAAQ,SAAS;AAEtD,UAAO,KAAK,UAAU,eAAe,CAClC,UAAU,QACT,IAAI,eAAe,iBAAiB,MAAM;IACxC,MAAM,QAAQ,EACX,WAAW,6BAA6B,OAAO,GAAG,aAAa,KAAK,UAAU,CAAC,CAC/E,aAAa,4BAA4B,OAAO,CAChD,SAAS,SAAS;AAErB,WAAO,QAAQ,SAAS,MAAM,MAAM,QAAQ,OAAO,GAAG;KACtD,CACH,CACA,mBAAmB,CAAC,WAAW;IAC9B,OAAO,KAAK,MAAM,KAAK,WAAW;KAChC,GAAG;KACH,QAAQ,iBAAiB,MAAM,QAAQ,yBAAyB,MAAM,CAAC;KACxE,EAAE;IACH,QAAQ,KAAK;IACb,aAAa,KAAK;IACnB,EAAE,CACF,OAAO;;EAMZ,oBAAoB,WAAmB;AACrC,UAAO,KAAK,UAAU,eAAe,CAClC,UAAU,QACT,IAAI,KAAK,iBAAiB,MACxB,EAAE,WAAW,+BAA+B,OAAO,GAAG,aAAa,KAAK,UAAU,CAAC,CACpF,CACF,CACA,mBAAmB,CAAC,YACnB,OAAO,KAAK,WAAW;IACrB,GAAG;IACH,QAAQ,iBAAiB,MAAM,QAAQ,yBAAyB,MAAM,CAAC;IACxE,EAAE,CACJ,CACA,OAAO;;EAEb,CAAC;EACF,CACD,gBAAgB,kBAAkB,EAAE,oBAAoB;AACvD,QAAO,cAAc,EAInB,KAAK,EAAE,mBAAmB,UAA0D,EAAE,EAAE;EACtF,MAAM,aAAa,mBAAmB,aAAa;AAEnD,SAAO,KAAK,UAAU,eAAe,CAClC,UAAU,QACT,IAAI,KAAK,qBAAqB,MAAM;GAClC,IAAI,UAAU,aACV,EAAE,WAAW,4BAA4B,OACvC,GAAG,gBAAgB,KAAK,WAAW,CACpC,GACD,EAAE,WAAW,0BAA0B;AAE3C,aAAU,QAAQ,aAAa,2BAA2B,MAAM;AAChE,OAAI,UAAU,OACZ,WAAU,QAAQ,SAAS,MAAM;AAEnC,UAAO;IACP,CACH,CACA,mBAAmB,CAAC,aACnB,QAAQ,KAAK,WAAW;GACtB,IAAI,MAAM;GACV,cAAc,MAAM;GACpB,OAAO,MAAM;GACb,SAAS,MAAM;GACf,QAAQ,MAAM,UAAU;GACxB,WAAW,MAAM;GAClB,EAAE,CACJ,CACA,OAAO;IAEb,CAAC;EACF,CACD,OAAO;AAUV,eAAsB,6BACpB,UACA,WACiB;AACjB,KAAI;EACF,MAAM,oBAAoB,OAAO,oBAAyD;GACxF,MAAM,UAAU,MAAM,SAAS,UAAU,iBAAkB;AACzD,WAAO,MAAM,KAAK,WAAW,CAC1B,uBAEG,CAAC,SAAS,SAAS,gBAAgB,IAAI,iBAAiB,iBAAiB,CAAC,CAC7E,CACA,WAAW,EAAE,eAAe,CAAC,cAAc,OAAO,CAClD,SAAS;KACZ;AACF,OAAI,CAAC,QACH;GAEF,MAAM,SAAS,SAAS,QAAQ,OAAO,GAAG;AAC1C,UAAO,OAAO,MAAM,OAAO,GAAG,SAAY;;EAG5C,MAAM,UAAU,MAAM,kBAAkB,UAAU;AAClD,MAAI,YAAY,OACd,QAAO;EAKT,MAAM,kBACJ,cAAc,KAAK,eAAe,OAAO,cAAc,eAAe,OAAO,KAAK;AACpF,MAAI,oBAAoB,MAAM;GAC5B,MAAM,SAAS,MAAM,kBAAkB,gBAAgB;AACvD,OAAI,WAAW,OACb,QAAO;;AAIX,SAAO;SACD;AACN,SAAO"}
@@ -0,0 +1,164 @@
1
+ import { SETTINGS_NAMESPACE, internalSchema } from "./internal-fragment.schema.js";
2
+ import { internalFragmentDef } from "./internal-fragment.js";
3
+ import { submitSyncRequest } from "../sync/submit.js";
4
+ import { defineRoutes } from "@fragno-dev/core";
5
+
6
+ //#region src/fragments/internal-fragment.routes.ts
7
+ const ADAPTER_IDENTITY_KEY = "adapter_identity";
8
+ const passthroughInputSchema = { "~standard": {
9
+ version: 1,
10
+ vendor: "fragno",
11
+ validate: async (value) => ({ value })
12
+ } };
13
+ const getOrCreateAdapterIdentity = async (handlerTx, services) => {
14
+ const readIdentity = async () => handlerTx().withServiceCalls(() => [services.settingsService.get(SETTINGS_NAMESPACE, ADAPTER_IDENTITY_KEY)]).transform(({ serviceResult: [result] }) => result?.value).execute();
15
+ try {
16
+ const existingIdentity = await readIdentity();
17
+ if (existingIdentity) return {
18
+ ok: true,
19
+ value: existingIdentity
20
+ };
21
+ const adapterIdentity = crypto.randomUUID();
22
+ try {
23
+ await handlerTx().withServiceCalls(() => [services.settingsService.setIfMissing(SETTINGS_NAMESPACE, ADAPTER_IDENTITY_KEY, adapterIdentity)]).execute();
24
+ } catch (error) {
25
+ const recoveredIdentity = await readIdentity();
26
+ if (recoveredIdentity) return {
27
+ ok: true,
28
+ value: recoveredIdentity
29
+ };
30
+ throw error;
31
+ }
32
+ return {
33
+ ok: true,
34
+ value: await readIdentity() ?? adapterIdentity
35
+ };
36
+ } catch (error) {
37
+ return {
38
+ ok: false,
39
+ error: { error: {
40
+ code: "SETTINGS_UNAVAILABLE",
41
+ message: "Internal settings table is not available.",
42
+ detail: error instanceof Error ? error.message : void 0
43
+ } }
44
+ };
45
+ }
46
+ };
47
+ const createInternalFragmentDescribeRoutes = () => defineRoutes(internalFragmentDef).create(({ defineRoute, config, services }) => [defineRoute({
48
+ method: "GET",
49
+ path: "/",
50
+ handler: async function(_input, { json }) {
51
+ const registry = config.registry;
52
+ if (!registry) return json({ error: {
53
+ code: "REGISTRY_UNAVAILABLE",
54
+ message: "Adapter registry is not configured."
55
+ } }, { status: 500 });
56
+ const adapterIdentityResult = await getOrCreateAdapterIdentity(() => this.handlerTx(), services);
57
+ if (!adapterIdentityResult.ok) return json(adapterIdentityResult.error, { status: 500 });
58
+ const outboxEnabled = registry.isOutboxEnabled();
59
+ return json({
60
+ adapterIdentity: adapterIdentityResult.value,
61
+ fragments: outboxEnabled ? registry.listOutboxFragments() : [],
62
+ schemas: registry.listSchemas(),
63
+ routes: {
64
+ internal: "/_internal",
65
+ outbox: outboxEnabled ? "/_internal/outbox" : void 0
66
+ }
67
+ });
68
+ }
69
+ })]);
70
+ const createInternalFragmentOutboxRoutes = () => defineRoutes(internalFragmentDef).create(({ defineRoute, services, config }) => [defineRoute({
71
+ method: "GET",
72
+ path: "/outbox",
73
+ handler: async function(input, { json }) {
74
+ const registry = config.registry;
75
+ if (!registry || !registry.isOutboxEnabled()) return json({ error: {
76
+ code: "OUTBOX_UNAVAILABLE",
77
+ message: "Outbox is not enabled for this adapter."
78
+ } }, { status: 404 });
79
+ const afterVersionstamp = input.query.get("afterVersionstamp") ?? void 0;
80
+ const limitValue = input.query.get("limit");
81
+ let limit;
82
+ if (limitValue !== null) {
83
+ const parsed = Number.parseInt(limitValue, 10);
84
+ if (!Number.isFinite(parsed) || parsed < 1) return json({
85
+ error: "Invalid limit query parameter.",
86
+ code: "INVALID_LIMIT"
87
+ }, { status: 400 });
88
+ limit = parsed;
89
+ }
90
+ return json(await this.handlerTx().withServiceCalls(() => [services.outboxService.list({
91
+ afterVersionstamp,
92
+ limit
93
+ })]).transform(({ serviceResult: [result] }) => result).execute());
94
+ }
95
+ })]);
96
+ const createInternalFragmentSyncRoutes = () => defineRoutes(internalFragmentDef).create(({ defineRoute, services, config }) => [defineRoute({
97
+ method: "POST",
98
+ path: "/sync",
99
+ inputSchema: passthroughInputSchema,
100
+ handler: async function(input, { json }) {
101
+ const registry = config.registry;
102
+ if (!registry || !registry.isOutboxEnabled()) return json({ error: {
103
+ code: "SYNC_UNAVAILABLE",
104
+ message: "Sync is not enabled for this adapter."
105
+ } }, { status: 404 });
106
+ const adapterIdentityResult = await getOrCreateAdapterIdentity(() => this.handlerTx(), services);
107
+ if (!adapterIdentityResult.ok) return json(adapterIdentityResult.error, { status: 500 });
108
+ const result = await submitSyncRequest(await input.input?.valid(), {
109
+ getAdapterIdentity: async () => adapterIdentityResult.value,
110
+ listOutboxEntries: async (afterVersionstamp) => await this.handlerTx().withServiceCalls(() => [services.outboxService.list({
111
+ afterVersionstamp,
112
+ limit: void 0
113
+ })]).transform(({ serviceResult: [entries] }) => entries).execute(),
114
+ countOutboxMutations: async (afterVersionstamp) => {
115
+ return await this.handlerTx().retrieve(({ forSchema }) => {
116
+ return afterVersionstamp ? forSchema(internalSchema).find("fragno_db_outbox_mutations", (b) => b.whereIndex("idx_outbox_mutations_entry", (eb) => eb("entryVersionstamp", ">", afterVersionstamp)).selectCount()) : forSchema(internalSchema).find("fragno_db_outbox_mutations", (b) => b.whereIndex("idx_outbox_mutations_entry").selectCount());
117
+ }).transformRetrieve(([result$1]) => typeof result$1 === "number" ? result$1 : 0).execute();
118
+ },
119
+ getSyncRequest: async (requestId) => await this.handlerTx().retrieve(({ forSchema }) => forSchema(internalSchema).findFirst("fragno_db_sync_requests", (b) => b.whereIndex("idx_sync_request_id", (eb) => eb("requestId", "=", requestId)))).transformRetrieve(([result$1]) => {
120
+ if (!result$1) return;
121
+ const confirmed = Array.isArray(result$1.confirmedCommandIds) ? result$1.confirmedCommandIds : [];
122
+ const status = result$1.status === "applied" ? "applied" : "conflict";
123
+ return {
124
+ requestId: result$1.requestId,
125
+ status,
126
+ confirmedCommandIds: confirmed,
127
+ conflictCommandId: result$1.conflictCommandId ?? void 0,
128
+ baseVersionstamp: result$1.baseVersionstamp ?? void 0,
129
+ lastVersionstamp: result$1.lastVersionstamp ?? void 0
130
+ };
131
+ }).execute(),
132
+ storeSyncRequest: async (record) => {
133
+ await this.handlerTx().mutate(({ forSchema }) => {
134
+ forSchema(internalSchema).create("fragno_db_sync_requests", {
135
+ requestId: record.requestId,
136
+ status: record.status,
137
+ confirmedCommandIds: record.confirmedCommandIds,
138
+ conflictCommandId: record.conflictCommandId ?? null,
139
+ baseVersionstamp: record.baseVersionstamp ?? null,
140
+ lastVersionstamp: record.lastVersionstamp ?? null
141
+ });
142
+ }).execute();
143
+ },
144
+ resolveCommand: (fragment, schema, name) => registry.resolveSyncCommand(fragment, schema, name),
145
+ createCommandContext: (command) => command.createServerContext?.(this) ?? { mode: "server" },
146
+ executeCommand: async (command, inputPayload, ctx) => {
147
+ await command.handler({
148
+ input: inputPayload,
149
+ ctx,
150
+ tx: (options) => this.handlerTx(options)
151
+ });
152
+ }
153
+ });
154
+ if (result.status === "error") {
155
+ const statusCode = result.statusCode;
156
+ return json(result.body, { status: statusCode });
157
+ }
158
+ return json(result.response);
159
+ }
160
+ })]);
161
+
162
+ //#endregion
163
+ export { createInternalFragmentDescribeRoutes, createInternalFragmentOutboxRoutes, createInternalFragmentSyncRoutes };
164
+ //# sourceMappingURL=internal-fragment.routes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"internal-fragment.routes.js","names":["passthroughInputSchema: StandardSchemaV1","limit: number | undefined","result"],"sources":["../../src/fragments/internal-fragment.routes.ts"],"sourcesContent":["import { defineRoutes } from \"@fragno-dev/core\";\n\nimport type { StandardSchemaV1 } from \"@standard-schema/spec\";\n\nimport type { DatabaseHandlerContext } from \"../db-fragment-definition-builder\";\nimport type { OutboxEntry } from \"../outbox/outbox\";\nimport { submitSyncRequest, type SyncRequestRecord } from \"../sync/submit\";\nimport type { SubmitRequest, SyncCommandDefinition } from \"../sync/types\";\nimport {\n SETTINGS_NAMESPACE,\n internalFragmentDef,\n internalSchema,\n type InternalFragmentInstance,\n} from \"./internal-fragment\";\n\ntype InternalDescribeResponse = {\n adapterIdentity: string;\n fragments: Array<{ name: string; mountRoute: string }>;\n schemas: Array<{\n name: string;\n namespace: string | null;\n version: number;\n tables: string[];\n }>;\n routes: {\n internal: \"/_internal\";\n outbox?: \"/_internal/outbox\";\n };\n};\n\ntype InternalDescribeError = {\n error: {\n code: string;\n message: string;\n detail?: string;\n };\n};\n\nconst ADAPTER_IDENTITY_KEY = \"adapter_identity\" as const;\n\nconst passthroughInputSchema: StandardSchemaV1 = {\n \"~standard\": {\n version: 1,\n vendor: \"fragno\",\n validate: async (value: unknown) => ({ value }),\n },\n};\n\ntype AdapterIdentityResult =\n | { ok: true; value: string }\n | { ok: false; error: InternalDescribeError };\n\nconst getOrCreateAdapterIdentity = async (\n handlerTx: () => ReturnType<DatabaseHandlerContext[\"handlerTx\"]>,\n services: Pick<InternalFragmentInstance[\"services\"], \"settingsService\">,\n): Promise<AdapterIdentityResult> => {\n const readIdentity = async () =>\n handlerTx()\n .withServiceCalls(\n () => [services.settingsService.get(SETTINGS_NAMESPACE, ADAPTER_IDENTITY_KEY)] as const,\n )\n .transform(({ serviceResult: [result] }) => result?.value as string | undefined)\n .execute();\n\n try {\n const existingIdentity = await readIdentity();\n if (existingIdentity) {\n return { ok: true, value: existingIdentity };\n }\n\n const adapterIdentity = crypto.randomUUID();\n try {\n await handlerTx()\n .withServiceCalls(\n () =>\n [\n services.settingsService.setIfMissing(\n SETTINGS_NAMESPACE,\n ADAPTER_IDENTITY_KEY,\n adapterIdentity,\n ),\n ] as const,\n )\n .execute();\n } catch (error) {\n const recoveredIdentity = await readIdentity();\n if (recoveredIdentity) {\n return { ok: true, value: recoveredIdentity };\n }\n throw error;\n }\n\n const persistedIdentity = await readIdentity();\n return { ok: true, value: persistedIdentity ?? adapterIdentity };\n } catch (error) {\n return {\n ok: false,\n error: {\n error: {\n code: \"SETTINGS_UNAVAILABLE\",\n message: \"Internal settings table is not available.\",\n detail: error instanceof Error ? error.message : undefined,\n },\n },\n };\n }\n};\n\nexport const createInternalFragmentDescribeRoutes = () =>\n defineRoutes(internalFragmentDef).create(({ defineRoute, config, services }) => [\n defineRoute({\n method: \"GET\",\n path: \"/\",\n handler: async function (_input, { json }) {\n const registry = config.registry;\n if (!registry) {\n return json(\n {\n error: {\n code: \"REGISTRY_UNAVAILABLE\",\n message: \"Adapter registry is not configured.\",\n },\n } satisfies InternalDescribeError,\n { status: 500 },\n );\n }\n\n const adapterIdentityResult = await getOrCreateAdapterIdentity(\n () => this.handlerTx(),\n services,\n );\n if (!adapterIdentityResult.ok) {\n return json(adapterIdentityResult.error, { status: 500 });\n }\n\n const outboxEnabled = registry.isOutboxEnabled();\n const response: InternalDescribeResponse = {\n adapterIdentity: adapterIdentityResult.value,\n fragments: outboxEnabled ? registry.listOutboxFragments() : [],\n schemas: registry.listSchemas(),\n routes: {\n internal: \"/_internal\",\n outbox: outboxEnabled ? \"/_internal/outbox\" : undefined,\n },\n };\n\n return json(response);\n },\n }),\n ]);\n\nexport const createInternalFragmentOutboxRoutes = () =>\n defineRoutes(internalFragmentDef).create(({ defineRoute, services, config }) => [\n defineRoute({\n method: \"GET\",\n path: \"/outbox\",\n handler: async function (input, { json }) {\n const registry = config.registry;\n if (!registry || !registry.isOutboxEnabled()) {\n return json(\n {\n error: {\n code: \"OUTBOX_UNAVAILABLE\",\n message: \"Outbox is not enabled for this adapter.\",\n },\n },\n { status: 404 },\n );\n }\n\n // We intentionally skip input/output schemas here to keep the internal route lightweight.\n // Query params are validated manually and the response shape is stable (OutboxEntry[]),\n // while the public API surface is still gated behind adapter config.\n const afterVersionstamp = input.query.get(\"afterVersionstamp\") ?? undefined;\n const limitValue = input.query.get(\"limit\");\n let limit: number | undefined;\n\n if (limitValue !== null) {\n const parsed = Number.parseInt(limitValue, 10);\n if (!Number.isFinite(parsed) || parsed < 1) {\n return json(\n {\n error: \"Invalid limit query parameter.\",\n code: \"INVALID_LIMIT\",\n },\n { status: 400 },\n );\n }\n limit = parsed;\n }\n\n const entries = await this.handlerTx()\n .withServiceCalls(\n () => [services.outboxService.list({ afterVersionstamp, limit })] as const,\n )\n .transform(({ serviceResult: [result] }) => result)\n .execute();\n\n return json(entries);\n },\n }),\n ]);\n\ntype InternalSyncError = {\n error: {\n code: string;\n message: string;\n detail?: string;\n };\n};\n\nexport const createInternalFragmentSyncRoutes = () =>\n defineRoutes(internalFragmentDef).create(({ defineRoute, services, config }) => [\n defineRoute({\n method: \"POST\",\n path: \"/sync\",\n inputSchema: passthroughInputSchema,\n handler: async function (input, { json }) {\n const registry = config.registry;\n if (!registry || !registry.isOutboxEnabled()) {\n return json(\n {\n error: {\n code: \"SYNC_UNAVAILABLE\",\n message: \"Sync is not enabled for this adapter.\",\n },\n } satisfies InternalSyncError,\n { status: 404 },\n );\n }\n\n const adapterIdentityResult = await getOrCreateAdapterIdentity(\n () => this.handlerTx(),\n services,\n );\n if (!adapterIdentityResult.ok) {\n return json(adapterIdentityResult.error, { status: 500 });\n }\n\n const body = (await input.input?.valid()) as SubmitRequest | undefined;\n\n const result = await submitSyncRequest(body, {\n getAdapterIdentity: async () => adapterIdentityResult.value,\n listOutboxEntries: async (afterVersionstamp) =>\n await this.handlerTx()\n .withServiceCalls(\n () =>\n [services.outboxService.list({ afterVersionstamp, limit: undefined })] as const,\n )\n .transform(({ serviceResult: [entries] }) => entries as OutboxEntry[])\n .execute(),\n countOutboxMutations: async (afterVersionstamp) => {\n const count = await this.handlerTx()\n .retrieve(({ forSchema }) => {\n const builder = afterVersionstamp\n ? forSchema(internalSchema).find(\"fragno_db_outbox_mutations\", (b) =>\n b\n .whereIndex(\"idx_outbox_mutations_entry\", (eb) =>\n eb(\"entryVersionstamp\", \">\", afterVersionstamp),\n )\n .selectCount(),\n )\n : forSchema(internalSchema).find(\"fragno_db_outbox_mutations\", (b) =>\n b.whereIndex(\"idx_outbox_mutations_entry\").selectCount(),\n );\n return builder;\n })\n .transformRetrieve(([result]) => (typeof result === \"number\" ? result : 0))\n .execute();\n return count;\n },\n getSyncRequest: async (requestId) =>\n await this.handlerTx()\n .retrieve(({ forSchema }) =>\n forSchema(internalSchema).findFirst(\"fragno_db_sync_requests\", (b) =>\n b.whereIndex(\"idx_sync_request_id\", (eb) => eb(\"requestId\", \"=\", requestId)),\n ),\n )\n .transformRetrieve(([result]) => {\n if (!result) {\n return undefined;\n }\n const confirmed = Array.isArray(result.confirmedCommandIds)\n ? (result.confirmedCommandIds as string[])\n : [];\n const status = result.status === \"applied\" ? \"applied\" : \"conflict\";\n return {\n requestId: result.requestId,\n status,\n confirmedCommandIds: confirmed,\n conflictCommandId: result.conflictCommandId ?? undefined,\n baseVersionstamp: result.baseVersionstamp ?? undefined,\n lastVersionstamp: result.lastVersionstamp ?? undefined,\n } satisfies SyncRequestRecord;\n })\n .execute(),\n storeSyncRequest: async (record) => {\n await this.handlerTx()\n .mutate(({ forSchema }) => {\n forSchema(internalSchema).create(\"fragno_db_sync_requests\", {\n requestId: record.requestId,\n status: record.status,\n confirmedCommandIds: record.confirmedCommandIds,\n conflictCommandId: record.conflictCommandId ?? null,\n baseVersionstamp: record.baseVersionstamp ?? null,\n lastVersionstamp: record.lastVersionstamp ?? null,\n });\n })\n .execute();\n },\n resolveCommand: (fragment, schema, name) =>\n registry.resolveSyncCommand(fragment, schema, name) as\n | { command: SyncCommandDefinition; namespace: string | null }\n | undefined,\n createCommandContext: (command) =>\n command.createServerContext?.(this) ?? { mode: \"server\" },\n executeCommand: async (command, inputPayload, ctx) => {\n await command.handler({\n input: inputPayload,\n ctx,\n tx: (options) => this.handlerTx(options),\n });\n },\n });\n\n if (result.status === \"error\") {\n const statusCode = result.statusCode as 400 | 409 | 500;\n return json(result.body, { status: statusCode });\n }\n\n return json(result.response);\n },\n }),\n ]);\n"],"mappings":"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"}