@effect-app/infra 4.0.0-beta.31 → 4.0.0-beta.310

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