@effect-app/infra 4.0.0-beta.20 → 4.0.0-beta.201

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 (305) hide show
  1. package/CHANGELOG.md +1410 -0
  2. package/_check.sh +1 -1
  3. package/dist/CUPS.d.ts +15 -7
  4. package/dist/CUPS.d.ts.map +1 -1
  5. package/dist/CUPS.js +10 -12
  6. package/dist/Emailer/Sendgrid.d.ts +14 -14
  7. package/dist/Emailer/Sendgrid.d.ts.map +1 -1
  8. package/dist/Emailer/Sendgrid.js +16 -15
  9. package/dist/Emailer/fake.d.ts +1 -1
  10. package/dist/Emailer/service.d.ts +10 -4
  11. package/dist/Emailer/service.d.ts.map +1 -1
  12. package/dist/Emailer/service.js +3 -3
  13. package/dist/Emailer.d.ts +1 -1
  14. package/dist/MainFiberSet.d.ts +9 -9
  15. package/dist/MainFiberSet.d.ts.map +1 -1
  16. package/dist/MainFiberSet.js +3 -3
  17. package/dist/Model/Repository/Registry.d.ts +20 -0
  18. package/dist/Model/Repository/Registry.d.ts.map +1 -0
  19. package/dist/Model/Repository/Registry.js +17 -0
  20. package/dist/Model/Repository/ext.d.ts +33 -15
  21. package/dist/Model/Repository/ext.d.ts.map +1 -1
  22. package/dist/Model/Repository/ext.js +54 -2
  23. package/dist/Model/Repository/internal/internal.d.ts +6 -6
  24. package/dist/Model/Repository/internal/internal.d.ts.map +1 -1
  25. package/dist/Model/Repository/internal/internal.js +43 -32
  26. package/dist/Model/Repository/legacy.d.ts +1 -1
  27. package/dist/Model/Repository/makeRepo.d.ts +7 -6
  28. package/dist/Model/Repository/makeRepo.d.ts.map +1 -1
  29. package/dist/Model/Repository/makeRepo.js +5 -1
  30. package/dist/Model/Repository/service.d.ts +28 -23
  31. package/dist/Model/Repository/service.d.ts.map +1 -1
  32. package/dist/Model/Repository/validation.d.ts +142 -17
  33. package/dist/Model/Repository/validation.d.ts.map +1 -1
  34. package/dist/Model/Repository/validation.js +5 -5
  35. package/dist/Model/Repository.d.ts +2 -1
  36. package/dist/Model/Repository.d.ts.map +1 -1
  37. package/dist/Model/Repository.js +2 -1
  38. package/dist/Model/dsl.d.ts +4 -4
  39. package/dist/Model/dsl.d.ts.map +1 -1
  40. package/dist/Model/filter/filterApi.d.ts +5 -5
  41. package/dist/Model/filter/filterApi.d.ts.map +1 -1
  42. package/dist/Model/filter/types/errors.d.ts +1 -1
  43. package/dist/Model/filter/types/fields.d.ts +1 -1
  44. package/dist/Model/filter/types/path/common.d.ts +1 -1
  45. package/dist/Model/filter/types/path/eager.d.ts +1 -1
  46. package/dist/Model/filter/types/path/eager.d.ts.map +1 -1
  47. package/dist/Model/filter/types/path/eager.js +1 -1
  48. package/dist/Model/filter/types/path/index.d.ts +1 -1
  49. package/dist/Model/filter/types/utils.d.ts +1 -1
  50. package/dist/Model/filter/types/validator.d.ts +1 -1
  51. package/dist/Model/filter/types.d.ts +1 -1
  52. package/dist/Model/query/dsl.d.ts +16 -16
  53. package/dist/Model/query/dsl.d.ts.map +1 -1
  54. package/dist/Model/query/new-kid-interpreter.d.ts +6 -6
  55. package/dist/Model/query/new-kid-interpreter.d.ts.map +1 -1
  56. package/dist/Model/query/new-kid-interpreter.js +3 -3
  57. package/dist/Model/query.d.ts +1 -1
  58. package/dist/Model.d.ts +2 -1
  59. package/dist/Model.d.ts.map +1 -1
  60. package/dist/Model.js +2 -1
  61. package/dist/QueueMaker/SQLQueue.d.ts +5 -7
  62. package/dist/QueueMaker/SQLQueue.d.ts.map +1 -1
  63. package/dist/QueueMaker/SQLQueue.js +105 -114
  64. package/dist/QueueMaker/errors.d.ts +2 -2
  65. package/dist/QueueMaker/errors.d.ts.map +1 -1
  66. package/dist/QueueMaker/memQueue.d.ts +7 -4
  67. package/dist/QueueMaker/memQueue.d.ts.map +1 -1
  68. package/dist/QueueMaker/memQueue.js +51 -62
  69. package/dist/QueueMaker/sbqueue.d.ts +6 -3
  70. package/dist/QueueMaker/sbqueue.d.ts.map +1 -1
  71. package/dist/QueueMaker/sbqueue.js +37 -53
  72. package/dist/QueueMaker/service.d.ts +1 -1
  73. package/dist/RequestContext.d.ts +112 -26
  74. package/dist/RequestContext.d.ts.map +1 -1
  75. package/dist/RequestContext.js +7 -8
  76. package/dist/RequestFiberSet.d.ts +7 -7
  77. package/dist/RequestFiberSet.d.ts.map +1 -1
  78. package/dist/RequestFiberSet.js +5 -5
  79. package/dist/Store/ContextMapContainer.d.ts +19 -3
  80. package/dist/Store/ContextMapContainer.d.ts.map +1 -1
  81. package/dist/Store/ContextMapContainer.js +13 -3
  82. package/dist/Store/Cosmos/query.d.ts +1 -1
  83. package/dist/Store/Cosmos/query.d.ts.map +1 -1
  84. package/dist/Store/Cosmos/query.js +10 -12
  85. package/dist/Store/Cosmos.d.ts +1 -1
  86. package/dist/Store/Cosmos.d.ts.map +1 -1
  87. package/dist/Store/Cosmos.js +318 -240
  88. package/dist/Store/Disk.d.ts +2 -2
  89. package/dist/Store/Disk.d.ts.map +1 -1
  90. package/dist/Store/Disk.js +25 -22
  91. package/dist/Store/Memory.d.ts +4 -4
  92. package/dist/Store/Memory.d.ts.map +1 -1
  93. package/dist/Store/Memory.js +27 -22
  94. package/dist/Store/SQL/Pg.d.ts +4 -0
  95. package/dist/Store/SQL/Pg.d.ts.map +1 -0
  96. package/dist/Store/SQL/Pg.js +189 -0
  97. package/dist/Store/SQL/query.d.ts +38 -0
  98. package/dist/Store/SQL/query.d.ts.map +1 -0
  99. package/dist/Store/SQL/query.js +367 -0
  100. package/dist/Store/SQL.d.ts +20 -0
  101. package/dist/Store/SQL.d.ts.map +1 -0
  102. package/dist/Store/SQL.js +381 -0
  103. package/dist/Store/codeFilter.d.ts +1 -1
  104. package/dist/Store/codeFilter.d.ts.map +1 -1
  105. package/dist/Store/codeFilter.js +2 -1
  106. package/dist/Store/index.d.ts +5 -2
  107. package/dist/Store/index.d.ts.map +1 -1
  108. package/dist/Store/index.js +15 -3
  109. package/dist/Store/service.d.ts +18 -7
  110. package/dist/Store/service.d.ts.map +1 -1
  111. package/dist/Store/service.js +24 -6
  112. package/dist/Store/utils.d.ts +1 -1
  113. package/dist/Store/utils.d.ts.map +1 -1
  114. package/dist/Store/utils.js +3 -4
  115. package/dist/Store.d.ts +1 -1
  116. package/dist/adapters/SQL/Model.d.ts +28 -42
  117. package/dist/adapters/SQL/Model.d.ts.map +1 -1
  118. package/dist/adapters/SQL/Model.js +2 -2
  119. package/dist/adapters/SQL.d.ts +1 -1
  120. package/dist/adapters/ServiceBus.d.ts +11 -11
  121. package/dist/adapters/ServiceBus.d.ts.map +1 -1
  122. package/dist/adapters/ServiceBus.js +13 -15
  123. package/dist/adapters/cosmos-client.d.ts +3 -3
  124. package/dist/adapters/cosmos-client.d.ts.map +1 -1
  125. package/dist/adapters/cosmos-client.js +3 -3
  126. package/dist/adapters/index.d.ts +8 -2
  127. package/dist/adapters/index.d.ts.map +1 -1
  128. package/dist/adapters/index.js +8 -2
  129. package/dist/adapters/logger.d.ts +2 -2
  130. package/dist/adapters/logger.d.ts.map +1 -1
  131. package/dist/adapters/memQueue.d.ts +3 -3
  132. package/dist/adapters/memQueue.d.ts.map +1 -1
  133. package/dist/adapters/memQueue.js +3 -3
  134. package/dist/adapters/mongo-client.d.ts +3 -3
  135. package/dist/adapters/mongo-client.d.ts.map +1 -1
  136. package/dist/adapters/mongo-client.js +3 -3
  137. package/dist/adapters/redis-client.d.ts +3 -3
  138. package/dist/adapters/redis-client.d.ts.map +1 -1
  139. package/dist/adapters/redis-client.js +3 -3
  140. package/dist/api/ContextProvider.d.ts +8 -8
  141. package/dist/api/ContextProvider.d.ts.map +1 -1
  142. package/dist/api/ContextProvider.js +6 -6
  143. package/dist/api/codec.d.ts +1 -1
  144. package/dist/api/internal/RequestContextMiddleware.d.ts +2 -2
  145. package/dist/api/internal/RequestContextMiddleware.d.ts.map +1 -1
  146. package/dist/api/internal/RequestContextMiddleware.js +2 -2
  147. package/dist/api/internal/auth.d.ts +44 -6
  148. package/dist/api/internal/auth.d.ts.map +1 -1
  149. package/dist/api/internal/auth.js +160 -29
  150. package/dist/api/internal/events.d.ts +3 -3
  151. package/dist/api/internal/events.d.ts.map +1 -1
  152. package/dist/api/internal/events.js +9 -7
  153. package/dist/api/internal/health.d.ts +1 -1
  154. package/dist/api/layerUtils.d.ts +6 -6
  155. package/dist/api/layerUtils.d.ts.map +1 -1
  156. package/dist/api/layerUtils.js +5 -5
  157. package/dist/api/middlewares.d.ts +1 -1
  158. package/dist/api/reportError.d.ts +1 -1
  159. package/dist/api/routing/middleware/RouterMiddleware.d.ts +4 -4
  160. package/dist/api/routing/middleware/RouterMiddleware.d.ts.map +1 -1
  161. package/dist/api/routing/middleware/middleware.d.ts +39 -3
  162. package/dist/api/routing/middleware/middleware.d.ts.map +1 -1
  163. package/dist/api/routing/middleware/middleware.js +46 -14
  164. package/dist/api/routing/middleware.d.ts +1 -2
  165. package/dist/api/routing/middleware.d.ts.map +1 -1
  166. package/dist/api/routing/middleware.js +1 -2
  167. package/dist/api/routing/schema/jwt.d.ts +1 -1
  168. package/dist/api/routing/schema/jwt.d.ts.map +1 -1
  169. package/dist/api/routing/tsort.d.ts +1 -1
  170. package/dist/api/routing/tsort.d.ts.map +1 -1
  171. package/dist/api/routing/utils.d.ts +3 -3
  172. package/dist/api/routing/utils.d.ts.map +1 -1
  173. package/dist/api/routing.d.ts +25 -26
  174. package/dist/api/routing.d.ts.map +1 -1
  175. package/dist/api/routing.js +99 -35
  176. package/dist/api/setupRequest.d.ts +8 -5
  177. package/dist/api/setupRequest.d.ts.map +1 -1
  178. package/dist/api/setupRequest.js +12 -7
  179. package/dist/api/util.d.ts +1 -1
  180. package/dist/arbs.d.ts +1 -1
  181. package/dist/arbs.d.ts.map +1 -1
  182. package/dist/arbs.js +5 -3
  183. package/dist/errorReporter.d.ts +4 -4
  184. package/dist/errorReporter.d.ts.map +1 -1
  185. package/dist/errorReporter.js +20 -25
  186. package/dist/errors.d.ts +1 -1
  187. package/dist/fileUtil.d.ts +1 -1
  188. package/dist/fileUtil.d.ts.map +1 -1
  189. package/dist/index.d.ts +1 -1
  190. package/dist/logger/jsonLogger.d.ts +1 -1
  191. package/dist/logger/logFmtLogger.d.ts +1 -1
  192. package/dist/logger/shared.d.ts +1 -1
  193. package/dist/logger/shared.js +2 -2
  194. package/dist/logger.d.ts +1 -1
  195. package/dist/logger.d.ts.map +1 -1
  196. package/dist/rateLimit.d.ts +9 -3
  197. package/dist/rateLimit.d.ts.map +1 -1
  198. package/dist/rateLimit.js +5 -11
  199. package/dist/test.d.ts +2 -2
  200. package/dist/test.d.ts.map +1 -1
  201. package/dist/test.js +1 -1
  202. package/dist/vitest.d.ts +1 -1
  203. package/examples/query.ts +39 -35
  204. package/package.json +41 -37
  205. package/src/CUPS.ts +9 -11
  206. package/src/Emailer/Sendgrid.ts +17 -14
  207. package/src/Emailer/service.ts +9 -3
  208. package/src/MainFiberSet.ts +5 -6
  209. package/src/Model/Repository/Registry.ts +33 -0
  210. package/src/Model/Repository/ext.ts +96 -10
  211. package/src/Model/Repository/internal/internal.ts +97 -88
  212. package/src/Model/Repository/makeRepo.ts +12 -10
  213. package/src/Model/Repository/service.ts +31 -22
  214. package/src/Model/Repository/validation.ts +4 -4
  215. package/src/Model/Repository.ts +1 -0
  216. package/src/Model/dsl.ts +3 -3
  217. package/src/Model/filter/types/path/eager.ts +1 -2
  218. package/src/Model/query/dsl.ts +18 -18
  219. package/src/Model/query/new-kid-interpreter.ts +2 -2
  220. package/src/Model.ts +1 -0
  221. package/src/QueueMaker/SQLQueue.ts +121 -151
  222. package/src/QueueMaker/memQueue.ts +82 -103
  223. package/src/QueueMaker/sbqueue.ts +56 -86
  224. package/src/RequestContext.ts +8 -10
  225. package/src/RequestFiberSet.ts +4 -4
  226. package/src/Store/ContextMapContainer.ts +41 -2
  227. package/src/Store/Cosmos/query.ts +16 -20
  228. package/src/Store/Cosmos.ts +452 -342
  229. package/src/Store/Disk.ts +52 -49
  230. package/src/Store/Memory.ts +54 -48
  231. package/src/Store/SQL/Pg.ts +318 -0
  232. package/src/Store/SQL/query.ts +409 -0
  233. package/src/Store/SQL.ts +668 -0
  234. package/src/Store/codeFilter.ts +1 -0
  235. package/src/Store/index.ts +17 -2
  236. package/src/Store/service.ts +32 -8
  237. package/src/Store/utils.ts +23 -22
  238. package/src/adapters/SQL/Model.ts +10 -4
  239. package/src/adapters/ServiceBus.ts +112 -116
  240. package/src/adapters/cosmos-client.ts +2 -2
  241. package/src/adapters/index.ts +7 -0
  242. package/src/adapters/memQueue.ts +2 -2
  243. package/src/adapters/mongo-client.ts +2 -2
  244. package/src/adapters/redis-client.ts +2 -2
  245. package/src/api/ContextProvider.ts +12 -13
  246. package/src/api/internal/RequestContextMiddleware.ts +1 -1
  247. package/src/api/internal/auth.ts +246 -44
  248. package/src/api/internal/events.ts +12 -8
  249. package/src/api/layerUtils.ts +8 -8
  250. package/src/api/routing/middleware/RouterMiddleware.ts +4 -4
  251. package/src/api/routing/middleware/middleware.ts +53 -12
  252. package/src/api/routing/middleware.ts +0 -2
  253. package/src/api/routing.ts +173 -63
  254. package/src/api/setupRequest.ts +28 -8
  255. package/src/arbs.ts +4 -2
  256. package/src/errorReporter.ts +62 -74
  257. package/src/logger/shared.ts +1 -1
  258. package/src/rateLimit.ts +30 -22
  259. package/src/test.ts +1 -1
  260. package/test/auth.test.ts +101 -0
  261. package/test/contextProvider.test.ts +11 -11
  262. package/test/controller.test.ts +19 -17
  263. package/test/dist/auth.test.d.ts.map +1 -0
  264. package/test/dist/contextProvider.test.d.ts.map +1 -1
  265. package/test/dist/controller.test.d.ts.map +1 -1
  266. package/test/dist/date-query.test.d.ts.map +1 -0
  267. package/test/dist/fixtures.d.ts +26 -12
  268. package/test/dist/fixtures.d.ts.map +1 -1
  269. package/test/dist/fixtures.js +12 -10
  270. package/test/dist/query.test.d.ts.map +1 -1
  271. package/test/dist/rawQuery.test.d.ts.map +1 -1
  272. package/test/dist/repository-ext.test.d.ts.map +1 -0
  273. package/test/dist/requires.test.d.ts.map +1 -1
  274. package/test/dist/router-generator.test.d.ts.map +1 -0
  275. package/test/dist/routing-interruptibility.test.d.ts.map +1 -0
  276. package/test/dist/rpc-e2e-invalidation.test.d.ts.map +1 -0
  277. package/test/dist/rpc-multi-middleware.test.d.ts.map +1 -1
  278. package/test/dist/rpc-stream-fullstack.test.d.ts.map +1 -0
  279. package/test/dist/sql-store.test.d.ts.map +1 -0
  280. package/test/fixtures.ts +11 -9
  281. package/test/query.test.ts +216 -34
  282. package/test/rawQuery.test.ts +23 -19
  283. package/test/repository-ext.test.ts +60 -0
  284. package/test/requires.test.ts +6 -6
  285. package/test/router-generator.test.ts +183 -0
  286. package/test/routing-interruptibility.test.ts +63 -0
  287. package/test/rpc-e2e-invalidation.test.ts +249 -0
  288. package/test/rpc-multi-middleware.test.ts +78 -9
  289. package/test/rpc-stream-fullstack.test.ts +325 -0
  290. package/test/sql-store.test.ts +1064 -0
  291. package/test/validateSample.test.ts +15 -12
  292. package/tsconfig.examples.json +1 -1
  293. package/tsconfig.json +0 -1
  294. package/tsconfig.json.bak +2 -2
  295. package/tsconfig.src.json +35 -35
  296. package/tsconfig.test.json +2 -2
  297. package/dist/Operations.d.ts +0 -55
  298. package/dist/Operations.d.ts.map +0 -1
  299. package/dist/Operations.js +0 -102
  300. package/dist/OperationsRepo.d.ts +0 -41
  301. package/dist/OperationsRepo.d.ts.map +0 -1
  302. package/dist/OperationsRepo.js +0 -14
  303. package/eslint.config.mjs +0 -24
  304. package/src/Operations.ts +0 -235
  305. package/src/OperationsRepo.ts +0 -16
