@effect-app/infra 4.0.0-beta.99 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (486) hide show
  1. package/CHANGELOG.md +2884 -0
  2. package/_check.sh +1 -1
  3. package/dist/CUPS.d.ts +28 -9
  4. package/dist/CUPS.d.ts.map +1 -1
  5. package/dist/CUPS.js +35 -14
  6. package/dist/ClusterCosmos.d.ts +67 -0
  7. package/dist/ClusterCosmos.d.ts.map +1 -0
  8. package/dist/ClusterCosmos.js +588 -0
  9. package/dist/ClusterServiceBus.d.ts +67 -0
  10. package/dist/ClusterServiceBus.d.ts.map +1 -0
  11. package/dist/ClusterServiceBus.js +84 -0
  12. package/dist/{api/ContextProvider.d.ts → ContextProvider.d.ts} +7 -4
  13. package/dist/ContextProvider.d.ts.map +1 -0
  14. package/dist/ContextProvider.js +40 -0
  15. package/dist/Emailer/Sendgrid.d.ts +110 -146
  16. package/dist/Emailer/Sendgrid.d.ts.map +1 -1
  17. package/dist/Emailer/Sendgrid.js +24 -19
  18. package/dist/Emailer/fake.d.ts +1 -1
  19. package/dist/Emailer/fake.d.ts.map +1 -1
  20. package/dist/Emailer/fake.js +4 -4
  21. package/dist/MainFiberSet.d.ts +11 -7
  22. package/dist/MainFiberSet.d.ts.map +1 -1
  23. package/dist/MainFiberSet.js +22 -6
  24. package/dist/QueueMaker/errors.d.ts +3 -1
  25. package/dist/QueueMaker/errors.d.ts.map +1 -1
  26. package/dist/QueueMaker/errors.js +4 -2
  27. package/dist/{adapters/SQL → SQL}/Model.d.ts +34 -45
  28. package/dist/SQL/Model.d.ts.map +1 -0
  29. package/dist/SQL/Model.js +469 -0
  30. package/dist/SQL.d.ts.map +1 -0
  31. package/dist/{adapters/SQL.js → SQL.js} +1 -1
  32. package/dist/Store/Cosmos/query.d.ts +16 -4
  33. package/dist/Store/Cosmos/query.d.ts.map +1 -1
  34. package/dist/Store/Cosmos/query.js +238 -42
  35. package/dist/Store/Cosmos.d.ts +2 -2
  36. package/dist/Store/Cosmos.d.ts.map +1 -1
  37. package/dist/Store/Cosmos.js +394 -319
  38. package/dist/Store/Disk.d.ts +4 -4
  39. package/dist/Store/Disk.d.ts.map +1 -1
  40. package/dist/Store/Disk.js +91 -39
  41. package/dist/Store/Memory.d.ts +7 -10
  42. package/dist/Store/Memory.d.ts.map +1 -1
  43. package/dist/Store/Memory.js +348 -78
  44. package/dist/Store/SQL/Pg.d.ts +2 -2
  45. package/dist/Store/SQL/Pg.d.ts.map +1 -1
  46. package/dist/Store/SQL/Pg.js +229 -154
  47. package/dist/Store/SQL/query.d.ts +19 -3
  48. package/dist/Store/SQL/query.d.ts.map +1 -1
  49. package/dist/Store/SQL/query.js +306 -12
  50. package/dist/Store/SQL.d.ts +22 -5
  51. package/dist/Store/SQL.d.ts.map +1 -1
  52. package/dist/Store/SQL.js +369 -98
  53. package/dist/Store/codeFilter.d.ts +4 -4
  54. package/dist/Store/codeFilter.d.ts.map +1 -1
  55. package/dist/Store/codeFilter.js +71 -22
  56. package/dist/Store/index.d.ts +6 -4
  57. package/dist/Store/index.d.ts.map +1 -1
  58. package/dist/Store/index.js +9 -6
  59. package/dist/Store/jsonDocument.d.ts +67 -0
  60. package/dist/Store/jsonDocument.d.ts.map +1 -0
  61. package/dist/Store/jsonDocument.js +107 -0
  62. package/dist/Store/utils.d.ts +21 -2
  63. package/dist/Store/utils.d.ts.map +1 -1
  64. package/dist/Store/utils.js +253 -10
  65. package/dist/WorkflowEngineCosmos.d.ts +30 -0
  66. package/dist/WorkflowEngineCosmos.d.ts.map +1 -0
  67. package/dist/WorkflowEngineCosmos.js +542 -0
  68. package/dist/WorkflowEngineSqlite.d.ts +24 -0
  69. package/dist/WorkflowEngineSqlite.d.ts.map +1 -0
  70. package/dist/WorkflowEngineSqlite.js +550 -0
  71. package/dist/arbs.d.ts +6 -3
  72. package/dist/arbs.d.ts.map +1 -1
  73. package/dist/arbs.js +20 -4
  74. package/dist/codec.d.ts.map +1 -0
  75. package/dist/codec.js +5 -0
  76. package/dist/cosmos-client.d.ts +40 -0
  77. package/dist/cosmos-client.d.ts.map +1 -0
  78. package/dist/cosmos-client.js +41 -0
  79. package/dist/errorReporter.d.ts +6 -4
  80. package/dist/errorReporter.d.ts.map +1 -1
  81. package/dist/errorReporter.js +23 -27
  82. package/dist/fileUtil.d.ts +1 -1
  83. package/dist/fileUtil.d.ts.map +1 -1
  84. package/dist/fileUtil.js +2 -2
  85. package/dist/index.d.ts +2 -1
  86. package/dist/index.d.ts.map +1 -1
  87. package/dist/index.js +3 -2
  88. package/dist/internal/RequestContextMiddleware.d.ts +5 -0
  89. package/dist/internal/RequestContextMiddleware.d.ts.map +1 -0
  90. package/dist/internal/RequestContextMiddleware.js +45 -0
  91. package/dist/internal/auth.d.ts +53 -0
  92. package/dist/internal/auth.d.ts.map +1 -0
  93. package/dist/internal/auth.js +180 -0
  94. package/dist/internal/events.d.ts +11 -0
  95. package/dist/internal/events.d.ts.map +1 -0
  96. package/dist/internal/events.js +49 -0
  97. package/dist/{api/internal → internal}/health.d.ts +1 -1
  98. package/dist/internal/health.d.ts.map +1 -0
  99. package/dist/internal/health.js +5 -0
  100. package/dist/{api/layerUtils.d.ts → layerUtils.d.ts} +10 -2
  101. package/dist/layerUtils.d.ts.map +1 -0
  102. package/dist/layerUtils.js +17 -0
  103. package/dist/logger/jsonLogger.d.ts +1 -1
  104. package/dist/logger/jsonLogger.d.ts.map +1 -1
  105. package/dist/logger/jsonLogger.js +5 -3
  106. package/dist/logger/logFmtLogger.d.ts +1 -1
  107. package/dist/logger/logFmtLogger.d.ts.map +1 -1
  108. package/dist/logger/logFmtLogger.js +3 -3
  109. package/dist/logger/shared.d.ts +2 -2
  110. package/dist/logger/shared.d.ts.map +1 -1
  111. package/dist/logger/shared.js +6 -6
  112. package/dist/logger.d.ts.map +1 -1
  113. package/dist/middlewares.d.ts.map +1 -0
  114. package/dist/{api/middlewares.js → middlewares.js} +1 -1
  115. package/dist/{adapters/mongo-client.d.ts → mongo-client.d.ts} +2 -1
  116. package/dist/mongo-client.d.ts.map +1 -0
  117. package/dist/mongo-client.js +15 -0
  118. package/dist/otel.d.ts +75 -0
  119. package/dist/otel.d.ts.map +1 -0
  120. package/dist/otel.js +84 -0
  121. package/dist/rateLimit.d.ts +11 -3
  122. package/dist/rateLimit.d.ts.map +1 -1
  123. package/dist/rateLimit.js +7 -12
  124. package/dist/{adapters/redis-client.d.ts → redis-client.d.ts} +4 -1
  125. package/dist/redis-client.d.ts.map +1 -0
  126. package/dist/redis-client.js +98 -0
  127. package/dist/{api/reportError.d.ts → reportError.d.ts} +1 -1
  128. package/dist/reportError.d.ts.map +1 -0
  129. package/dist/reportError.js +28 -0
  130. package/dist/{api/routing → routing}/middleware/RouterMiddleware.d.ts +2 -1
  131. package/dist/routing/middleware/RouterMiddleware.d.ts.map +1 -0
  132. package/dist/{api/routing → routing}/middleware/RouterMiddleware.js +1 -1
  133. package/dist/{api/routing → routing}/middleware/middleware.d.ts +11 -6
  134. package/dist/routing/middleware/middleware.d.ts.map +1 -0
  135. package/dist/routing/middleware/middleware.js +152 -0
  136. package/dist/{api/routing → routing}/middleware.d.ts +0 -1
  137. package/dist/routing/middleware.d.ts.map +1 -0
  138. package/dist/{api/routing → routing}/middleware.js +1 -2
  139. package/dist/routing/schema/jwt.d.ts.map +1 -0
  140. package/dist/routing/schema/jwt.js +12 -0
  141. package/dist/routing/tsort.d.ts.map +1 -0
  142. package/dist/routing/tsort.js +51 -0
  143. package/dist/{api/routing → routing}/utils.d.ts +3 -3
  144. package/dist/routing/utils.d.ts.map +1 -0
  145. package/dist/routing/utils.js +45 -0
  146. package/dist/routing.d.ts +182 -0
  147. package/dist/routing.d.ts.map +1 -0
  148. package/dist/routing.js +256 -0
  149. package/dist/test.d.ts +2 -2
  150. package/dist/test.d.ts.map +1 -1
  151. package/dist/test.js +5 -5
  152. package/dist/util.d.ts.map +1 -0
  153. package/dist/util.js +14 -0
  154. package/docs/cluster-storage.md +26 -0
  155. package/docs/workflow-engine.md +262 -0
  156. package/examples/query.ts +23 -19
  157. package/package.json +36 -364
  158. package/src/CUPS.ts +53 -14
  159. package/src/ClusterCosmos.ts +1170 -0
  160. package/src/ClusterServiceBus.ts +244 -0
  161. package/src/{api/ContextProvider.ts → ContextProvider.ts} +10 -7
  162. package/src/Emailer/Sendgrid.ts +83 -60
  163. package/src/Emailer/fake.ts +4 -4
  164. package/src/MainFiberSet.ts +31 -12
  165. package/src/QueueMaker/errors.ts +3 -1
  166. package/src/{adapters/SQL → SQL}/Model.ts +48 -47
  167. package/src/SQL.ts +1 -0
  168. package/src/Store/Cosmos/query.ts +275 -55
  169. package/src/Store/Cosmos.ts +597 -511
  170. package/src/Store/Disk.ts +145 -71
  171. package/src/Store/Memory.ts +420 -115
  172. package/src/Store/SQL/Pg.ts +352 -268
  173. package/src/Store/SQL/query.ts +366 -20
  174. package/src/Store/SQL.ts +742 -293
  175. package/src/Store/codeFilter.ts +78 -28
  176. package/src/Store/index.ts +18 -13
  177. package/src/Store/jsonDocument.ts +143 -0
  178. package/src/Store/utils.ts +307 -30
  179. package/src/WorkflowEngineCosmos.ts +749 -0
  180. package/src/WorkflowEngineSqlite.ts +813 -0
  181. package/src/arbs.ts +25 -5
  182. package/src/cosmos-client.ts +72 -0
  183. package/src/errorReporter.ts +68 -78
  184. package/src/fileUtil.ts +1 -1
  185. package/src/index.ts +2 -1
  186. package/src/{api/internal → internal}/RequestContextMiddleware.ts +23 -6
  187. package/src/internal/auth.ts +272 -0
  188. package/src/{api/internal → internal}/events.ts +18 -9
  189. package/src/{api/layerUtils.ts → layerUtils.ts} +7 -3
  190. package/src/logger/jsonLogger.ts +5 -3
  191. package/src/logger/logFmtLogger.ts +3 -3
  192. package/src/logger/shared.ts +6 -5
  193. package/src/middlewares.ts +10 -0
  194. package/src/{adapters/mongo-client.ts → mongo-client.ts} +3 -1
  195. package/src/otel.ts +177 -0
  196. package/src/rateLimit.ts +35 -24
  197. package/src/{adapters/redis-client.ts → redis-client.ts} +6 -2
  198. package/src/{api/reportError.ts → reportError.ts} +3 -2
  199. package/src/{api/routing → routing}/middleware/RouterMiddleware.ts +2 -1
  200. package/src/{api/routing → routing}/middleware/middleware.ts +75 -50
  201. package/src/routing/middleware.ts +4 -0
  202. package/src/{api/routing → routing}/schema/jwt.ts +2 -2
  203. package/src/{api/routing → routing}/utils.ts +2 -1
  204. package/src/routing.ts +823 -0
  205. package/src/test.ts +6 -6
  206. package/src/vitest.ts +1 -1
  207. package/test/arbs-magnitude.test.ts +33 -0
  208. package/test/arbs.test.ts +41 -0
  209. package/test/auth.test.ts +101 -0
  210. package/test/cluster-cosmos.test.ts +634 -0
  211. package/test/cluster-servicebus.test.ts +180 -0
  212. package/test/cluster-sqlite.test.ts +207 -0
  213. package/test/contextProvider.test.ts +11 -8
  214. package/test/controller.test.ts +23 -28
  215. package/test/cosmos-container-throughput.test.ts +80 -0
  216. package/test/cosmos-query.test.ts +368 -0
  217. package/test/dist/arbs-magnitude.test.d.ts.map +1 -0
  218. package/test/dist/arbs.test.d.ts.map +1 -0
  219. package/test/dist/auth.test.d.ts.map +1 -0
  220. package/test/dist/cluster-cosmos.test.d.ts.map +1 -0
  221. package/test/dist/cluster-servicebus.test.d.ts.map +1 -0
  222. package/test/dist/cluster-sqlite.test.d.ts.map +1 -0
  223. package/test/dist/contextProvider.test.d.ts.map +1 -1
  224. package/test/dist/controller.test.d.ts.map +1 -1
  225. package/test/dist/cosmos-container-throughput.test.d.ts.map +1 -0
  226. package/test/dist/cosmos-query.test.d.ts.map +1 -0
  227. package/test/dist/fixtures.d.ts +17 -9
  228. package/test/dist/fixtures.d.ts.map +1 -1
  229. package/test/dist/fixtures.js +8 -3
  230. package/test/dist/json-lower.test.d.ts.map +1 -0
  231. package/test/dist/query.test.d.ts.map +1 -1
  232. package/test/dist/rawQuery.test.d.ts.map +1 -1
  233. package/test/dist/repository-ext.test.d.ts.map +1 -0
  234. package/test/dist/repository-legacy-document.test.d.ts.map +1 -0
  235. package/test/dist/requires.test.d.ts.map +1 -1
  236. package/test/dist/router-generator.test.d.ts.map +1 -0
  237. package/test/dist/routing-interruptibility.test.d.ts.map +1 -0
  238. package/test/dist/rpc-context-map-streaming.test.d.ts.map +1 -0
  239. package/test/dist/rpc-e2e-invalidation.test.d.ts.map +1 -0
  240. package/test/dist/rpc-multi-middleware.test.d.ts.map +1 -1
  241. package/test/dist/rpc-stream-fullstack.test.d.ts.map +1 -0
  242. package/test/dist/workflow-engine-cosmos.test.d.ts.map +1 -0
  243. package/test/dist/workflow-engine-sqlite.test.d.ts.map +1 -0
  244. package/test/fixtures.ts +7 -2
  245. package/test/json-lower.test.ts +129 -0
  246. package/test/layerUtils.test.ts +2 -2
  247. package/test/query.test.ts +1232 -42
  248. package/test/rawQuery.test.ts +432 -7
  249. package/test/repository-ext.test.ts +456 -0
  250. package/test/repository-legacy-document.test.ts +394 -0
  251. package/test/requires.test.ts +7 -3
  252. package/test/router-generator.test.ts +187 -0
  253. package/test/routing-interruptibility.test.ts +66 -0
  254. package/test/rpc-context-map-streaming.test.ts +265 -0
  255. package/test/rpc-e2e-invalidation.test.ts +421 -0
  256. package/test/rpc-multi-middleware.test.ts +17 -11
  257. package/test/rpc-stream-fullstack.test.ts +307 -0
  258. package/test/sql-store.test.ts +1202 -47
  259. package/test/validateSample.test.ts +70 -42
  260. package/test/workflow-engine-cosmos.test.ts +345 -0
  261. package/test/workflow-engine-sqlite.test.ts +297 -0
  262. package/tsconfig.examples.json +1 -1
  263. package/tsconfig.json +9 -1
  264. package/tsconfig.src.json +35 -35
  265. package/tsconfig.test.json +2 -2
  266. package/dist/Emailer/service.d.ts +0 -55
  267. package/dist/Emailer/service.d.ts.map +0 -1
  268. package/dist/Emailer/service.js +0 -6
  269. package/dist/Emailer.d.ts +0 -2
  270. package/dist/Emailer.d.ts.map +0 -1
  271. package/dist/Emailer.js +0 -2
  272. package/dist/Model/Repository/ext.d.ts +0 -41
  273. package/dist/Model/Repository/ext.d.ts.map +0 -1
  274. package/dist/Model/Repository/ext.js +0 -65
  275. package/dist/Model/Repository/internal/internal.d.ts +0 -59
  276. package/dist/Model/Repository/internal/internal.d.ts.map +0 -1
  277. package/dist/Model/Repository/internal/internal.js +0 -320
  278. package/dist/Model/Repository/legacy.d.ts +0 -19
  279. package/dist/Model/Repository/legacy.d.ts.map +0 -1
  280. package/dist/Model/Repository/legacy.js +0 -2
  281. package/dist/Model/Repository/makeRepo.d.ts +0 -49
  282. package/dist/Model/Repository/makeRepo.d.ts.map +0 -1
  283. package/dist/Model/Repository/makeRepo.js +0 -24
  284. package/dist/Model/Repository/service.d.ts +0 -89
  285. package/dist/Model/Repository/service.d.ts.map +0 -1
  286. package/dist/Model/Repository/service.js +0 -2
  287. package/dist/Model/Repository/validation.d.ts +0 -43
  288. package/dist/Model/Repository/validation.d.ts.map +0 -1
  289. package/dist/Model/Repository/validation.js +0 -32
  290. package/dist/Model/Repository.d.ts +0 -6
  291. package/dist/Model/Repository.d.ts.map +0 -1
  292. package/dist/Model/Repository.js +0 -6
  293. package/dist/Model/dsl.d.ts +0 -32
  294. package/dist/Model/dsl.d.ts.map +0 -1
  295. package/dist/Model/dsl.js +0 -44
  296. package/dist/Model/filter/filterApi.d.ts +0 -30
  297. package/dist/Model/filter/filterApi.d.ts.map +0 -1
  298. package/dist/Model/filter/filterApi.js +0 -2
  299. package/dist/Model/filter/types/errors.d.ts +0 -29
  300. package/dist/Model/filter/types/errors.d.ts.map +0 -1
  301. package/dist/Model/filter/types/errors.js +0 -2
  302. package/dist/Model/filter/types/fields.d.ts +0 -15
  303. package/dist/Model/filter/types/fields.d.ts.map +0 -1
  304. package/dist/Model/filter/types/fields.js +0 -2
  305. package/dist/Model/filter/types/path/common.d.ts +0 -316
  306. package/dist/Model/filter/types/path/common.d.ts.map +0 -1
  307. package/dist/Model/filter/types/path/common.js +0 -2
  308. package/dist/Model/filter/types/path/eager.d.ts +0 -95
  309. package/dist/Model/filter/types/path/eager.d.ts.map +0 -1
  310. package/dist/Model/filter/types/path/eager.js +0 -31
  311. package/dist/Model/filter/types/path/index.d.ts +0 -4
  312. package/dist/Model/filter/types/path/index.d.ts.map +0 -1
  313. package/dist/Model/filter/types/path/index.js +0 -3
  314. package/dist/Model/filter/types/utils.d.ts +0 -79
  315. package/dist/Model/filter/types/utils.d.ts.map +0 -1
  316. package/dist/Model/filter/types/utils.js +0 -2
  317. package/dist/Model/filter/types/validator.d.ts +0 -30
  318. package/dist/Model/filter/types/validator.d.ts.map +0 -1
  319. package/dist/Model/filter/types/validator.js +0 -2
  320. package/dist/Model/filter/types.d.ts +0 -5
  321. package/dist/Model/filter/types.d.ts.map +0 -1
  322. package/dist/Model/filter/types.js +0 -7
  323. package/dist/Model/query/dsl.d.ts +0 -248
  324. package/dist/Model/query/dsl.d.ts.map +0 -1
  325. package/dist/Model/query/dsl.js +0 -104
  326. package/dist/Model/query/new-kid-interpreter.d.ts +0 -28
  327. package/dist/Model/query/new-kid-interpreter.d.ts.map +0 -1
  328. package/dist/Model/query/new-kid-interpreter.js +0 -165
  329. package/dist/Model/query.d.ts +0 -15
  330. package/dist/Model/query.d.ts.map +0 -1
  331. package/dist/Model/query.js +0 -3
  332. package/dist/Model.d.ts +0 -4
  333. package/dist/Model.d.ts.map +0 -1
  334. package/dist/Model.js +0 -4
  335. package/dist/Operations.d.ts +0 -55
  336. package/dist/Operations.d.ts.map +0 -1
  337. package/dist/Operations.js +0 -102
  338. package/dist/OperationsRepo.d.ts +0 -41
  339. package/dist/OperationsRepo.d.ts.map +0 -1
  340. package/dist/OperationsRepo.js +0 -14
  341. package/dist/QueueMaker/SQLQueue.d.ts +0 -14
  342. package/dist/QueueMaker/SQLQueue.d.ts.map +0 -1
  343. package/dist/QueueMaker/SQLQueue.js +0 -132
  344. package/dist/QueueMaker/memQueue.d.ts +0 -11
  345. package/dist/QueueMaker/memQueue.d.ts.map +0 -1
  346. package/dist/QueueMaker/memQueue.js +0 -76
  347. package/dist/QueueMaker/sbqueue.d.ts +0 -12
  348. package/dist/QueueMaker/sbqueue.d.ts.map +0 -1
  349. package/dist/QueueMaker/sbqueue.js +0 -91
  350. package/dist/QueueMaker/service.d.ts +0 -11
  351. package/dist/QueueMaker/service.d.ts.map +0 -1
  352. package/dist/QueueMaker/service.js +0 -4
  353. package/dist/RequestContext.d.ts +0 -68
  354. package/dist/RequestContext.d.ts.map +0 -1
  355. package/dist/RequestContext.js +0 -49
  356. package/dist/RequestFiberSet.d.ts +0 -36
  357. package/dist/RequestFiberSet.d.ts.map +0 -1
  358. package/dist/RequestFiberSet.js +0 -78
  359. package/dist/Store/ContextMapContainer.d.ts +0 -25
  360. package/dist/Store/ContextMapContainer.d.ts.map +0 -1
  361. package/dist/Store/ContextMapContainer.js +0 -77
  362. package/dist/Store/service.d.ts +0 -111
  363. package/dist/Store/service.d.ts.map +0 -1
  364. package/dist/Store/service.js +0 -79
  365. package/dist/Store.d.ts +0 -2
  366. package/dist/Store.d.ts.map +0 -1
  367. package/dist/Store.js +0 -2
  368. package/dist/adapters/SQL/Model.d.ts.map +0 -1
  369. package/dist/adapters/SQL/Model.js +0 -478
  370. package/dist/adapters/SQL.d.ts.map +0 -1
  371. package/dist/adapters/ServiceBus.d.ts +0 -58
  372. package/dist/adapters/ServiceBus.d.ts.map +0 -1
  373. package/dist/adapters/ServiceBus.js +0 -99
  374. package/dist/adapters/cosmos-client.d.ts +0 -14
  375. package/dist/adapters/cosmos-client.d.ts.map +0 -1
  376. package/dist/adapters/cosmos-client.js +0 -9
  377. package/dist/adapters/index.d.ts +0 -2
  378. package/dist/adapters/index.d.ts.map +0 -1
  379. package/dist/adapters/index.js +0 -2
  380. package/dist/adapters/logger.d.ts +0 -9
  381. package/dist/adapters/logger.d.ts.map +0 -1
  382. package/dist/adapters/logger.js +0 -3
  383. package/dist/adapters/memQueue.d.ts +0 -13
  384. package/dist/adapters/memQueue.d.ts.map +0 -1
  385. package/dist/adapters/memQueue.js +0 -20
  386. package/dist/adapters/mongo-client.d.ts.map +0 -1
  387. package/dist/adapters/mongo-client.js +0 -13
  388. package/dist/adapters/redis-client.d.ts.map +0 -1
  389. package/dist/adapters/redis-client.js +0 -94
  390. package/dist/api/ContextProvider.d.ts.map +0 -1
  391. package/dist/api/ContextProvider.js +0 -38
  392. package/dist/api/codec.d.ts.map +0 -1
  393. package/dist/api/codec.js +0 -5
  394. package/dist/api/internal/RequestContextMiddleware.d.ts +0 -5
  395. package/dist/api/internal/RequestContextMiddleware.d.ts.map +0 -1
  396. package/dist/api/internal/RequestContextMiddleware.js +0 -35
  397. package/dist/api/internal/auth.d.ts +0 -15
  398. package/dist/api/internal/auth.d.ts.map +0 -1
  399. package/dist/api/internal/auth.js +0 -47
  400. package/dist/api/internal/events.d.ts +0 -9
  401. package/dist/api/internal/events.d.ts.map +0 -1
  402. package/dist/api/internal/events.js +0 -42
  403. package/dist/api/internal/health.d.ts.map +0 -1
  404. package/dist/api/internal/health.js +0 -5
  405. package/dist/api/layerUtils.d.ts.map +0 -1
  406. package/dist/api/layerUtils.js +0 -16
  407. package/dist/api/middlewares.d.ts.map +0 -1
  408. package/dist/api/reportError.d.ts.map +0 -1
  409. package/dist/api/reportError.js +0 -27
  410. package/dist/api/routing/middleware/RouterMiddleware.d.ts.map +0 -1
  411. package/dist/api/routing/middleware/middleware.d.ts.map +0 -1
  412. package/dist/api/routing/middleware/middleware.js +0 -130
  413. package/dist/api/routing/middleware.d.ts.map +0 -1
  414. package/dist/api/routing/schema/jwt.d.ts.map +0 -1
  415. package/dist/api/routing/schema/jwt.js +0 -12
  416. package/dist/api/routing/tsort.d.ts.map +0 -1
  417. package/dist/api/routing/tsort.js +0 -51
  418. package/dist/api/routing/utils.d.ts.map +0 -1
  419. package/dist/api/routing/utils.js +0 -44
  420. package/dist/api/routing.d.ts +0 -134
  421. package/dist/api/routing.d.ts.map +0 -1
  422. package/dist/api/routing.js +0 -167
  423. package/dist/api/setupRequest.d.ts +0 -15
  424. package/dist/api/setupRequest.d.ts.map +0 -1
  425. package/dist/api/setupRequest.js +0 -49
  426. package/dist/api/util.d.ts.map +0 -1
  427. package/dist/api/util.js +0 -14
  428. package/eslint.config.mjs +0 -24
  429. package/src/Emailer/service.ts +0 -52
  430. package/src/Emailer.ts +0 -1
  431. package/src/Model/Repository/ext.ts +0 -283
  432. package/src/Model/Repository/internal/internal.ts +0 -580
  433. package/src/Model/Repository/legacy.ts +0 -27
  434. package/src/Model/Repository/makeRepo.ts +0 -139
  435. package/src/Model/Repository/service.ts +0 -627
  436. package/src/Model/Repository/validation.ts +0 -31
  437. package/src/Model/Repository.ts +0 -5
  438. package/src/Model/dsl.ts +0 -128
  439. package/src/Model/filter/filterApi.ts +0 -60
  440. package/src/Model/filter/types/errors.ts +0 -47
  441. package/src/Model/filter/types/fields.ts +0 -50
  442. package/src/Model/filter/types/path/common.ts +0 -404
  443. package/src/Model/filter/types/path/eager.ts +0 -298
  444. package/src/Model/filter/types/path/index.ts +0 -4
  445. package/src/Model/filter/types/utils.ts +0 -128
  446. package/src/Model/filter/types/validator.ts +0 -46
  447. package/src/Model/filter/types.ts +0 -6
  448. package/src/Model/query/dsl.ts +0 -2110
  449. package/src/Model/query/new-kid-interpreter.ts +0 -210
  450. package/src/Model/query.ts +0 -13
  451. package/src/Model.ts +0 -3
  452. package/src/Operations.ts +0 -235
  453. package/src/OperationsRepo.ts +0 -16
  454. package/src/QueueMaker/SQLQueue.ts +0 -190
  455. package/src/QueueMaker/memQueue.ts +0 -130
  456. package/src/QueueMaker/sbqueue.ts +0 -137
  457. package/src/QueueMaker/service.ts +0 -17
  458. package/src/RequestContext.ts +0 -63
  459. package/src/RequestFiberSet.ts +0 -105
  460. package/src/Store/ContextMapContainer.ts +0 -116
  461. package/src/Store/index.test.ts.bak +0 -112
  462. package/src/Store/service.ts +0 -193
  463. package/src/Store.ts +0 -1
  464. package/src/adapters/SQL.ts +0 -1
  465. package/src/adapters/ServiceBus.ts +0 -209
  466. package/src/adapters/cosmos-client.ts +0 -16
  467. package/src/adapters/index.ts +0 -0
  468. package/src/adapters/logger.ts +0 -3
  469. package/src/adapters/memQueue.ts +0 -21
  470. package/src/api/internal/auth.ts +0 -68
  471. package/src/api/middlewares.ts +0 -10
  472. package/src/api/routing/middleware.ts +0 -6
  473. package/src/api/routing.ts +0 -598
  474. package/src/api/setupRequest.ts +0 -104
  475. package/test/dist/date-query.test.d.ts.map +0 -1
  476. package/tsconfig.json.bak +0 -12
  477. /package/dist/{adapters/SQL.d.ts → SQL.d.ts} +0 -0
  478. /package/dist/{api/codec.d.ts → codec.d.ts} +0 -0
  479. /package/dist/{api/middlewares.d.ts → middlewares.d.ts} +0 -0
  480. /package/dist/{api/routing → routing}/schema/jwt.d.ts +0 -0
  481. /package/dist/{api/routing → routing}/tsort.d.ts +0 -0
  482. /package/dist/{api/util.d.ts → util.d.ts} +0 -0
  483. /package/src/{api/codec.ts → codec.ts} +0 -0
  484. /package/src/{api/internal → internal}/health.ts +0 -0
  485. /package/src/{api/routing → routing}/tsort.ts +0 -0
  486. /package/src/{api/util.ts → util.ts} +0 -0
