@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.
- package/CHANGELOG.md +1410 -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 +112 -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 +318 -240
- 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 +39 -3
- package/dist/api/routing/middleware/middleware.d.ts.map +1 -1
- package/dist/api/routing/middleware/middleware.js +46 -14
- 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 +25 -26
- package/dist/api/routing.d.ts.map +1 -1
- package/dist/api/routing.js +99 -35
- 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 +8 -10
- 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 +452 -342
- 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 +53 -12
- package/src/api/routing/middleware.ts +0 -2
- package/src/api/routing.ts +173 -63
- 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 +19 -17
- 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 +183 -0
- package/test/routing-interruptibility.test.ts +63 -0
- package/test/rpc-e2e-invalidation.test.ts +249 -0
- package/test/rpc-multi-middleware.test.ts +78 -9
- package/test/rpc-stream-fullstack.test.ts +325 -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,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: (
|
|
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]>) =>
|
|
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
|
|
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
|
|
233
|
+
type HandlerWithInputStream<
|
|
223
234
|
Action extends AnyRequestModule,
|
|
224
235
|
RT extends RequestType
|
|
225
|
-
> =
|
|
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
|
-
|
|
|
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:
|
|
254
|
+
| { raw: HandlerWithInputStream<Action, RequestTypes.RAW> }
|
|
244
255
|
|
|
245
256
|
type AnyHandlers<Action extends AnyRequestModule> = HandlersRaw<Action> | HandlersDecoded<Action>
|
|
246
257
|
|
|
247
|
-
const
|
|
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]
|
|
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
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
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
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
419
|
-
|
|
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
|
|
576
|
-
: Make extends { readonly effect: (_: any) => Generator<Yieldable<any, any, infer E, any
|
|
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
|
|
584
|
-
: Make extends { readonly effect: (_: any) => Generator<Yieldable<any, any, any, infer 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
|
|
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>>
|
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
|
),
|