@@ -2,22 +2,31 @@
2
2
  /* eslint-disable @typescript-eslint/no-unsafe-argument */
3
3
  /* eslint-disable @typescript-eslint/no-empty-object-type */
4
4
  /* eslint-disable @typescript-eslint/no-explicit-any */
5
- import { Config, Effect, Layer, type NonEmptyReadonlyArray, Predicate, S, type Scope } from "effect-app"
5
+ import { Config, Effect, Layer, type NonEmptyReadonlyArray, Predicate, Ref, S, type Scope, Stream } from "effect-app"
6
+ import { getMeta } from "effect-app/client"
6
7
  import { type HttpHeaders } from "effect-app/http"
8
+ import { Invalidation } from "effect-app/rpc"
7
9
  import { type GetEffectContext, type GetEffectError, type RpcContextMap } from "effect-app/rpc/RpcContextMap"
8
10
  import { type TypeTestId } from "effect-app/TypeTest"
9
11
  import { typedKeysOf, typedValuesOf } from "effect-app/utils"
10
12
  import { type Yieldable } from "effect/Effect"
11
13
  import { Rpc, RpcGroup, type RpcSerialization, RpcServer } from "effect/unstable/rpc"
12
14
  import { type LayerUtils } from "./layerUtils.js"
13
- import { type RouterMiddleware } from "./routing/middleware.js"
15
+ import { RequestType as RequestTypeAnnotation, type RouterMiddleware } from "./routing/middleware.js"
14
16
 