package/src/Store/SQL.ts CHANGED
@@ -1,24 +1,64 @@
1
1
  /* eslint-disable @typescript-eslint/no-explicit-any */
2
2
 
3
- import { Effect, type NonEmptyReadonlyArray, Option, Struct } from "effect-app"
3
+ import type { NonEmptyReadonlyArray } from "effect-app/Array"
4
4
  import { toNonEmptyArray } from "effect-app/Array"
5
- import { SqlClient } from "effect/unstable/sql"
6
- import { OptimisticConcurrencyException } from "../errors.js"
7
- import { InfraLogger } from "../logger.js"
8
- import type { FieldValues } from "../Model/filter/types.js"
9
- import { storeId } from "./Memory.js"
10
- import { type FilterArgs, type PersistenceModelType, type StorageConfig, type Store, type StoreConfig, StoreMaker } from "./service.js"
11
- import { buildWhereSQLQuery, logQuery, type SQLDialect, sqliteDialect } from "./SQL/query.js"
12
- import { makeETag } from "./utils.js"
13
-
14
- /** @internal */
5
+ import * as Effect from "effect-app/Effect"
6
+ import type { FieldValues } from "effect-app/Model/filter/types"
7
+ import type { ComputedProjectionIrExpression } from "effect-app/Model/query"
8
+ import * as Option from "effect-app/Option"
9
+ import { type FilterArgs, type PersistenceModelType, type StorageConfig, type Store, type StoreConfig, storeId, StoreMaker } from "effect-app/Store"
10
+ import * as Context from "effect/Context"
11
+ import * as Layer from "effect/Layer"
12
+ import * as LayerMap from "effect/LayerMap"
13
+ import { SqlClient } from "effect/sql"
14
+ import * as Struct from "effect/Struct"
15
+ import { DatabaseError, OptimisticConcurrencyException } from "../errors.ts"
16
+ import { InfraLogger } from "../logger.ts"
17
+ import { annotateDb, type DbSystem } from "../otel.ts"
18
+ import { decodeStoredMany, decodeStoredOption, makeJsonDocumentCodec, makeStoredDecode } from "./jsonDocument.ts"
19
+ import { buildWhereSQLQuery, logQuery, type SQLDialect, sqliteDialect } from "./SQL/query.ts"
20
+ import { makeETag, makeJsonLower, toJsonQueryValue } from "./utils.ts"
21
+
22
+ const sqlErrorMessage = (e: unknown) => (e as any)?.message ? String((e as any).message) : String(e)
23
+ const sqlIsTransient = (e: unknown) =>
24
+ /timeout|ETIMEDOUT|ECONNRESET|ECONNREFUSED|connection|deadlock|too many connections/i.test(sqlErrorMessage(e))
25
+ // Map a SqlError into a typed, serializable DatabaseError (instead of `.orDie`,
26
+ // which would turn it into an opaque, non-serializable defect).
27
+ const toDatabaseError = (e: unknown) =>
28
+ new DatabaseError({ message: `SQL request failed: ${sqlErrorMessage(e)}`, transient: sqlIsTransient(e), cause: e })
29
+ // withTransaction may re-raise setInternal's typed errors or add SqlError on begin/commit.
30
+ // Preserve DatabaseError / OCC by `_tag` (not instanceof — dual package instances break it);
31
+ // map residual SQL failures to DatabaseError.
32
+ const preserveStoreError = (e: unknown): DatabaseError | OptimisticConcurrencyException => {
33
+ if (e !== null && typeof e === "object" && "_tag" in e) {
34
+ if (e._tag === "DatabaseError") return e as DatabaseError
35
+ if (e._tag === "OptimisticConcurrencyException") return e as OptimisticConcurrencyException
36
+ }
37
+ return toDatabaseError(e)
38
+ }
39
+
40
+ export type WithNsTransactionFn = <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>
41
+
42
+ export class WithNsTransaction
43
+ extends Context.Service<WithNsTransaction, WithNsTransactionFn>()("effect-app/WithNsTransaction")
44
+ {}
45
+
46
+ /**
47
+ * Row -> raw stored JSON document: `data` parsed, `defaultValues` merged, `id`
48
+ * and `_etag` re-injected from their columns. Decoding it is a separate step
49
+ * (`makeStoredDecode`), so a document `jitM` does not repair fails as a typed
50
+ * `S.SchemaError` rather than throwing out of here.
51
+ *
52
+ * @internal
53
+ */
15
54
  export const parseRow = <Encoded extends FieldValues>(
16
55
  row: { id: string; _etag: string | null; data: string },
17
56
  idKey: PropertyKey,
18
57
  defaultValues: Partial<Encoded>
19
58
  ): PersistenceModelType<Encoded> => {
20
59
  const data = (typeof row.data === "string" ? JSON.parse(row.data) : row.data) as object
21
- return { ...defaultValues, ...data, [idKey]: row.id, _etag: row._etag ?? undefined } as PersistenceModelType<Encoded>
60
+ const jsonDefaults = toJsonQueryValue(defaultValues) as Partial<Encoded>
61
+ return { ...jsonDefaults, ...data, [idKey]: row.id, _etag: row._etag ?? undefined } as PersistenceModelType<Encoded>
22
62
  }
