@effect-app/infra 4.0.0-beta.33 → 4.0.0-beta.331

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 (490) hide show
  1. package/CHANGELOG.md +2562 -0
  2. package/_check.sh +1 -1
  3. package/dist/CUPS.d.ts +29 -10
  4. package/dist/CUPS.d.ts.map +1 -1
  5. package/dist/CUPS.js +36 -15
  6. package/dist/ClusterCosmos.d.ts +64 -0
  7. package/dist/ClusterCosmos.d.ts.map +1 -0
  8. package/dist/ClusterCosmos.js +576 -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/ContextProvider.d.ts +34 -0
  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 +12 -8
  22. package/dist/MainFiberSet.d.ts.map +1 -1
  23. package/dist/MainFiberSet.js +23 -7
  24. package/dist/QueueMaker/errors.d.ts +4 -2
  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 +31 -42
  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 +395 -256
  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 +93 -42
  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 +349 -79
  44. package/dist/Store/SQL/Pg.d.ts +4 -0
  45. package/dist/Store/SQL/Pg.d.ts.map +1 -0
  46. package/dist/Store/SQL/Pg.js +261 -0
  47. package/dist/Store/SQL/query.d.ts +53 -0
  48. package/dist/Store/SQL/query.d.ts.map +1 -0
  49. package/dist/Store/SQL/query.js +656 -0
  50. package/dist/Store/SQL.d.ts +28 -0
  51. package/dist/Store/SQL.d.ts.map +1 -0
  52. package/dist/Store/SQL.js +483 -0
  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 +18 -5
  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/internal/health.d.ts.map +1 -0
  98. package/dist/internal/health.js +5 -0
  99. package/dist/{api/layerUtils.d.ts → layerUtils.d.ts} +14 -6
  100. package/dist/layerUtils.d.ts.map +1 -0
  101. package/dist/layerUtils.js +17 -0
  102. package/dist/logger/jsonLogger.d.ts +1 -1
  103. package/dist/logger/jsonLogger.d.ts.map +1 -1
  104. package/dist/logger/jsonLogger.js +5 -3
  105. package/dist/logger/logFmtLogger.d.ts +1 -1
  106. package/dist/logger/logFmtLogger.d.ts.map +1 -1
  107. package/dist/logger/logFmtLogger.js +3 -3
  108. package/dist/logger/shared.d.ts +2 -2
  109. package/dist/logger/shared.d.ts.map +1 -1
  110. package/dist/logger/shared.js +6 -6
  111. package/dist/logger.d.ts +4 -4
  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} +3 -2
  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} +5 -2
  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 +4 -3
  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/routing/middleware/middleware.d.ts +48 -0
  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 +25 -21
  157. package/package.json +38 -352
  158. package/src/CUPS.ts +54 -15
  159. package/src/ClusterCosmos.ts +1150 -0
  160. package/src/ClusterServiceBus.ts +244 -0
  161. package/src/{api/ContextProvider.ts → ContextProvider.ts} +20 -17
  162. package/src/Emailer/Sendgrid.ts +83 -60
  163. package/src/Emailer/fake.ts +4 -4
  164. package/src/MainFiberSet.ts +32 -13
  165. package/src/QueueMaker/errors.ts +3 -1
  166. package/src/{adapters/SQL → SQL}/Model.ts +42 -41
  167. package/src/SQL.ts +1 -0
  168. package/src/Store/Cosmos/query.ts +275 -55
  169. package/src/Store/Cosmos.ts +547 -366
  170. package/src/Store/Disk.ts +146 -73
  171. package/src/Store/Memory.ts +420 -115
  172. package/src/Store/SQL/Pg.ts +412 -0
  173. package/src/Store/SQL/query.ts +748 -0
  174. package/src/Store/SQL.ts +806 -0
  175. package/src/Store/codeFilter.ts +78 -28
  176. package/src/Store/index.ts +25 -10
  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 +22 -13
  189. package/src/{api/layerUtils.ts → layerUtils.ts} +14 -10
  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} +4 -2
  195. package/src/otel.ts +177 -0
  196. package/src/rateLimit.ts +35 -24
  197. package/src/{adapters/redis-client.ts → redis-client.ts} +7 -3
  198. package/src/{api/reportError.ts → reportError.ts} +3 -2
  199. package/src/{api/routing → routing}/middleware/RouterMiddleware.ts +5 -4
  200. package/src/routing/middleware/middleware.ts +196 -0
  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 +612 -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 +15 -12
  214. package/test/controller.test.ts +27 -31
  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 +29 -11
  228. package/test/dist/fixtures.d.ts.map +1 -1
  229. package/test/dist/fixtures.js +17 -10
  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/sql-store.test.d.ts.map +1 -0
  243. package/test/dist/workflow-engine-cosmos.test.d.ts.map +1 -0
  244. package/test/dist/workflow-engine-sqlite.test.d.ts.map +1 -0
  245. package/test/fixtures.ts +16 -9
  246. package/test/json-lower.test.ts +129 -0
  247. package/test/layerUtils.test.ts +2 -2
  248. package/test/query.test.ts +1382 -44
  249. package/test/rawQuery.test.ts +433 -8
  250. package/test/repository-ext.test.ts +456 -0
  251. package/test/repository-legacy-document.test.ts +394 -0
  252. package/test/requires.test.ts +10 -5
  253. package/test/router-generator.test.ts +187 -0
  254. package/test/routing-interruptibility.test.ts +66 -0
  255. package/test/rpc-context-map-streaming.test.ts +265 -0
  256. package/test/rpc-e2e-invalidation.test.ts +421 -0
  257. package/test/rpc-multi-middleware.test.ts +85 -10
  258. package/test/rpc-stream-fullstack.test.ts +307 -0
  259. package/test/sql-store.test.ts +1931 -0
  260. package/test/validateSample.test.ts +71 -43
  261. package/test/workflow-engine-cosmos.test.ts +345 -0
  262. package/test/workflow-engine-sqlite.test.ts +297 -0
  263. package/tsconfig.examples.json +1 -1
  264. package/tsconfig.json +9 -2
  265. package/tsconfig.src.json +35 -35
  266. package/tsconfig.test.json +2 -2
  267. package/dist/Emailer/service.d.ts +0 -55
  268. package/dist/Emailer/service.d.ts.map +0 -1
  269. package/dist/Emailer/service.js +0 -6
  270. package/dist/Emailer.d.ts +0 -2
  271. package/dist/Emailer.d.ts.map +0 -1
  272. package/dist/Emailer.js +0 -2
  273. package/dist/Model/Repository/ext.d.ts +0 -41
  274. package/dist/Model/Repository/ext.d.ts.map +0 -1
  275. package/dist/Model/Repository/ext.js +0 -65
  276. package/dist/Model/Repository/internal/internal.d.ts +0 -59
  277. package/dist/Model/Repository/internal/internal.d.ts.map +0 -1
  278. package/dist/Model/Repository/internal/internal.js +0 -316
  279. package/dist/Model/Repository/legacy.d.ts +0 -19
  280. package/dist/Model/Repository/legacy.d.ts.map +0 -1
  281. package/dist/Model/Repository/legacy.js +0 -2
  282. package/dist/Model/Repository/makeRepo.d.ts +0 -49
  283. package/dist/Model/Repository/makeRepo.d.ts.map +0 -1
  284. package/dist/Model/Repository/makeRepo.js +0 -24
  285. package/dist/Model/Repository/service.d.ts +0 -89
  286. package/dist/Model/Repository/service.d.ts.map +0 -1
  287. package/dist/Model/Repository/service.js +0 -2
  288. package/dist/Model/Repository/validation.d.ts +0 -42
  289. package/dist/Model/Repository/validation.d.ts.map +0 -1
  290. package/dist/Model/Repository/validation.js +0 -32
  291. package/dist/Model/Repository.d.ts +0 -6
  292. package/dist/Model/Repository.d.ts.map +0 -1
  293. package/dist/Model/Repository.js +0 -6
  294. package/dist/Model/dsl.d.ts +0 -32
  295. package/dist/Model/dsl.d.ts.map +0 -1
  296. package/dist/Model/dsl.js +0 -44
  297. package/dist/Model/filter/filterApi.d.ts +0 -30
  298. package/dist/Model/filter/filterApi.d.ts.map +0 -1
  299. package/dist/Model/filter/filterApi.js +0 -2
  300. package/dist/Model/filter/types/errors.d.ts +0 -29
  301. package/dist/Model/filter/types/errors.d.ts.map +0 -1
  302. package/dist/Model/filter/types/errors.js +0 -2
  303. package/dist/Model/filter/types/fields.d.ts +0 -15
  304. package/dist/Model/filter/types/fields.d.ts.map +0 -1
  305. package/dist/Model/filter/types/fields.js +0 -2
  306. package/dist/Model/filter/types/path/common.d.ts +0 -316
  307. package/dist/Model/filter/types/path/common.d.ts.map +0 -1
  308. package/dist/Model/filter/types/path/common.js +0 -2
  309. package/dist/Model/filter/types/path/eager.d.ts +0 -95
  310. package/dist/Model/filter/types/path/eager.d.ts.map +0 -1
  311. package/dist/Model/filter/types/path/eager.js +0 -31
  312. package/dist/Model/filter/types/path/index.d.ts +0 -4
  313. package/dist/Model/filter/types/path/index.d.ts.map +0 -1
  314. package/dist/Model/filter/types/path/index.js +0 -3
  315. package/dist/Model/filter/types/utils.d.ts +0 -79
  316. package/dist/Model/filter/types/utils.d.ts.map +0 -1
  317. package/dist/Model/filter/types/utils.js +0 -2
  318. package/dist/Model/filter/types/validator.d.ts +0 -30
  319. package/dist/Model/filter/types/validator.d.ts.map +0 -1
  320. package/dist/Model/filter/types/validator.js +0 -2
  321. package/dist/Model/filter/types.d.ts +0 -5
  322. package/dist/Model/filter/types.d.ts.map +0 -1
  323. package/dist/Model/filter/types.js +0 -7
  324. package/dist/Model/query/dsl.d.ts +0 -248
  325. package/dist/Model/query/dsl.d.ts.map +0 -1
  326. package/dist/Model/query/dsl.js +0 -104
  327. package/dist/Model/query/new-kid-interpreter.d.ts +0 -28
  328. package/dist/Model/query/new-kid-interpreter.d.ts.map +0 -1
  329. package/dist/Model/query/new-kid-interpreter.js +0 -165
  330. package/dist/Model/query.d.ts +0 -15
  331. package/dist/Model/query.d.ts.map +0 -1
  332. package/dist/Model/query.js +0 -3
  333. package/dist/Model.d.ts +0 -4
  334. package/dist/Model.d.ts.map +0 -1
  335. package/dist/Model.js +0 -4
  336. package/dist/Operations.d.ts +0 -55
  337. package/dist/Operations.d.ts.map +0 -1
  338. package/dist/Operations.js +0 -102
  339. package/dist/OperationsRepo.d.ts +0 -41
  340. package/dist/OperationsRepo.d.ts.map +0 -1
  341. package/dist/OperationsRepo.js +0 -14
  342. package/dist/QueueMaker/SQLQueue.d.ts +0 -16
  343. package/dist/QueueMaker/SQLQueue.d.ts.map +0 -1
  344. package/dist/QueueMaker/SQLQueue.js +0 -130
  345. package/dist/QueueMaker/memQueue.d.ts +0 -11
  346. package/dist/QueueMaker/memQueue.d.ts.map +0 -1
  347. package/dist/QueueMaker/memQueue.js +0 -76
  348. package/dist/QueueMaker/sbqueue.d.ts +0 -12
  349. package/dist/QueueMaker/sbqueue.d.ts.map +0 -1
  350. package/dist/QueueMaker/sbqueue.js +0 -91
  351. package/dist/QueueMaker/service.d.ts +0 -11
  352. package/dist/QueueMaker/service.d.ts.map +0 -1
  353. package/dist/QueueMaker/service.js +0 -4
  354. package/dist/RequestContext.d.ts +0 -63
  355. package/dist/RequestContext.d.ts.map +0 -1
  356. package/dist/RequestContext.js +0 -49
  357. package/dist/RequestFiberSet.d.ts +0 -36
  358. package/dist/RequestFiberSet.d.ts.map +0 -1
  359. package/dist/RequestFiberSet.js +0 -78
  360. package/dist/Store/ContextMapContainer.d.ts +0 -14
  361. package/dist/Store/ContextMapContainer.d.ts.map +0 -1
  362. package/dist/Store/ContextMapContainer.js +0 -16
  363. package/dist/Store/service.d.ts +0 -108
  364. package/dist/Store/service.d.ts.map +0 -1
  365. package/dist/Store/service.js +0 -71
  366. package/dist/Store.d.ts +0 -2
  367. package/dist/Store.d.ts.map +0 -1
  368. package/dist/Store.js +0 -2
  369. package/dist/adapters/SQL/Model.d.ts.map +0 -1
  370. package/dist/adapters/SQL/Model.js +0 -478
  371. package/dist/adapters/SQL.d.ts.map +0 -1
  372. package/dist/adapters/ServiceBus.d.ts +0 -58
  373. package/dist/adapters/ServiceBus.d.ts.map +0 -1
  374. package/dist/adapters/ServiceBus.js +0 -99
  375. package/dist/adapters/cosmos-client.d.ts +0 -14
  376. package/dist/adapters/cosmos-client.d.ts.map +0 -1
  377. package/dist/adapters/cosmos-client.js +0 -9
  378. package/dist/adapters/index.d.ts +0 -2
  379. package/dist/adapters/index.d.ts.map +0 -1
  380. package/dist/adapters/index.js +0 -2
  381. package/dist/adapters/logger.d.ts +0 -9
  382. package/dist/adapters/logger.d.ts.map +0 -1
  383. package/dist/adapters/logger.js +0 -3
  384. package/dist/adapters/memQueue.d.ts +0 -13
  385. package/dist/adapters/memQueue.d.ts.map +0 -1
  386. package/dist/adapters/memQueue.js +0 -20
  387. package/dist/adapters/mongo-client.d.ts.map +0 -1
  388. package/dist/adapters/mongo-client.js +0 -13
  389. package/dist/adapters/redis-client.d.ts.map +0 -1
  390. package/dist/adapters/redis-client.js +0 -94
  391. package/dist/api/ContextProvider.d.ts +0 -31
  392. package/dist/api/ContextProvider.d.ts.map +0 -1
  393. package/dist/api/ContextProvider.js +0 -38
  394. package/dist/api/codec.d.ts.map +0 -1
  395. package/dist/api/codec.js +0 -5
  396. package/dist/api/internal/RequestContextMiddleware.d.ts +0 -5
  397. package/dist/api/internal/RequestContextMiddleware.d.ts.map +0 -1
  398. package/dist/api/internal/RequestContextMiddleware.js +0 -35
  399. package/dist/api/internal/auth.d.ts +0 -15
  400. package/dist/api/internal/auth.d.ts.map +0 -1
  401. package/dist/api/internal/auth.js +0 -47
  402. package/dist/api/internal/events.d.ts +0 -9
  403. package/dist/api/internal/events.d.ts.map +0 -1
  404. package/dist/api/internal/events.js +0 -42
  405. package/dist/api/internal/health.d.ts.map +0 -1
  406. package/dist/api/internal/health.js +0 -5
  407. package/dist/api/layerUtils.d.ts.map +0 -1
  408. package/dist/api/layerUtils.js +0 -16
  409. package/dist/api/middlewares.d.ts.map +0 -1
  410. package/dist/api/reportError.d.ts.map +0 -1
  411. package/dist/api/reportError.js +0 -27
  412. package/dist/api/routing/middleware/RouterMiddleware.d.ts.map +0 -1
  413. package/dist/api/routing/middleware/middleware.d.ts +0 -9
  414. package/dist/api/routing/middleware/middleware.d.ts.map +0 -1
  415. package/dist/api/routing/middleware/middleware.js +0 -92
  416. package/dist/api/routing/middleware.d.ts.map +0 -1
  417. package/dist/api/routing/schema/jwt.d.ts.map +0 -1
  418. package/dist/api/routing/schema/jwt.js +0 -12
  419. package/dist/api/routing/tsort.d.ts.map +0 -1
  420. package/dist/api/routing/tsort.js +0 -51
  421. package/dist/api/routing/utils.d.ts.map +0 -1
  422. package/dist/api/routing/utils.js +0 -44
  423. package/dist/api/routing.d.ts +0 -138
  424. package/dist/api/routing.d.ts.map +0 -1
  425. package/dist/api/routing.js +0 -166
  426. package/dist/api/setupRequest.d.ts +0 -12
  427. package/dist/api/setupRequest.d.ts.map +0 -1
  428. package/dist/api/setupRequest.js +0 -44
  429. package/dist/api/util.d.ts.map +0 -1
  430. package/dist/api/util.js +0 -14
  431. package/eslint.config.mjs +0 -24
  432. package/src/Emailer/service.ts +0 -52
  433. package/src/Emailer.ts +0 -1
  434. package/src/Model/Repository/ext.ts +0 -283
  435. package/src/Model/Repository/internal/internal.ts +0 -577
  436. package/src/Model/Repository/legacy.ts +0 -27
  437. package/src/Model/Repository/makeRepo.ts +0 -139
  438. package/src/Model/Repository/service.ts +0 -627
  439. package/src/Model/Repository/validation.ts +0 -31
  440. package/src/Model/Repository.ts +0 -5
  441. package/src/Model/dsl.ts +0 -128
  442. package/src/Model/filter/filterApi.ts +0 -60
  443. package/src/Model/filter/types/errors.ts +0 -47
  444. package/src/Model/filter/types/fields.ts +0 -50
  445. package/src/Model/filter/types/path/common.ts +0 -404
  446. package/src/Model/filter/types/path/eager.ts +0 -298
  447. package/src/Model/filter/types/path/index.ts +0 -4
  448. package/src/Model/filter/types/utils.ts +0 -128
  449. package/src/Model/filter/types/validator.ts +0 -46
  450. package/src/Model/filter/types.ts +0 -6
  451. package/src/Model/query/dsl.ts +0 -2110
  452. package/src/Model/query/new-kid-interpreter.ts +0 -210
  453. package/src/Model/query.ts +0 -13
  454. package/src/Model.ts +0 -3
  455. package/src/Operations.ts +0 -235
  456. package/src/OperationsRepo.ts +0 -16
  457. package/src/QueueMaker/SQLQueue.ts +0 -189
  458. package/src/QueueMaker/memQueue.ts +0 -130
  459. package/src/QueueMaker/sbqueue.ts +0 -137
  460. package/src/QueueMaker/service.ts +0 -17
  461. package/src/RequestContext.ts +0 -63
  462. package/src/RequestFiberSet.ts +0 -105
  463. package/src/Store/ContextMapContainer.ts +0 -20
  464. package/src/Store/index.test.ts.bak +0 -112
  465. package/src/Store/service.ts +0 -184
  466. package/src/Store.ts +0 -1
  467. package/src/adapters/SQL.ts +0 -1
  468. package/src/adapters/ServiceBus.ts +0 -209
  469. package/src/adapters/cosmos-client.ts +0 -16
  470. package/src/adapters/index.ts +0 -0
  471. package/src/adapters/logger.ts +0 -3
  472. package/src/adapters/memQueue.ts +0 -21
  473. package/src/api/internal/auth.ts +0 -68
  474. package/src/api/middlewares.ts +0 -10
  475. package/src/api/routing/middleware/middleware.ts +0 -128
  476. package/src/api/routing/middleware.ts +0 -6
  477. package/src/api/routing.ts +0 -598
  478. package/src/api/setupRequest.ts +0 -84
  479. package/tsconfig.json.bak +0 -12
  480. /package/dist/{adapters/SQL.d.ts → SQL.d.ts} +0 -0
  481. /package/dist/{api/codec.d.ts → codec.d.ts} +0 -0
  482. /package/dist/{api/internal → internal}/health.d.ts +0 -0
  483. /package/dist/{api/middlewares.d.ts → middlewares.d.ts} +0 -0
  484. /package/dist/{api/routing → routing}/schema/jwt.d.ts +0 -0
  485. /package/dist/{api/routing → routing}/tsort.d.ts +0 -0
  486. /package/dist/{api/util.d.ts → util.d.ts} +0 -0
  487. /package/src/{api/codec.ts → codec.ts} +0 -0
  488. /package/src/{api/internal → internal}/health.ts +0 -0
  489. /package/src/{api/routing → routing}/tsort.ts +0 -0
  490. /package/src/{api/util.ts → util.ts} +0 -0
