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

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