@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
@@ -1,15 +1,24 @@
1
1
  /* eslint-disable @typescript-eslint/no-explicit-any */
2
2
 
3
- import { Array, Duration, Effect, Layer, type NonEmptyReadonlyArray, Option, pipe, Redacted, Struct } from "effect-app"
3
+ import * as Array from "effect-app/Array"
4
+ import type { NonEmptyReadonlyArray } from "effect-app/Array"
4
5
  import { toNonEmptyArray } from "effect-app/Array"
6
+ import * as Effect from "effect-app/Effect"
7
+ import * as Layer from "effect-app/Layer"
8
+ import type { FieldValues } from "effect-app/Model/filter/types"
9
+ import { type ComputedProjectionIrExpression, type RawQuery } from "effect-app/Model/query"
10
+ import * as Option from "effect-app/Option"
11
+ import { type FilterArgs, type PersistenceModelType, type StorageConfig, type Store, type StoreConfig, storeId, StoreMaker } from "effect-app/Store"
5
12
  import { dropUndefinedT, mutable } from "effect-app/utils"
6
- import { CosmosClient, CosmosClientLayer } from "../adapters/cosmos-client.js"
7
- import { OptimisticConcurrencyException } from "../errors.js"
8
- import { InfraLogger } from "../logger.js"
9
- import type { FieldValues } from "../Model/filter/types.js"
10
- import { type RawQuery } from "../Model/query.js"
11
- import { buildWhereCosmosQuery3, logQuery } from "./Cosmos/query.js"
12
- import { type FilterArgs, type PersistenceModelType, type StorageConfig, type Store, type StoreConfig, StoreMaker } from "./service.js"
13
+ import * as Duration from "effect/Duration"
14
+ import { pipe } from "effect/Function"
15
+ import * as Redacted from "effect/Redacted"
16
+ import * as Struct from "effect/Struct"
17
+ import { CosmosClient, CosmosClientLayer } from "../cosmos-client.ts"
18
+ import { DatabaseError, OptimisticConcurrencyException } from "../errors.ts"
19
+ import { InfraLogger } from "../logger.ts"
20
+ import { annotateCosmosResponse, annotateDb } from "../otel.ts"
21
+ import { buildWhereCosmosQuery3, logQuery } from "./Cosmos/query.ts"
13
22
 
14
23
  const makeMapId =