15
17
  export * from "./routing/middleware.js"
16
18
 
19
+ export const applyRequestTypeInterruptibility = <A, E, R>(
20
+ requestType: "command" | "query",
21
+ effect: Effect.Effect<A, E, R>
22
+ ) => requestType === "command" ? Rpc.uninterruptible(effect) : effect
23
+
17
24
  // it's the result of extending S.Req setting success, config
18
25
  // it's a schema plus some metadata
19
26
  export type AnyRequestModule = S.Top & {
20
27
  _tag: string // unique identifier for the request module
28
+ type: "command" | "query"
29
+ stream: boolean
21
30
  config: any // ?
22
31
  success: S.Top // validates the success response
23
32
  error: S.Top // validates the failure response
@@ -65,7 +74,10 @@ interface HandlerBase<Action extends AnyRequestModule, RT extends RequestType, A
65
74
  new(): {}
66
75
  _tag: RT
67
76
  stack: string
68
- handler: (req: S.Schema.Type<Action>, headers: HttpHeaders.Headers) => Effect.Effect<A, E, R>
77
+ handler: (
78
+ req: S.Schema.Type<Action>,
79
+ headers: HttpHeaders.Headers
80
+ ) => Effect.Effect<A, E, R> | Stream.Stream<A, E, R>
69
81
  }
