@effect-app/infra 4.0.0-beta.19 → 4.0.0-beta.191
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.
- package/CHANGELOG.md +1285 -0
- package/_check.sh +1 -1
- package/dist/CUPS.d.ts +15 -7
- package/dist/CUPS.d.ts.map +1 -1
- package/dist/CUPS.js +10 -12
- package/dist/Emailer/Sendgrid.d.ts +14 -14
- package/dist/Emailer/Sendgrid.d.ts.map +1 -1
- package/dist/Emailer/Sendgrid.js +16 -15
- package/dist/Emailer/fake.d.ts +1 -1
- package/dist/Emailer/service.d.ts +10 -4
- package/dist/Emailer/service.d.ts.map +1 -1
- package/dist/Emailer/service.js +3 -3
- package/dist/Emailer.d.ts +1 -1
- package/dist/MainFiberSet.d.ts +9 -9
- package/dist/MainFiberSet.d.ts.map +1 -1
- package/dist/MainFiberSet.js +3 -3
- package/dist/Model/Repository/Registry.d.ts +20 -0
- package/dist/Model/Repository/Registry.d.ts.map +1 -0
- package/dist/Model/Repository/Registry.js +17 -0
- package/dist/Model/Repository/ext.d.ts +33 -15
- package/dist/Model/Repository/ext.d.ts.map +1 -1
- package/dist/Model/Repository/ext.js +54 -2
- package/dist/Model/Repository/internal/internal.d.ts +6 -6
- package/dist/Model/Repository/internal/internal.d.ts.map +1 -1
- package/dist/Model/Repository/internal/internal.js +43 -32
- package/dist/Model/Repository/legacy.d.ts +1 -1
- package/dist/Model/Repository/makeRepo.d.ts +7 -6
- package/dist/Model/Repository/makeRepo.d.ts.map +1 -1
- package/dist/Model/Repository/makeRepo.js +5 -1
- package/dist/Model/Repository/service.d.ts +28 -23
- package/dist/Model/Repository/service.d.ts.map +1 -1
- package/dist/Model/Repository/validation.d.ts +142 -17
- package/dist/Model/Repository/validation.d.ts.map +1 -1
- package/dist/Model/Repository/validation.js +5 -5
- package/dist/Model/Repository.d.ts +2 -1
- package/dist/Model/Repository.d.ts.map +1 -1
- package/dist/Model/Repository.js +2 -1
- package/dist/Model/dsl.d.ts +4 -4
- package/dist/Model/dsl.d.ts.map +1 -1
- package/dist/Model/filter/filterApi.d.ts +5 -5
- package/dist/Model/filter/filterApi.d.ts.map +1 -1
- package/dist/Model/filter/types/errors.d.ts +1 -1
- package/dist/Model/filter/types/fields.d.ts +1 -1
- package/dist/Model/filter/types/path/common.d.ts +1 -1
- package/dist/Model/filter/types/path/eager.d.ts +1 -1
- package/dist/Model/filter/types/path/eager.d.ts.map +1 -1
- package/dist/Model/filter/types/path/eager.js +1 -1
- package/dist/Model/filter/types/path/index.d.ts +1 -1
- package/dist/Model/filter/types/utils.d.ts +1 -1
- package/dist/Model/filter/types/validator.d.ts +1 -1
- package/dist/Model/filter/types.d.ts +1 -1
- package/dist/Model/query/dsl.d.ts +16 -16
- package/dist/Model/query/dsl.d.ts.map +1 -1
- package/dist/Model/query/new-kid-interpreter.d.ts +6 -6
- package/dist/Model/query/new-kid-interpreter.d.ts.map +1 -1
- package/dist/Model/query/new-kid-interpreter.js +3 -3
- package/dist/Model/query.d.ts +1 -1
- package/dist/Model.d.ts +2 -1
- package/dist/Model.d.ts.map +1 -1
- package/dist/Model.js +2 -1
- package/dist/QueueMaker/SQLQueue.d.ts +5 -7
- package/dist/QueueMaker/SQLQueue.d.ts.map +1 -1
- package/dist/QueueMaker/SQLQueue.js +105 -114
- package/dist/QueueMaker/errors.d.ts +2 -2
- package/dist/QueueMaker/errors.d.ts.map +1 -1
- package/dist/QueueMaker/memQueue.d.ts +7 -4
- package/dist/QueueMaker/memQueue.d.ts.map +1 -1
- package/dist/QueueMaker/memQueue.js +51 -62
- package/dist/QueueMaker/sbqueue.d.ts +6 -3
- package/dist/QueueMaker/sbqueue.d.ts.map +1 -1
- package/dist/QueueMaker/sbqueue.js +37 -53
- package/dist/QueueMaker/service.d.ts +1 -1
- package/dist/RequestContext.d.ts +114 -26
- package/dist/RequestContext.d.ts.map +1 -1
- package/dist/RequestContext.js +7 -8
- package/dist/RequestFiberSet.d.ts +7 -7
- package/dist/RequestFiberSet.d.ts.map +1 -1
- package/dist/RequestFiberSet.js +5 -5
- package/dist/Store/ContextMapContainer.d.ts +19 -3
- package/dist/Store/ContextMapContainer.d.ts.map +1 -1
- package/dist/Store/ContextMapContainer.js +13 -3
- package/dist/Store/Cosmos/query.d.ts +1 -1
- package/dist/Store/Cosmos/query.d.ts.map +1 -1
- package/dist/Store/Cosmos/query.js +10 -12
- package/dist/Store/Cosmos.d.ts +1 -1
- package/dist/Store/Cosmos.d.ts.map +1 -1
- package/dist/Store/Cosmos.js +308 -242
- package/dist/Store/Disk.d.ts +2 -2
- package/dist/Store/Disk.d.ts.map +1 -1
- package/dist/Store/Disk.js +25 -22
- package/dist/Store/Memory.d.ts +4 -4
- package/dist/Store/Memory.d.ts.map +1 -1
- package/dist/Store/Memory.js +27 -22
- package/dist/Store/SQL/Pg.d.ts +4 -0
- package/dist/Store/SQL/Pg.d.ts.map +1 -0
- package/dist/Store/SQL/Pg.js +189 -0
- package/dist/Store/SQL/query.d.ts +38 -0
- package/dist/Store/SQL/query.d.ts.map +1 -0
- package/dist/Store/SQL/query.js +367 -0
- package/dist/Store/SQL.d.ts +20 -0
- package/dist/Store/SQL.d.ts.map +1 -0
- package/dist/Store/SQL.js +381 -0
- package/dist/Store/codeFilter.d.ts +1 -1
- package/dist/Store/codeFilter.d.ts.map +1 -1
- package/dist/Store/codeFilter.js +2 -1
- package/dist/Store/index.d.ts +5 -2
- package/dist/Store/index.d.ts.map +1 -1
- package/dist/Store/index.js +15 -3
- package/dist/Store/service.d.ts +18 -7
- package/dist/Store/service.d.ts.map +1 -1
- package/dist/Store/service.js +24 -6
- package/dist/Store/utils.d.ts +1 -1
- package/dist/Store/utils.d.ts.map +1 -1
- package/dist/Store/utils.js +3 -4
- package/dist/Store.d.ts +1 -1
- package/dist/adapters/SQL/Model.d.ts +28 -42
- package/dist/adapters/SQL/Model.d.ts.map +1 -1
- package/dist/adapters/SQL/Model.js +2 -2
- package/dist/adapters/SQL.d.ts +1 -1
- package/dist/adapters/ServiceBus.d.ts +11 -11
- package/dist/adapters/ServiceBus.d.ts.map +1 -1
- package/dist/adapters/ServiceBus.js +13 -15
- package/dist/adapters/cosmos-client.d.ts +3 -3
- package/dist/adapters/cosmos-client.d.ts.map +1 -1
- package/dist/adapters/cosmos-client.js +3 -3
- package/dist/adapters/index.d.ts +8 -2
- package/dist/adapters/index.d.ts.map +1 -1
- package/dist/adapters/index.js +8 -2
- package/dist/adapters/logger.d.ts +2 -2
- package/dist/adapters/logger.d.ts.map +1 -1
- package/dist/adapters/memQueue.d.ts +3 -3
- package/dist/adapters/memQueue.d.ts.map +1 -1
- package/dist/adapters/memQueue.js +3 -3
- package/dist/adapters/mongo-client.d.ts +3 -3
- package/dist/adapters/mongo-client.d.ts.map +1 -1
- package/dist/adapters/mongo-client.js +3 -3
- package/dist/adapters/redis-client.d.ts +3 -3
- package/dist/adapters/redis-client.d.ts.map +1 -1
- package/dist/adapters/redis-client.js +3 -3
- package/dist/api/ContextProvider.d.ts +8 -8
- package/dist/api/ContextProvider.d.ts.map +1 -1
- package/dist/api/ContextProvider.js +6 -6
- package/dist/api/codec.d.ts +1 -1
- package/dist/api/internal/RequestContextMiddleware.d.ts +2 -2
- package/dist/api/internal/RequestContextMiddleware.d.ts.map +1 -1
- package/dist/api/internal/RequestContextMiddleware.js +2 -2
- package/dist/api/internal/auth.d.ts +44 -6
- package/dist/api/internal/auth.d.ts.map +1 -1
- package/dist/api/internal/auth.js +160 -29
- package/dist/api/internal/events.d.ts +3 -3
- package/dist/api/internal/events.d.ts.map +1 -1
- package/dist/api/internal/events.js +9 -7
- package/dist/api/internal/health.d.ts +1 -1
- package/dist/api/layerUtils.d.ts +6 -6
- package/dist/api/layerUtils.d.ts.map +1 -1
- package/dist/api/layerUtils.js +5 -5
- package/dist/api/middlewares.d.ts +1 -1
- package/dist/api/reportError.d.ts +1 -1
- package/dist/api/routing/middleware/RouterMiddleware.d.ts +4 -4
- package/dist/api/routing/middleware/RouterMiddleware.d.ts.map +1 -1
- package/dist/api/routing/middleware/middleware.d.ts +50 -4
- package/dist/api/routing/middleware/middleware.d.ts.map +1 -1
- package/dist/api/routing/middleware/middleware.js +75 -17
- package/dist/api/routing/middleware.d.ts +1 -2
- package/dist/api/routing/middleware.d.ts.map +1 -1
- package/dist/api/routing/middleware.js +1 -2
- package/dist/api/routing/schema/jwt.d.ts +1 -1
- package/dist/api/routing/schema/jwt.d.ts.map +1 -1
- package/dist/api/routing/tsort.d.ts +1 -1
- package/dist/api/routing/tsort.d.ts.map +1 -1
- package/dist/api/routing/utils.d.ts +3 -3
- package/dist/api/routing/utils.d.ts.map +1 -1
- package/dist/api/routing.d.ts +31 -23
- package/dist/api/routing.d.ts.map +1 -1
- package/dist/api/routing.js +70 -11
- package/dist/api/setupRequest.d.ts +8 -5
- package/dist/api/setupRequest.d.ts.map +1 -1
- package/dist/api/setupRequest.js +12 -7
- package/dist/api/util.d.ts +1 -1
- package/dist/arbs.d.ts +1 -1
- package/dist/arbs.d.ts.map +1 -1
- package/dist/arbs.js +5 -3
- package/dist/errorReporter.d.ts +4 -4
- package/dist/errorReporter.d.ts.map +1 -1
- package/dist/errorReporter.js +20 -25
- package/dist/errors.d.ts +1 -1
- package/dist/fileUtil.d.ts +1 -1
- package/dist/fileUtil.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/logger/jsonLogger.d.ts +1 -1
- package/dist/logger/logFmtLogger.d.ts +1 -1
- package/dist/logger/shared.d.ts +1 -1
- package/dist/logger/shared.js +2 -2
- package/dist/logger.d.ts +1 -1
- package/dist/logger.d.ts.map +1 -1
- package/dist/rateLimit.d.ts +9 -3
- package/dist/rateLimit.d.ts.map +1 -1
- package/dist/rateLimit.js +5 -11
- package/dist/test.d.ts +2 -2
- package/dist/test.d.ts.map +1 -1
- package/dist/test.js +1 -1
- package/dist/vitest.d.ts +1 -1
- package/examples/query.ts +39 -35
- package/package.json +41 -37
- package/src/CUPS.ts +9 -11
- package/src/Emailer/Sendgrid.ts +17 -14
- package/src/Emailer/service.ts +9 -3
- package/src/MainFiberSet.ts +5 -6
- package/src/Model/Repository/Registry.ts +33 -0
- package/src/Model/Repository/ext.ts +96 -10
- package/src/Model/Repository/internal/internal.ts +97 -88
- package/src/Model/Repository/makeRepo.ts +12 -10
- package/src/Model/Repository/service.ts +31 -22
- package/src/Model/Repository/validation.ts +4 -4
- package/src/Model/Repository.ts +1 -0
- package/src/Model/dsl.ts +3 -3
- package/src/Model/filter/types/path/eager.ts +1 -2
- package/src/Model/query/dsl.ts +18 -18
- package/src/Model/query/new-kid-interpreter.ts +2 -2
- package/src/Model.ts +1 -0
- package/src/QueueMaker/SQLQueue.ts +121 -151
- package/src/QueueMaker/memQueue.ts +82 -103
- package/src/QueueMaker/sbqueue.ts +56 -86
- package/src/RequestContext.ts +7 -9
- package/src/RequestFiberSet.ts +4 -4
- package/src/Store/ContextMapContainer.ts +41 -2
- package/src/Store/Cosmos/query.ts +16 -20
- package/src/Store/Cosmos.ts +437 -343
- package/src/Store/Disk.ts +52 -49
- package/src/Store/Memory.ts +54 -48
- package/src/Store/SQL/Pg.ts +318 -0
- package/src/Store/SQL/query.ts +409 -0
- package/src/Store/SQL.ts +668 -0
- package/src/Store/codeFilter.ts +1 -0
- package/src/Store/index.ts +17 -2
- package/src/Store/service.ts +32 -8
- package/src/Store/utils.ts +23 -22
- package/src/adapters/SQL/Model.ts +10 -4
- package/src/adapters/ServiceBus.ts +112 -116
- package/src/adapters/cosmos-client.ts +2 -2
- package/src/adapters/index.ts +7 -0
- package/src/adapters/memQueue.ts +2 -2
- package/src/adapters/mongo-client.ts +2 -2
- package/src/adapters/redis-client.ts +2 -2
- package/src/api/ContextProvider.ts +12 -13
- package/src/api/internal/RequestContextMiddleware.ts +1 -1
- package/src/api/internal/auth.ts +246 -44
- package/src/api/internal/events.ts +12 -8
- package/src/api/layerUtils.ts +8 -8
- package/src/api/routing/middleware/RouterMiddleware.ts +4 -4
- package/src/api/routing/middleware/middleware.ts +109 -15
- package/src/api/routing/middleware.ts +0 -2
- package/src/api/routing.ts +164 -29
- package/src/api/setupRequest.ts +28 -8
- package/src/arbs.ts +4 -2
- package/src/errorReporter.ts +62 -74
- package/src/logger/shared.ts +1 -1
- package/src/rateLimit.ts +30 -22
- package/src/test.ts +1 -1
- package/test/auth.test.ts +101 -0
- package/test/contextProvider.test.ts +11 -11
- package/test/controller.test.ts +18 -14
- package/test/dist/auth.test.d.ts.map +1 -0
- package/test/dist/contextProvider.test.d.ts.map +1 -1
- package/test/dist/controller.test.d.ts.map +1 -1
- package/test/dist/date-query.test.d.ts.map +1 -0
- package/test/dist/fixtures.d.ts +26 -12
- package/test/dist/fixtures.d.ts.map +1 -1
- package/test/dist/fixtures.js +12 -10
- package/test/dist/query.test.d.ts.map +1 -1
- package/test/dist/rawQuery.test.d.ts.map +1 -1
- package/test/dist/repository-ext.test.d.ts.map +1 -0
- package/test/dist/requires.test.d.ts.map +1 -1
- package/test/dist/router-generator.test.d.ts.map +1 -0
- package/test/dist/routing-interruptibility.test.d.ts.map +1 -0
- package/test/dist/rpc-e2e-invalidation.test.d.ts.map +1 -0
- package/test/dist/rpc-multi-middleware.test.d.ts.map +1 -1
- package/test/dist/rpc-stream-fullstack.test.d.ts.map +1 -0
- package/test/dist/sql-store.test.d.ts.map +1 -0
- package/test/fixtures.ts +11 -9
- package/test/query.test.ts +216 -34
- package/test/rawQuery.test.ts +23 -19
- package/test/repository-ext.test.ts +60 -0
- package/test/requires.test.ts +6 -6
- package/test/router-generator.test.ts +180 -0
- package/test/routing-interruptibility.test.ts +63 -0
- package/test/rpc-e2e-invalidation.test.ts +507 -0
- package/test/rpc-multi-middleware.test.ts +78 -9
- package/test/rpc-stream-fullstack.test.ts +181 -0
- package/test/sql-store.test.ts +1064 -0
- package/test/validateSample.test.ts +15 -12
- package/tsconfig.examples.json +1 -1
- package/tsconfig.json +0 -1
- package/tsconfig.json.bak +2 -2
- package/tsconfig.src.json +35 -35
- package/tsconfig.test.json +2 -2
- package/dist/Operations.d.ts +0 -55
- package/dist/Operations.d.ts.map +0 -1
- package/dist/Operations.js +0 -102
- package/dist/OperationsRepo.d.ts +0 -41
- package/dist/OperationsRepo.d.ts.map +0 -1
- package/dist/OperationsRepo.js +0 -14
- package/eslint.config.mjs +0 -24
- package/src/Operations.ts +0 -235
- package/src/OperationsRepo.ts +0 -16
package/src/api/routing.ts
CHANGED
|
@@ -2,22 +2,30 @@
|
|
|
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" | "stream"
|
|
21
29
|
config: any // ?
|
|
22
30
|
success: S.Top // validates the success response
|
|
23
31
|
error: S.Top // validates the failure response
|
|
@@ -65,7 +73,10 @@ interface HandlerBase<Action extends AnyRequestModule, RT extends RequestType, A
|
|
|
65
73
|
new(): {}
|
|
66
74
|
_tag: RT
|
|
67
75
|
stack: string
|
|
68
|
-
handler: (
|
|
76
|
+
handler: (
|
|
77
|
+
req: S.Schema.Type<Action>,
|
|
78
|
+
headers: HttpHeaders.Headers
|
|
79
|
+
) => Effect.Effect<A, E, R> | Stream.Stream<A, E, R>
|
|
69
80
|
}
|
|
70
81
|
|
|
71
82
|
export interface Handler<Action extends AnyRequestModule, RT extends RequestType, R> extends
|
|
@@ -126,6 +137,28 @@ type Match<
|
|
|
126
137
|
Scope.Scope
|
|
127
138
|
>
|
|
128
139
|
>
|
|
140
|
+
|
|
141
|
+
<A extends GetSuccessShape<Resource[Key], RT>, R2 = never, E = never>(
|
|
142
|
+
f: Stream.Stream<A, E, R2>
|
|
143
|
+
): Handler<
|
|
144
|
+
Resource[Key],
|
|
145
|
+
RT,
|
|
146
|
+
Exclude<
|
|
147
|
+
Exclude<R2, GetEffectContext<RequestContextMap, Resource[Key]["config"]>>,
|
|
148
|
+
Scope.Scope
|
|
149
|
+
>
|
|
150
|
+
>
|
|
151
|
+
|
|
152
|
+
<A extends GetSuccessShape<Resource[Key], RT>, R2 = never, E = never>(
|
|
153
|
+
f: (req: S.Schema.Type<Resource[Key]>) => Stream.Stream<A, E, R2>
|
|
154
|
+
): Handler<
|
|
155
|
+
Resource[Key],
|
|
156
|
+
RT,
|
|
157
|
+
Exclude<
|
|
158
|
+
Exclude<R2, GetEffectContext<RequestContextMap, Resource[Key]["config"]>>,
|
|
159
|
+
Scope.Scope
|
|
160
|
+
>
|
|
161
|
+
>
|
|
129
162
|
}
|
|
130
163
|
|
|
131
164
|
export type RouteMatcher<
|
|
@@ -182,10 +215,9 @@ export const makeRouter = <
|
|
|
182
215
|
* if `check` is provided, the router will only be created if the effect succeeds with true
|
|
183
216
|
*/
|
|
184
217
|
function matchFor<
|
|
185
|
-
const ModuleName extends string,
|
|
186
218
|
const Resource extends Record<string, any>
|
|
187
219
|
>(
|
|
188
|
-
rsc: Resource
|
|
220
|
+
rsc: Resource,
|
|
189
221
|
options?: { check?: Effect.Effect<boolean> }
|
|
190
222
|
) {
|
|
191
223
|
type HandlerWithInputGen<
|
|
@@ -230,10 +262,32 @@ export const makeRouter = <
|
|
|
230
262
|
GetEffectContext<RequestContextMap, Action["config"]> | ContextProviderA
|
|
231
263
|
>
|
|
232
264
|
|
|
265
|
+
type HandlerWithInputStream<
|
|
266
|
+
Action extends AnyRequestModule,
|
|
267
|
+
RT extends RequestType
|
|
268
|
+
> = (
|
|
269
|
+
req: S.Schema.Type<Action>
|
|
270
|
+
) => Stream.Stream<
|
|
271
|
+
GetSuccessShape<Action, RT>,
|
|
272
|
+
S.Schema.Type<GetFailure<Action>> | S.SchemaError,
|
|
273
|
+
GetEffectContext<RequestContextMap, Action["config"]> | ContextProviderA
|
|
274
|
+
>
|
|
275
|
+
|
|
276
|
+
type HandlerStream<
|
|
277
|
+
Action extends AnyRequestModule,
|
|
278
|
+
RT extends RequestType
|
|
279
|
+
> = Stream.Stream<
|
|
280
|
+
GetSuccessShape<Action, RT>,
|
|
281
|
+
S.Schema.Type<GetFailure<Action>> | S.SchemaError,
|
|
282
|
+
GetEffectContext<RequestContextMap, Action["config"]> | ContextProviderA
|
|
283
|
+
>
|
|
284
|
+
|
|
233
285
|
type Handlers<Action extends AnyRequestModule, RT extends RequestType> =
|
|
234
286
|
| HandlerWithInputGen<Action, RT>
|
|
235
287
|
| HandlerWithInputEff<Action, RT>
|
|
236
288
|
| HandlerEff<Action, RT>
|
|
289
|
+
| HandlerWithInputStream<Action, RT>
|
|
290
|
+
| HandlerStream<Action, RT>
|
|
237
291
|
|
|
238
292
|
type HandlersDecoded<Action extends AnyRequestModule> = Handlers<Action, RequestTypes.DECODED>
|
|
239
293
|
|
|
@@ -241,15 +295,17 @@ export const makeRouter = <
|
|
|
241
295
|
| { raw: HandlerWithInputGen<Action, RequestTypes.RAW> }
|
|
242
296
|
| { raw: HandlerWithInputEff<Action, RequestTypes.RAW> }
|
|
243
297
|
| { raw: HandlerEff<Action, RequestTypes.RAW> }
|
|
298
|
+
| { raw: HandlerWithInputStream<Action, RequestTypes.RAW> }
|
|
299
|
+
| { raw: HandlerStream<Action, RequestTypes.RAW> }
|
|
244
300
|
|
|
245
301
|
type AnyHandlers<Action extends AnyRequestModule> = HandlersRaw<Action> | HandlersDecoded<Action>
|
|
246
302
|
|
|
247
|
-
const
|
|
303
|
+
const meta = getMeta(rsc)
|
|
248
304
|
|
|
249
305
|
type RequestModules = FilterRequestModules<Resource>
|
|
250
306
|
const requestModules = typedKeysOf(rsc).reduce((acc, cur) => {
|
|
251
307
|
if (Predicate.isObjectKeyword(rsc[cur]) && rsc[cur]["success"]) {
|
|
252
|
-
acc[cur as keyof RequestModules] = rsc[cur]
|
|
308
|
+
acc[cur as keyof RequestModules] = rsc[cur]
|
|
253
309
|
}
|
|
254
310
|
return acc
|
|
255
311
|
}, {} as RequestModules)
|
|
@@ -260,13 +316,16 @@ export const makeRouter = <
|
|
|
260
316
|
// handlerImpl is the actual handler implementation
|
|
261
317
|
if (handlerImpl[Symbol.toStringTag] === "GeneratorFunction") handlerImpl = Effect.fnUntraced(handlerImpl)
|
|
262
318
|
const stack = new Error().stack?.split("\n").slice(2).join("\n")
|
|
263
|
-
|
|
319
|
+
const isValueShape = Effect.isEffect(handlerImpl) || Stream.isStream(handlerImpl)
|
|
320
|
+
return isValueShape
|
|
321
|
+
// oxlint-disable-next-line typescript/no-extraneous-class
|
|
264
322
|
? class {
|
|
265
323
|
static request = rsc[cur]
|
|
266
324
|
static stack = stack
|
|
267
325
|
static _tag = RequestTypes.DECODED
|
|
268
326
|
static handler = () => handlerImpl
|
|
269
327
|
}
|
|
328
|
+
// oxlint-disable-next-line typescript/no-extraneous-class
|
|
270
329
|
: class {
|
|
271
330
|
static request = rsc[cur]
|
|
272
331
|
static stack = stack
|
|
@@ -283,13 +342,16 @@ export const makeRouter = <
|
|
|
283
342
|
(handlerImpl: any) => {
|
|
284
343
|
if (handlerImpl[Symbol.toStringTag] === "GeneratorFunction") handlerImpl = Effect.fnUntraced(handlerImpl)
|
|
285
344
|
const stack = new Error().stack?.split("\n").slice(2).join("\n")
|
|
286
|
-
|
|
345
|
+
const isValueShape = Effect.isEffect(handlerImpl) || Stream.isStream(handlerImpl)
|
|
346
|
+
return isValueShape
|
|
347
|
+
// oxlint-disable-next-line typescript/no-extraneous-class
|
|
287
348
|
? class {
|
|
288
349
|
static request = rsc[cur]
|
|
289
350
|
static stack = stack
|
|
290
351
|
static _tag = RequestTypes.RAW
|
|
291
352
|
static handler = () => handlerImpl
|
|
292
353
|
}
|
|
354
|
+
// oxlint-disable-next-line typescript/no-extraneous-class
|
|
293
355
|
: class {
|
|
294
356
|
static request = rsc[cur]
|
|
295
357
|
static stack = stack
|
|
@@ -319,18 +381,18 @@ export const makeRouter = <
|
|
|
319
381
|
Impl[K] extends { raw: any }
|
|
320
382
|
? Impl[K]["raw"] extends (...args: any[]) => Effect.Effect<any, any, infer R> ? R
|
|
321
383
|
: Impl[K]["raw"] extends Effect.Effect<any, any, infer R> ? R
|
|
384
|
+
: Impl[K]["raw"] extends (...args: any[]) => Stream.Stream<any, any, infer R> ? R
|
|
385
|
+
: Impl[K]["raw"] extends Stream.Stream<any, any, infer R> ? R
|
|
322
386
|
: Impl[K]["raw"] extends (...args: any[]) => Generator<
|
|
323
|
-
Yieldable<any, any, any, infer R
|
|
324
|
-
any,
|
|
325
|
-
any
|
|
387
|
+
Yieldable<any, any, any, infer R>
|
|
326
388
|
> ? R
|
|
327
389
|
: never
|
|
328
390
|
: Impl[K] extends (...args: any[]) => Effect.Effect<any, any, infer R> ? R
|
|
329
391
|
: Impl[K] extends Effect.Effect<any, any, infer R> ? R
|
|
392
|
+
: Impl[K] extends (...args: any[]) => Stream.Stream<any, any, infer R> ? R
|
|
393
|
+
: Impl[K] extends Stream.Stream<any, any, infer R> ? R
|
|
330
394
|
: Impl[K] extends (...args: any[]) => Generator<
|
|
331
|
-
Yieldable<any, any, any, infer R
|
|
332
|
-
any,
|
|
333
|
-
any
|
|
395
|
+
Yieldable<any, any, any, infer R>
|
|
334
396
|
> ? R
|
|
335
397
|
: never,
|
|
336
398
|
| GetEffectContext<RequestContextMap, Resource[K]["config"]>
|
|
@@ -359,7 +421,7 @@ export const makeRouter = <
|
|
|
359
421
|
match: any
|
|
360
422
|
) =>
|
|
361
423
|
| Effect.Effect<THandlers, MakeE, MakeR>
|
|
362
|
-
| Generator<Yieldable<any, any, MakeE, MakeR>, THandlers
|
|
424
|
+
| Generator<Yieldable<any, any, MakeE, MakeR>, THandlers>
|
|
363
425
|
) => {
|
|
364
426
|
const dependenciesL = (dependencies ? Layer.mergeAll(...dependencies as any) : Layer.empty) as Layer.Layer<
|
|
365
427
|
LayerUtils.GetLayersSuccess<MakeDependencies>,
|
|
@@ -386,12 +448,68 @@ export const makeRouter = <
|
|
|
386
448
|
static success = S.toEncoded(resource.success)
|
|
387
449
|
} as any
|
|
388
450
|
: resource,
|
|
389
|
-
(payload: any, headers: any) =>
|
|
390
|
-
|
|
451
|
+
(payload: any, headers: any) => {
|
|
452
|
+
const result = handler.handler(payload, headers)
|
|
453
|
+
if (Stream.isStream(result)) {
|
|
454
|
+
// Wrap stream items as { _tag: "value", value } and append a final
|
|
455
|
+
// { _tag: "done", metadata } chunk carrying accumulated invalidation keys.
|
|
456
|
+
// V2: on failure, convert to { _tag: "error", error, metadata } chunk so
|
|
457
|
+
// clients can invalidate queries even when the stream fails.
|
|
458
|
+
const keysRef = Ref.makeUnsafe<ReadonlyArray<Invalidation.InvalidationKey>>([])
|
|
459
|
+
const invalidationSet = Invalidation.makeInvalidationSet(keysRef)
|
|
460
|
+
return Stream.concat(
|
|
461
|
+
(result as Stream.Stream<any, any, any>).pipe(
|
|
462
|
+
Stream.map((item: any) => ({ _tag: "value" as const, value: item })),
|
|
463
|
+
Stream.provideService(Invalidation.InvalidationSet, invalidationSet),
|
|
464
|
+
// V3: after each value chunk, drain accumulated keys and emit a "metadata"
|
|
465
|
+
// chunk if any keys were collected since the last drain. This lets clients
|
|
466
|
+
// invalidate queries mid-stream without waiting for the "done" chunk.
|
|
467
|
+
Stream.flatMap((valueChunk: any) =>
|
|
468
|
+
Stream
|
|
469
|
+
.fromEffect(
|
|
470
|
+
Ref.getAndSet(keysRef, []).pipe(
|
|
471
|
+
Effect.map((keys) =>
|
|
472
|
+
keys.length > 0
|
|
473
|
+
? [
|
|
474
|
+
valueChunk,
|
|
475
|
+
{ _tag: "metadata" as const, metadata: { invalidateQueries: keys } }
|
|
476
|
+
]
|
|
477
|
+
: [valueChunk]
|
|
478
|
+
)
|
|
479
|
+
)
|
|
480
|
+
)
|
|
481
|
+
.pipe(Stream.flatMap(Stream.fromIterable))
|
|
482
|
+
),
|
|
483
|
+
// V2: catch stream failures and embed them in the stream as an error chunk
|
|
484
|
+
Stream.catch((err: any) =>
|
|
485
|
+
Stream.fromEffect(
|
|
486
|
+
Ref.get(keysRef).pipe(
|
|
487
|
+
Effect.flatMap((keys) =>
|
|
488
|
+
Effect.fail({
|
|
489
|
+
_tag: "error" as const,
|
|
490
|
+
error: err,
|
|
491
|
+
metadata: { invalidateQueries: keys }
|
|
492
|
+
})
|
|
493
|
+
)
|
|
494
|
+
)
|
|
495
|
+
)
|
|
496
|
+
)
|
|
497
|
+
),
|
|
498
|
+
Stream.fromEffect(
|
|
499
|
+
Ref.get(keysRef).pipe(
|
|
500
|
+
Effect.map((keys) => ({ _tag: "done" as const, metadata: { invalidateQueries: keys } }))
|
|
501
|
+
)
|
|
502
|
+
)
|
|
503
|
+
)
|
|
504
|
+
}
|
|
505
|
+
const effect = (result as Effect.Effect<unknown, unknown, unknown>).pipe(
|
|
391
506
|
Effect.withSpan(`Request.${meta.moduleName}.${resource._tag}`, {}, {
|
|
392
507
|
captureStackTrace: () => handler.stack // capturing the handler stack is the main reason why we are doing the span here
|
|
393
508
|
})
|
|
394
509
|
)
|
|
510
|
+
|
|
511
|
+
return applyRequestTypeInterruptibility(resource.type, effect)
|
|
512
|
+
}
|
|
395
513
|
] as const
|
|
396
514
|
return acc
|
|
397
515
|
}, {} as any) as {
|
|
@@ -415,9 +533,28 @@ export const makeRouter = <
|
|
|
415
533
|
const rpcs = RpcGroup
|
|
416
534
|
.make(
|
|
417
535
|
...typedValuesOf(mapped).map(([resource]) => {
|
|
418
|
-
|
|
419
|
-
|
|
536
|
+
const isStream = resource.type === "stream"
|
|
537
|
+
const isCommand = resource.type === "command"
|
|
538
|
+
return (isCommand
|
|
539
|
+
? Invalidation.makeCommandRpc(resource._tag, {
|
|
540
|
+
payload: resource,
|
|
541
|
+
success: resource.success,
|
|
542
|
+
error: resource.error
|
|
543
|
+
})
|
|
544
|
+
: isStream
|
|
545
|
+
? Invalidation.makeStreamRpc(resource._tag, {
|
|
546
|
+
payload: resource,
|
|
547
|
+
success: resource.success,
|
|
548
|
+
error: resource.error,
|
|
549
|
+
stream: true as const
|
|
550
|
+
})
|
|
551
|
+
: Rpc.make(resource._tag, {
|
|
552
|
+
payload: resource,
|
|
553
|
+
success: resource.success,
|
|
554
|
+
error: resource.error
|
|
555
|
+
}))
|
|
420
556
|
.annotate(middleware.requestContext, resource.config ?? {})
|
|
557
|
+
.annotate(RequestTypeAnnotation, resource.type)
|
|
421
558
|
})
|
|
422
559
|
)
|
|
423
560
|
.prefix(`${meta.moduleName}.`)
|
|
@@ -479,8 +616,7 @@ export const makeRouter = <
|
|
|
479
616
|
any,
|
|
480
617
|
any
|
|
481
618
|
>,
|
|
482
|
-
{ [K in keyof FilterRequestModules<Resource>]: AnyHandler<Resource[K]> }
|
|
483
|
-
any
|
|
619
|
+
{ [K in keyof FilterRequestModules<Resource>]: AnyHandler<Resource[K]> }
|
|
484
620
|
>
|
|
485
621
|
/** @deprecated */
|
|
486
622
|
readonly ಠ_ಠ: never
|
|
@@ -511,8 +647,7 @@ export const makeRouter = <
|
|
|
511
647
|
// v4: generators yield Yieldable with asEffect()
|
|
512
648
|
effect: (match: typeof router3) => Generator<
|
|
513
649
|
Yieldable<any, any, any, any>,
|
|
514
|
-
{ [K in keyof FilterRequestModules<Resource>]: AnyHandler<Resource[K]> }
|
|
515
|
-
any
|
|
650
|
+
{ [K in keyof FilterRequestModules<Resource>]: AnyHandler<Resource[K]> }
|
|
516
651
|
>
|
|
517
652
|
}
|
|
518
653
|
>(
|
|
@@ -572,23 +707,23 @@ export type MakeErrors<Make> = /*Make extends { readonly effect: (_: any) => Eff
|
|
|
572
707
|
: Make extends { readonly effect: (_: any) => Effect.Effect<any, never, any> } ? never
|
|
573
708
|
: */
|
|
574
709
|
// v4: generators yield Yieldable with asEffect()
|
|
575
|
-
Make extends { readonly effect: (_: any) => Generator<Yieldable<any, any, never, any
|
|
576
|
-
: Make extends { readonly effect: (_: any) => Generator<Yieldable<any, any, infer E, any
|
|
710
|
+
Make extends { readonly effect: (_: any) => Generator<Yieldable<any, any, never, any>> } ? never
|
|
711
|
+
: Make extends { readonly effect: (_: any) => Generator<Yieldable<any, any, infer E, any>> } ? E
|
|
577
712
|
: never
|
|
578
713
|
|
|
579
714
|
export type MakeContext<Make> = /*Make extends { readonly effect: (_: any) => Effect.Effect<any, any, infer R> } ? R
|
|
580
715
|
: Make extends { readonly effect: (_: any) => Effect.Effect<any, any, never> } ? never
|
|
581
716
|
: */
|
|
582
717
|
// v4: generators yield Yieldable with asEffect()
|
|
583
|
-
Make extends { readonly effect: (_: any) => Generator<Yieldable<any, any, any
|
|
584
|
-
: Make extends { readonly effect: (_: any) => Generator<Yieldable<any, any, any, infer R
|
|
718
|
+
Make extends { readonly effect: (_: any) => Generator<Yieldable<any, any, any>> } ? never
|
|
719
|
+
: Make extends { readonly effect: (_: any) => Generator<Yieldable<any, any, any, infer R>> } ? R
|
|
585
720
|
: never
|
|
586
721
|
|
|
587
722
|
export type MakeHandlers<Make, _Handlers extends Record<string, any>> = /*Make extends
|
|
588
723
|
{ readonly effect: (_: any) => Effect.Effect<{ [K in keyof Handlers]: AnyHandler<Handlers[K]> }, any, any> }
|
|
589
724
|
? Effect.Success<ReturnType<Make["effect"]>>
|
|
590
725
|
: */
|
|
591
|
-
Make extends { readonly effect: (_: any) => Generator<any, infer S
|
|
726
|
+
Make extends { readonly effect: (_: any) => Generator<any, infer S> } ? S
|
|
592
727
|
: never
|
|
593
728
|
|
|
594
729
|
export type MakeDepsE<Make> = Layer.Error<MakeDeps<Make>>
|
package/src/api/setupRequest.ts
CHANGED
|
@@ -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
|
-
|
|
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>(
|
|
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
|
|
8
|
+
import { congruential32 } from "pure-rand/generator/congruential32"
|
|
9
9
|
|
|
10
|
-
const
|
|
10
|
+
const seed = 5
|
|
11
|
+
const rng = congruential32(seed)
|
|
12
|
+
const rnd = new Random(rng)
|
|
11
13
|
|
|
12
14
|
setFaker(faker)
|
|
13
15
|
|
package/src/errorReporter.ts
CHANGED
|
@@ -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
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
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
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
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
|
-
|
|
70
|
-
scope.setContext("
|
|
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
|
-
|
|
77
|
-
) {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
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
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
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
|
-
|
|
109
|
-
|
|
110
|
-
}
|
|
97
|
+
console.warn(message, extras)
|
|
98
|
+
})
|
package/src/logger/shared.ts
CHANGED
|
@@ -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
|
|
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
|
),
|