15
24
  <IdKey extends keyof Encoded, Encoded extends FieldValues>(idKey: IdKey) => ({ [idKey]: id, ...e }: Encoded) => ({
@@ -21,152 +30,281 @@ const makeReverseMapId =
21
30
  ({ id, ...t }: PersistenceModelType<Omit<Encoded, IdKey> & { id: string }>) =>
22
31
  ({ ...t, [idKey]: id }) as any as PersistenceModelType<Encoded>
23
32
 
24
- class CosmosDbOperationError {
25
- constructor(readonly message: string, readonly raw?: unknown) {}
26
- } // TODO: Retry operation when running into RU limit.
33
+ // Cosmos statuses worth retrying: request timeout, throttle, retry-with,
34
+ // internal, and service unavailable.
35
+ const RETRYABLE_COSMOS_STATUS = new Set([408, 429, 449, 500, 503])
36
+ const statusIsTransient = (code: number) => RETRYABLE_COSMOS_STATUS.has(code)
27
37
 
28
- function makeCosmosStore({ prefix }: StorageConfig) {
29
- return Effect.gen(function*() {
30
- const { db } = yield* CosmosClient
31
- return {
32
- make: <IdKey extends keyof Encoded, Encoded extends FieldValues, R = never, E = never>(
33
- name: string,
34
- idKey: IdKey,
35
- seed?: Effect.Effect<Iterable<Encoded>, E, R>,
36
- config?: StoreConfig<Encoded>
37
- ) =>
38
- Effect.gen(function*() {
39
- const mapId = makeMapId<IdKey, Encoded>(idKey)
40
- const mapReverseId = makeReverseMapId<IdKey, Encoded>(idKey)
41
- type PM = PersistenceModelType<Encoded>
42
- type PMCosmos = PersistenceModelType<Omit<Encoded, IdKey> & { id: string }>
43
- const containerId = `${prefix}${name}`
44
- yield* Effect.promise(() =>
45
- db.containers.createIfNotExists(dropUndefinedT({
46
- id: containerId,
47
- uniqueKeyPolicy: config?.uniqueKeys
48
- ? { uniqueKeys: config.uniqueKeys }
49
- : undefined
50
- }))
51
- )
38
+ // A thrown SDK error is transient if its status/code is retryable or its message
39
+ // looks like a timeout / throttle / dropped connection.
40
+ const thrownIsTransient = (e: unknown): boolean => {
41
+ const code = (e as any)?.code ?? (e as any)?.statusCode
42
+ if (typeof code === "number" && RETRYABLE_COSMOS_STATUS.has(code)) return true
43
+ const msg = e instanceof Error ? e.message : String(e)
44
+ return /request timed out|timed out|\btimeout\b|ETIMEDOUT|ECONNRESET|ECONNREFUSED|EAI_AGAIN|socket hang up|ServiceUnavailable|RequestTimeout|TooManyRequests|throttl/i
45
+ .test(msg)
46
+ }
52
47
 
53
- const mainPartitionKey = config?.partitionValue() ?? "primary"
48
+ // Wrap a Cosmos SDK promise so a rejection becomes a typed, serializable
49
+ // `DatabaseError` (transient-classified) instead of a bare-`Error` defect — the
50
+ // latter both bypasses retry and breaks JSON encoding of the failure channel.
51
+ const tryCosmos = <A>(f: () => Promise<A>): Effect.Effect<A, DatabaseError> =>
52
+ Effect.tryPromise({
53
+ try: f,
54
+ catch: (e) =>
55
+ new DatabaseError({
56
+ message: `Cosmos request failed: ${e instanceof Error ? e.message : String(e)}`,
57
+ transient: thrownIsTransient(e),
58
+ cause: e
59
+ })
60
+ })
54
61
 
55
- const defaultValues = config?.defaultValues ?? {}
56
- const container = db.container(containerId)
57
- const bulk = container.items.bulk.bind(container.items)
58
- const execBatch = container.items.batch.bind(container.items)
59
- // TODO: move the marker to a separate container and get rid of the checks on every query
60
- // then need to clean up the actual data.. perhaps first do with a config toggle to prescribe to it.
61
- const importedMarkerId = containerId
62
+ const respBytes = (
63
+ resp: { diagnostics?: { clientSideRequestStatistics?: { totalResponsePayloadLengthInBytes?: number } } }
64
+ ) => resp.diagnostics?.clientSideRequestStatistics?.totalResponsePayloadLengthInBytes ?? 0
62
65
 
63
- const bulkSet = (items: NonEmptyReadonlyArray<PM>) =>
64
- Effect
65
- .gen(function*() {
66
- // TODO: disable batching if need atomicity
67
- // we delay and batch to keep low amount of RUs
68
- const b = [...items]
69
- .map(
70
- (x) =>
71
- [
72
- x,
73
- Option.match(Option.fromNullishOr(x._etag), {
74
- onNone: () =>
75
- dropUndefinedT({
76
- operationType: "Create" as const,
77
- resourceBody: {
78
- ...Struct.omit(x, ["_etag", idKey]),
79
- id: x[idKey],
80
- _partitionKey: config?.partitionValue(x)
81
- }
82
- // don't use this or we get an error that the request and some item partition key dont match - makese no sense
83
- // partitionKey: config?.partitionValue(x)
84
- }),
85
- onSome: (eTag) =>
86
- dropUndefinedT({
87
- operationType: "Replace" as const,
88
- id: x[idKey],
89
- resourceBody: {
90
- ...Struct.omit(x, ["_etag", idKey]),
91
- id: x[idKey],
92
- _partitionKey: config?.partitionValue(x)
93
- },
94
- ifMatch: eTag
95
- // don't use this or we get an error that the request and some item partition key dont match - makese no sense
96
- // partitionKey: config?.partitionValue(x)
97
- })
98
- })
99
- ] as const
66
+ const annotateFeed = (resp: {
67
+ resources: readonly unknown[]
68
+ requestCharge?: number
69
+ diagnostics?: { clientSideRequestStatistics?: { totalResponsePayloadLengthInBytes?: number } }
70
+ }) =>
71
+ annotateCosmosResponse({
72
+ requestCharge: resp.requestCharge,
73
+ returnedRows: resp.resources.length,
74
+ responseBytes: respBytes(resp)
75
+ })
76
+
77
+ const annotateItem = (resp: {
78
+ requestCharge?: number
79
+ statusCode?: number
80
+ diagnostics?: { clientSideRequestStatistics?: { totalResponsePayloadLengthInBytes?: number } }
81
+ }) =>
82
+ annotateCosmosResponse({
83
+ requestCharge: resp.requestCharge,
84
+ statusCode: resp.statusCode,
85
+ responseBytes: respBytes(resp)
86
+ })
87
+
88
+ const makeCosmosStore = Effect.fnUntraced(function*({ prefix }: StorageConfig) {
89
+ const { db } = yield* CosmosClient
90
+ return {
91
+ make: Effect.fnUntraced(function*<IdKey extends keyof Encoded, Encoded extends FieldValues, R = never, E = never>(
92
+ name: string,
93
+ idKey: IdKey,
94
+ seed?: Effect.Effect<Iterable<Encoded>, E, R>,
95
+ config?: StoreConfig<Encoded>
96
+ ) {
97
+ const mapId = makeMapId<IdKey, Encoded>(idKey)
98
+ const mapReverseId = makeReverseMapId<IdKey, Encoded>(idKey)
99
+ type PM = PersistenceModelType<Encoded>
100
+ type PMCosmos = PersistenceModelType<Omit<Encoded, IdKey> & { id: string }>
101
+ const containerId = `${prefix}${name}`
102
+ yield* Effect.promise(() =>
103
+ db.containers.createIfNotExists(dropUndefinedT({
104
+ id: containerId,
105
+ uniqueKeyPolicy: config?.uniqueKeys
106
+ ? { uniqueKeys: config.uniqueKeys }
107
+ : undefined,
108
+ partitionKey: {
109
+ paths: ["/_partitionKey"],
110
+ version: 2 // support large partitionkeys so that the hash is not based on just the first 100 bytes!
111
+ }
112
+ }))
113
+ )
114
+
115
+ const basePartitionKey = config?.partitionValue() ?? "primary"
116
+ const nsPrefix = (ns: string) => ns === "primary" ? "" : `${ns}::`
117
+ const nsPartitionValue = (ns: string, e?: Encoded) => {
118
+ const base = config?.partitionValue(e) ?? "primary"
119
+ return `${nsPrefix(ns)}${base}`
120
+ }
121
+ const nsBasePartitionKey = (ns: string) => `${nsPrefix(ns)}${basePartitionKey}`
122
+ const resolveNamespace = !config?.allowNamespace
123
+ ? Effect.succeed("primary")
124
+ : storeId.pipe(Effect.map((namespace) => {
125
+ if (namespace !== "primary" && !config.allowNamespace!(namespace)) {
126
+ throw new Error(`Namespace ${namespace} not allowed!`)
127
+ }
128
+ return namespace
129
+ }))
130
+
131
+ const defaultValues = config?.defaultValues ?? {}
132
+ const container = db.container(containerId)
133
+ const bulk = container.items.bulk.bind(container.items)
134
+ const execBatch = container.items.batch.bind(container.items)
135
+ // TODO: move the marker to a separate container and get rid of the checks on every query
136
+ // then need to clean up the actual data.. perhaps first do with a config toggle to prescribe to it.
137
+ const importedMarkerId = containerId
138
+
139
+ const ctx = yield* Effect.context<R>()
140
+ const seedCache = new Map<string, Effect.Effect<void>>()
141
+ const makeSeedEffect = (ns: string) => {
142
+ const markerId = ns === "primary" ? importedMarkerId : `${importedMarkerId}::${ns}`
143
+ return Effect
144
+ .promise(() =>
145
+ container
146
+ .item(markerId, markerId)
147
+ .read<{ id: string }>()
148
+ .then(({ resource }) => Option.fromNullishOr(resource))
149
+ )
150
+ .pipe(
151
+ Effect.flatMap((marker) => {
152
+ if (Option.isSome(marker)) return Effect.void
153
+ return InfraLogger.logInfo(`Creating mock data for ${name} (namespace: ${ns})`).pipe(
154
+ Effect.andThen(seed!),
155
+ Effect.flatMap((m) =>
156
+ Effect.flatMapOption(
157
+ Effect.succeed(toNonEmptyArray([...m])),
158
+ (a) => bulkSetInternal(a, ns).pipe(Effect.orDie)
100
159
  )
101
- const batches = Array.chunksOf(b, config?.maxBulkSize ?? 10)
160
+ ),
161
+ Effect.andThen(
162
+ Effect.promise(() =>
163
+ container.items.create({
164
+ _partitionKey: markerId,
165
+ id: markerId,
166
+ ttl: -1
167
+ })
168
+ )
169
+ ),
170
+ Effect.provide(ctx),
171
+ Effect.orDie
172
+ )
173
+ }),
174
+ Effect.withLogSpan(`Cosmos.seedCheck ${name} in ${ns} [effect-app/infra/Store]`),
175
+ annotateDb({
176
+ operation: "seed",
177
+ system: "cosmosdb",
178
+ collection: containerId,
179
+ namespace: ns,
180
+ entity: name
181
+ })
182
+ )
183
+ }
184
+ const seedNamespace = Effect.fn("seedNamespace")(function*(ns: string) {
185
+ if (!seed) return
186
+ let cached = seedCache.get(ns)
187
+ if (!cached) {
188
+ cached = yield* Effect.cached(Effect.uninterruptible(makeSeedEffect(ns)))
189
+ seedCache.set(ns, cached)
190
+ }
191
+ yield* cached
192
+ })
193
+ const bulkSetInternal = (items: NonEmptyReadonlyArray<PM>, ns: string) =>
194
+ Effect
195
+ .gen(function*() {
196
+ // TODO: disable batching if need atomicity
197
+ // we delay and batch to keep low amount of RUs
198
+ const b = [...items]
199
+ .map(
200
+ (x) =>
201
+ [
202
+ x,
203
+ Option.match(Option.fromNullishOr(x._etag), {
204
+ onNone: () =>
205
+ dropUndefinedT({
206
+ operationType: "Create" as const,
207
+ resourceBody: {
208
+ ...Struct.omit(x, ["_etag", idKey]),
209
+ id: x[idKey],
210
+ _partitionKey: nsPartitionValue(ns, x)
211
+ }
212
+ // don't use this or we get an error that the request and some item partition key dont match - makese no sense
213
+ // partitionKey: config?.partitionValue(x)
214
+ }),
215
+ onSome: (eTag) =>
216
+ dropUndefinedT({
217
+ operationType: "Replace" as const,
218
+ id: x[idKey],
219
+ resourceBody: {
220
+ ...Struct.omit(x, ["_etag", idKey]),
221
+ id: x[idKey],
222
+ _partitionKey: nsPartitionValue(ns, x)
223
+ },
224
+ ifMatch: eTag
225
+ // don't use this or we get an error that the request and some item partition key dont match - makese no sense
226
+ // partitionKey: config?.partitionValue(x)
227
+ })
228
+ })
229
+ ] as const
230
+ )
231
+ const batches = Array.chunksOf(b, config?.maxBulkSize ?? 10)
102
232
 
103
- const batchResult = yield* Effect.forEach(
104
- batches
105
- .map((x, i) => [i, x] as const),
106
- ([i, batch]) =>
233
+ const batchResult = yield* Effect.forEach(
234
+ batches
235
+ .map((x, i) => [i, x] as const),
236
+ ([i, batch]) =>
237
+ tryCosmos(() => bulk(batch.map(([, op]) => op)))
238
+ .pipe(
107
239
  Effect
108
- .promise(() => bulk(batch.map(([, op]) => op)))
109
- .pipe(
110
- Effect
111
- .delay(Duration.millis(i === 0 ? 0 : 1100)),
112
- Effect
113
- .flatMap((responses) =>
114
- Effect.gen(function*() {
115
- const r = responses.find((x) =>
116
- x.statusCode === 412 || x.statusCode === 404 || x.statusCode === 409
117
- )
118
- if (r) {
119
- return yield* Effect.fail(
120
- new OptimisticConcurrencyException(
121
- {
122
- type: name,
123
- id: JSON.stringify(r.resourceBody?.["id"]),
124
- code: r.statusCode,
125
- raw: responses
126
- }
127
- )
128
- )
129
- }
130
- const r2 = responses.find(
131
- (x) => x.statusCode !== 424 && (x.statusCode > 299 || x.statusCode < 200)
132
- )
133
- if (r2) {
134
- return yield* Effect.die(
135
- new CosmosDbOperationError(
136
- "not able to update records: " + r2.statusCode,
137
- responses
138
- )
139
- )
140
- }
141
- const r3 = responses.find(
142
- (x) => x.statusCode > 299 || x.statusCode < 200
240
+ .delay(Duration.millis(i === 0 ? 0 : 150)),
241
+ Effect
242
+ .flatMap((responses) =>
243
+ Effect.gen(function*() {
244
+ const r = responses.find((x) =>
245
+ x.statusCode === 412 || x.statusCode === 404 || x.statusCode === 409
246
+ )
247
+ if (r) {
248
+ return yield* Effect.fail(
249
+ new OptimisticConcurrencyException(
250
+ {
251
+ type: name,
252
+ id: JSON.stringify(r.resourceBody?.["id"]),
253
+ code: r.statusCode,
254
+ raw: responses
255
+ }
143
256
  )
144
- if (r3) {
145
- return yield* Effect.die(
146
- new CosmosDbOperationError(
147
- "not able to update records: " + r3.statusCode,
148
- responses
149
- )
150
- )
151
- }
152
- return batch.map(([e], i) => ({
153
- ...e,
154
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
155
- _etag: responses[i]!.eTag
156
- }))
257
+ )
258
+ }
259
+ const r2 = responses.find(
260
+ (x) => x.statusCode !== 424 && (x.statusCode > 299 || x.statusCode < 200)
261
+ )
262
+ if (r2) {
263
+ return yield* new DatabaseError({
264
+ message: "not able to update records: " + r2.statusCode,
265
+ transient: statusIsTransient(r2.statusCode),
266
+ cause: responses
157
267
  })
268
+ }
269
+ const r3 = responses.find(
270
+ (x) => x.statusCode > 299 || x.statusCode < 200
158
271
  )
272
+ if (r3) {
273
+ return yield* new DatabaseError({
274
+ message: "not able to update records: " + r3.statusCode,
275
+ transient: statusIsTransient(r3.statusCode),
276
+ cause: responses
277
+ })
278
+ }
279
+ return batch.map(([e], i) => ({
280
+ ...e,
281
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
282
+ _etag: responses[i]!.eTag
283
+ }))
284
+ })
159
285
  )
160
- )
286
+ )
287
+ )
161
288
 
162
- return batchResult.flat() as unknown as NonEmptyReadonlyArray<Encoded>
163
- })
164
- .pipe(Effect.withSpan("Cosmos.bulkSet [effect-app/infra/Store]", {
165
- attributes: { "repository.container_id": containerId, "repository.model_name": name }
166
- }, { captureStackTrace: false }))
289
+ return batchResult.flat() as unknown as NonEmptyReadonlyArray<Encoded>
290
+ })
291
+ .pipe(
292
+ annotateDb({
293
+ operation: "bulkSet",
294
+ system: "cosmosdb",
295
+ collection: containerId,
296
+ namespace: ns,
297
+ entity: name
298
+ })
299
+ )
167
300
 
168
- const batchSet = (items: NonEmptyReadonlyArray<PM>) => {
169
- return Effect
301
+ const bulkSet = (items: NonEmptyReadonlyArray<PM>) =>
302
+ resolveNamespace.pipe(Effect.flatMap((ns) => bulkSetInternal(items, ns)))
303
+
304
+ const batchSet = (items: NonEmptyReadonlyArray<PM>) => {
305
+ return resolveNamespace
306
+ .pipe(Effect.flatMap((ns) =>
307
+ Effect
170
308
  .suspend(() => {
171
309
  const batch = [...items].map(
172
310
  (x) =>
@@ -178,7 +316,7 @@ function makeCosmosStore({ prefix }: StorageConfig) {
178
316
  resourceBody: {
179
317
  ...Struct.omit(x, ["_etag", idKey]),
180
318
  id: x[idKey],
181
- _partitionKey: config?.partitionValue(x)
319
+ _partitionKey: nsPartitionValue(ns, x)
182
320
  }
183
321
  // don't use this or we get an error that the request and some item partition key dont match - makese no sense
184
322
  // partitionKey: config?.partitionValue(x)
@@ -189,7 +327,7 @@ function makeCosmosStore({ prefix }: StorageConfig) {
189
327
  resourceBody: {
190
328
  ...Struct.omit(x, ["_etag", idKey]),
191
329
  id: x[idKey],
192
- _partitionKey: config?.partitionValue(x)
330
+ _partitionKey: nsPartitionValue(ns, x)
193
331
  },
194
332
  // don't use this or we get an error that the request and some item partition key dont match - makese no sense
195
333
  // partitionKey: config?.partitionValue(x)
@@ -201,8 +339,7 @@ function makeCosmosStore({ prefix }: StorageConfig) {
201
339
 
202
340
  const ex = batch.map(([, c]) => c)
203
341
 
204
- return Effect
205
- .promise(() => execBatch(ex, ex[0]?.resourceBody._partitionKey))
342
+ return tryCosmos(() => execBatch(ex, ex[0]?.resourceBody._partitionKey))
206
343
  .pipe(Effect.flatMap(Effect.fnUntraced(function*(x) {
207
344
  const result = x.result ?? []
208
345
  const firstFailed = result.find(
@@ -214,9 +351,11 @@ function makeCosmosStore({ prefix }: StorageConfig) {
214
351
  return yield* new OptimisticConcurrencyException({ type: name, id: "batch", code })
215
352
  }
216
353
 
217
- return yield* Effect.die(
218
- new CosmosDbOperationError("not able to update record: " + code)
219
- )
354
+ return yield* new DatabaseError({
355
+ message: "not able to update record: " + code,
356
+ transient: statusIsTransient(code),
357
+ cause: x
358
+ })
220
359
  }
221
360
 
222
361
  return batch.map(([e], i) => ({
@@ -225,249 +364,274 @@ function makeCosmosStore({ prefix }: StorageConfig) {
225
364
  })) as unknown as NonEmptyReadonlyArray<Encoded>
226
365
  })))
227
366
  })
228
- .pipe(Effect
229
- .withSpan("Cosmos.batchSet [effect-app/infra/Store]", {
230
- attributes: { "repository.container_id": containerId, "repository.model_name": name }
231
- }, { captureStackTrace: false }))
232
- }
367
+ .pipe(annotateDb({
368
+ operation: "batchSet",
369
+ system: "cosmosdb",
370
+ collection: containerId,
371
+ namespace: ns,
372
+ entity: name
373
+ }))
374
+ ))
375
+ }
233
376
 
234
- const s: Store<IdKey, Encoded> = {
235
- queryRaw: <Out>(query: RawQuery<Encoded, Out>) =>
236
- Effect
237
- .sync(() => query.cosmos({ name }))
238
- .pipe(
239
- Effect.tap((q) => logQuery(q)),
240
- Effect.flatMap((q) =>
241
- Effect.promise(() =>
242
- container
243
- .items
244
- .query<Out>(q, { partitionKey: mainPartitionKey })
245
- .fetchAll()
246
- .then(({ resources }) =>
247
- resources.map(
248
- (_) => ({ ...defaultValues, ...mapReverseId(_ as any) }) as Out
249
- )
250
- )
377
+ const s: Store<IdKey, Encoded> = {
378
+ seedNamespace: (ns) => seedNamespace(ns),
379
+
380
+ queryRaw: <Out>(query: RawQuery<Encoded, Out>) =>
381
+ Effect
382
+ .all({ q: Effect.sync(() => query.cosmos({ name })), ns: resolveNamespace })
383
+ .pipe(
384
+ Effect.tap(({ q }) => logQuery(q)),
385
+ Effect.flatMap(({ ns, q }) =>
386
+ Effect
387
+ .gen(function*() {
388
+ const response = yield* tryCosmos(() =>
389
+ container.items.query<Out>(q, { partitionKey: nsBasePartitionKey(ns) }).fetchAll()
251
390
  )
252
- ),
253
- Effect
254
- .withSpan("Cosmos.queryRaw [effect-app/infra/Store]", {
255
- attributes: { "repository.container_id": containerId, "repository.model_name": name }
256
- }, { captureStackTrace: false })
257
- ),
258
- batchRemove: (ids, partitionKey?: string) =>
259
- Effect.promise(() =>
260
- execBatch(
261
- mutable(ids.map((id) =>
262
- dropUndefinedT({
263
- operationType: "Delete" as const,
264
- id
265
- // don't use this or we get an error that the request and some item partition key dont match - makese no sense
266
- // partitionKey: config?.partitionValue({ [idKey]: id } as Encoded)
391
+ yield* annotateFeed(response)
392
+ return response.resources.map(
393
+ (_) => ({ ...defaultValues, ...mapReverseId(_ as any) }) as Out
394
+ )
395
+ })
396
+ .pipe(
397
+ annotateDb({
398
+ operation: "queryRaw",
399
+ system: "cosmosdb",
400
+ collection: containerId,
401
+ namespace: ns,
402
+ entity: name,
403
+ query: q.query
267
404
  })
268
- )),
269
- partitionKey ?? mainPartitionKey
270
- )
271
- ),
272
- all: Effect
273
- .sync(() => ({
274
- query: `SELECT * FROM ${name}`,
275
- parameters: []
276
- }))
277
- .pipe(
278
- Effect.tap((q) => logQuery(q)),
279
- Effect.flatMap((q) =>
280
- Effect.promise(() =>
281
- container
282
- .items
283
- .query<PMCosmos>(q, { partitionKey: mainPartitionKey })
284
- .fetchAll()
285
- .then(({ resources }) =>
286
- resources.map(
287
- (_) => ({ ...defaultValues, ...mapReverseId(_) })
288
- )
289
- )
290
405
  )
291
- ),
292
- Effect
293
- .withSpan("Cosmos.all [effect-app/infra/Store]", {
294
- attributes: { "repository.container_id": containerId, "repository.model_name": name }
295
- }, { captureStackTrace: false })
296
- ),
297
- /**
298
- * May return duplicate results for "join_find", when matching more than once.
299
- */
300
- filter: <U extends keyof Encoded = never>(
301
- f: FilterArgs<Encoded, U>
302
- ) => {
303
- const skip = f?.skip
304
- const limit = f?.limit
305
- const filter = f.filter
306
- type M = U extends undefined ? Encoded : Pick<Encoded, U>
307
- return Effect
308
- .sync(() =>
309
- buildWhereCosmosQuery3(
310
- idKey,
311
- filter ? [{ t: "where-scope", result: filter, relation: "some" }] : [],
312
- name,
313
- defaultValues,
314
- f.select as NonEmptyReadonlyArray<string | { key: string; subKeys: readonly string[] }> | undefined,
315
- f.order as NonEmptyReadonlyArray<{ key: string; direction: "ASC" | "DESC" }> | undefined,
316
- skip,
317
- limit
406
+ )
407
+ ),
408
+ batchRemove: (ids, partitionKey?: string) =>
409
+ resolveNamespace.pipe(Effect.flatMap((ns) =>
410
+ tryCosmos(() =>
411
+ execBatch(
412
+ mutable(ids.map((id) =>
413
+ dropUndefinedT({
414
+ operationType: "Delete" as const,
415
+ id
416
+ // don't use this or we get an error that the request and some item partition key dont match - makese no sense
417
+ // partitionKey: config?.partitionValue({ [idKey]: id } as Encoded)
418
+ })
419
+ )),
420
+ partitionKey ?? nsBasePartitionKey(ns)
421
+ )
422
+ )
423
+ .pipe(
424
+ annotateDb({
425
+ operation: "batchRemove",
426
+ system: "cosmosdb",
427
+ collection: containerId,
428
+ namespace: ns,
429
+ entity: name
430
+ })
431
+ )
432
+ )),
433
+ all: Effect
434
+ .all({
435
+ q: Effect.sync(() => ({
436
+ query: `SELECT * FROM ${name}`,
437
+ parameters: []
438
+ })),
439
+ ns: resolveNamespace
440
+ })
441
+ .pipe(
442
+ Effect.tap(({ q }) => logQuery(q)),
443
+ Effect.flatMap(({ ns, q }) =>
444
+ Effect
445
+ .gen(function*() {
446
+ const response = yield* tryCosmos(() =>
447
+ container.items.query<PMCosmos>(q, { partitionKey: nsBasePartitionKey(ns) }).fetchAll()
318
448
  )
319
- )
449
+ yield* annotateFeed(response)
450
+ return response.resources.map((_) => ({ ...defaultValues, ...mapReverseId(_) }))
451
+ })
320
452
  .pipe(
321
- Effect.tap((q) => logQuery(q)),
453
+ annotateDb({
454
+ operation: "all",
455
+ system: "cosmosdb",
456
+ collection: containerId,
457
+ namespace: ns,
458
+ entity: name,
459
+ query: q.query
460
+ })
461
+ )
462
+ )
463
+ ),
464
+ /**
465
+ * May return duplicate results for "join_find", when matching more than once.
466
+ */
467
+ filter: <U extends keyof Encoded = never>(
468
+ f: FilterArgs<Encoded, U>
469
+ ) => {
470
+ const skip = f?.skip
471
+ const limit = f?.limit
472
+ const filter = f.filter
473
+ type M = U extends undefined ? Encoded : Pick<Encoded, U>
474
+ return Effect
475
+ .all({
476
+ q: Effect.sync(() =>
477
+ buildWhereCosmosQuery3(
478
+ idKey,
479
+ filter ? [{ t: "where-scope", result: filter, relation: "some" }] : [],
480
+ name,
481
+ defaultValues,
482
+ f.select as
483
+ | NonEmptyReadonlyArray<
484
+ string | {
485
+ key: string
486
+ subKeys: readonly string[]
487
+ } | {
488
+ key: string
489
+ computed: ComputedProjectionIrExpression
490
+ }
491
+ >
492
+ | undefined,
493
+ f.order as NonEmptyReadonlyArray<{ key: string; direction: "ASC" | "DESC" }> | undefined,
494
+ skip,
495
+ limit
496
+ )
497
+ ),
498
+ ns: resolveNamespace
499
+ })
500
+ .pipe(
501
+ Effect.tap(({ q }) => logQuery(q)),
502
+ Effect
503
+ .flatMap(({ ns, q }) =>
322
504
  Effect
323
- .flatMap((q) =>
324
- Effect.promise(() =>
325
- f.select
326
- ? container
327
- .items
328
- .query<M>(q, { partitionKey: mainPartitionKey })
329
- .fetchAll()
330
- .then(({ resources }) =>
331
- resources.map((_) => ({
332
- ...pipe(
333
- defaultValues,
334
- Struct.pick(f.select!.filter((_) => typeof _ === "string") as never[])
335
- ),
336
- ...mapReverseId(_ as any)
337
- }))
338
- )
339
- : container
340
- .items
341
- .query<{ f: M }>(q, { partitionKey: mainPartitionKey })
342
- .fetchAll()
343
- .then(({ resources }) =>
344
- resources.map(({ f }) => ({ ...defaultValues, ...mapReverseId(f as any) }) as any)
345
- )
505
+ .gen(function*() {
506
+ if (f.select) {
507
+ const response = yield* tryCosmos(() =>
508
+ container.items.query<M>(q, { partitionKey: nsBasePartitionKey(ns) }).fetchAll()
509
+ )
510
+ yield* annotateFeed(response)
511
+ return response.resources.map((_) => ({
512
+ ...pipe(
513
+ defaultValues,
514
+ Struct.pick(f.select!.filter((_) => typeof _ === "string") as never[])
515
+ ),
516
+ ...mapReverseId(_ as any)
517
+ }))
518
+ }
519
+ const response = yield* tryCosmos(() =>
520
+ container.items.query<{ f: M }>(q, { partitionKey: nsBasePartitionKey(ns) }).fetchAll()
346
521
  )
522
+ yield* annotateFeed(response)
523
+ return response.resources.map(({ f }) => ({ ...defaultValues, ...mapReverseId(f as any) }) as any)
524
+ })
525
+ .pipe(
526
+ annotateDb({
527
+ operation: "filter",
528
+ system: "cosmosdb",
529
+ collection: containerId,
530
+ namespace: ns,
531
+ entity: name,
532
+ query: q.query
533
+ })
347
534
  )
348
535
  )
349
- .pipe(
350
- Effect.withSpan("Cosmos.filter [effect-app/infra/Store]", {
351
- attributes: { "repository.container_id": containerId, "repository.model_name": name }
352
- }, { captureStackTrace: false })
353
- )
354
- },
355
- find: (id) =>
356
- Effect
357
- .promise(() =>
536
+ )
537
+ },
538
+ find: (id) =>
539
+ resolveNamespace.pipe(Effect.flatMap((ns) =>
540
+ Effect
541
+ .gen(function*() {
542
+ const response = yield* tryCosmos(() =>
358
543
  container
359
- .item(id, config?.partitionValue({ [idKey]: id } as Encoded))
544
+ .item(id, nsPartitionValue(ns, { [idKey]: id } as Encoded))
360
545
  .read<Encoded>()
361
- .then(({ resource }) =>
362
- Option.fromNullishOr(resource).pipe(Option.map((_) => ({ ...defaultValues, ...mapReverseId(_) })))
363
- )
364
546
  )
365
- .pipe(Effect
366
- .withSpan("Cosmos.find [effect-app/infra/Store]", {
367
- attributes: {
368
- "repository.container_id": containerId,
369
- "repository.model_name": name,
370
- partitionValue: config?.partitionValue({ [idKey]: id } as Encoded),
371
- id
372
- }
373
- }, { captureStackTrace: false })),
374
- set: (e) =>
547
+ yield* annotateItem(response)
548
+ return Option.fromNullishOr(response.resource).pipe(
549
+ Option.map((_) => ({ ...defaultValues, ...mapReverseId(_) }))
550
+ )
551
+ })
552
+ .pipe(annotateDb({
553
+ operation: "find",
554
+ system: "cosmosdb",
555
+ collection: containerId,
556
+ namespace: ns,
557
+ entity: name,
558
+ extra: {
559
+ "azure.cosmosdb.operation.partition_key": nsPartitionValue(ns, { [idKey]: id } as Encoded),
560
+ "app.entity.id": id
561
+ }
562
+ }))
563
+ )),
564
+ set: (e) =>
565
+ resolveNamespace.pipe(Effect.flatMap((ns) =>
566
+ // Annotate the result so the create/replace promise union collapses to
567
+ // one type (otherwise `A` infers as `unknown` and the chain degrades).
568
+ tryCosmos((): Promise<{ statusCode: number; etag: string }> =>
375
569
  Option
376
570
  .match(
377
571
  Option
378
572
  .fromNullishOr(e._etag),
379
573
  {
380
574
  onNone: () =>
381
- Effect.promise(() =>
382
- container.items.create({
383
- ...mapId(e),
384
- _partitionKey: config?.partitionValue(e)
385
- })
386
- ),
575
+ container.items.create({
576
+ ...mapId(e),
577
+ _partitionKey: nsPartitionValue(ns, e)
578
+ }),
387
579
  onSome: (eTag) =>
388
- Effect.promise(() =>
389
- container.item(e[idKey], config?.partitionValue(e)).replace(
390
- { ...mapId(e), _partitionKey: config?.partitionValue(e) },
391
- {
392
- accessCondition: {
393
- type: "IfMatch",
394
- condition: eTag
395
- }
580
+ container.item(e[idKey], nsPartitionValue(ns, e)).replace(
581
+ { ...mapId(e), _partitionKey: nsPartitionValue(ns, e) },
582
+ {
583
+ accessCondition: {
584
+ type: "IfMatch",
585
+ condition: eTag
396
586
  }
397
- )
587
+ }
398
588
  )
399
589
  }
400
590
  )
401
- .pipe(
402
- Effect
403
- .flatMap((x) => {
404
- if (x.statusCode === 412 || x.statusCode === 404 || x.statusCode === 409) {
405
- return Effect.fail(
406
- new OptimisticConcurrencyException({ type: name, id: e[idKey], code: x.statusCode })
407
- )
408
- }
409
- if (x.statusCode > 299 || x.statusCode < 200) {
410
- return Effect.die(
411
- new CosmosDbOperationError(
412
- "not able to update record: " + x.statusCode
413
- )
414
- )
415
- }
416
- return Effect.sync(() => ({
417
- ...e,
418
- _etag: x.etag
419
- }))
420
- }),
421
- Effect
422
- .withSpan("Cosmos.set [effect-app/infra/Store]", {
423
- attributes: {
424
- "repository.container_id": containerId,
425
- "repository.model_name": name,
426
- id: e[idKey]
427
- }
428
- }, { captureStackTrace: false })
429
- ),
430
- batchSet,
431
- bulkSet
432
- }
591
+ )
592
+ .pipe(
593
+ Effect
594
+ .flatMap((x): Effect.Effect<PM, OptimisticConcurrencyException | DatabaseError> => {
595
+ if (x.statusCode === 412 || x.statusCode === 404 || x.statusCode === 409) {
596
+ return Effect.fail(
597
+ new OptimisticConcurrencyException({ type: name, id: e[idKey], code: x.statusCode })
598
+ )
599
+ }
600
+ if (x.statusCode > 299 || x.statusCode < 200) {
601
+ return Effect.fail(
602
+ new DatabaseError({
603
+ message: "not able to update record: " + x.statusCode,
604
+ transient: statusIsTransient(x.statusCode),
605
+ cause: x
606
+ })
607
+ )
608
+ }
609
+ return Effect.sync(() => ({
610
+ ...e,
611
+ _etag: x.etag
612
+ }))
613
+ }),
614
+ annotateDb({
615
+ operation: "set",
616
+ system: "cosmosdb",
617
+ collection: containerId,
618
+ namespace: ns,
619
+ entity: name,
620
+ extra: { "app.entity.id": e[idKey] }
621
+ })
622
+ )
623
+ )),
624
+ batchSet,
625
+ bulkSet
626
+ }
433
627
 
434
- // handle mock data
435
- const marker = yield* Effect.promise(() =>
436
- container
437
- .item(importedMarkerId, importedMarkerId)
438
- .read<{ id: string }>()
439
- .then(({ resource }) => Option.fromNullishOr(resource))
440
- )
628
+ // Eagerly seed primary namespace on initialization
629
+ yield* seedNamespace("primary")
441
630
 
442
- if (!Option.isSome(marker)) {
443
- yield* InfraLogger.logInfo("Creating mock data for " + name)
444
- if (seed) {
445
- const m = yield* seed
446
- yield* Effect.flatMapOption(
447
- Effect.succeed(toNonEmptyArray([...m])),
448
- (a) =>
449
- s.bulkSet(a).pipe(
450
- Effect.orDie,
451
- Effect
452
- // we delay extra here, so that initial creation between Companies/POs also have an interval between them.
453
- .delay(Duration.millis(1100))
454
- )
455
- )
456
- }
457
- // Mark as imported
458
- yield* Effect.promise(() =>
459
- container.items.create({
460
- _partitionKey: importedMarkerId,
461
- id: importedMarkerId,
462
- ttl: -1
463
- })
464
- )
465
- }
466
- return s
467
- })
468
- }
469
- })
470
- }
631
+ return s
632
+ })
633
+ }
634
+ })
471
635
 
472
636
  export function CosmosStoreLayer(cfg: StorageConfig) {
473
637
  return StoreMaker