@effect-app/infra 4.0.0-beta.24 → 4.0.0-beta.241
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 +1818 -0
- package/_check.sh +1 -1
- package/dist/CUPS.d.ts +12 -7
- package/dist/CUPS.d.ts.map +1 -1
- package/dist/CUPS.js +16 -12
- package/dist/Emailer/Sendgrid.d.ts +15 -15
- package/dist/Emailer/Sendgrid.d.ts.map +1 -1
- package/dist/Emailer/Sendgrid.js +21 -17
- package/dist/Emailer/fake.d.ts +1 -1
- package/dist/Emailer/fake.js +3 -3
- package/dist/Emailer/service.d.ts +13 -4
- package/dist/Emailer/service.d.ts.map +1 -1
- package/dist/Emailer/service.js +4 -3
- package/dist/Emailer.d.ts +1 -1
- package/dist/MainFiberSet.d.ts +12 -9
- package/dist/MainFiberSet.d.ts.map +1 -1
- package/dist/MainFiberSet.js +10 -6
- package/dist/Model/Repository/Registry.d.ts +21 -0
- package/dist/Model/Repository/Registry.d.ts.map +1 -0
- package/dist/Model/Repository/Registry.js +18 -0
- package/dist/Model/Repository/ext.d.ts +35 -16
- package/dist/Model/Repository/ext.d.ts.map +1 -1
- package/dist/Model/Repository/ext.js +60 -3
- package/dist/Model/Repository/internal/internal.d.ts +9 -6
- package/dist/Model/Repository/internal/internal.d.ts.map +1 -1
- package/dist/Model/Repository/internal/internal.js +141 -59
- package/dist/Model/Repository/legacy.d.ts +4 -2
- package/dist/Model/Repository/legacy.d.ts.map +1 -1
- package/dist/Model/Repository/makeRepo.d.ts +10 -6
- package/dist/Model/Repository/makeRepo.d.ts.map +1 -1
- package/dist/Model/Repository/makeRepo.js +5 -2
- package/dist/Model/Repository/service.d.ts +32 -24
- package/dist/Model/Repository/service.d.ts.map +1 -1
- package/dist/Model/Repository/validation.d.ts +47 -18
- package/dist/Model/Repository/validation.d.ts.map +1 -1
- package/dist/Model/Repository/validation.js +6 -6
- 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 +6 -5
- package/dist/Model/dsl.d.ts.map +1 -1
- package/dist/Model/dsl.js +2 -3
- 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 +5 -5
- package/dist/Model/query/dsl.d.ts +216 -18
- package/dist/Model/query/dsl.d.ts.map +1 -1
- package/dist/Model/query/dsl.js +240 -5
- package/dist/Model/query/new-kid-interpreter.d.ts +116 -8
- package/dist/Model/query/new-kid-interpreter.d.ts.map +1 -1
- package/dist/Model/query/new-kid-interpreter.js +177 -6
- 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 +7 -8
- package/dist/QueueMaker/SQLQueue.d.ts.map +1 -1
- package/dist/QueueMaker/SQLQueue.js +135 -117
- package/dist/QueueMaker/errors.d.ts +5 -3
- package/dist/QueueMaker/errors.d.ts.map +1 -1
- package/dist/QueueMaker/errors.js +4 -2
- package/dist/QueueMaker/memQueue.d.ts +9 -5
- package/dist/QueueMaker/memQueue.d.ts.map +1 -1
- package/dist/QueueMaker/memQueue.js +81 -65
- package/dist/QueueMaker/sbqueue.d.ts +8 -4
- package/dist/QueueMaker/sbqueue.d.ts.map +1 -1
- package/dist/QueueMaker/sbqueue.js +57 -55
- package/dist/QueueMaker/service.d.ts +4 -2
- package/dist/QueueMaker/service.d.ts.map +1 -1
- package/dist/QueueMaker/service.js +1 -1
- package/dist/RequestContext.d.ts +75 -35
- package/dist/RequestContext.d.ts.map +1 -1
- package/dist/RequestContext.js +14 -14
- package/dist/RequestFiberSet.d.ts +10 -7
- package/dist/RequestFiberSet.d.ts.map +1 -1
- package/dist/RequestFiberSet.js +12 -7
- package/dist/Store/ContextMapContainer.d.ts +22 -3
- package/dist/Store/ContextMapContainer.d.ts.map +1 -1
- package/dist/Store/ContextMapContainer.js +18 -4
- package/dist/Store/Cosmos/query.d.ts +13 -2
- package/dist/Store/Cosmos/query.d.ts.map +1 -1
- package/dist/Store/Cosmos/query.js +179 -41
- package/dist/Store/Cosmos.d.ts +2 -2
- package/dist/Store/Cosmos.d.ts.map +1 -1
- package/dist/Store/Cosmos.js +343 -244
- package/dist/Store/Disk.d.ts +3 -3
- package/dist/Store/Disk.d.ts.map +1 -1
- package/dist/Store/Disk.js +76 -36
- package/dist/Store/Memory.d.ts +7 -4
- package/dist/Store/Memory.d.ts.map +1 -1
- package/dist/Store/Memory.js +327 -62
- 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 +233 -0
- package/dist/Store/SQL/query.d.ts +49 -0
- package/dist/Store/SQL/query.d.ts.map +1 -0
- package/dist/Store/SQL/query.js +527 -0
- package/dist/Store/SQL.d.ts +21 -0
- package/dist/Store/SQL.d.ts.map +1 -0
- package/dist/Store/SQL.js +450 -0
- package/dist/Store/codeFilter.d.ts +2 -2
- package/dist/Store/codeFilter.d.ts.map +1 -1
- package/dist/Store/codeFilter.js +6 -3
- package/dist/Store/index.d.ts +6 -3
- package/dist/Store/index.d.ts.map +1 -1
- package/dist/Store/index.js +18 -4
- package/dist/Store/service.d.ts +39 -9
- package/dist/Store/service.d.ts.map +1 -1
- package/dist/Store/service.js +31 -7
- package/dist/Store/utils.d.ts +3 -2
- package/dist/Store/utils.d.ts.map +1 -1
- package/dist/Store/utils.js +5 -5
- package/dist/Store.d.ts +1 -1
- package/dist/adapters/SQL/Model.d.ts +32 -43
- package/dist/adapters/SQL/Model.d.ts.map +1 -1
- package/dist/adapters/SQL/Model.js +30 -39
- package/dist/adapters/SQL.d.ts +1 -1
- package/dist/adapters/ServiceBus.d.ts +14 -11
- package/dist/adapters/ServiceBus.d.ts.map +1 -1
- package/dist/adapters/ServiceBus.js +30 -21
- package/dist/adapters/cosmos-client.d.ts +5 -3
- package/dist/adapters/cosmos-client.d.ts.map +1 -1
- package/dist/adapters/cosmos-client.js +6 -4
- 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 +1 -1
- package/dist/adapters/logger.d.ts.map +1 -1
- package/dist/adapters/memQueue.d.ts +5 -3
- package/dist/adapters/memQueue.d.ts.map +1 -1
- package/dist/adapters/memQueue.js +6 -5
- package/dist/adapters/mongo-client.d.ts +4 -3
- package/dist/adapters/mongo-client.d.ts.map +1 -1
- package/dist/adapters/mongo-client.js +5 -3
- package/dist/adapters/redis-client.d.ts +6 -3
- package/dist/adapters/redis-client.d.ts.map +1 -1
- package/dist/adapters/redis-client.js +7 -3
- package/dist/api/ContextProvider.d.ts +12 -9
- package/dist/api/ContextProvider.d.ts.map +1 -1
- package/dist/api/ContextProvider.js +9 -7
- package/dist/api/codec.d.ts +1 -1
- package/dist/api/internal/RequestContextMiddleware.d.ts +3 -3
- package/dist/api/internal/RequestContextMiddleware.d.ts.map +1 -1
- package/dist/api/internal/RequestContextMiddleware.js +18 -7
- package/dist/api/internal/auth.d.ts +45 -7
- package/dist/api/internal/auth.d.ts.map +1 -1
- package/dist/api/internal/auth.js +162 -29
- package/dist/api/internal/events.d.ts +6 -4
- package/dist/api/internal/events.d.ts.map +1 -1
- package/dist/api/internal/events.js +18 -11
- package/dist/api/internal/health.d.ts +1 -1
- package/dist/api/layerUtils.d.ts +15 -7
- package/dist/api/layerUtils.d.ts.map +1 -1
- package/dist/api/layerUtils.js +7 -6
- package/dist/api/middlewares.d.ts +1 -1
- package/dist/api/reportError.d.ts +2 -2
- package/dist/api/reportError.d.ts.map +1 -1
- package/dist/api/reportError.js +3 -2
- package/dist/api/routing/middleware/RouterMiddleware.d.ts +5 -4
- package/dist/api/routing/middleware/RouterMiddleware.d.ts.map +1 -1
- package/dist/api/routing/middleware/middleware.d.ts +42 -3
- package/dist/api/routing/middleware/middleware.d.ts.map +1 -1
- package/dist/api/routing/middleware/middleware.js +53 -17
- package/dist/api/routing/middleware.d.ts +3 -4
- 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/schema/jwt.js +3 -2
- 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 +4 -4
- package/dist/api/routing/utils.d.ts.map +1 -1
- package/dist/api/routing/utils.js +3 -2
- package/dist/api/routing.d.ts +84 -38
- package/dist/api/routing.d.ts.map +1 -1
- package/dist/api/routing.js +115 -45
- package/dist/api/setupRequest.d.ts +13 -6
- package/dist/api/setupRequest.d.ts.map +1 -1
- package/dist/api/setupRequest.js +37 -11
- package/dist/api/util.d.ts +1 -1
- package/dist/arbs.d.ts +2 -2
- package/dist/arbs.d.ts.map +1 -1
- package/dist/arbs.js +5 -3
- package/dist/errorReporter.d.ts +7 -5
- package/dist/errorReporter.d.ts.map +1 -1
- package/dist/errorReporter.js +22 -26
- package/dist/errors.d.ts +1 -1
- package/dist/fileUtil.d.ts +2 -2
- package/dist/fileUtil.d.ts.map +1 -1
- package/dist/fileUtil.js +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/logger/jsonLogger.d.ts +2 -2
- package/dist/logger/jsonLogger.d.ts.map +1 -1
- package/dist/logger/jsonLogger.js +4 -2
- package/dist/logger/logFmtLogger.d.ts +2 -2
- package/dist/logger/logFmtLogger.d.ts.map +1 -1
- package/dist/logger/logFmtLogger.js +2 -2
- package/dist/logger/shared.d.ts +2 -2
- package/dist/logger/shared.d.ts.map +1 -1
- package/dist/logger/shared.js +3 -3
- package/dist/logger.d.ts +2 -2
- package/dist/logger.d.ts.map +1 -1
- package/dist/otel.d.ts +75 -0
- package/dist/otel.d.ts.map +1 -0
- package/dist/otel.js +65 -0
- package/dist/rateLimit.d.ts +12 -4
- package/dist/rateLimit.d.ts.map +1 -1
- package/dist/rateLimit.js +7 -12
- package/dist/test.d.ts +3 -3
- package/dist/test.d.ts.map +1 -1
- package/dist/test.js +2 -2
- package/dist/vitest.d.ts +1 -1
- package/examples/query.ts +46 -38
- package/package.json +46 -37
- package/src/CUPS.ts +15 -11
- package/src/Emailer/Sendgrid.ts +65 -57
- package/src/Emailer/fake.ts +2 -2
- package/src/Emailer/service.ts +13 -3
- package/src/MainFiberSet.ts +12 -10
- package/src/Model/Repository/Registry.ts +34 -0
- package/src/Model/Repository/ext.ts +103 -11
- package/src/Model/Repository/internal/internal.ts +266 -151
- package/src/Model/Repository/legacy.ts +3 -1
- package/src/Model/Repository/makeRepo.ts +15 -10
- package/src/Model/Repository/service.ts +35 -23
- package/src/Model/Repository/validation.ts +5 -5
- package/src/Model/Repository.ts +1 -0
- package/src/Model/dsl.ts +5 -4
- package/src/Model/filter/types/path/eager.ts +1 -2
- package/src/Model/filter/types.ts +4 -4
- package/src/Model/query/dsl.ts +456 -20
- package/src/Model/query/new-kid-interpreter.ts +281 -7
- package/src/Model.ts +1 -0
- package/src/QueueMaker/SQLQueue.ts +150 -153
- package/src/QueueMaker/errors.ts +3 -1
- package/src/QueueMaker/memQueue.ts +111 -105
- package/src/QueueMaker/sbqueue.ts +76 -88
- package/src/QueueMaker/service.ts +3 -1
- package/src/RequestContext.ts +15 -16
- package/src/RequestFiberSet.ts +12 -7
- package/src/Store/ContextMapContainer.ts +46 -3
- package/src/Store/Cosmos/query.ts +214 -50
- package/src/Store/Cosmos.ts +491 -350
- package/src/Store/Disk.ts +106 -66
- package/src/Store/Memory.ts +365 -91
- package/src/Store/SQL/Pg.ts +364 -0
- package/src/Store/SQL/query.ts +603 -0
- package/src/Store/SQL.ts +736 -0
- package/src/Store/codeFilter.ts +5 -2
- package/src/Store/index.ts +20 -3
- package/src/Store/service.ts +60 -11
- package/src/Store/utils.ts +25 -23
- package/src/adapters/SQL/Model.ts +42 -41
- package/src/adapters/ServiceBus.ts +131 -121
- package/src/adapters/cosmos-client.ts +5 -3
- package/src/adapters/index.ts +7 -0
- package/src/adapters/memQueue.ts +5 -4
- package/src/adapters/mongo-client.ts +4 -2
- package/src/adapters/redis-client.ts +6 -2
- package/src/api/ContextProvider.ts +19 -16
- package/src/api/internal/RequestContextMiddleware.ts +24 -6
- package/src/api/internal/auth.ts +248 -44
- package/src/api/internal/events.ts +21 -12
- package/src/api/layerUtils.ts +13 -9
- package/src/api/reportError.ts +2 -1
- package/src/api/routing/middleware/RouterMiddleware.ts +5 -4
- package/src/api/routing/middleware/middleware.ts +60 -15
- package/src/api/routing/middleware.ts +2 -4
- package/src/api/routing/schema/jwt.ts +2 -1
- package/src/api/routing/utils.ts +2 -1
- package/src/api/routing.ts +309 -139
- package/src/api/setupRequest.ts +63 -12
- package/src/arbs.ts +5 -3
- package/src/errorReporter.ts +65 -75
- package/src/fileUtil.ts +1 -1
- package/src/logger/jsonLogger.ts +3 -1
- package/src/logger/logFmtLogger.ts +1 -1
- package/src/logger/shared.ts +3 -2
- package/src/otel.ts +152 -0
- package/src/rateLimit.ts +34 -23
- package/src/test.ts +2 -2
- package/test/auth.test.ts +101 -0
- package/test/contextProvider.test.ts +14 -11
- package/test/controller.test.ts +25 -29
- package/test/cosmos-query.test.ts +159 -0
- 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/cosmos-query.test.d.ts.map +1 -0
- package/test/dist/date-query.test.d.ts.map +1 -0
- package/test/dist/fixtures.d.ts +30 -12
- package/test/dist/fixtures.d.ts.map +1 -1
- package/test/dist/fixtures.js +17 -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-context-map-streaming.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 +16 -9
- package/test/layerUtils.test.ts +1 -1
- package/test/query.test.ts +901 -38
- package/test/rawQuery.test.ts +338 -20
- package/test/repository-ext.test.ts +62 -0
- package/test/requires.test.ts +10 -5
- package/test/router-generator.test.ts +187 -0
- package/test/routing-interruptibility.test.ts +66 -0
- package/test/rpc-context-map-streaming.test.ts +262 -0
- package/test/rpc-e2e-invalidation.test.ts +256 -0
- package/test/rpc-multi-middleware.test.ts +84 -9
- package/test/rpc-stream-fullstack.test.ts +304 -0
- package/test/sql-store.test.ts +1711 -0
- package/test/validateSample.test.ts +17 -12
- package/tsconfig.examples.json +1 -1
- package/tsconfig.json +2 -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
|
@@ -1,67 +1,69 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/prefer-promise-reject-errors */
|
|
2
2
|
import { type OperationOptionsBase, type ProcessErrorArgs, ServiceBusClient, type ServiceBusMessage, type ServiceBusMessageBatch, type ServiceBusReceivedMessage, type ServiceBusReceiver } from "@azure/service-bus"
|
|
3
|
-
import
|
|
3
|
+
import * as Context from "effect-app/Context"
|
|
4
|
+
import * as Effect from "effect-app/Effect"
|
|
5
|
+
import * as Layer from "effect-app/Layer"
|
|
6
|
+
import * as Cause from "effect/Cause"
|
|
7
|
+
import * as Exit from "effect/Exit"
|
|
8
|
+
import * as FiberSet from "effect/FiberSet"
|
|
9
|
+
import type * as Scope from "effect/Scope"
|
|
4
10
|
import { InfraLogger } from "../logger.js"
|
|
5
11
|
|
|
6
|
-
const
|
|
12
|
+
const logged = (name: string) => <A, E, R>(self: Effect.Effect<A, E, R>) =>
|
|
7
13
|
Effect.logInfo(name).pipe(
|
|
8
14
|
Effect.andThen(self),
|
|
9
15
|
Effect.tap(Effect.logInfo(name + " done")),
|
|
10
|
-
Effect.withLogSpan(name)
|
|
11
|
-
Effect.withSpan(name)
|
|
16
|
+
Effect.withLogSpan(name)
|
|
12
17
|
)
|
|
13
18
|
|
|
14
19
|
function makeClient(url: string) {
|
|
15
20
|
return Effect.acquireRelease(
|
|
16
|
-
Effect.sync(() => new ServiceBusClient(url)).pipe(
|
|
17
|
-
(client) => Effect.promise(() => client.close()).pipe(
|
|
21
|
+
Effect.sync(() => new ServiceBusClient(url)).pipe(logged("ServiceBus.client.create")),
|
|
22
|
+
(client) => Effect.promise(() => client.close()).pipe(logged("ServiceBus.client.close"))
|
|
18
23
|
)
|
|
19
24
|
}
|
|
20
25
|
|
|
21
26
|
export class ServiceBusClientTag
|
|
22
|
-
extends
|
|
27
|
+
extends Context.Opaque<ServiceBusClientTag, ServiceBusClient>()("@services/Client", { make: makeClient })
|
|
23
28
|
{
|
|
24
29
|
static readonly layer = (url: string) => this.toLayer(this.make(url))
|
|
25
30
|
}
|
|
26
31
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
const serviceBusClient = yield* ServiceBusClientTag
|
|
32
|
+
const makeSender_ = Effect.fnUntraced(function*(queueName: string) {
|
|
33
|
+
const serviceBusClient = yield* ServiceBusClientTag
|
|
30
34
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
const makeSender = (name: string) =>
|
|
41
|
-
Effect.gen(function*() {
|
|
42
|
-
const sender = yield* makeSender_(name)
|
|
43
|
-
const sendMessages = Effect.fnUntraced(function*(
|
|
44
|
-
messages: ServiceBusMessage | ServiceBusMessage[] | ServiceBusMessageBatch,
|
|
45
|
-
options?: Omit<OperationOptionsBase, "abortSignal">
|
|
46
|
-
) {
|
|
47
|
-
return yield* Effect.promise((abortSignal) => sender.sendMessages(messages, { ...options, abortSignal }))
|
|
48
|
-
})
|
|
35
|
+
return yield* Effect.acquireRelease(
|
|
36
|
+
Effect.sync(() => serviceBusClient.createSender(queueName)).pipe(
|
|
37
|
+
logged(`ServiceBus.sender.create ${queueName}`)
|
|
38
|
+
),
|
|
39
|
+
(sender) => Effect.promise(() => sender.close()).pipe(logged(`ServiceBus.sender.close ${queueName}`))
|
|
40
|
+
)
|
|
41
|
+
})
|
|
49
42
|
|
|
50
|
-
|
|
43
|
+
const makeSender = Effect.fnUntraced(function*(name: string) {
|
|
44
|
+
const sender = yield* makeSender_(name)
|
|
45
|
+
const sendMessages = Effect.fnUntraced(function*(
|
|
46
|
+
messages: ServiceBusMessage | ServiceBusMessage[] | ServiceBusMessageBatch,
|
|
47
|
+
options?: Omit<OperationOptionsBase, "abortSignal">
|
|
48
|
+
) {
|
|
49
|
+
return yield* Effect.promise((abortSignal) => sender.sendMessages(messages, { ...options, abortSignal }))
|
|
51
50
|
})
|
|
52
51
|
|
|
53
|
-
|
|
52
|
+
return { name, sendMessages }
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
export class Sender extends Context.Opaque<Sender, {
|
|
54
56
|
name: string
|
|
55
57
|
sendMessages: (
|
|
56
58
|
messages: ServiceBusMessage | ServiceBusMessage[] | ServiceBusMessageBatch,
|
|
57
59
|
options?: Omit<OperationOptionsBase, "abortSignal">
|
|
58
|
-
) => Effect.Effect<void
|
|
60
|
+
) => Effect.Effect<void>
|
|
59
61
|
}>()("Sender", { make: makeSender }) {
|
|
60
62
|
static readonly layer = (name: string) => this.toLayer(this.make(name))
|
|
61
63
|
}
|
|
62
64
|
|
|
63
65
|
export const SenderTag = <Id>() => <Key extends string>(queueName: Key) => {
|
|
64
|
-
const tag =
|
|
66
|
+
const tag = Context.Service<Id, Sender>(`ServiceBus.Sender.${queueName}`)
|
|
65
67
|
|
|
66
68
|
return Object.assign(tag, {
|
|
67
69
|
layer: Layer.effect(
|
|
@@ -71,99 +73,107 @@ export const SenderTag = <Id>() => <Key extends string>(queueName: Key) => {
|
|
|
71
73
|
})
|
|
72
74
|
}
|
|
73
75
|
|
|
74
|
-
const makeReceiver = (name: string)
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
(
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
)
|
|
76
|
+
const makeReceiver = Effect.fnUntraced(function*(name: string) {
|
|
77
|
+
const serviceBusClient = yield* ServiceBusClientTag
|
|
78
|
+
|
|
79
|
+
const makeReceiver = Effect.fnUntraced(
|
|
80
|
+
function*(queueName: string, waitTillEmpty: Effect.Effect<void>, sessionId?: string) {
|
|
81
|
+
const annotate = sessionId !== undefined
|
|
82
|
+
? Effect.annotateLogs({ "messaging.session.id": sessionId })
|
|
83
|
+
: <A, E, R>(self: Effect.Effect<A, E, R>): Effect.Effect<A, E, R> => self
|
|
84
|
+
return yield* Effect.acquireRelease(
|
|
85
|
+
(sessionId
|
|
86
|
+
? Effect.promise(() => serviceBusClient.acceptSession(queueName, sessionId))
|
|
87
|
+
: Effect.sync(() => serviceBusClient.createReceiver(queueName)))
|
|
88
|
+
.pipe(logged(`ServiceBus.receiver.create ${queueName}`), annotate),
|
|
89
|
+
(r) =>
|
|
90
|
+
waitTillEmpty.pipe(
|
|
91
|
+
logged(`ServiceBus.receiver.waitTillEmpty ${queueName}`),
|
|
92
|
+
Effect.andThen(
|
|
93
|
+
Effect.promise(() => r.close()).pipe(
|
|
94
|
+
logged(`ServiceBus.receiver.close ${queueName}`)
|
|
95
|
+
)
|
|
96
|
+
),
|
|
97
|
+
logged(`ServiceBus.receiver.release ${queueName}`),
|
|
98
|
+
annotate
|
|
99
|
+
)
|
|
100
|
+
)
|
|
101
|
+
}
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
const make = (waitTillEmpty: Effect.Effect<void>) => makeReceiver(name, waitTillEmpty)
|
|
105
|
+
|
|
106
|
+
const makeSession = (sessionId: string, waitTillEmpty: Effect.Effect<void>) =>
|
|
107
|
+
makeReceiver(name, waitTillEmpty, sessionId)
|
|
108
|
+
|
|
109
|
+
return {
|
|
110
|
+
name,
|
|
111
|
+
make,
|
|
112
|
+
makeSession,
|
|
113
|
+
subscribe: Effect.fnUntraced(function*<RMsg, RErr>(hndlr: MessageHandlers<RMsg, RErr>, sessionId?: string) {
|
|
114
|
+
const fs = yield* FiberSet.make()
|
|
115
|
+
const fr = yield* FiberSet.runtime(fs)<RMsg | RErr>()
|
|
116
|
+
const wait = Effect
|
|
117
|
+
.gen(function*() {
|
|
118
|
+
if ((yield* FiberSet.size(fs)) > 0) {
|
|
119
|
+
yield* InfraLogger.logDebug("Waiting ServiceBusFiberSet to be empty: " + (yield* FiberSet.size(fs)))
|
|
120
|
+
}
|
|
121
|
+
while ((yield* FiberSet.size(fs)) > 0) yield* Effect.sleep("250 millis")
|
|
122
|
+
})
|
|
123
|
+
const r = yield* sessionId
|
|
124
|
+
? makeSession(
|
|
125
|
+
sessionId,
|
|
126
|
+
wait
|
|
127
|
+
)
|
|
128
|
+
: make(wait)
|
|
129
|
+
|
|
130
|
+
const runEffect = <E>(effect: Effect.Effect<void, E, RMsg | RErr>) =>
|
|
131
|
+
new Promise<void>((resolve, reject) =>
|
|
132
|
+
fr(effect)
|
|
133
|
+
.addObserver((exit) => {
|
|
134
|
+
if (Exit.isSuccess(exit)) {
|
|
135
|
+
resolve(exit.value)
|
|
136
|
+
} else {
|
|
137
|
+
// disable @typescript-eslint/prefer-promise-reject-errors
|
|
138
|
+
reject(Cause.pretty(exit.cause))
|
|
139
|
+
}
|
|
140
|
+
})
|
|
95
141
|
)
|
|
96
|
-
}
|
|
97
|
-
)
|
|
98
142
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
const r = yield* sessionId
|
|
119
|
-
? makeSession(
|
|
120
|
-
sessionId,
|
|
121
|
-
wait
|
|
122
|
-
)
|
|
123
|
-
: make(wait)
|
|
124
|
-
|
|
125
|
-
const runEffect = <E>(effect: Effect.Effect<void, E, RMsg | RErr>) =>
|
|
126
|
-
new Promise<void>((resolve, reject) =>
|
|
127
|
-
fr(effect)
|
|
128
|
-
.addObserver((exit) => {
|
|
129
|
-
if (Exit.isSuccess(exit)) {
|
|
130
|
-
resolve(exit.value)
|
|
131
|
-
} else {
|
|
132
|
-
// disable @typescript-eslint/prefer-promise-reject-errors
|
|
133
|
-
reject(Cause.pretty(exit.cause))
|
|
134
|
-
}
|
|
143
|
+
const annotate = sessionId !== undefined
|
|
144
|
+
? Effect.annotateLogs({ "messaging.session.id": sessionId })
|
|
145
|
+
: <A, E, R>(self: Effect.Effect<A, E, R>): Effect.Effect<A, E, R> => self
|
|
146
|
+
yield* Effect.acquireRelease(
|
|
147
|
+
Effect
|
|
148
|
+
.sync(() => {
|
|
149
|
+
const s = r
|
|
150
|
+
.subscribe({
|
|
151
|
+
processError: (err) =>
|
|
152
|
+
runEffect(
|
|
153
|
+
hndlr
|
|
154
|
+
.processError(err)
|
|
155
|
+
.pipe(
|
|
156
|
+
Effect.catchCause((cause) => Effect.logError("ServiceBus Error", cause)),
|
|
157
|
+
annotate
|
|
158
|
+
)
|
|
159
|
+
),
|
|
160
|
+
processMessage: (msg) => runEffect(hndlr.processMessage(msg).pipe(annotate))
|
|
161
|
+
// DO NOT CATCH ERRORS here as they should return to the queue!
|
|
135
162
|
})
|
|
163
|
+
return { close: Effect.promise(() => s.close()) }
|
|
164
|
+
})
|
|
165
|
+
.pipe(logged("ServiceBus.subscription.create"), annotate),
|
|
166
|
+
(subscription) =>
|
|
167
|
+
subscription.close.pipe(
|
|
168
|
+
logged("ServiceBus.subscription.close"),
|
|
169
|
+
annotate
|
|
136
170
|
)
|
|
171
|
+
) as Effect.Effect<void, never, Scope.Scope> // wth is going on here
|
|
172
|
+
})
|
|
173
|
+
}
|
|
174
|
+
})
|
|
137
175
|
|
|
138
|
-
|
|
139
|
-
Effect
|
|
140
|
-
.sync(() => {
|
|
141
|
-
const s = r
|
|
142
|
-
.subscribe({
|
|
143
|
-
processError: (err) =>
|
|
144
|
-
runEffect(
|
|
145
|
-
hndlr
|
|
146
|
-
.processError(err)
|
|
147
|
-
.pipe(
|
|
148
|
-
Effect.catchCause((cause) => Effect.logError(`ServiceBus Error ${sessionId}`, cause))
|
|
149
|
-
)
|
|
150
|
-
),
|
|
151
|
-
processMessage: (msg) => runEffect(hndlr.processMessage(msg))
|
|
152
|
-
// DO NOT CATCH ERRORS here as they should return to the queue!
|
|
153
|
-
})
|
|
154
|
-
return { close: Effect.promise(() => s.close()) }
|
|
155
|
-
})
|
|
156
|
-
.pipe(withSpanAndLog(`ServiceBus.subscription.create ${sessionId}`)),
|
|
157
|
-
(subscription) =>
|
|
158
|
-
subscription.close.pipe(
|
|
159
|
-
withSpanAndLog(`ServiceBus.subscription.close ${sessionId}`)
|
|
160
|
-
)
|
|
161
|
-
) as Effect.Effect<void, never, Scope.Scope> // wth is going on here
|
|
162
|
-
})
|
|
163
|
-
}
|
|
164
|
-
})
|
|
165
|
-
|
|
166
|
-
export class Receiver extends ServiceMap.Opaque<Receiver, {
|
|
176
|
+
export class Receiver extends Context.Opaque<Receiver, {
|
|
167
177
|
name: string
|
|
168
178
|
make: (waitTillEmpty: Effect.Effect<void>) => Effect.Effect<ServiceBusReceiver, never, Scope.Scope>
|
|
169
179
|
makeSession: (
|
|
@@ -180,7 +190,7 @@ export class Receiver extends ServiceMap.Opaque<Receiver, {
|
|
|
180
190
|
}
|
|
181
191
|
|
|
182
192
|
export const ReceiverTag = <Id>() => <Key extends string>(queueName: Key) => {
|
|
183
|
-
const tag =
|
|
193
|
+
const tag = Context.Service<Id, Receiver>(`ServiceBus.Receiver.${queueName}`)
|
|
184
194
|
|
|
185
195
|
return Object.assign(tag, {
|
|
186
196
|
layer: Layer.effect(
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
import { CosmosClient as ComosClient_ } from "@azure/cosmos"
|
|
2
|
-
import
|
|
2
|
+
import * as Context from "effect-app/Context"
|
|
3
|
+
import * as Effect from "effect-app/Effect"
|
|
4
|
+
import * as Layer from "effect-app/Layer"
|
|
3
5
|
|
|
4
6
|
const withClient = (url: string) => Effect.sync(() => new ComosClient_(url))
|
|
5
7
|
|
|
6
8
|
export const makeCosmosClient = (url: string, dbName: string) =>
|
|
7
9
|
Effect.map(withClient(url), (x) => ({ db: x.database(dbName) }))
|
|
8
10
|
|
|
9
|
-
export class CosmosClient extends
|
|
11
|
+
export class CosmosClient extends Context.Service<CosmosClient, {
|
|
10
12
|
readonly db: ReturnType<InstanceType<typeof ComosClient_>["database"]>
|
|
11
13
|
}>()("@services/CosmosClient") {}
|
|
12
14
|
|
|
13
|
-
export const db = CosmosClient.
|
|
15
|
+
export const db = CosmosClient.pipe(Effect.map((_) => _.db))
|
|
14
16
|
|
|
15
17
|
export const CosmosClientLayer = (cosmosUrl: string, dbName: string) =>
|
|
16
18
|
Layer.effect(CosmosClient, makeCosmosClient(cosmosUrl, dbName))
|
package/src/adapters/index.ts
CHANGED
package/src/adapters/memQueue.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import
|
|
2
|
-
import * as
|
|
1
|
+
import * as Context from "effect-app/Context"
|
|
2
|
+
import * as Effect from "effect-app/Effect"
|
|
3
|
+
import * as Queue from "effect/Queue"
|
|
3
4
|
|
|
4
5
|
const make = Effect
|
|
5
6
|
.gen(function*() {
|
|
@@ -9,13 +10,13 @@ const make = Effect
|
|
|
9
10
|
getOrCreateQueue: Effect.fnUntraced(function*(k: string) {
|
|
10
11
|
const q = store.get(k)
|
|
11
12
|
if (q) return q
|
|
12
|
-
const newQ = yield*
|
|
13
|
+
const newQ = yield* Queue.unbounded<string>()
|
|
13
14
|
store.set(k, newQ)
|
|
14
15
|
return newQ
|
|
15
16
|
})
|
|
16
17
|
}
|
|
17
18
|
})
|
|
18
19
|
|
|
19
|
-
export class MemQueue extends
|
|
20
|
+
export class MemQueue extends Context.Opaque<MemQueue>()("effect-app/MemQueue", { make }) {
|
|
20
21
|
static readonly Live = this.toLayer(this.make)
|
|
21
22
|
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as Context from "effect-app/Context"
|
|
2
|
+
import * as Effect from "effect-app/Effect"
|
|
3
|
+
import * as Layer from "effect-app/Layer"
|
|
2
4
|
import { MongoClient as MongoClient_ } from "mongodb"
|
|
3
5
|
|
|
4
6
|
// TODO: we should probably share a single client...
|
|
@@ -15,7 +17,7 @@ const withClient = (url: string) =>
|
|
|
15
17
|
|
|
16
18
|
const makeMongoClient = (url: string, dbName?: string) => Effect.map(withClient(url), (x) => ({ db: x.db(dbName) }))
|
|
17
19
|
|
|
18
|
-
export class MongoClient extends
|
|
20
|
+
export class MongoClient extends Context.Service<MongoClient, {
|
|
19
21
|
readonly db: ReturnType<InstanceType<typeof MongoClient_>["db"]>
|
|
20
22
|
}>()("@services/MongoClient") {}
|
|
21
23
|
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as Context from "effect-app/Context"
|
|
2
|
+
import * as Effect from "effect-app/Effect"
|
|
3
|
+
import * as Layer from "effect-app/Layer"
|
|
4
|
+
import * as Option from "effect-app/Option"
|
|
5
|
+
import * as Data from "effect/Data"
|
|
2
6
|
import type { RedisClient as Client } from "redis"
|
|
3
7
|
import Redlock from "redlock"
|
|
4
8
|
|
|
@@ -90,7 +94,7 @@ export const makeRedisClient = (makeClient: () => Client) =>
|
|
|
90
94
|
.pipe(Effect.uninterruptible, Effect.orDie)
|
|
91
95
|
)
|
|
92
96
|
|
|
93
|
-
export class RedisClient extends
|
|
97
|
+
export class RedisClient extends Context.Service<RedisClient, {
|
|
94
98
|
readonly client: Client
|
|
95
99
|
readonly lock: Redlock
|
|
96
100
|
readonly get: (key: string) => Effect.Effect<Option.Option<string>, ConnectionException>
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
-
import {
|
|
2
|
+
import type { NonEmptyReadonlyArray } from "effect-app/Array"
|
|
3
|
+
import * as Context from "effect-app/Context"
|
|
4
|
+
import * as Effect from "effect-app/Effect"
|
|
5
|
+
import * as Layer from "effect-app/Layer"
|
|
6
|
+
import { pipe } from "effect/Function"
|
|
7
|
+
import type * as Scope from "effect/Scope"
|
|
3
8
|
|
|
4
9
|
import { type HttpRouter } from "effect-app/http"
|
|
5
10
|
import { type EffectGenUtils } from "effect-app/utils/gen"
|
|
6
|
-
import { type Yieldable } from "effect/Effect"
|
|
7
11
|
import { type ContextTagWithDefault, type GetContext, type LayerUtils, mergeContexts } from "./layerUtils.js"
|
|
8
12
|
|
|
9
13
|
export interface ContextProviderId {
|
|
@@ -23,7 +27,7 @@ type TDepsArr<TDeps extends ReadonlyArray<any>> = {
|
|
|
23
27
|
// E = never => the context provided cannot trigger errors
|
|
24
28
|
// TODO: remove HttpLayerRouter.Provided - it's not even relevant outside of Http context, while ContextProviders are for anywhere. Only support Scope.Scope?
|
|
25
29
|
// _R extends HttpLayerRouter.Provided => the context provided can only have what HttpLayerRouter.Provided provides as requirements
|
|
26
|
-
ContextTagWithDefault.Base<Effect.Effect<
|
|
30
|
+
ContextTagWithDefault.Base<Effect.Effect<Context.Context<infer _1>, never, infer _R>> // & { _tag: infer _2 }>
|
|
27
31
|
? [_R] extends [HttpRouter.Provided] ? TDeps[K]
|
|
28
32
|
: `HttpLayerRouter.Provided is the only requirement ${TDeps[K]["Service"][
|
|
29
33
|
"_tag"
|
|
@@ -38,7 +42,7 @@ type TDepsArr<TDeps extends ReadonlyArray<any>> = {
|
|
|
38
42
|
> // & { _tag: infer _3 }
|
|
39
43
|
) // [_YW] extends [never] if no yield* is used and just some context is returned
|
|
40
44
|
? [_YW] extends [never] ? TDeps[K]
|
|
41
|
-
: [_YW] extends [
|
|
45
|
+
: [_YW] extends [Effect.Effect<any, never, infer _R>] ? [_R] extends [HttpRouter.Provided] ? TDeps[K]
|
|
42
46
|
: `HttpLayerRouter.Provided is the only requirement ${TDeps[K]["Service"][
|
|
43
47
|
"_tag"
|
|
44
48
|
]}'s returned effect can have`
|
|
@@ -58,9 +62,9 @@ export const mergeContextProviders = <
|
|
|
58
62
|
Effect.Effect<
|
|
59
63
|
// we need to merge all contexts into one
|
|
60
64
|
// v4: Service.Shape extracts the service value type (v3's Tag.Identifier)
|
|
61
|
-
|
|
65
|
+
Context.Context<GetContext<EffectGenUtils.Success<Context.Service.Shape<TDeps[number]>>>>,
|
|
62
66
|
never,
|
|
63
|
-
EffectGenUtils.
|
|
67
|
+
EffectGenUtils.Context<Context.Service.Shape<TDeps[number]>>
|
|
64
68
|
>,
|
|
65
69
|
LayerUtils.GetLayersError<{ [K in keyof TDeps]: TDeps[K]["Default"] }>,
|
|
66
70
|
LayerUtils.GetLayersSuccess<{ [K in keyof TDeps]: TDeps[K]["Default"] }>
|
|
@@ -78,14 +82,14 @@ export const mergeContextProviders = <
|
|
|
78
82
|
handle: handle[Symbol.toStringTag] === "GeneratorFunction" ? Effect.fnUntraced(handle)() : handle
|
|
79
83
|
}
|
|
80
84
|
))
|
|
81
|
-
// services are effects which return some
|
|
85
|
+
// services are effects which return some Context.Context<...>
|
|
82
86
|
const context = yield* mergeContexts(services as any)
|
|
83
87
|
return context
|
|
84
88
|
})
|
|
85
89
|
}) as any
|
|
86
90
|
})
|
|
87
91
|
|
|
88
|
-
// Effect Rpc Middleware: for single tag providing, we could use Provides, for providing
|
|
92
|
+
// Effect Rpc Middleware: for single tag providing, we could use Provides, for providing Context or Layer (bad boy) we could use Wrap..
|
|
89
93
|
export const ContextProvider = <
|
|
90
94
|
ContextProviderA,
|
|
91
95
|
MakeContextProviderE,
|
|
@@ -97,9 +101,8 @@ export const ContextProvider = <
|
|
|
97
101
|
effect: Effect.Effect<
|
|
98
102
|
| Effect.Effect<ContextProviderA, never, ContextProviderR>
|
|
99
103
|
| (() => Generator<
|
|
100
|
-
|
|
101
|
-
ContextProviderA
|
|
102
|
-
any
|
|
104
|
+
Effect.Effect<any, never, ContextProviderR>,
|
|
105
|
+
ContextProviderA
|
|
103
106
|
>),
|
|
104
107
|
MakeContextProviderE,
|
|
105
108
|
MakeContextProviderR | Scope.Scope
|
|
@@ -107,7 +110,7 @@ export const ContextProvider = <
|
|
|
107
110
|
dependencies?: Dependencies
|
|
108
111
|
}
|
|
109
112
|
) => {
|
|
110
|
-
const ctx =
|
|
113
|
+
const ctx = Context.Service<
|
|
111
114
|
ContextProviderId,
|
|
112
115
|
Effect.Effect<ContextProviderA, never, ContextProviderR>
|
|
113
116
|
>(
|
|
@@ -146,17 +149,17 @@ export const MergedContextProvider = <
|
|
|
146
149
|
Effect.Effect<
|
|
147
150
|
// we need to merge all contexts into one
|
|
148
151
|
// v4: Service.Shape extracts the service value type (v3's Tag.Identifier)
|
|
149
|
-
|
|
152
|
+
Context.Context<GetContext<EffectGenUtils.Success<Context.Service.Shape<TDeps[number]>>>>,
|
|
150
153
|
never,
|
|
151
|
-
EffectGenUtils.
|
|
154
|
+
EffectGenUtils.Context<Context.Service.Shape<TDeps[number]>>
|
|
152
155
|
>,
|
|
153
156
|
LayerUtils.GetLayersError<{ [K in keyof TDeps]: TDeps[K]["Default"] }>,
|
|
154
157
|
// v4: Identifier here is correct — it's the nominal service identity for layer provide/exclude
|
|
155
158
|
| Exclude<
|
|
156
|
-
|
|
159
|
+
Context.Service.Identifier<TDeps[number]>,
|
|
157
160
|
LayerUtils.GetLayersSuccess<{ [K in keyof TDeps]: TDeps[K]["Default"] }>
|
|
158
161
|
>
|
|
159
162
|
| LayerUtils.GetLayersContext<{ [K in keyof TDeps]: TDeps[K]["Default"] }>
|
|
160
163
|
>
|
|
161
164
|
|
|
162
|
-
export const EmptyContextProvider = ContextProvider({ effect: Effect.succeed(Effect.succeed(
|
|
165
|
+
export const EmptyContextProvider = ContextProvider({ effect: Effect.succeed(Effect.succeed(Context.empty())) })
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as Effect from "effect-app/Effect"
|
|
2
2
|
import { HttpMiddleware, HttpServerRequest, HttpServerResponse } from "effect-app/http"
|
|
3
|
+
import * as Layer from "effect-app/Layer"
|
|
3
4
|
import { NonEmptyString255 } from "effect-app/Schema"
|
|
4
|
-
import { Locale, RequestContext } from "../../RequestContext.js"
|
|
5
|
-
import {
|
|
5
|
+
import { Locale, LocaleRef, RequestContext, spanAttributes } from "../../RequestContext.js"
|
|
6
|
+
import { ContextMapContainer } from "../../Store/ContextMapContainer.js"
|
|
7
|
+
import { storeId } from "../../Store/Memory.js"
|
|
8
|
+
import { provideOnRequestScope } from "../setupRequest.js"
|
|
6
9
|
|
|
7
10
|
export const RequestContextMiddleware = (defaultLocale: Locale = "en") =>
|
|
8
11
|
HttpMiddleware.make((app) =>
|
|
@@ -21,18 +24,33 @@ export const RequestContextMiddleware = (defaultLocale: Locale = "en") =>
|
|
|
21
24
|
const namespace = NonEmptyString255((ns && (Array.isArray(ns) ? ns[0] : ns)) || "primary")
|
|
22
25
|
const deviceId = req.headers["x-fe-device-id"]
|
|
23
26
|
|
|
24
|
-
const requestContext =
|
|
27
|
+
const requestContext = RequestContext.make({
|
|
25
28
|
span: {
|
|
26
29
|
traceId: currentSpan.traceId,
|
|
27
30
|
spanId: currentSpan.spanId,
|
|
28
31
|
sampled: currentSpan.sampled
|
|
29
32
|
},
|
|
30
|
-
name: NonEmptyString255(req.originalUrl), // set more detailed elsewhere
|
|
33
|
+
name: NonEmptyString255(`HTTP ${req.method} ${req.originalUrl.split("?")[0]}`), // set more detailed elsewhere
|
|
31
34
|
locale,
|
|
32
35
|
namespace,
|
|
33
36
|
sourceId: deviceId ? NonEmptyString255(deviceId) : undefined
|
|
34
37
|
})
|
|
35
|
-
|
|
38
|
+
yield* Effect.annotateCurrentSpan(spanAttributes(requestContext))
|
|
39
|
+
const layer = Layer.mergeAll(
|
|
40
|
+
ContextMapContainer.layer,
|
|
41
|
+
Layer.succeed(LocaleRef, requestContext.locale),
|
|
42
|
+
Layer.succeed(storeId, requestContext.namespace)
|
|
43
|
+
)
|
|
44
|
+
// Bind layer to the request scope so ContextMap's finalizer (clear()) runs only
|
|
45
|
+
// after the response body is fully drained — not when `app` returns its
|
|
46
|
+
// HttpServerResponse value. Streaming RPC responses keep producing chunks (and
|
|
47
|
+
// using ContextMap-cached etags) after `app` returns; a sub-scope from
|
|
48
|
+
// `Effect.provide(layer)` would close too early and wipe etags mid-stream,
|
|
49
|
+
// causing spurious OptimisticConcurrencyException on later writes.
|
|
50
|
+
const res = yield* app.pipe(
|
|
51
|
+
Effect.withLogSpan(requestContext.name),
|
|
52
|
+
provideOnRequestScope(layer)
|
|
53
|
+
)
|
|
36
54
|
|
|
37
55
|
// TODO: how to set also on errors?
|
|
38
56
|
return HttpServerResponse.setHeaders(res, {
|