@effect-app/infra 4.0.0-beta.20 → 4.0.0-beta.200
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 +1378 -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 +50 -4
- package/dist/api/routing/middleware/middleware.d.ts.map +1 -1
- package/dist/api/routing/middleware/middleware.js +79 -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 +25 -26
- package/dist/api/routing.d.ts.map +1 -1
- package/dist/api/routing.js +83 -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 +112 -15
- package/src/api/routing/middleware.ts +0 -2
- package/src/api/routing.ts +142 -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 +18 -16
- 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/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 +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/Store/index.ts
CHANGED
|
@@ -1,12 +1,19 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
2
|
import { Effect, Layer, Redacted } from "effect-app"
|
|
3
|
+
import type { SqlClient } from "effect/unstable/sql"
|
|
3
4
|
import { CosmosStoreLayer } from "./Cosmos.js"
|
|
4
5
|
import { DiskStoreLayer } from "./Disk.js"
|
|
5
6
|
import { MemoryStoreLive } from "./Memory.js"
|
|
6
7
|
// import { RedisStoreLayer } from "./Redis.js"
|
|
8
|
+
import { RepositoryRegistryLive } from "../Model.js"
|
|
7
9
|
import type { StorageConfig } from "./service.js"
|
|
10
|
+
import { SQLiteStoreLayer } from "./SQL.js"
|
|
11
|
+
import { PgStoreLayer } from "./SQL/Pg.js"
|
|
8
12
|
|
|
9
|
-
export function StoreMakerLayer(
|
|
13
|
+
export function StoreMakerLayer(
|
|
14
|
+
cfg: StorageConfig,
|
|
15
|
+
options?: { makeSqlClientLayer?: (namespace: string) => Layer.Layer<SqlClient.SqlClient> }
|
|
16
|
+
) {
|
|
10
17
|
return Effect
|
|
11
18
|
.sync(() => {
|
|
12
19
|
const storageUrl = Redacted.value(cfg.url)
|
|
@@ -19,6 +26,14 @@ export function StoreMakerLayer(cfg: StorageConfig) {
|
|
|
19
26
|
console.log("Using disk store at " + dir)
|
|
20
27
|
return DiskStoreLayer(cfg, dir)
|
|
21
28
|
}
|
|
29
|
+
if (storageUrl.startsWith("sqlite://")) {
|
|
30
|
+
console.log("Using SQLite store")
|
|
31
|
+
return SQLiteStoreLayer(cfg, options)
|
|
32
|
+
}
|
|
33
|
+
if (storageUrl.startsWith("pg://")) {
|
|
34
|
+
console.log("Using PostgreSQL store")
|
|
35
|
+
return PgStoreLayer(cfg)
|
|
36
|
+
}
|
|
22
37
|
// if (storageUrl.startsWith("redis://")) {
|
|
23
38
|
// console.log("Using Redis store")
|
|
24
39
|
// return RedisStoreLayer(cfg)
|
|
@@ -27,7 +42,7 @@ export function StoreMakerLayer(cfg: StorageConfig) {
|
|
|
27
42
|
console.log("Using Cosmos DB store")
|
|
28
43
|
return CosmosStoreLayer(cfg)
|
|
29
44
|
})
|
|
30
|
-
.pipe(Layer.unwrap)
|
|
45
|
+
.pipe(Layer.unwrap, Layer.merge(RepositoryRegistryLive))
|
|
31
46
|
}
|
|
32
47
|
|
|
33
48
|
export * from "./service.js"
|
package/src/Store/service.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
2
|
import type { UniqueKey } from "@azure/cosmos"
|
|
3
|
-
import { Effect, type NonEmptyReadonlyArray, type Option, type Redacted
|
|
3
|
+
import { Context, Effect, type NonEmptyReadonlyArray, type Option, type Redacted } from "effect-app"
|
|
4
|
+
import * as Semaphore from "effect/Semaphore"
|
|
4
5
|
import type { OptimisticConcurrencyException } from "../errors.js"
|
|
5
6
|
import type { FilterResult } from "../Model/filter/filterApi.js"
|
|
6
7
|
import type { FieldValues } from "../Model/filter/types.js"
|
|
@@ -10,8 +11,8 @@ import { type RawQuery } from "../Model/query.js"
|
|
|
10
11
|
export interface StoreConfig<E> {
|
|
11
12
|
partitionValue: (e?: E) => string
|
|
12
13
|
/**
|
|
13
|
-
* Primarily used for testing, creating namespaces in the database to separate data e.g to run multiple tests in isolation within the same database
|
|
14
|
-
*
|
|
14
|
+
* Primarily used for testing, creating namespaces in the database to separate data e.g to run multiple tests in isolation within the same database.
|
|
15
|
+
* Memory/Disk use separate store instances per namespace. CosmosDB uses namespace-prefixed partition keys. SQL uses a `_namespace` column.
|
|
15
16
|
*/
|
|
16
17
|
allowNamespace?: (namespace: string) => boolean
|
|
17
18
|
/**
|
|
@@ -87,9 +88,14 @@ export interface Store<
|
|
|
87
88
|
) => Effect.Effect<NonEmptyReadonlyArray<PM>, OptimisticConcurrencyException>
|
|
88
89
|
batchRemove: (ids: NonEmptyReadonlyArray<Encoded[IdKey]>, partitionKey?: string) => Effect.Effect<void>
|
|
89
90
|
queryRaw: <Out>(query: RawQuery<Encoded, Out>) => Effect.Effect<readonly Out[]>
|
|
91
|
+
/**
|
|
92
|
+
* Explicitly seed a namespace. Primary is seeded eagerly on initialization.
|
|
93
|
+
* Non-primary namespaces must be seeded explicitly before use.
|
|
94
|
+
*/
|
|
95
|
+
seedNamespace: (namespace: string) => Effect.Effect<void>
|
|
90
96
|
}
|
|
91
97
|
|
|
92
|
-
export class StoreMaker extends
|
|
98
|
+
export class StoreMaker extends Context.Opaque<StoreMaker, {
|
|
93
99
|
make: <IdKey extends keyof Encoded, Encoded extends FieldValues, R = never, E = never>(
|
|
94
100
|
name: string,
|
|
95
101
|
idKey: IdKey,
|
|
@@ -161,16 +167,34 @@ export const makeContextMap = () => {
|
|
|
161
167
|
// }
|
|
162
168
|
// }
|
|
163
169
|
|
|
170
|
+
const store = new Map<symbol, unknown>()
|
|
171
|
+
const sem = Semaphore.makeUnsafe(1)
|
|
172
|
+
|
|
164
173
|
return {
|
|
165
174
|
get: getEtag,
|
|
166
|
-
set: setEtag
|
|
167
|
-
|
|
175
|
+
set: setEtag,
|
|
176
|
+
getOrCreateStore: <T>(key: symbol, make: () => T): T => {
|
|
177
|
+
let value = store.get(key) as T | undefined
|
|
178
|
+
if (value === undefined) {
|
|
179
|
+
value = make()
|
|
180
|
+
store.set(key, value)
|
|
181
|
+
}
|
|
182
|
+
return value
|
|
183
|
+
},
|
|
184
|
+
getOrCreateStoreEffect: <T, E, R>(key: symbol, make: Effect.Effect<T, E, R>): Effect.Effect<T, E, R> =>
|
|
185
|
+
sem.withPermits(1)(Effect.uninterruptible(Effect.gen(function*() {
|
|
186
|
+
const value = store.get(key) as T | undefined
|
|
187
|
+
if (value !== undefined) return value
|
|
188
|
+
const v = yield* make
|
|
189
|
+
store.set(key, v)
|
|
190
|
+
return v
|
|
191
|
+
})))
|
|
168
192
|
}
|
|
169
193
|
}
|
|
170
194
|
|
|
171
195
|
const makeMap = Effect.sync(() => makeContextMap())
|
|
172
196
|
|
|
173
|
-
export class ContextMap extends
|
|
197
|
+
export class ContextMap extends Context.Opaque<ContextMap>()("effect-app/ContextMap", { make: makeMap }) {
|
|
174
198
|
}
|
|
175
199
|
|
|
176
200
|
export type PersistenceModelType<Encoded extends object> = Encoded & {
|
|
@@ -178,7 +202,7 @@ export type PersistenceModelType<Encoded extends object> = Encoded & {
|
|
|
178
202
|
}
|
|
179
203
|
|
|
180
204
|
export interface StorageConfig {
|
|
181
|
-
url: Redacted.Redacted
|
|
205
|
+
url: Redacted.Redacted
|
|
182
206
|
prefix: string
|
|
183
207
|
dbName: string
|
|
184
208
|
}
|
package/src/Store/utils.ts
CHANGED
|
@@ -12,33 +12,34 @@ export const makeETag = <E extends PersistenceModelType<{}>>(
|
|
|
12
12
|
_etag: crypto.createHash("sha256").update(JSON.stringify(e)).digest("hex")
|
|
13
13
|
}) as any
|
|
14
14
|
|
|
15
|
-
export const makeUpdateETag =
|
|
16
|
-
(
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
id: e[idKey] as string,
|
|
24
|
-
current: "",
|
|
25
|
-
found: e._etag,
|
|
26
|
-
code: 409
|
|
27
|
-
})
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
if (Option.isSome(current) && current.value._etag !== e._etag) {
|
|
15
|
+
export const makeUpdateETag = (type: string) =>
|
|
16
|
+
Effect.fnUntraced(function*<IdKey extends keyof E, E extends PersistenceModelType<{}>>(
|
|
17
|
+
e: E,
|
|
18
|
+
idKey: IdKey,
|
|
19
|
+
current: Option.Option<E>
|
|
20
|
+
) {
|
|
21
|
+
if (e._etag) {
|
|
22
|
+
if (Option.isNone(current)) {
|
|
31
23
|
return yield* new OptimisticConcurrencyException({
|
|
32
24
|
type,
|
|
33
|
-
id:
|
|
34
|
-
current:
|
|
25
|
+
id: e[idKey] as string,
|
|
26
|
+
current: "",
|
|
35
27
|
found: e._etag,
|
|
36
|
-
code:
|
|
28
|
+
code: 409
|
|
37
29
|
})
|
|
38
30
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
31
|
+
}
|
|
32
|
+
if (Option.isSome(current) && current.value._etag !== e._etag) {
|
|
33
|
+
return yield* new OptimisticConcurrencyException({
|
|
34
|
+
type,
|
|
35
|
+
id: current.value[idKey] as string,
|
|
36
|
+
current: current.value._etag,
|
|
37
|
+
found: e._etag,
|
|
38
|
+
code: 412
|
|
39
|
+
})
|
|
40
|
+
}
|
|
41
|
+
return makeETag(e)
|
|
42
|
+
})
|
|
42
43
|
|
|
43
44
|
export function lowercaseIfString<T>(val: T) {
|
|
44
45
|
if (typeof val === "string") {
|
|
@@ -545,9 +545,15 @@ export const DateTimeUpdateFromNumber: DateTimeUpdateFromNumber = Field({
|
|
|
545
545
|
*/
|
|
546
546
|
export interface JsonFromString<S extends Schema.Top> extends
|
|
547
547
|
VariantSchema.Field<{
|
|
548
|
-
readonly select: Schema.fromJsonString<
|
|
549
|
-
|
|
550
|
-
|
|
548
|
+
readonly select: Schema.fromJsonString<
|
|
549
|
+
Schema.Codec<S["Type"], Schema.Json, S["DecodingServices"], S["EncodingServices"]>
|
|
550
|
+
>
|
|
551
|
+
readonly insert: Schema.fromJsonString<
|
|
552
|
+
Schema.Codec<S["Type"], Schema.Json, S["DecodingServices"], S["EncodingServices"]>
|
|
553
|
+
>
|
|
554
|
+
readonly update: Schema.fromJsonString<
|
|
555
|
+
Schema.Codec<S["Type"], Schema.Json, S["DecodingServices"], S["EncodingServices"]>
|
|
556
|
+
>
|
|
551
557
|
readonly json: S
|
|
552
558
|
readonly jsonCreate: S
|
|
553
559
|
readonly jsonUpdate: S
|
|
@@ -565,7 +571,7 @@ export interface JsonFromString<S extends Schema.Top> extends
|
|
|
565
571
|
export const JsonFromString = <S extends Schema.Top>(
|
|
566
572
|
schema: S
|
|
567
573
|
): JsonFromString<S> => {
|
|
568
|
-
const parsed = Schema.fromJsonString(schema)
|
|
574
|
+
const parsed = Schema.fromJsonString(Schema.toCodecJson(schema))
|
|
569
575
|
return Field({
|
|
570
576
|
select: parsed,
|
|
571
577
|
insert: parsed,
|
|
@@ -1,6 +1,6 @@
|
|
|
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 { Cause, Effect, Exit, FiberSet, Layer, type Scope
|
|
3
|
+
import { Cause, Context, Effect, Exit, FiberSet, Layer, type Scope } from "effect-app"
|
|
4
4
|
import { InfraLogger } from "../logger.js"
|
|
5
5
|
|
|
6
6
|
const withSpanAndLog = (name: string) => <A, E, R>(self: Effect.Effect<A, E, R>) =>
|
|
@@ -19,49 +19,46 @@ function makeClient(url: string) {
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
export class ServiceBusClientTag
|
|
22
|
-
extends
|
|
22
|
+
extends Context.Opaque<ServiceBusClientTag, ServiceBusClient>()("@services/Client", { make: makeClient })
|
|
23
23
|
{
|
|
24
24
|
static readonly layer = (url: string) => this.toLayer(this.make(url))
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
const serviceBusClient = yield* ServiceBusClientTag
|
|
27
|
+
const makeSender_ = Effect.fnUntraced(function*(queueName: string) {
|
|
28
|
+
const serviceBusClient = yield* ServiceBusClientTag
|
|
30
29
|
|
|
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
|
-
})
|
|
30
|
+
return yield* Effect.acquireRelease(
|
|
31
|
+
Effect.sync(() => serviceBusClient.createSender(queueName)).pipe(
|
|
32
|
+
withSpanAndLog(`ServiceBus.sender.create ${queueName}`)
|
|
33
|
+
),
|
|
34
|
+
(sender) => Effect.promise(() => sender.close()).pipe(withSpanAndLog(`ServiceBus.sender.close ${queueName}`))
|
|
35
|
+
)
|
|
36
|
+
})
|
|
49
37
|
|
|
50
|
-
|
|
38
|
+
const makeSender = Effect.fnUntraced(function*(name: string) {
|
|
39
|
+
const sender = yield* makeSender_(name)
|
|
40
|
+
const sendMessages = Effect.fnUntraced(function*(
|
|
41
|
+
messages: ServiceBusMessage | ServiceBusMessage[] | ServiceBusMessageBatch,
|
|
42
|
+
options?: Omit<OperationOptionsBase, "abortSignal">
|
|
43
|
+
) {
|
|
44
|
+
return yield* Effect.promise((abortSignal) => sender.sendMessages(messages, { ...options, abortSignal }))
|
|
51
45
|
})
|
|
52
46
|
|
|
53
|
-
|
|
47
|
+
return { name, sendMessages }
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
export class Sender extends Context.Opaque<Sender, {
|
|
54
51
|
name: string
|
|
55
52
|
sendMessages: (
|
|
56
53
|
messages: ServiceBusMessage | ServiceBusMessage[] | ServiceBusMessageBatch,
|
|
57
54
|
options?: Omit<OperationOptionsBase, "abortSignal">
|
|
58
|
-
) => Effect.Effect<void
|
|
55
|
+
) => Effect.Effect<void>
|
|
59
56
|
}>()("Sender", { make: makeSender }) {
|
|
60
57
|
static readonly layer = (name: string) => this.toLayer(this.make(name))
|
|
61
58
|
}
|
|
62
59
|
|
|
63
60
|
export const SenderTag = <Id>() => <Key extends string>(queueName: Key) => {
|
|
64
|
-
const tag =
|
|
61
|
+
const tag = Context.Service<Id, Sender>(`ServiceBus.Sender.${queueName}`)
|
|
65
62
|
|
|
66
63
|
return Object.assign(tag, {
|
|
67
64
|
layer: Layer.effect(
|
|
@@ -71,99 +68,98 @@ export const SenderTag = <Id>() => <Key extends string>(queueName: Key) => {
|
|
|
71
68
|
})
|
|
72
69
|
}
|
|
73
70
|
|
|
74
|
-
const makeReceiver = (name: string)
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
(sessionId
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
(
|
|
86
|
-
waitTillEmpty
|
|
87
|
-
|
|
88
|
-
Effect.
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
71
|
+
const makeReceiver = Effect.fnUntraced(function*(name: string) {
|
|
72
|
+
const serviceBusClient = yield* ServiceBusClientTag
|
|
73
|
+
|
|
74
|
+
const makeReceiver = Effect.fnUntraced(
|
|
75
|
+
function*(queueName: string, waitTillEmpty: Effect.Effect<void>, sessionId?: string) {
|
|
76
|
+
return yield* Effect.acquireRelease(
|
|
77
|
+
(sessionId
|
|
78
|
+
? Effect.promise(() => serviceBusClient.acceptSession(queueName, sessionId))
|
|
79
|
+
: Effect.sync(() => serviceBusClient.createReceiver(queueName)))
|
|
80
|
+
.pipe(withSpanAndLog(`ServiceBus.receiver.create ${queueName}.${sessionId}`)),
|
|
81
|
+
(r) =>
|
|
82
|
+
waitTillEmpty.pipe(
|
|
83
|
+
withSpanAndLog(`ServiceBus.receiver.waitTillEmpty ${queueName}.${sessionId}`),
|
|
84
|
+
Effect.andThen(
|
|
85
|
+
Effect.promise(() => r.close()).pipe(
|
|
86
|
+
withSpanAndLog(`ServiceBus.receiver.close ${queueName}.${sessionId}`)
|
|
87
|
+
)
|
|
88
|
+
),
|
|
89
|
+
withSpanAndLog(`ServiceBus.receiver.release ${queueName}.${sessionId}`)
|
|
90
|
+
)
|
|
91
|
+
)
|
|
92
|
+
}
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
const make = (waitTillEmpty: Effect.Effect<void>) => makeReceiver(name, waitTillEmpty)
|
|
96
|
+
|
|
97
|
+
const makeSession = (sessionId: string, waitTillEmpty: Effect.Effect<void>) =>
|
|
98
|
+
makeReceiver(name, waitTillEmpty, sessionId)
|
|
99
|
+
|
|
100
|
+
return {
|
|
101
|
+
name,
|
|
102
|
+
make,
|
|
103
|
+
makeSession,
|
|
104
|
+
subscribe: Effect.fnUntraced(function*<RMsg, RErr>(hndlr: MessageHandlers<RMsg, RErr>, sessionId?: string) {
|
|
105
|
+
const fs = yield* FiberSet.make()
|
|
106
|
+
const fr = yield* FiberSet.runtime(fs)<RMsg | RErr>()
|
|
107
|
+
const wait = Effect
|
|
108
|
+
.gen(function*() {
|
|
109
|
+
if ((yield* FiberSet.size(fs)) > 0) {
|
|
110
|
+
yield* InfraLogger.logDebug("Waiting ServiceBusFiberSet to be empty: " + (yield* FiberSet.size(fs)))
|
|
111
|
+
}
|
|
112
|
+
while ((yield* FiberSet.size(fs)) > 0) yield* Effect.sleep("250 millis")
|
|
113
|
+
})
|
|
114
|
+
const r = yield* sessionId
|
|
115
|
+
? makeSession(
|
|
116
|
+
sessionId,
|
|
117
|
+
wait
|
|
118
|
+
)
|
|
119
|
+
: make(wait)
|
|
120
|
+
|
|
121
|
+
const runEffect = <E>(effect: Effect.Effect<void, E, RMsg | RErr>) =>
|
|
122
|
+
new Promise<void>((resolve, reject) =>
|
|
123
|
+
fr(effect)
|
|
124
|
+
.addObserver((exit) => {
|
|
125
|
+
if (Exit.isSuccess(exit)) {
|
|
126
|
+
resolve(exit.value)
|
|
127
|
+
} else {
|
|
128
|
+
// disable @typescript-eslint/prefer-promise-reject-errors
|
|
129
|
+
reject(Cause.pretty(exit.cause))
|
|
130
|
+
}
|
|
131
|
+
})
|
|
95
132
|
)
|
|
96
|
-
}
|
|
97
|
-
)
|
|
98
133
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
yield* InfraLogger.logDebug("Waiting ServiceBusFiberSet to be empty: " + (yield* FiberSet.size(fs)))
|
|
115
|
-
}
|
|
116
|
-
while ((yield* FiberSet.size(fs)) > 0) yield* Effect.sleep("250 millis")
|
|
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
|
-
}
|
|
134
|
+
yield* Effect.acquireRelease(
|
|
135
|
+
Effect
|
|
136
|
+
.sync(() => {
|
|
137
|
+
const s = r
|
|
138
|
+
.subscribe({
|
|
139
|
+
processError: (err) =>
|
|
140
|
+
runEffect(
|
|
141
|
+
hndlr
|
|
142
|
+
.processError(err)
|
|
143
|
+
.pipe(
|
|
144
|
+
Effect.catchCause((cause) => Effect.logError(`ServiceBus Error ${sessionId}`, cause))
|
|
145
|
+
)
|
|
146
|
+
),
|
|
147
|
+
processMessage: (msg) => runEffect(hndlr.processMessage(msg))
|
|
148
|
+
// DO NOT CATCH ERRORS here as they should return to the queue!
|
|
135
149
|
})
|
|
150
|
+
return { close: Effect.promise(() => s.close()) }
|
|
151
|
+
})
|
|
152
|
+
.pipe(withSpanAndLog(`ServiceBus.subscription.create ${sessionId}`)),
|
|
153
|
+
(subscription) =>
|
|
154
|
+
subscription.close.pipe(
|
|
155
|
+
withSpanAndLog(`ServiceBus.subscription.close ${sessionId}`)
|
|
136
156
|
)
|
|
157
|
+
) as Effect.Effect<void, never, Scope.Scope> // wth is going on here
|
|
158
|
+
})
|
|
159
|
+
}
|
|
160
|
+
})
|
|
137
161
|
|
|
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, {
|
|
162
|
+
export class Receiver extends Context.Opaque<Receiver, {
|
|
167
163
|
name: string
|
|
168
164
|
make: (waitTillEmpty: Effect.Effect<void>) => Effect.Effect<ServiceBusReceiver, never, Scope.Scope>
|
|
169
165
|
makeSession: (
|
|
@@ -180,7 +176,7 @@ export class Receiver extends ServiceMap.Opaque<Receiver, {
|
|
|
180
176
|
}
|
|
181
177
|
|
|
182
178
|
export const ReceiverTag = <Id>() => <Key extends string>(queueName: Key) => {
|
|
183
|
-
const tag =
|
|
179
|
+
const tag = Context.Service<Id, Receiver>(`ServiceBus.Receiver.${queueName}`)
|
|
184
180
|
|
|
185
181
|
return Object.assign(tag, {
|
|
186
182
|
layer: Layer.effect(
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { CosmosClient as ComosClient_ } from "@azure/cosmos"
|
|
2
|
-
import { Effect, Layer
|
|
2
|
+
import { Context, Effect, Layer } from "effect-app"
|
|
3
3
|
|
|
4
4
|
const withClient = (url: string) => Effect.sync(() => new ComosClient_(url))
|
|
5
5
|
|
|
6
6
|
export const makeCosmosClient = (url: string, dbName: string) =>
|
|
7
7
|
Effect.map(withClient(url), (x) => ({ db: x.database(dbName) }))
|
|
8
8
|
|
|
9
|
-
export class CosmosClient extends
|
|
9
|
+
export class CosmosClient extends Context.Service<CosmosClient, {
|
|
10
10
|
readonly db: ReturnType<InstanceType<typeof ComosClient_>["database"]>
|
|
11
11
|
}>()("@services/CosmosClient") {}
|
|
12
12
|
|
package/src/adapters/index.ts
CHANGED
package/src/adapters/memQueue.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Effect, type Queue
|
|
1
|
+
import { Context, Effect, type Queue } from "effect-app"
|
|
2
2
|
import * as Q from "effect/Queue"
|
|
3
3
|
|
|
4
4
|
const make = Effect
|
|
@@ -16,6 +16,6 @@ const make = Effect
|
|
|
16
16
|
}
|
|
17
17
|
})
|
|
18
18
|
|
|
19
|
-
export class MemQueue extends
|
|
19
|
+
export class MemQueue extends Context.Opaque<MemQueue>()("effect-app/MemQueue", { make }) {
|
|
20
20
|
static readonly Live = this.toLayer(this.make)
|
|
21
21
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Effect, Layer
|
|
1
|
+
import { Context, Effect, Layer } from "effect-app"
|
|
2
2
|
import { MongoClient as MongoClient_ } from "mongodb"
|
|
3
3
|
|
|
4
4
|
// TODO: we should probably share a single client...
|
|
@@ -15,7 +15,7 @@ const withClient = (url: string) =>
|
|
|
15
15
|
|
|
16
16
|
const makeMongoClient = (url: string, dbName?: string) => Effect.map(withClient(url), (x) => ({ db: x.db(dbName) }))
|
|
17
17
|
|
|
18
|
-
export class MongoClient extends
|
|
18
|
+
export class MongoClient extends Context.Service<MongoClient, {
|
|
19
19
|
readonly db: ReturnType<InstanceType<typeof MongoClient_>["db"]>
|
|
20
20
|
}>()("@services/MongoClient") {}
|
|
21
21
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Data, Effect, Layer, Option
|
|
1
|
+
import { Context, Data, Effect, Layer, Option } from "effect-app"
|
|
2
2
|
import type { RedisClient as Client } from "redis"
|
|
3
3
|
import Redlock from "redlock"
|
|
4
4
|
|
|
@@ -90,7 +90,7 @@ export const makeRedisClient = (makeClient: () => Client) =>
|
|
|
90
90
|
.pipe(Effect.uninterruptible, Effect.orDie)
|
|
91
91
|
)
|
|
92
92
|
|
|
93
|
-
export class RedisClient extends
|
|
93
|
+
export class RedisClient extends Context.Service<RedisClient, {
|
|
94
94
|
readonly client: Client
|
|
95
95
|
readonly lock: Redlock
|
|
96
96
|
readonly get: (key: string) => Effect.Effect<Option.Option<string>, ConnectionException>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
-
import { Effect, Layer, type NonEmptyReadonlyArray, pipe, type Scope
|
|
2
|
+
import { Context, Effect, Layer, type NonEmptyReadonlyArray, pipe, type Scope } from "effect-app"
|
|
3
3
|
|
|
4
4
|
import { type HttpRouter } from "effect-app/http"
|
|
5
5
|
import { type EffectGenUtils } from "effect-app/utils/gen"
|
|
@@ -23,7 +23,7 @@ type TDepsArr<TDeps extends ReadonlyArray<any>> = {
|
|
|
23
23
|
// E = never => the context provided cannot trigger errors
|
|
24
24
|
// TODO: remove HttpLayerRouter.Provided - it's not even relevant outside of Http context, while ContextProviders are for anywhere. Only support Scope.Scope?
|
|
25
25
|
// _R extends HttpLayerRouter.Provided => the context provided can only have what HttpLayerRouter.Provided provides as requirements
|
|
26
|
-
ContextTagWithDefault.Base<Effect.Effect<
|
|
26
|
+
ContextTagWithDefault.Base<Effect.Effect<Context.Context<infer _1>, never, infer _R>> // & { _tag: infer _2 }>
|
|
27
27
|
? [_R] extends [HttpRouter.Provided] ? TDeps[K]
|
|
28
28
|
: `HttpLayerRouter.Provided is the only requirement ${TDeps[K]["Service"][
|
|
29
29
|
"_tag"
|
|
@@ -58,9 +58,9 @@ export const mergeContextProviders = <
|
|
|
58
58
|
Effect.Effect<
|
|
59
59
|
// we need to merge all contexts into one
|
|
60
60
|
// v4: Service.Shape extracts the service value type (v3's Tag.Identifier)
|
|
61
|
-
|
|
61
|
+
Context.Context<GetContext<EffectGenUtils.Success<Context.Service.Shape<TDeps[number]>>>>,
|
|
62
62
|
never,
|
|
63
|
-
EffectGenUtils.
|
|
63
|
+
EffectGenUtils.Context<Context.Service.Shape<TDeps[number]>>
|
|
64
64
|
>,
|
|
65
65
|
LayerUtils.GetLayersError<{ [K in keyof TDeps]: TDeps[K]["Default"] }>,
|
|
66
66
|
LayerUtils.GetLayersSuccess<{ [K in keyof TDeps]: TDeps[K]["Default"] }>
|
|
@@ -78,14 +78,14 @@ export const mergeContextProviders = <
|
|
|
78
78
|
handle: handle[Symbol.toStringTag] === "GeneratorFunction" ? Effect.fnUntraced(handle)() : handle
|
|
79
79
|
}
|
|
80
80
|
))
|
|
81
|
-
// services are effects which return some
|
|
81
|
+
// services are effects which return some Context.Context<...>
|
|
82
82
|
const context = yield* mergeContexts(services as any)
|
|
83
83
|
return context
|
|
84
84
|
})
|
|
85
85
|
}) as any
|
|
86
86
|
})
|
|
87
87
|
|
|
88
|
-
// Effect Rpc Middleware: for single tag providing, we could use Provides, for providing
|
|
88
|
+
// Effect Rpc Middleware: for single tag providing, we could use Provides, for providing Context or Layer (bad boy) we could use Wrap..
|
|
89
89
|
export const ContextProvider = <
|
|
90
90
|
ContextProviderA,
|
|
91
91
|
MakeContextProviderE,
|
|
@@ -98,8 +98,7 @@ export const ContextProvider = <
|
|
|
98
98
|
| Effect.Effect<ContextProviderA, never, ContextProviderR>
|
|
99
99
|
| (() => Generator<
|
|
100
100
|
Yieldable<any, any, never, ContextProviderR>,
|
|
101
|
-
ContextProviderA
|
|
102
|
-
any
|
|
101
|
+
ContextProviderA
|
|
103
102
|
>),
|
|
104
103
|
MakeContextProviderE,
|
|
105
104
|
MakeContextProviderR | Scope.Scope
|
|
@@ -107,7 +106,7 @@ export const ContextProvider = <
|
|
|
107
106
|
dependencies?: Dependencies
|
|
108
107
|
}
|
|
109
108
|
) => {
|
|
110
|
-
const ctx =
|
|
109
|
+
const ctx = Context.Service<
|
|
111
110
|
ContextProviderId,
|
|
112
111
|
Effect.Effect<ContextProviderA, never, ContextProviderR>
|
|
113
112
|
>(
|
|
@@ -146,17 +145,17 @@ export const MergedContextProvider = <
|
|
|
146
145
|
Effect.Effect<
|
|
147
146
|
// we need to merge all contexts into one
|
|
148
147
|
// v4: Service.Shape extracts the service value type (v3's Tag.Identifier)
|
|
149
|
-
|
|
148
|
+
Context.Context<GetContext<EffectGenUtils.Success<Context.Service.Shape<TDeps[number]>>>>,
|
|
150
149
|
never,
|
|
151
|
-
EffectGenUtils.
|
|
150
|
+
EffectGenUtils.Context<Context.Service.Shape<TDeps[number]>>
|
|
152
151
|
>,
|
|
153
152
|
LayerUtils.GetLayersError<{ [K in keyof TDeps]: TDeps[K]["Default"] }>,
|
|
154
153
|
// v4: Identifier here is correct — it's the nominal service identity for layer provide/exclude
|
|
155
154
|
| Exclude<
|
|
156
|
-
|
|
155
|
+
Context.Service.Identifier<TDeps[number]>,
|
|
157
156
|
LayerUtils.GetLayersSuccess<{ [K in keyof TDeps]: TDeps[K]["Default"] }>
|
|
158
157
|
>
|
|
159
158
|
| LayerUtils.GetLayersContext<{ [K in keyof TDeps]: TDeps[K]["Default"] }>
|
|
160
159
|
>
|
|
161
160
|
|
|
162
|
-
export const EmptyContextProvider = ContextProvider({ effect: Effect.succeed(Effect.succeed(
|
|
161
|
+
export const EmptyContextProvider = ContextProvider({ effect: Effect.succeed(Effect.succeed(Context.empty())) })
|
|
@@ -21,7 +21,7 @@ export const RequestContextMiddleware = (defaultLocale: Locale = "en") =>
|
|
|
21
21
|
const namespace = NonEmptyString255((ns && (Array.isArray(ns) ? ns[0] : ns)) || "primary")
|
|
22
22
|
const deviceId = req.headers["x-fe-device-id"]
|
|
23
23
|
|
|
24
|
-
const requestContext =
|
|
24
|
+
const requestContext = RequestContext.make({
|
|
25
25
|
span: {
|
|
26
26
|
traceId: currentSpan.traceId,
|
|
27
27
|
spanId: currentSpan.spanId,
|