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