23
63
 
24
64
  const parseSelectRow = (
@@ -43,315 +83,724 @@ const parseSelectRow = (
43
83
  return result
44
84
  }
45
85
 
46
- function makeSQLStoreInt(dialect: SQLDialect, jsonColumnType: string) {
47
- return ({ prefix }: StorageConfig) =>
48
- Effect.gen(function*() {
49
- const sql = yield* SqlClient.SqlClient
50
- return {
51
- make: <IdKey extends keyof Encoded, Encoded extends FieldValues, R = never, E = never>(
52
- name: string,
53
- idKey: IdKey,
54
- seed?: Effect.Effect<Iterable<Encoded>, E, R>,
55
- config?: StoreConfig<Encoded>
56
- ) =>
57
- Effect.gen(function*() {
58
- type PM = PersistenceModelType<Encoded>
59
- const tableName = `${prefix}${name}`
60
- const defaultValues = config?.defaultValues ?? {}
61
-
62
- const resolveNamespace = !config?.allowNamespace
63
- ? Effect.succeed("primary")
64
- : storeId.asEffect().pipe(Effect.map((namespace) => {
65
- if (namespace !== "primary" && !config.allowNamespace!(namespace)) {
66
- throw new Error(`Namespace ${namespace} not allowed!`)
67
- }
68
- return namespace
69
- }))
70
-
71
- yield* sql
72
- .unsafe(
73
- `CREATE TABLE IF NOT EXISTS "${tableName}" (id TEXT NOT NULL, _namespace TEXT NOT NULL DEFAULT 'primary', _etag TEXT, data ${jsonColumnType} NOT NULL, PRIMARY KEY (id, _namespace))`
74
- )
75
- .pipe(Effect.orDie)
76
-
77
- const toRow = (e: PM) => {
78
- const newE = makeETag(e)
79
- const id = newE[idKey] as string
80
- const { _etag, [idKey]: _id, ...rest } = newE as any
81
- const data = JSON.stringify(rest)
82
- return { id, _etag: newE._etag!, data, item: newE }
86
+ function makeSQLStoreInt(system: DbSystem, dialect: SQLDialect, jsonColumnType: string) {
87
+ return Effect.fnUntraced(function*({ prefix }: StorageConfig) {
88
+ const sql = yield* SqlClient.SqlClient
89
+ return {
90
+ make: Effect.fnUntraced(function*<IdKey extends keyof Encoded, Encoded extends FieldValues, R = never, E = never>(
91
+ name: string,
92
+ idKey: IdKey,
93
+ seed?: Effect.Effect<Iterable<Encoded>, E, R>,
94
+ config?: StoreConfig<Encoded>
95
+ ) {
96
+ type PM = PersistenceModelType<Encoded>
97
+ const tableName = `${prefix}${name}`
98
+ const json = makeJsonLower(config)
99
+ const defaultValues = json.toJson(config?.defaultValues ?? {}) as Partial<Encoded>
100
+ const codec = makeJsonDocumentCodec<Encoded>(config?.schema)
101
+ // read path: stored JSON -> defaultValues -> jitM -> JSON→Encoded decode
102
+ const decodeStored = makeStoredDecode<Encoded>(config?.schema, config?.jitM)
103
+ const decodeRow = (row: { id: string; _etag: string | null; data: string }) =>
104
+ decodeStored(parseRow<Encoded>(row, idKey, defaultValues))
105
+
106
+ const resolveNamespace = !config?.allowNamespace
107
+ ? Effect.succeed("primary")
108
+ : storeId.pipe(Effect.map((namespace) => {
109
+ if (namespace !== "primary" && !config.allowNamespace!(namespace)) {
110
+ throw new Error(`Namespace ${namespace} not allowed!`)
83
111
  }
112
+ return namespace
113
+ }))
84
114
 
85
- const exec = (query: string, params?: readonly unknown[]) =>
86
- sql.unsafe(query, params as any).pipe(Effect.orDie)
115
+ const ensureTable = sql
116
+ .unsafe(
117
+ `CREATE TABLE IF NOT EXISTS "${tableName}" (id TEXT NOT NULL, _namespace TEXT NOT NULL DEFAULT 'primary', _etag TEXT, data ${jsonColumnType} NOT NULL, PRIMARY KEY (id, _namespace))`
118
+ )
119
+ .pipe(
120
+ Effect.andThen(
121
+ sql.unsafe(
122
+ `CREATE TABLE IF NOT EXISTS "_migrations" (id TEXT NOT NULL, version TEXT NOT NULL, PRIMARY KEY (id, version))`
123
+ )
124
+ ),
125
+ Effect.orDie,
126
+ Effect.asVoid
127
+ )
87
128
 
88
- const seedMarkerId = `__seed_marker__`
129
+ const toRow = (e: PM) => {
130
+ const newE = makeETag(codec.encode(e))
131
+ const id = newE[idKey] as string
132
+ const { _etag, [idKey]: _id, ...rest } = newE as any
133
+ const data = JSON.stringify(rest)
134
+ return { id, _etag: newE._etag!, data, item: codec.decode(newE) }
135
+ }
89
136
 
90
- const setInternal = (e: PM, ns: string) =>
91
- Effect.gen(function*() {
92
- const row = toRow(e)
93
- if (e._etag) {
94
- yield* exec(
95
- `UPDATE "${tableName}" SET _etag = ?, data = ? WHERE id = ? AND _etag = ? AND _namespace = ?`,
96
- [row._etag, row.data, row.id, e._etag, ns]
97
- )
98
- const existing = yield* exec(
99
- `SELECT _etag FROM "${tableName}" WHERE id = ? AND _namespace = ?`,
100
- [row.id, ns]
101
- )
102
- const current = (existing as any[])[0]
103
- if (!current || current._etag !== row._etag) {
104
- if (current) {
105
- return yield* new OptimisticConcurrencyException({
106
- type: name,
107
- id: row.id,
108
- current: current._etag,
109
- found: e._etag,
110
- code: 412
111
- })
112
- }
113
- return yield* new OptimisticConcurrencyException({
114
- type: name,
115
- id: row.id,
116
- current: "",
117
- found: e._etag,
118
- code: 404
119
- })
120
- }
121
- } else {
122
- yield* exec(
123
- `INSERT INTO "${tableName}" (id, _namespace, _etag, data) VALUES (?, ?, ?, ?)`,
124
- [row.id, ns, row._etag, row.data]
125
- )
126
- }
127
- return row.item
137
+ const exec = (query: string, params?: readonly unknown[]) =>
138
+ sql.unsafe(query, params as any).pipe(Effect.mapError(toDatabaseError))
139
+
140
+ const setInternal = Effect.fnUntraced(function*(e: PM, ns: string) {
141
+ const row = toRow(e)
142
+ if (e._etag) {
143
+ yield* exec(
144
+ `UPDATE "${tableName}" SET _etag = ?, data = ? WHERE id = ? AND _etag = ? AND _namespace = ?`,
145
+ [row._etag, row.data, row.id, e._etag, ns]
146
+ )
147
+ const existing = yield* exec(
148
+ `SELECT _etag FROM "${tableName}" WHERE id = ? AND _namespace = ?`,
149
+ [row.id, ns]
150
+ )
151
+ const current = (existing as any[])[0]
152
+ if (!current || current._etag !== row._etag) {
153
+ if (current) {
154
+ return yield* new OptimisticConcurrencyException({
155
+ type: name,
156
+ id: row.id,
157
+ current: current._etag,
158
+ found: e._etag,
159
+ code: 412
160
+ })
161
+ }
162
+ return yield* new OptimisticConcurrencyException({
163
+ type: name,
164
+ id: row.id,
165
+ current: "",
166
+ found: e._etag,
167
+ code: 404
128
168
  })
169
+ }
170
+ } else {
171
+ yield* exec(
172
+ `INSERT INTO "${tableName}" (id, _namespace, _etag, data) VALUES (?, ?, ?, ?)`,
173
+ [row.id, ns, row._etag, row.data]
174
+ )
175
+ }
176
+ return row.item
177
+ })
129
178
 
130
- const bulkSetInternal = (items: NonEmptyReadonlyArray<PM>, ns: string) =>
131
- sql
132
- .withTransaction(Effect.forEach(items, (e) => setInternal(e, ns)))
133
- .pipe(
134
- Effect.orDie,
135
- Effect.map((_) => _ as unknown as NonEmptyReadonlyArray<PM>)
136
- )
179
+ const bulkSetInternal = (items: NonEmptyReadonlyArray<PM>, ns: string) =>
180
+ sql
181
+ .withTransaction(Effect.forEach(items, (e) => setInternal(e, ns)))
182
+ .pipe(
183
+ Effect.mapError(preserveStoreError),
184
+ Effect.map((_) => _ as unknown as NonEmptyReadonlyArray<PM>)
185
+ )
137
186
 
138
- const ctx = yield* Effect.context<R>()
139
- const seedCache = new Map<string, Effect.Effect<void>>()
140
- const makeSeedEffect = (ns: string) =>
141
- exec(
142
- `SELECT id FROM "${tableName}" WHERE id = ? AND _namespace = ?`,
143
- [seedMarkerId, `__seed__::${ns}`]
144
- )
187
+ const ctx = yield* Effect.context<R>()
188
+ const seedCache = new Map<string, Effect.Effect<void, DatabaseError>>()
189
+ const makeSeedEffect = Effect.fnUntraced(function*(ns: string) {
190
+ yield* ensureTable
191
+ if (!seed) return
192
+ const existing = yield* exec(
193
+ `SELECT id FROM "_migrations" WHERE id = ? AND version = ?`,
194
+ [`${tableName}::${ns}`, tableName]
195
+ )
196
+ if ((existing as any[]).length > 0) return
197
+ yield* InfraLogger.logInfo(`Seeding data for ${name} (namespace: ${ns})`)
198
+ const items = yield* seed.pipe(Effect.provide(ctx), Effect.orDie)
199
+ const ne = toNonEmptyArray([...items])
200
+ // Seed inserts are not concurrent; OCC here is a programming defect.
201
+ if (Option.isSome(ne)) {
202
+ yield* bulkSetInternal(ne.value, ns).pipe(
203
+ Effect.catchTag("OptimisticConcurrencyException", Effect.die)
204
+ )
205
+ }
206
+ yield* exec(
207
+ `INSERT INTO "_migrations" (id, version) VALUES (?, ?)`,
208
+ [`${tableName}::${ns}`, tableName]
209
+ )
210
+ })
211
+ const seedNamespace = (ns: string) => {
212
+ let cached = seedCache.get(ns)
213
+ if (!cached) {
214
+ cached = Effect.cached(Effect.uninterruptible(makeSeedEffect(ns))).pipe(Effect.runSync)
215
+ seedCache.set(ns, cached)
216
+ }
217
+ return cached
218
+ }
219
+ const selectAllSql = `SELECT id, _etag, data FROM "${tableName}" WHERE _namespace = ?`
220
+ const allStored = resolveNamespace.pipe(
221
+ Effect.flatMap((ns) =>
222
+ exec(selectAllSql, [ns]).pipe(
223
+ Effect.map((rows) => (rows as any[]).map((row) => parseRow<Encoded>(row, idKey, defaultValues)))
224
+ )
225
+ )
226
+ )
227
+
228
+ const s: Store<IdKey, Encoded> = {
229
+ seedNamespace: (ns) => seedNamespace(ns),
230
+
231
+ all: resolveNamespace.pipe(
232
+ Effect.flatMap((ns) => {
233
+ return exec(selectAllSql, [ns])
145
234
  .pipe(
146
- Effect.flatMap((existing) => {
147
- if ((existing as any[]).length > 0) return Effect.void
148
- return InfraLogger.logInfo(`Seeding data for ${name} (namespace: ${ns})`).pipe(
149
- Effect.andThen(seed!),
150
- Effect.flatMap((items) =>
151
- Effect.flatMapOption(
152
- Effect.succeed(toNonEmptyArray([...items])),
153
- (a) => bulkSetInternal(a, ns)
154
- )
155
- ),
156
- Effect.andThen(
157
- exec(
158
- `INSERT INTO "${tableName}" (id, _namespace, _etag, data) VALUES (?, ?, ?, ?)`,
159
- [seedMarkerId, `__seed__::${ns}`, null, JSON.stringify({ _marker: true })]
160
- )
161
- ),
162
- Effect.provide(ctx),
163
- Effect.orDie
164
- )
235
+ Effect.flatMap((rows) => Effect.fromResult(decodeStoredMany(rows as any[], decodeRow))),
236
+ annotateDb({
237
+ operation: "all",
238
+ system,
239
+ collection: tableName,
240
+ namespace: ns,
241
+ entity: name,
242
+ query: selectAllSql
165
243
  })
166
244
  )
167
- const seedNamespace = Effect.fn("seedNamespace")(function*(ns: string) {
168
- if (!seed) return
169
- let cached = seedCache.get(ns)
170
- if (!cached) {
171
- cached = yield* Effect.cached(makeSeedEffect(ns))
172
- seedCache.set(ns, cached)
173
- }
174
- yield* cached
175
245
  })
176
- const resolveAndSeed = resolveNamespace.pipe(
177
- Effect.tap((ns) => seedNamespace(ns))
178
- )
246
+ ),
179
247
 
180
- const s: Store<IdKey, Encoded> = {
181
- all: resolveAndSeed.pipe(Effect.flatMap((ns) =>
182
- exec(`SELECT id, _etag, data FROM "${tableName}" WHERE _namespace = ?`, [ns])
248
+ find: (id) =>
249
+ resolveNamespace.pipe(
250
+ Effect.flatMap((ns) => {
251
+ const sqlText = `SELECT id, _etag, data FROM "${tableName}" WHERE id = ? AND _namespace = ?`
252
+ return exec(sqlText, [id, ns])
183
253
  .pipe(
184
- Effect.map((rows) => (rows as any[]).map((r) => parseRow<Encoded>(r, idKey, defaultValues))),
185
- Effect.withSpan("SQL.all [effect-app/infra/Store]", {
186
- attributes: {
187
- "repository.table_name": tableName,
188
- "repository.model_name": name,
189
- "repository.namespace": ns
190
- }
191
- }, { captureStackTrace: false })
254
+ Effect.flatMap((rows) =>
255
+ Effect.fromResult(decodeStoredOption(Option.fromNullishOr((rows as any[])[0]), decodeRow))
256
+ ),
257
+ annotateDb({
258
+ operation: "find",
259
+ system,
260
+ collection: tableName,
261
+ namespace: ns,
262
+ entity: name,
263
+ query: sqlText,
264
+ extra: { "app.entity.id": id }
265
+ })
192
266
  )
193
- )),
267
+ })
268
+ ),
194
269
 
195
- find: (id) =>
196
- resolveAndSeed.pipe(Effect.flatMap((ns) =>
197
- exec(`SELECT id, _etag, data FROM "${tableName}" WHERE id = ? AND _namespace = ?`, [id, ns])
270
+ filter: <U extends keyof Encoded = never>(f: FilterArgs<Encoded, U>) => {
271
+ const filter = f
272
+ .filter
273
+ type M = U extends undefined ? Encoded
274
+ : Pick<Encoded, U>
275
+ return resolveNamespace
276
+ .pipe(Effect
277
+ .flatMap((ns) =>
278
+ Effect
279
+ .sync(() => {
280
+ return buildWhereSQLQuery(
281
+ dialect,
282
+ idKey,
283
+ filter ? [{ t: "where-scope", result: filter, relation: "some" }] : [],
284
+ tableName,
285
+ defaultValues,
286
+ f
287
+ .select as
288
+ | NonEmptyReadonlyArray<
289
+ string | {
290
+ key: string
291
+ subKeys: readonly string[]
292
+ } | {
293
+ key: string
294
+ computed: ComputedProjectionIrExpression
295
+ }
296
+ >
297
+ | undefined,
298
+ f
299
+ .order,
300
+ f
301
+ .skip,
302
+ f
303
+ .limit,
304
+ ns,
305
+ json
306
+ )
307
+ })
198
308
  .pipe(
199
- Effect.map((rows) => {
200
- const row = (rows as any[])[0]
201
- return row
202
- ? Option.some(parseRow<Encoded>(row, idKey, defaultValues))
203
- : Option.none()
204
- }),
205
- Effect.withSpan("SQL.find [effect-app/infra/Store]", {
206
- attributes: { "repository.table_name": tableName, "repository.model_name": name, id }
207
- }, { captureStackTrace: false })
208
- )
209
- )),
210
-
211
- filter: <U extends keyof Encoded = never>(f: FilterArgs<Encoded, U>) => {
212
- const filter = f
213
- .filter
214
- type M = U extends undefined ? Encoded
215
- : Pick<Encoded, U>
216
- return resolveAndSeed
217
- .pipe(Effect
218
- .flatMap((ns) =>
219
309
  Effect
220
- .sync(() => {
221
- const q = buildWhereSQLQuery(
222
- dialect,
223
- idKey,
224
- filter ? [{ t: "where-scope", result: filter, relation: "some" }] : [],
225
- tableName,
226
- defaultValues,
227
- f
228
- .select as
229
- | NonEmptyReadonlyArray<string | { key: string; subKeys: readonly string[] }>
230
- | undefined,
231
- f
232
- .order as NonEmptyReadonlyArray<{ key: string; direction: "ASC" | "DESC" }> | undefined,
233
- f
234
- .skip,
235
- f
236
- .limit
237
- )
238
- const hasWhere = q
239
- .sql
240
- .includes("WHERE")
241
- const nsSql = hasWhere
242
- ? q
243
- .sql
244
- .replace("WHERE", `WHERE _namespace = ? AND`)
245
- : q
246
- .sql
247
- .replace(
248
- `FROM "${tableName}"`,
249
- `FROM "${tableName}" WHERE _namespace = ?`
250
- )
251
- return {
252
- sql: nsSql,
253
- params: [
254
- ns,
255
- ...q
256
- .params
257
- ]
258
- }
259
- })
260
- .pipe(
261
- Effect
262
- .tap((q) =>
263
- logQuery(q)
264
- ),
265
- Effect.flatMap((q) =>
266
- exec(q.sql, q.params).pipe(
267
- Effect.map((rows) => {
268
- if (f.select) {
269
- return (rows as any[]).map((r) => {
270
- const selected = parseSelectRow(r, idKey)
271
- return {
272
- ...Struct.pick(
273
- defaultValues as any,
274
- f.select!.filter((_) => typeof _ === "string") as never[]
275
- ),
276
- ...selected
277
- } as M
278
- })
279
- }
280
- return (rows as any[]).map((r) =>
281
- parseRow<Encoded>(r, idKey, defaultValues) as any as M
282
- )
283
- })
310
+ .tap((q) => logQuery(q)),
311
+ Effect.tap((q) => Effect.annotateCurrentSpan({ "db.query.text": q.sql })),
312
+ Effect.flatMap((q) =>
313
+ exec(q.sql, q.params).pipe(
314
+ Effect.flatMap((rows) => {
315
+ if (f.select) {
316
+ return Effect.succeed((rows as any[]).map((r) => {
317
+ const selected = parseSelectRow(r, idKey)
318
+ return {
319
+ ...Struct.pick(
320
+ defaultValues as any,
321
+ f.select!.filter((_) => typeof _ === "string") as never[]
322
+ ),
323
+ ...selected
324
+ } as M
325
+ }))
326
+ }
327
+ return Effect.map(
328
+ Effect.fromResult(decodeStoredMany(rows as any[], decodeRow)),
329
+ (decoded) => decoded as any as M[]
284
330
  )
285
- ),
286
- Effect.withSpan("SQL.filter [effect-app/infra/Store]", {
287
- attributes: { "repository.table_name": tableName, "repository.model_name": name }
288
- }, { captureStackTrace: false })
331
+ })
289
332
  )
290
- ))
291
- },
292
-
293
- set: (e) =>
294
- resolveAndSeed.pipe(Effect.flatMap((ns) =>
295
- setInternal(e, ns).pipe(
296
- Effect.withSpan("SQL.set [effect-app/infra/Store]", {
297
- attributes: { "repository.table_name": tableName, "repository.model_name": name, id: e[idKey] }
298
- }, { captureStackTrace: false })
299
- )
300
- )),
301
-
302
- batchSet: (items) =>
303
- resolveAndSeed.pipe(Effect.flatMap((ns) =>
304
- bulkSetInternal(items, ns).pipe(
305
- Effect.withSpan("SQL.batchSet [effect-app/infra/Store]", {
306
- attributes: { "repository.table_name": tableName, "repository.model_name": name }
307
- }, { captureStackTrace: false })
308
- )
309
- )),
310
-
311
- bulkSet: (items) =>
312
- resolveAndSeed.pipe(Effect.flatMap((ns) =>
313
- bulkSetInternal(items, ns).pipe(
314
- Effect.withSpan("SQL.bulkSet [effect-app/infra/Store]", {
315
- attributes: { "repository.table_name": tableName, "repository.model_name": name }
316
- }, { captureStackTrace: false })
317
- )
318
- )),
319
-
320
- batchRemove: (ids) => {
321
- const placeholders = ids.map(() => "?").join(", ")
322
- return resolveAndSeed.pipe(Effect.flatMap((ns) =>
323
- exec(
324
- `DELETE FROM "${tableName}" WHERE id IN (${placeholders}) AND _namespace = ?`,
325
- [...ids, ns]
326
- )
327
- .pipe(
328
- Effect.asVoid,
329
- Effect.withSpan("SQL.batchRemove [effect-app/infra/Store]", {
330
- attributes: { "repository.table_name": tableName, "repository.model_name": name }
331
- }, { captureStackTrace: false })
333
+ ),
334
+ annotateDb({
335
+ operation: "filter",
336
+ system,
337
+ collection: tableName,
338
+ namespace: ns,
339
+ entity: name
340
+ })
332
341
  )
333
342
  ))
334
- },
335
-
336
- queryRaw: (query) =>
337
- s.all.pipe(
338
- Effect.map(query.memory),
339
- Effect.withSpan("SQL.queryRaw [effect-app/infra/Store]", {
340
- attributes: { "repository.table_name": tableName, "repository.model_name": name }
341
- }, { captureStackTrace: false })
343
+ },
344
+
345
+ set: (e) =>
346
+ resolveNamespace.pipe(Effect.flatMap((ns) =>
347
+ setInternal(e, ns).pipe(
348
+ annotateDb({
349
+ operation: "set",
350
+ system,
351
+ collection: tableName,
352
+ namespace: ns,
353
+ entity: name,
354
+ extra: { "app.entity.id": e[idKey] }
355
+ })
356
+ )
357
+ )),
358
+
359
+ batchSet: (items) =>
360
+ resolveNamespace.pipe(Effect.flatMap((ns) =>
361
+ bulkSetInternal(items, ns).pipe(
362
+ annotateDb({
363
+ operation: "batchSet",
364
+ system,
365
+ collection: tableName,
366
+ namespace: ns,
367
+ entity: name
368
+ })
369
+ )
370
+ )),
371
+
372
+ bulkSet: (items) =>
373
+ resolveNamespace.pipe(Effect.flatMap((ns) =>
374
+ bulkSetInternal(items, ns).pipe(
375
+ annotateDb({
376
+ operation: "bulkSet",
377
+ system,
378
+ collection: tableName,
379
+ namespace: ns,
380
+ entity: name
381
+ })
382
+ )
383
+ )),
384
+
385
+ batchRemove: (ids) => {
386
+ const placeholders = ids.map(() => "?").join(", ")
387
+ return resolveNamespace.pipe(Effect.flatMap((ns) => {
388
+ const sqlText = `DELETE FROM "${tableName}" WHERE id IN (${placeholders}) AND _namespace = ?`
389
+ return exec(sqlText, [...ids, ns])
390
+ .pipe(
391
+ Effect.asVoid,
392
+ annotateDb({
393
+ operation: "batchRemove",
394
+ system,
395
+ collection: tableName,
396
+ namespace: ns,
397
+ entity: name,
398
+ query: sqlText
399
+ })
400
+ )
401
+ }))
402
+ },
403
+
404
+ queryRaw: (query) =>
405
+ allStored.pipe(
406
+ Effect.map(query.memory),
407
+ annotateDb({
408
+ operation: "queryRaw",
409
+ system,
410
+ collection: tableName,
411
+ entity: name
412
+ })
413
+ )
414
+ }
415
+
416
+ // Eagerly seed primary namespace on initialization. A seed failure at
417
+ // construction is fatal (orDie); the per-call `seedNamespace` still
418
+ // surfaces DatabaseError to callers.
419
+ yield* seedNamespace("primary").pipe(Effect.orDie)
420
+
421
+ return s
422
+ })
423
+ }
424
+ })
425
+ }
426
+
427
+ type WithNsSqlFn = <A, E2, R2>(
428
+ ns: string,
429
+ f: (sql: SqlClient.SqlClient) => Effect.Effect<A, E2, R2>
430
+ ) => Effect.Effect<A, E2, R2>
431
+
432
+ function makeSQLiteStorePerNs(
433
+ withNsSql: WithNsSqlFn,
434
+ { prefix }: StorageConfig
435
+ ) {
436
+ return {
437
+ make: Effect.fnUntraced(function*<IdKey extends keyof Encoded, Encoded extends FieldValues, R = never, E = never>(
438
+ name: string,
439
+ idKey: IdKey,
440
+ seed?: Effect.Effect<Iterable<Encoded>, E, R>,
441
+ config?: StoreConfig<Encoded>
442
+ ) {
443
+ type PM = PersistenceModelType<Encoded>
444
+ const tableName = `${prefix}${name}`
445
+ const json = makeJsonLower(config)
446
+ const defaultValues = json.toJson(config?.defaultValues ?? {}) as Partial<Encoded>
447
+ const codec = makeJsonDocumentCodec<Encoded>(config?.schema)
448
+ // read path: stored JSON -> defaultValues -> jitM -> JSON→Encoded decode
449
+ const decodeStored = makeStoredDecode<Encoded>(config?.schema, config?.jitM)
450
+ const decodeRow = (row: { id: string; _etag: string | null; data: string }) =>
451
+ decodeStored(parseRow<Encoded>(row, idKey, defaultValues))
452
+
453
+ const resolveNamespace = !config?.allowNamespace
454
+ ? Effect.succeed("primary")
455
+ : storeId.pipe(Effect.map((namespace) => {
456
+ if (namespace !== "primary" && !config.allowNamespace!(namespace)) {
457
+ throw new Error(`Namespace ${namespace} not allowed!`)
458
+ }
459
+ return namespace
460
+ }))
461
+
462
+ const toRow = (e: PM) => {
463
+ const newE = makeETag(codec.encode(e))
464
+ const id = newE[idKey] as string
465
+ const { _etag, [idKey]: _id, ...rest } = newE as any
466
+ const data = JSON.stringify(rest)
467
+ return { id, _etag: newE._etag!, data, item: codec.decode(newE) }
468
+ }
469
+
470
+ const exec = (ns: string, query: string, params?: readonly unknown[]) =>
471
+ withNsSql(ns, (sql) => sql.unsafe(query, params as any).pipe(Effect.mapError(toDatabaseError)))
472
+
473
+ const ensureTable = (ns: string) =>
474
+ withNsSql(ns, (sql) =>
475
+ sql
476
+ .unsafe(
477
+ `CREATE TABLE IF NOT EXISTS "${tableName}" (id TEXT NOT NULL PRIMARY KEY, _etag TEXT, data JSON NOT NULL)`
478
+ )
479
+ .pipe(
480
+ Effect.andThen(
481
+ sql.unsafe(
482
+ `CREATE TABLE IF NOT EXISTS "_migrations" (id TEXT NOT NULL, version TEXT NOT NULL, PRIMARY KEY (id, version))`
342
483
  )
484
+ ),
485
+ Effect.orDie,
486
+ Effect.asVoid
487
+ ))
488
+
489
+ const setInternal = Effect.fnUntraced(function*(e: PM, ns: string) {
490
+ const row = toRow(e)
491
+ if (e._etag) {
492
+ yield* exec(
493
+ ns,
494
+ `UPDATE "${tableName}" SET _etag = ?, data = ? WHERE id = ? AND _etag = ?`,
495
+ [row._etag, row.data, row.id, e._etag]
496
+ )
497
+ const existing = yield* exec(
498
+ ns,
499
+ `SELECT _etag FROM "${tableName}" WHERE id = ?`,
500
+ [row.id]
501
+ )
502
+ const current = (existing as any[])[0]
503
+ if (!current || current._etag !== row._etag) {
504
+ if (current) {
505
+ return yield* new OptimisticConcurrencyException({
506
+ type: name,
507
+ id: row.id,
508
+ current: current._etag,
509
+ found: e._etag,
510
+ code: 412
511
+ })
343
512
  }
513
+ return yield* new OptimisticConcurrencyException({
514
+ type: name,
515
+ id: row.id,
516
+ current: "",
517
+ found: e._etag,
518
+ code: 404
519
+ })
520
+ }
521
+ } else {
522
+ yield* exec(
523
+ ns,
524
+ `INSERT INTO "${tableName}" (id, _etag, data) VALUES (?, ?, ?)`,
525
+ [row.id, row._etag, row.data]
526
+ )
527
+ }
528
+ return row.item
529
+ })
344
530
 
345
- // Eagerly seed primary namespace on initialization
346
- yield* seedNamespace("primary")
531
+ const bulkSetInternal = (items: NonEmptyReadonlyArray<PM>, ns: string) =>
532
+ withNsSql(ns, (sql) =>
533
+ sql
534
+ .withTransaction(Effect.forEach(items, (e) => setInternal(e, ns)))
535
+ .pipe(
536
+ Effect.mapError(preserveStoreError),
537
+ Effect.map((_) => _ as unknown as NonEmptyReadonlyArray<PM>)
538
+ ))
347
539
 
348
- return s
349
- })
540
+ const ctx = yield* Effect.context<R>()
541
+ const seedCache = new Map<string, Effect.Effect<void, DatabaseError>>()
542
+ const makeSeedEffect = Effect.fnUntraced(function*(ns: string) {
543
+ yield* ensureTable(ns)
544
+ if (!seed) return
545
+ const existing = yield* exec(
546
+ ns,
547
+ `SELECT id FROM "_migrations" WHERE id = ? AND version = ?`,
548
+ [tableName, tableName]
549
+ )
550
+ if ((existing as any[]).length > 0) return
551
+ yield* InfraLogger.logInfo(`Seeding data for ${name} (namespace: ${ns})`)
552
+ const items = yield* seed.pipe(Effect.provide(ctx), Effect.orDie)
553
+ const ne = toNonEmptyArray([...items])
554
+ // Seed inserts are not concurrent; OCC here is a programming defect.
555
+ if (Option.isSome(ne)) {
556
+ yield* bulkSetInternal(ne.value, ns).pipe(
557
+ Effect.catchTag("OptimisticConcurrencyException", Effect.die)
558
+ )
559
+ }
560
+ yield* exec(
561
+ ns,
562
+ `INSERT INTO "_migrations" (id, version) VALUES (?, ?)`,
563
+ [tableName, tableName]
564
+ )
565
+ })
566
+ const seedNamespace = (ns: string) => {
567
+ let cached = seedCache.get(ns)
568
+ if (!cached) {
569
+ cached = Effect.cached(Effect.uninterruptible(makeSeedEffect(ns))).pipe(Effect.runSync)
570
+ seedCache.set(ns, cached)
571
+ }
572
+ return cached
350
573
  }
574
+
575
+ const selectAllSql = `SELECT id, _etag, data FROM "${tableName}"`
576
+ const allStored = resolveNamespace.pipe(
577
+ Effect.flatMap((ns) =>
578
+ exec(ns, selectAllSql).pipe(
579
+ Effect.map((rows) => (rows as any[]).map((row) => parseRow<Encoded>(row, idKey, defaultValues)))
580
+ )
581
+ )
582
+ )
583
+
584
+ const s: Store<IdKey, Encoded> = {
585
+ seedNamespace: (ns) => seedNamespace(ns),
586
+
587
+ all: resolveNamespace.pipe(Effect.flatMap((ns) => {
588
+ return exec(ns, selectAllSql)
589
+ .pipe(
590
+ Effect.flatMap((rows) => Effect.fromResult(decodeStoredMany(rows as any[], decodeRow))),
591
+ annotateDb({
592
+ operation: "all",
593
+ system: "sqlite",
594
+ collection: tableName,
595
+ namespace: ns,
596
+ entity: name,
597
+ query: selectAllSql
598
+ })
599
+ )
600
+ })),
601
+
602
+ find: (id) =>
603
+ resolveNamespace.pipe(
604
+ Effect.flatMap((ns) => {
605
+ const sqlText = `SELECT id, _etag, data FROM "${tableName}" WHERE id = ?`
606
+ return exec(ns, sqlText, [id])
607
+ .pipe(
608
+ Effect.flatMap((rows) =>
609
+ Effect.fromResult(decodeStoredOption(Option.fromNullishOr((rows as any[])[0]), decodeRow))
610
+ ),
611
+ annotateDb({
612
+ operation: "find",
613
+ system: "sqlite",
614
+ collection: tableName,
615
+ namespace: ns,
616
+ entity: name,
617
+ query: sqlText,
618
+ extra: { "app.entity.id": id }
619
+ })
620
+ )
621
+ })
622
+ ),
623
+
624
+ filter: <U extends keyof Encoded = never>(f: FilterArgs<Encoded, U>) => {
625
+ const filter = f
626
+ .filter
627
+ type M = U extends undefined ? Encoded
628
+ : Pick<Encoded, U>
629
+ return resolveNamespace
630
+ .pipe(Effect
631
+ .flatMap((ns) =>
632
+ Effect
633
+ .sync(() =>
634
+ buildWhereSQLQuery(
635
+ sqliteDialect,
636
+ idKey,
637
+ filter ? [{ t: "where-scope", result: filter, relation: "some" }] : [],
638
+ tableName,
639
+ defaultValues,
640
+ f
641
+ .select as
642
+ | NonEmptyReadonlyArray<
643
+ string | {
644
+ key: string
645
+ subKeys: readonly string[]
646
+ } | {
647
+ key: string
648
+ computed: ComputedProjectionIrExpression
649
+ }
650
+ >
651
+ | undefined,
652
+ f
653
+ .order as NonEmptyReadonlyArray<{ key: string; direction: "ASC" | "DESC" }> | undefined,
654
+ f
655
+ .skip,
656
+ f
657
+ .limit,
658
+ undefined,
659
+ json
660
+ )
661
+ )
662
+ .pipe(
663
+ Effect
664
+ .tap((q) => logQuery(q)),
665
+ Effect.tap((q) => Effect.annotateCurrentSpan({ "db.query.text": q.sql })),
666
+ Effect.flatMap((q) =>
667
+ exec(ns, q.sql, q.params).pipe(
668
+ Effect.flatMap((rows) => {
669
+ if (f.select) {
670
+ return Effect.succeed((rows as any[]).map((r) => {
671
+ const selected = parseSelectRow(r, idKey)
672
+ return {
673
+ ...Struct.pick(
674
+ defaultValues as any,
675
+ f.select!.filter((_) => typeof _ === "string") as never[]
676
+ ),
677
+ ...selected
678
+ } as M
679
+ }))
680
+ }
681
+ return Effect.map(
682
+ Effect.fromResult(decodeStoredMany(rows as any[], decodeRow)),
683
+ (decoded) => decoded as any as M[]
684
+ )
685
+ })
686
+ )
687
+ ),
688
+ annotateDb({
689
+ operation: "filter",
690
+ system: "sqlite",
691
+ collection: tableName,
692
+ namespace: ns,
693
+ entity: name
694
+ })
695
+ )
696
+ ))
697
+ },
698
+
699
+ set: (e) =>
700
+ resolveNamespace.pipe(Effect.flatMap((ns) =>
701
+ setInternal(e, ns).pipe(
702
+ annotateDb({
703
+ operation: "set",
704
+ system: "sqlite",
705
+ collection: tableName,
706
+ namespace: ns,
707
+ entity: name,
708
+ extra: { "app.entity.id": e[idKey] }
709
+ })
710
+ )
711
+ )),
712
+
713
+ batchSet: (items) =>
714
+ resolveNamespace.pipe(Effect.flatMap((ns) =>
715
+ bulkSetInternal(items, ns).pipe(
716
+ annotateDb({
717
+ operation: "batchSet",
718
+ system: "sqlite",
719
+ collection: tableName,
720
+ namespace: ns,
721
+ entity: name
722
+ })
723
+ )
724
+ )),
725
+
726
+ bulkSet: (items) =>
727
+ resolveNamespace.pipe(Effect.flatMap((ns) =>
728
+ bulkSetInternal(items, ns).pipe(
729
+ annotateDb({
730
+ operation: "bulkSet",
731
+ system: "sqlite",
732
+ collection: tableName,
733
+ namespace: ns,
734
+ entity: name
735
+ })
736
+ )
737
+ )),
738
+
739
+ batchRemove: (ids) => {
740
+ const placeholders = ids.map(() => "?").join(", ")
741
+ return resolveNamespace.pipe(Effect.flatMap((ns) => {
742
+ const sqlText = `DELETE FROM "${tableName}" WHERE id IN (${placeholders})`
743
+ return exec(ns, sqlText, [...ids])
744
+ .pipe(
745
+ Effect.asVoid,
746
+ annotateDb({
747
+ operation: "batchRemove",
748
+ system: "sqlite",
749
+ collection: tableName,
750
+ namespace: ns,
751
+ entity: name,
752
+ query: sqlText
753
+ })
754
+ )
755
+ }))
756
+ },
757
+
758
+ queryRaw: (query) =>
759
+ allStored.pipe(
760
+ Effect.map(query.memory),
761
+ annotateDb({
762
+ operation: "queryRaw",
763
+ system: "sqlite",
764
+ collection: tableName,
765
+ entity: name
766
+ })
767
+ )
768
+ }
769
+
770
+ yield* seedNamespace("primary").pipe(Effect.orDie)
771
+
772
+ return s
351
773
  })
774
+ }
352
775
  }
353
776
 
354
- export function SQLiteStoreLayer(cfg: StorageConfig) {
777
+ export function SQLiteStoreLayer(
778
+ cfg: StorageConfig,
779
+ options?: { makeSqlClientLayer?: (namespace: string) => Layer.Layer<SqlClient.SqlClient> }
780
+ ) {
781
+ if (options?.makeSqlClientLayer) {
782
+ return Layer.effectContext(
783
+ Effect.gen(function*() {
784
+ const layerMap = yield* LayerMap.make(
785
+ (namespace: string) => options.makeSqlClientLayer!(namespace),
786
+ { idleTimeToLive: "10 minutes" }
787
+ )
788
+
789
+ const withNsSql: WithNsSqlFn = (ns, f) => SqlClient.SqlClient.use(f).pipe(Effect.provide(layerMap.get(ns)))
790
+
791
+ const storeMaker = makeSQLiteStorePerNs(withNsSql, cfg)
792
+
793
+ const withTransaction: WithNsTransactionFn = (effect) =>
794
+ storeId.pipe(
795
+ Effect.flatMap((ns) => withNsSql(ns, (sql) => sql.withTransaction(effect).pipe(Effect.orDie)))
796
+ )
797
+
798
+ return StoreMaker.context(storeMaker).pipe(
799
+ Context.add(WithNsTransaction, withTransaction)
800
+ )
801
+ })
802
+ )
803
+ }
355
804
  return StoreMaker
356
- .toLayer(makeSQLStoreInt(sqliteDialect, "JSON")(cfg))
805
+ .toLayer(makeSQLStoreInt("sqlite", sqliteDialect, "JSON")(cfg))
357
806
  }