@@ -0,0 +1,806 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+
3
+ import type { NonEmptyReadonlyArray } from "effect-app/Array"
4
+ import { toNonEmptyArray } from "effect-app/Array"
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 * as Struct from "effect/Struct"
14
+ import { SqlClient } from "effect/unstable/sql"
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
+ */
54
+ export const parseRow = <Encoded extends FieldValues>(
55
+ row: { id: string; _etag: string | null; data: string },
56
+ idKey: PropertyKey,
57
+ defaultValues: Partial<Encoded>
58
+ ): PersistenceModelType<Encoded> => {
59
+ const data = (typeof row.data === "string" ? JSON.parse(row.data) : row.data) as object
60
+ const jsonDefaults = toJsonQueryValue(defaultValues) as Partial<Encoded>
61
+ return { ...jsonDefaults, ...data, [idKey]: row.id, _etag: row._etag ?? undefined } as PersistenceModelType<Encoded>
62
+ }
63
+
64
+ const parseSelectRow = (
65
+ row: Record<string, unknown>,
66
+ idKey: PropertyKey
67
+ ): any => {
68
+ const result: Record<string, unknown> = {}
69
+ for (const [key, value] of Object.entries(row)) {
70
+ if (key === "id") {
71
+ result[idKey as string] = value
72
+ result["id"] = value
73
+ } else if (typeof value === "string") {
74
+ try {
75
+ result[key] = JSON.parse(value)
76
+ } catch {
77
+ result[key] = value
78
+ }
79
+ } else {
80
+ result[key] = value
81
+ }
82
+ }
83
+ return result
84
+ }
85
+
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!`)
111
+ }
112
+ return namespace
113
+ }))
114
+
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
+ )
128
+
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
+ }
136
+
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
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
+ })
178
+
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
+ )
186
+
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])
234
+ .pipe(
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
243
+ })
244
+ )
245
+ })
246
+ ),
247
+
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])
253
+ .pipe(
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
+ })
266
+ )
267
+ })
268
+ ),
269
+
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
+ })
308
+ .pipe(
309
+ Effect
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[]
330
+ )
331
+ })
332
+ )
333
+ ),
334
+ annotateDb({
335
+ operation: "filter",
336
+ system,
337
+ collection: tableName,
338
+ namespace: ns,
339
+ entity: name
340
+ })
341
+ )
342
+ ))
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))`
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
+ })
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
+ })
530
+
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
+ ))
539
+
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
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
773
+ })
774
+ }
775
+ }
776
+
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
+ }
804
+ return StoreMaker
805
+ .toLayer(makeSQLStoreInt("sqlite", sqliteDialect, "JSON")(cfg))
806
+ }