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

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