70
82
 
71
83
  export interface Handler<Action extends AnyRequestModule, RT extends RequestType, R> extends
@@ -106,7 +118,7 @@ type Match<
106
118
  > = {
107
119
  // note: the defaults of = never prevent the whole router to error (??)
108
120
  <A extends GetSuccessShape<Resource[Key], RT>, R2 = never, E = never>(
109
- f: Effect.Effect<A, E, R2>
121
+ f: (req: S.Schema.Type<Resource[Key]>) => Effect.Effect<A, E, R2>
110
122
  ): Handler<
111
123
  Resource[Key],
112
124
  RT,
@@ -117,7 +129,7 @@ type Match<
117
129
  >
118
130
 
119
131
  <A extends GetSuccessShape<Resource[Key], RT>, R2 = never, E = never>(
120
- f: (req: S.Schema.Type<Resource[Key]>) => Effect.Effect<A, E, R2>
132
+ f: (req: S.Schema.Type<Resource[Key]>) => Stream.Stream<A, E, R2>
121
133
  ): Handler<
122
134
  Resource[Key],
123
135
  RT,
@@ -182,10 +194,9 @@ export const makeRouter = <
182
194
  * if `check` is provided, the router will only be created if the effect succeeds with true
183
195
  */
184
196
  function matchFor<
185
- const ModuleName extends string,
186
197
  const Resource extends Record<string, any>
187
198
  >(
188
- rsc: Resource & { meta: { moduleName: ModuleName } },
199
+ rsc: Resource,
189
200
  options?: { check?: Effect.Effect<boolean> }
190
201
  ) {
191
202
  type HandlerWithInputGen<
@@ -219,37 +230,37 @@ export const makeRouter = <
219
230
  GetEffectContext<RequestContextMap, Action["config"]> | ContextProviderA
220
231
  >
221
232
 
222
- type HandlerEff<
233
+ type HandlerWithInputStream<
223
234
  Action extends AnyRequestModule,
224
235
  RT extends RequestType
225
- > = Effect.Effect<
236
+ > = (
237
+ req: S.Schema.Type<Action>
238
+ ) => Stream.Stream<
226
239
  GetSuccessShape<Action, RT>,
227
240
  S.Schema.Type<GetFailure<Action>> | S.SchemaError,
228
- // the actual implementation of the handler may just require the dynamic context provided by the middleware
229
- // and the per request context provided by the context provider
230
241
  GetEffectContext<RequestContextMap, Action["config"]> | ContextProviderA
231
242
  >
232
243
 
233
244
  type Handlers<Action extends AnyRequestModule, RT extends RequestType> =
234
245
  | HandlerWithInputGen<Action, RT>
235
246
  | HandlerWithInputEff<Action, RT>
236
- | HandlerEff<Action, RT>
247
+ | HandlerWithInputStream<Action, RT>
237
248
 
238
249
  type HandlersDecoded<Action extends AnyRequestModule> = Handlers<Action, RequestTypes.DECODED>
239
250
 
240
251
  type HandlersRaw<Action extends AnyRequestModule> =
241
252
  | { raw: HandlerWithInputGen<Action, RequestTypes.RAW> }
242
253
  | { raw: HandlerWithInputEff<Action, RequestTypes.RAW> }
243
- | { raw: HandlerEff<Action, RequestTypes.RAW> }
254
+ | { raw: HandlerWithInputStream<Action, RequestTypes.RAW> }
244
255
 
245
256
  type AnyHandlers<Action extends AnyRequestModule> = HandlersRaw<Action> | HandlersDecoded<Action>
246
257
 
247
- const { meta } = rsc
258
+ const meta = getMeta(rsc)
248
259
 
249
260
  type RequestModules = FilterRequestModules<Resource>
250
261
  const requestModules = typedKeysOf(rsc).reduce((acc, cur) => {
251
262
  if (Predicate.isObjectKeyword(rsc[cur]) && rsc[cur]["success"]) {
252
- acc[cur as keyof RequestModules] = rsc[cur] as RequestModules[keyof RequestModules]
263
+ acc[cur as keyof RequestModules] = rsc[cur]
253
264
  }
254
265
  return acc
255
266
  }, {} as RequestModules)
@@ -260,19 +271,13 @@ export const makeRouter = <
260
271
  // handlerImpl is the actual handler implementation
261
272
  if (handlerImpl[Symbol.toStringTag] === "GeneratorFunction") handlerImpl = Effect.fnUntraced(handlerImpl)
262
273
  const stack = new Error().stack?.split("\n").slice(2).join("\n")
263
- return Effect.isEffect(handlerImpl)
264
- ? class {
265
- static request = rsc[cur]
266
- static stack = stack
267
- static _tag = RequestTypes.DECODED
268
- static handler = () => handlerImpl
269
- }
270
- : class {
271
- static request = rsc[cur]
272
- static stack = stack
273
- static _tag = RequestTypes.DECODED
274
- static handler = handlerImpl
275
- }
274
+ // oxlint-disable-next-line typescript/no-extraneous-class
275
+ return class {
276
+ static request = rsc[cur]
277
+ static stack = stack
278
+ static _tag = RequestTypes.DECODED
279
+ static handler = handlerImpl
280
+ }
276
281
  }, {
277
282
  success: rsc[cur].success,
278
283
  successRaw: S.toEncoded(rsc[cur].success),
@@ -283,19 +288,13 @@ export const makeRouter = <
283
288
  (handlerImpl: any) => {
284
289
  if (handlerImpl[Symbol.toStringTag] === "GeneratorFunction") handlerImpl = Effect.fnUntraced(handlerImpl)
285
290
  const stack = new Error().stack?.split("\n").slice(2).join("\n")
286
- return Effect.isEffect(handlerImpl)
287
- ? class {
288
- static request = rsc[cur]
289
- static stack = stack
290
- static _tag = RequestTypes.RAW
291
- static handler = () => handlerImpl
292
- }
293
- : class {
294
- static request = rsc[cur]
295
- static stack = stack
296
- static _tag = RequestTypes.RAW
297
- static handler = handlerImpl
298
- }
291
+ // oxlint-disable-next-line typescript/no-extraneous-class
292
+ return class {
293
+ static request = rsc[cur]
294
+ static stack = stack
295
+ static _tag = RequestTypes.RAW
296
+ static handler = handlerImpl
297
+ }
299
298
  }
300
299
  })
