@effect-app/infra 4.0.0-beta.27 → 4.0.0-beta.272

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