@effect-app/infra 4.0.0-beta.32 → 4.0.0-beta.321

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