301
300
  return prev
@@ -318,19 +317,15 @@ export const makeRouter = <
318
317
  // retrieves context R from the actual implementation of the handler
319
318
  Impl[K] extends { raw: any }
320
319
  ? Impl[K]["raw"] extends (...args: any[]) => Effect.Effect<any, any, infer R> ? R
321
- : Impl[K]["raw"] extends Effect.Effect<any, any, infer R> ? R
320
+ : Impl[K]["raw"] extends (...args: any[]) => Stream.Stream<any, any, infer R> ? R
322
321
  : Impl[K]["raw"] extends (...args: any[]) => Generator<
323
- Yieldable<any, any, any, infer R>,
324
- any,
325
- any
322
+ Yieldable<any, any, any, infer R>
326
323
  > ? R
327
324
  : never
328
325
  : Impl[K] extends (...args: any[]) => Effect.Effect<any, any, infer R> ? R
329
- : Impl[K] extends Effect.Effect<any, any, infer R> ? R
326
+ : Impl[K] extends (...args: any[]) => Stream.Stream<any, any, infer R> ? R
330
327
  : Impl[K] extends (...args: any[]) => Generator<
331
- Yieldable<any, any, any, infer R>,
332
- any,
333
- any
328
+ Yieldable<any, any, any, infer R>
334
329
  > ? R
335
330
  : never,
336
331
  | GetEffectContext<RequestContextMap, Resource[K]["config"]>
@@ -359,7 +354,7 @@ export const makeRouter = <
359
354
  match: any
360
355
  ) =>
361
356
  | Effect.Effect<THandlers, MakeE, MakeR>
362
- | Generator<Yieldable<any, any, MakeE, MakeR>, THandlers, any>
357
+ | Generator<Yieldable<any, any, MakeE, MakeR>, THandlers>
363
358
  ) => {
364
359
  const dependenciesL = (dependencies ? Layer.mergeAll(...dependencies as any) : Layer.empty) as Layer.Layer<
365
360
  LayerUtils.GetLayersSuccess<MakeDependencies>,
@@ -386,12 +381,109 @@ export const makeRouter = <
386
381
  static success = S.toEncoded(resource.success)
387
382
  } as any
388
383
  : resource,
389
- (payload: any, headers: any) =>
390
- (handler.handler(payload, headers) as Effect.Effect<unknown, unknown, unknown>).pipe(
384
+ (payload: any, headers: any) => {
385
+ let result: any = handler.handler(payload, headers)
386
+ // Stream resources accept handlers returning either Stream or Effect.
387
+ // Lift Effect to Stream so `Effect.fail(...)` and `Effect<Stream>` (e.g.
388
+ // from generator handlers) work the same as a returned Stream.
389
+ if (resource.stream && Effect.isEffect(result)) {
390
+ result = Stream.unwrap(
391
+ (result as Effect.Effect<unknown, unknown, unknown>).pipe(
392
+ Effect.map((v) => Stream.isStream(v) ? v : Stream.succeed(v))
393
+ )
394
+ )
395
+ }
396
+ if (Stream.isStream(result)) {
397
+ // Wrap stream items as { _tag: "value", value } and append a final
398
+ // { _tag: "done", metadata } chunk carrying accumulated invalidation keys.
399
+ // V2: on failure, convert to { _tag: "error", error, metadata } chunk so
400
+ // clients can invalidate queries even when the stream fails.
401
+ const keysRef = Ref.makeUnsafe<ReadonlyArray<Invalidation.InvalidationKey>>([])
402
+ const invalidationSet = Invalidation.makeInvalidationSet(keysRef)
403
+ return Stream.concat(
404
+ (result as Stream.Stream<any, any, any>).pipe(
405
+ Stream.map((item: any) => ({ _tag: "value" as const, value: item })),
406
+ Stream.provideService(Invalidation.InvalidationSet, invalidationSet),
407
+ // V3: after each value chunk, drain accumulated keys and emit a "metadata"
408
+ // chunk if any keys were collected since the last drain. This lets clients
409
+ // invalidate queries mid-stream without waiting for the "done" chunk.
410
+ Stream.flatMap((valueChunk: any) =>
411
+ Stream
412
+ .fromEffect(
413
+ Ref.getAndSet(keysRef, []).pipe(
414
+ Effect.map((keys) =>
415
+ keys.length > 0
416
+ ? [
417
+ valueChunk,
418
+ { _tag: "metadata" as const, metadata: { invalidateQueries: keys } }
419
+ ]
420
+ : [valueChunk]
421
+ )
422
+ )
423
+ )
424
+ .pipe(Stream.flatMap(Stream.fromIterable))
425
+ ),
426
+ // V2: catch stream failures and embed them in the stream as an error chunk
427
+ Stream.catch((err: any) =>
428
+ Stream.fromEffect(
429
+ Ref.get(keysRef).pipe(
430
+ Effect.flatMap((keys) =>
431
+ Effect.fail({
432
+ _tag: "error" as const,
433
+ error: err,
434
+ metadata: { invalidateQueries: keys }
435
+ })
436
+ )
437
+ )
438
+ )
439
+ )
440
+ ),
441
+ Stream.fromEffect(
442
+ Ref.get(keysRef).pipe(
443
+ Effect.map((keys) => ({ _tag: "done" as const, metadata: { invalidateQueries: keys } }))
444
+ )
445
+ )
446
+ )
447
+ }
448
+ let effect = (result as Effect.Effect<unknown, unknown, unknown>).pipe(
391
449
  Effect.withSpan(`Request.${meta.moduleName}.${resource._tag}`, {}, {
392
450
  captureStackTrace: () => handler.stack // capturing the handler stack is the main reason why we are doing the span here
393
451
  })
394
452
  )
453
+
454
+ // Commands: provide a request-scoped `InvalidationSet` and wrap both
455
+ // success (`CommandResponseWithMetaData`) and handler-thrown failure
456
+ // (`CommandFailureWithMetaData`) so the client receives accumulated
457
+ // invalidation keys on either path. Middleware-thrown errors bypass the
458
+ // wrap (they fail the outer effect before reaching this `.catch`) and
459
+ // flow raw on the Cause; client decodes them via the rpc's
460
+ // `middlewares[*].error` failure-union channel.
461
+ if (resource.type === "command") {
462
+ const keysRef = Ref.makeUnsafe<ReadonlyArray<Invalidation.InvalidationKey>>([])
463
+ const invalidationSet = Invalidation.makeInvalidationSet(keysRef)
464
+ effect = effect.pipe(
465
+ Effect.provideService(Invalidation.InvalidationSet, invalidationSet),
466
+ Effect.flatMap((value) =>
467
+ Ref.get(keysRef).pipe(
468
+ Effect.map((keys) => ({ payload: value, metadata: { invalidateQueries: keys } }) as any)
469
+ )
470
+ ),
471
+ Effect.catch((err: any) =>
472
+ Ref.get(keysRef).pipe(
473
+ Effect.flatMap((keys) =>
474
+ Effect.fail({
475
+ _tag: "CommandFailureWithMetaData" as const,
476
+ error: err,
477
+ metadata: { invalidateQueries: keys }
478
+ })
479
+ )
480
+ )
481
+ )
482
+ )
483
+ }
484
+
485
+ return applyRequestTypeInterruptibility(resource.type, effect)
486
+ }
395
487
  ] as const
396
488
  return acc
397
489
  }, {} as any) as {
@@ -415,9 +507,29 @@ export const makeRouter = <
415
507
  const rpcs = RpcGroup
416
508
  .make(
417
509
  ...typedValuesOf(mapped).map(([resource]) => {
418
- return Rpc
419
- .make(resource._tag, { payload: resource, success: resource.success, error: resource.error })
510
+ const isStream = resource.stream
511
+ const isCommand = resource.type === "command"
512
+ return (isCommand
513
+ ? isStream
514
+ ? Invalidation.makeStreamRpc(resource._tag, {
515
+ payload: resource,
516
+ success: resource.success,
517
+ error: resource.error,
518
+ stream: true as const
519
+ })
520
+ : Invalidation.makeCommandRpc(resource._tag, {
521
+ payload: resource,
522
+ success: resource.success,
523
+ error: resource.error
524
+ })
525
+ : Rpc.make(resource._tag, {
526
+ payload: resource,
527
+ success: resource.success,
528
+ error: resource.error,
529
+ stream: isStream
530
+ }))
420
531
  .annotate(middleware.requestContext, resource.config ?? {})
532
+ .annotate(RequestTypeAnnotation, resource.type)
421
533
  })
422
534
  )
423
535
  .prefix(`${meta.moduleName}.`)
@@ -479,8 +591,7 @@ export const makeRouter = <
479
591
  any,
480
592
  any
481
593
  >,
482
- { [K in keyof FilterRequestModules<Resource>]: AnyHandler<Resource[K]> },
483
- any
594
+ { [K in keyof FilterRequestModules<Resource>]: AnyHandler<Resource[K]> }
484
595
  >
485
596
  /** @deprecated */
486
597
  readonly ಠ_ಠ: never
@@ -511,8 +622,7 @@ export const makeRouter = <
511
622
  // v4: generators yield Yieldable with asEffect()
512
623
  effect: (match: typeof router3) => Generator<
513
624
  Yieldable<any, any, any, any>,
514
- { [K in keyof FilterRequestModules<Resource>]: AnyHandler<Resource[K]> },
515
- any
625
+ { [K in keyof FilterRequestModules<Resource>]: AnyHandler<Resource[K]> }
516
626
  >
517
627
  }
518
628
  >(
@@ -572,23 +682,23 @@ export type MakeErrors<Make> = /*Make extends { readonly effect: (_: any) => Eff
572
682
  : Make extends { readonly effect: (_: any) => Effect.Effect<any, never, any> } ? never
573
683
  : */
574
684
  // v4: generators yield Yieldable with asEffect()
575
- Make extends { readonly effect: (_: any) => Generator<Yieldable<any, any, never, any>, any, any> } ? never
576
- : Make extends { readonly effect: (_: any) => Generator<Yieldable<any, any, infer E, any>, any, any> } ? E
685
+ Make extends { readonly effect: (_: any) => Generator<Yieldable<any, any, never, any>> } ? never
686
+ : Make extends { readonly effect: (_: any) => Generator<Yieldable<any, any, infer E, any>> } ? E
577
687
  : never
578
688
 
579
689
  export type MakeContext<Make> = /*Make extends { readonly effect: (_: any) => Effect.Effect<any, any, infer R> } ? R
580
690
  : Make extends { readonly effect: (_: any) => Effect.Effect<any, any, never> } ? never
581
691
  : */
582
692
  // v4: generators yield Yieldable with asEffect()
583
- Make extends { readonly effect: (_: any) => Generator<Yieldable<any, any, any, never>, any, any> } ? never
584
- : Make extends { readonly effect: (_: any) => Generator<Yieldable<any, any, any, infer R>, any, any> } ? R
693
+ Make extends { readonly effect: (_: any) => Generator<Yieldable<any, any, any>> } ? never
694
+ : Make extends { readonly effect: (_: any) => Generator<Yieldable<any, any, any, infer R>> } ? R
585
695
  : never
586
696
 
587
697
  export type MakeHandlers<Make, _Handlers extends Record<string, any>> = /*Make extends
588
698
  { readonly effect: (_: any) => Effect.Effect<{ [K in keyof Handlers]: AnyHandler<Handlers[K]> }, any, any> }
589
699
  ? Effect.Success<ReturnType<Make["effect"]>>
590
700
  : */
591
- Make extends { readonly effect: (_: any) => Generator<any, infer S, any> } ? S
701
+ Make extends { readonly effect: (_: any) => Generator<any, infer S> } ? S
592
702
  : never
593
703
 
594
704
  export type MakeDepsE<Make> = Layer.Error<MakeDeps<Make>>
@@ -1,9 +1,18 @@
1
- import { Effect, Layer, Tracer } from "effect-app"
1
+ import { Effect, Layer, Option, Tracer } from "effect-app"
2
2
  import { NonEmptyString255 } from "effect-app/Schema"
3
+ import { SqlClient } from "effect/unstable/sql"
3
4
  import { LocaleRef, RequestContext, spanAttributes } from "../RequestContext.js"
4
5
  import { ContextMapContainer } from "../Store/ContextMapContainer.js"
5
6
  import { storeId } from "../Store/Memory.js"
6
7
 
8
+ const withSqlTransaction = <R, E, A>(self: Effect.Effect<A, E, R>): Effect.Effect<A, E, R> =>
9
+ Effect.serviceOption(SqlClient.SqlClient).pipe(
10
+ Effect.flatMap(Option.match({
11
+ onNone: () => self,
12
+ onSome: (sql) => sql.withTransaction(self).pipe(Effect.orDie)
13
+ }))
14
+ )
15
+
7
16
  export const getRequestContext = Effect
8
17
  .all({
9
18
  span: Effect.currentSpan.pipe(Effect.orDie),
@@ -12,7 +21,7 @@ export const getRequestContext = Effect
12
21
  })
13
22
  .pipe(
14
23
  Effect.map(({ locale, namespace, span }) =>
15
- new RequestContext({
24
+ RequestContext.make({
16
25
  span: Tracer.externalSpan(span),
17
26
  locale,
18
27
  namespace,
@@ -43,16 +52,25 @@ const withRequestSpan = (name = "request", options?: Tracer.SpanOptions) => <R,
43
52
  )
44
53
  )
45
54
 
55
+ export interface SetupRequestOptions {
56
+ readonly withTransaction?: boolean
57
+ }
58
+
46
59
  export const setupRequestContextFromCurrent =
47
- (name = "request", options?: Tracer.SpanOptions) => <R, E, A>(self: Effect.Effect<A, E, R>) =>
60
+ (name = "request", options?: Tracer.SpanOptions & SetupRequestOptions) => <R, E, A>(self: Effect.Effect<A, E, R>) =>
48
61
  self
49
62
  .pipe(
63
+ options?.withTransaction === true ? withSqlTransaction : (_) => _,
50
64
  withRequestSpan(name, options),
51
- Effect.provide(ContextMapContainer.layer)
65
+ Effect.provide(ContextMapContainer.layer, { local: true })
52
66
  )
53
67
 
54
68
  // TODO: consider integrating Effect.withParentSpan
55
- export function setupRequestContext<R, E, A>(self: Effect.Effect<A, E, R>, requestContext: RequestContext) {
69
+ export function setupRequestContext<R, E, A>(
70
+ self: Effect.Effect<A, E, R>,
71
+ requestContext: RequestContext,
72
+ options?: SetupRequestOptions
73
+ ) {
56
74
  const layer = Layer.mergeAll(
57
75
  ContextMapContainer.layer,
58
76
  Layer.succeed(LocaleRef, requestContext.locale),
@@ -60,8 +78,9 @@ export function setupRequestContext<R, E, A>(self: Effect.Effect<A, E, R>, reque
60
78
  )
61
79
  return self
62
80
  .pipe(
81
+ options?.withTransaction === true ? withSqlTransaction : (_) => _,
63
82
  withRequestSpan(requestContext.name),
64
- Effect.provide(layer)
83
+ Effect.provide(layer, { local: true })
65
84
  )
66
85
  }
67
86
 
@@ -69,7 +88,7 @@ export function setupRequestContextWithCustomSpan<R, E, A>(
69
88
  self: Effect.Effect<A, E, R>,
70
89
  requestContext: RequestContext,
71
90
  name: string,
72
- options?: Tracer.SpanOptions
91
+ options?: Tracer.SpanOptions & SetupRequestOptions
73
92
  ) {
74
93
  const layer = Layer.mergeAll(
75
94
  ContextMapContainer.layer,
@@ -78,7 +97,8 @@ export function setupRequestContextWithCustomSpan<R, E, A>(
78
97
  )
79
98
  return self
80
99
  .pipe(
100
+ options?.withTransaction === true ? withSqlTransaction : (_) => _,
81
101
  withRequestSpan(name, options),
82
- Effect.provide(layer)
102
+ Effect.provide(layer, { local: true })
83
103
  )
84
104
  }
package/src/arbs.ts CHANGED
@@ -5,9 +5,11 @@ import { type S } from "effect-app"
5
5
  import { setFaker } from "effect-app/faker"
6
6
  import * as FastCheck from "effect/testing/FastCheck"
7
7
  import { Random } from "fast-check"
8
- import * as rand from "pure-rand"
8
+ import { congruential32 } from "pure-rand/generator/congruential32"
9
9
 
10
- const rnd = new Random(rand.congruential32(5))
10
+ const seed = 5
11
+ const rng = congruential32(seed)
12
+ const rnd = new Random(rng)
11
13
 
12
14
  setFaker(faker)
13
15
 
@@ -13,47 +13,41 @@ const tryCauseException = <E>(cause: Cause.Cause<E>, name: string): CauseExcepti
13
13
  }
14
14
  }
15
15
 
16
- export function reportError(
17
- name: string
18
- ) {
19
- return (
20
- cause: Cause.Cause<unknown>,
21
- extras?: Record<string, unknown>,
22
- level: LogLevel.Severity = "Error"
23
- ) =>
24
- Effect
25
- .gen(function*() {
26
- if (Cause.hasInterruptsOnly(cause)) {
27
- yield* InfraLogger.logDebug("Interrupted").pipe(Effect.annotateLogs("extras", JSON.stringify(extras ?? {})))
28
- return
29
- }
30
- const error = tryCauseException(cause, name)
31
-
32
- yield* reportSentry(error, extras, LogLevelToSentry(level))
33
- yield* InfraLogger
34
- .logWithLevel(level, "Reporting error", cause)
35
- .pipe(
36
- Effect.annotateLogs(dropUndefined({
37
- extras,
38
- error: tryToReport(error),
39
- cause: tryToJson(cause),
40
- __error_name__: name
41
- }))
42
- )
43
- .pipe(
44
- Effect.catchCause((cause) => InfraLogger.logWarning("Failed to log error", cause)),
45
- Effect.catchCause(() => InfraLogger.logFatal("Failed to log error cause"))
46
- )
16
+ export function reportError(name: string) {
17
+ return Effect.fnUntraced(
18
+ function*(
19
+ cause: Cause.Cause<unknown>,
20
+ extras?: Record<string, unknown>,
21
+ level: LogLevel.Severity = "Error"
22
+ ) {
23
+ if (Cause.hasInterruptsOnly(cause)) {
24
+ yield* InfraLogger.logDebug("Interrupted").pipe(Effect.annotateLogs("extras", JSON.stringify(extras ?? {})))
25
+ return
26
+ }
27
+ const error = tryCauseException(cause, name)
47
28
 
48
- return error
49
- })
50
- .pipe(
51
- Effect.tapCause((cause) =>
52
- InfraLogger.logError("Failed to report error", cause).pipe(
53
- Effect.tapCause(() => InfraLogger.logFatal("Failed to log error cause"))
54
- )
29
+ yield* reportSentry(error, extras, LogLevelToSentry(level))
30
+ yield* InfraLogger
31
+ .logWithLevel(level, "Reporting error", cause)
32
+ .pipe(
33
+ Effect.annotateLogs(dropUndefined({
34
+ extras,
35
+ error: tryToReport(error),
36
+ cause: tryToJson(cause),
37
+ __error_name__: name
38
+ })),
39
+ Effect.catchCause((cause) => InfraLogger.logWarning("Failed to log error", cause)),
40
+ Effect.catchCause(() => InfraLogger.logFatal("Failed to log error cause"))
55
41
  )
56
- )
42
+
43
+ return error
44
+ },
45
+ (effect) =>
46
+ Effect.tapCause(effect, (cause) =>
47
+ InfraLogger.logError("Failed to report error", cause).pipe(
48
+ Effect.tapCause(() => InfraLogger.logFatal("Failed to log error cause"))
49
+ ))
50
+ )
57
51
  }
58
52
 
59
53
  function reportSentry(
@@ -66,45 +60,39 @@ function reportSentry(
66
60
  scope.setLevel(level)
67
61
  if (context) scope.setContext("context", { ...context })
68
62
  if (extras) scope.setContext("extras", extras)
69
- scope.setContext("error", { data: tryToReport(error) })
70
- scope.setContext("cause", { data: tryToJson(error.originalCause) })
63
+ const squashed = Cause.squash(error.originalCause)
64
+ scope.setContext("mainError", tryToJson(squashed))
65
+ scope.setContext("error", tryToReport(error))
66
+ scope.setContext("cause", tryToJson(error.originalCause))
71
67
  Sentry.captureException(error, scope)
72
68
  }))
73
69
  }
74
70
 
75
- export function logError<E>(
76
- name: string
77
- ) {
78
- return (cause: Cause.Cause<E>, extras?: Record<string, unknown>) =>
79
- Effect
80
- .gen(function*() {
81
- if (Cause.hasInterruptsOnly(cause)) {
82
- yield* InfraLogger.logDebug("Interrupted").pipe(Effect.annotateLogs(dropUndefined({ extras })))
83
- return
84
- }
85
- yield* InfraLogger
86
- .logWarning("Logging error", cause)
87
- .pipe(
88
- Effect.annotateLogs(dropUndefined({
89
- extras,
90
- cause: tryToJson(cause),
91
- __error_name__: name
92
- }))
93
- )
94
- })
95
- .pipe(
96
- Effect.tapCause(() => InfraLogger.logFatal("Failed to log error cause"))
97
- )
71
+ export function logError<E>(name: string) {
72
+ return Effect.fnUntraced(
73
+ function*(cause: Cause.Cause<E>, extras?: Record<string, unknown>) {
74
+ if (Cause.hasInterruptsOnly(cause)) {
75
+ yield* InfraLogger.logDebug("Interrupted").pipe(Effect.annotateLogs(dropUndefined({ extras })))
76
+ return
77
+ }
78
+ yield* InfraLogger
79
+ .logWarning("Logging error", cause)
80
+ .pipe(Effect.annotateLogs(dropUndefined({
81
+ extras,
82
+ cause: tryToJson(cause),
83
+ __error_name__: name
84
+ })))
85
+ },
86
+ (effect) => Effect.tapCause(effect, () => InfraLogger.logFatal("Failed to log error cause"))
87
+ )
98
88
  }
99
89
 
100
- export function reportMessage(message: string, extras?: Record<string, unknown>) {
101
- return Effect.gen(function*() {
102
- const context = yield* getRC
103
- const scope = new Sentry.Scope()
104
- if (context) scope.setContext("context", { ...context })
105
- if (extras) scope.setContext("extras", extras)
106
- Sentry.captureMessage(message, scope)
90
+ export const reportMessage = Effect.fnUntraced(function*(message: string, extras?: Record<string, unknown>) {
91
+ const context = yield* getRC
92
+ const scope = new Sentry.Scope()
93
+ if (context) scope.setContext("context", { ...context })
94
+ if (extras) scope.setContext("extras", extras)
95
+ Sentry.captureMessage(message, scope)
107
96
 
108
- console.warn(message, extras)
109
- })
110
- }
97
+ console.warn(message, extras)
98
+ })
@@ -7,7 +7,7 @@ export function getRequestContextFromFiber(fiber: Fiber.Fiber<unknown, unknown>)
7
7
  const span = Option.fromNullishOr(fiber.currentSpan)
8
8
  const locale = fiber.getRef(LocaleRef)
9
9
  const namespace = fiber.getRef(storeId)
10
- return new RequestContext({
10
+ return RequestContext.make({
11
11
  span: Option.map(span, (s) => ({ spanId: s.spanId, traceId: s.traceId, sampled: s.sampled })).pipe(
12
12
  Option.getOrElse(() => ({ spanId: "bogus", sampled: true, traceId: "bogus" }))
13
13
  ),