@effect-app/infra 2.85.0 → 2.86.0
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 +6 -0
- package/dist/api/layerUtils.d.ts +3 -3
- package/dist/api/layerUtils.d.ts.map +1 -1
- package/dist/api/routing/middleware/ContextProvider.d.ts +2 -2
- package/dist/api/routing/middleware/ContextProvider.d.ts.map +1 -1
- package/dist/api/routing/middleware/DynamicMiddleware.d.ts +31 -17
- package/dist/api/routing/middleware/DynamicMiddleware.d.ts.map +1 -1
- package/dist/api/routing/middleware/DynamicMiddleware.js +1 -1
- package/dist/api/routing/middleware/dynamic-middleware.d.ts +2 -2
- package/dist/api/routing/middleware/dynamic-middleware.d.ts.map +1 -1
- package/dist/api/routing/middleware/dynamic-middleware.js +1 -1
- package/dist/api/routing/middleware/generic-middleware.d.ts +12 -0
- package/dist/api/routing/middleware/generic-middleware.d.ts.map +1 -1
- package/dist/api/routing/middleware/generic-middleware.js +1 -1
- package/dist/api/routing/middleware/middleware-api.d.ts +18 -7
- package/dist/api/routing/middleware/middleware-api.d.ts.map +1 -1
- package/dist/api/routing/middleware/middleware-api.js +19 -8
- package/dist/api/routing/middleware/middleware.d.ts +5 -4
- package/dist/api/routing/middleware/middleware.d.ts.map +1 -1
- package/dist/api/routing/middleware/middleware.js +6 -5
- package/dist/api/routing.d.ts +0 -1
- package/dist/api/routing.d.ts.map +1 -1
- package/dist/api/routing.js +2 -3
- package/package.json +1 -1
- package/src/api/layerUtils.ts +3 -3
- package/src/api/routing/middleware/ContextProvider.ts +5 -5
- package/src/api/routing/middleware/DynamicMiddleware.ts +39 -17
- package/src/api/routing/middleware/dynamic-middleware.ts +5 -3
- package/src/api/routing/middleware/generic-middleware.ts +11 -0
- package/src/api/routing/middleware/middleware-api.ts +109 -22
- package/src/api/routing/middleware/middleware.ts +13 -5
- package/src/api/routing.ts +1 -9
- package/test/contextProvider.test.ts +1 -2
- package/test/controller.test.ts +17 -101
- 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 +144 -0
- package/test/dist/fixtures.d.ts.map +1 -0
- package/test/dist/fixtures.js +70 -0
- package/test/dist/layerUtils.test.d.ts.map +1 -0
- package/test/dist/query.test.d.ts.map +1 -1
- package/test/dist/requires.d.ts +21 -0
- package/test/dist/requires.d.ts.map +1 -0
- package/test/dist/requires.js +27 -0
- package/test/dist/requires.test.d.ts.map +1 -0
- package/test/fixtures.ts +85 -0
- package/test/layerUtils.test.ts +19 -0
- package/test/query.test.ts +2 -4
- package/test/requires.test.ts +75 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { Array, Either, type NonEmptyArray } from "effect-app"
|
|
2
2
|
import { type RPCContextMap } from "effect-app/client"
|
|
3
3
|
import { type DynamicMiddlewareMaker, type GenericMiddlewareMaker, makeMiddleware, type makeMiddlewareBasic, type RequestContextMapProvider } from "../../routing.js"
|
|
4
4
|
|
|
@@ -9,41 +9,128 @@ export const contextMap = <RequestContextMap>() => <K extends keyof RequestConte
|
|
|
9
9
|
settings: null as any as RequestContextMap[typeof a]
|
|
10
10
|
})
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
export interface MiddlewareM<
|
|
13
13
|
RequestContext extends Record<string, RPCContextMap.Any>,
|
|
14
14
|
Provided extends keyof RequestContext,
|
|
15
|
-
Middlewares extends
|
|
16
|
-
DynamicMiddlewareProviders
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
15
|
+
Middlewares extends ReadonlyArray<GenericMiddlewareMaker>,
|
|
16
|
+
DynamicMiddlewareProviders,
|
|
17
|
+
// out MiddlewareR = never
|
|
18
|
+
MiddlewareR = never
|
|
19
|
+
> {
|
|
20
|
+
middleware<MW extends NonEmptyArray<GenericMiddlewareMaker>>(
|
|
21
|
+
...mw: MW
|
|
22
|
+
): DynamicMiddlewareMakerrsss<
|
|
23
|
+
RequestContext,
|
|
24
|
+
Provided,
|
|
25
|
+
[...Middlewares, ...MW],
|
|
26
|
+
DynamicMiddlewareProviders,
|
|
27
|
+
GenericMiddlewareMaker.ApplyManyServices<MW, MiddlewareR>
|
|
28
|
+
>
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface MiddlewareDynamic<
|
|
32
|
+
RequestContext extends Record<string, RPCContextMap.Any>,
|
|
33
|
+
Provided extends keyof RequestContext,
|
|
34
|
+
Middlewares extends ReadonlyArray<GenericMiddlewareMaker>,
|
|
35
|
+
DynamicMiddlewareProviders,
|
|
36
|
+
out MiddlewareR
|
|
37
|
+
> {
|
|
38
|
+
// TODO: this still allows to mix both types of middleware but with bad typing result
|
|
39
|
+
// either have to block it, or implement the support properly.
|
|
40
|
+
middleware<MW extends NonEmptyArray<DynamicMiddlewareMaker<RequestContext>> | NonEmptyArray<GenericMiddlewareMaker>>(
|
|
41
|
+
...mw: MW
|
|
42
|
+
): [MW] extends [NonEmptyArray<DynamicMiddlewareMaker<RequestContext>>] ? DynamicMiddlewareMakerrsss<
|
|
23
43
|
RequestContext,
|
|
24
44
|
Provided | MW[number]["dynamic"]["key"],
|
|
25
45
|
Middlewares,
|
|
26
46
|
& DynamicMiddlewareProviders
|
|
27
47
|
& {
|
|
28
|
-
[
|
|
29
|
-
}
|
|
48
|
+
[U in MW[number] as U["dynamic"]["key"]]: U
|
|
49
|
+
},
|
|
50
|
+
GenericMiddlewareMaker.ApplyManyServices<MW, MiddlewareR>
|
|
30
51
|
>
|
|
31
|
-
|
|
52
|
+
: DynamicMiddlewareMakerrsss<
|
|
53
|
+
RequestContext,
|
|
54
|
+
Provided,
|
|
55
|
+
[...Middlewares, ...MW],
|
|
56
|
+
DynamicMiddlewareProviders,
|
|
57
|
+
GenericMiddlewareMaker.ApplyManyServices<MW, MiddlewareR>
|
|
58
|
+
>
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
type GetDynamicMiddleware<T, RequestContext extends Record<string, RPCContextMap.Any>> = T extends
|
|
62
|
+
RequestContextMapProvider<RequestContext> ? T : never
|
|
63
|
+
|
|
64
|
+
type DynamicMiddlewareMakerrsss<
|
|
65
|
+
RequestContext extends Record<string, RPCContextMap.Any>,
|
|
66
|
+
Provided extends keyof RequestContext = never,
|
|
67
|
+
Middlewares extends ReadonlyArray<GenericMiddlewareMaker> = [],
|
|
68
|
+
DynamicMiddlewareProviders = unknown,
|
|
69
|
+
MiddlewareR = never
|
|
70
|
+
> = keyof Omit<RequestContext, Provided> extends never ? [MiddlewareR] extends [never] ?
|
|
71
|
+
& ReturnType<
|
|
72
|
+
typeof makeMiddlewareBasic<
|
|
73
|
+
RequestContext,
|
|
74
|
+
GetDynamicMiddleware<DynamicMiddlewareProviders, RequestContext>,
|
|
75
|
+
Middlewares
|
|
76
|
+
>
|
|
77
|
+
>
|
|
78
|
+
// & {
|
|
79
|
+
// MiddlewareR: MiddlewareR
|
|
80
|
+
// Provided: Provided
|
|
81
|
+
// Middlewares: Middlewares
|
|
82
|
+
// DynamicMiddlewareProviders: Simplify<DynamicMiddlewareProviders>
|
|
83
|
+
// }
|
|
84
|
+
& MiddlewareM<
|
|
85
|
+
RequestContext,
|
|
86
|
+
Provided,
|
|
87
|
+
Middlewares,
|
|
88
|
+
DynamicMiddlewareProviders,
|
|
89
|
+
MiddlewareR
|
|
90
|
+
>
|
|
91
|
+
: MiddlewareM<
|
|
92
|
+
RequestContext,
|
|
93
|
+
Provided,
|
|
94
|
+
Middlewares,
|
|
95
|
+
DynamicMiddlewareProviders,
|
|
96
|
+
MiddlewareR
|
|
97
|
+
>
|
|
98
|
+
: MiddlewareDynamic<
|
|
99
|
+
RequestContext,
|
|
100
|
+
Provided,
|
|
101
|
+
Middlewares,
|
|
102
|
+
DynamicMiddlewareProviders,
|
|
103
|
+
MiddlewareR
|
|
104
|
+
>
|
|
32
105
|
|
|
33
106
|
export const makeNewMiddleware: <
|
|
34
107
|
RequestContextMap extends Record<string, RPCContextMap.Any>
|
|
35
|
-
>() => <
|
|
36
|
-
...genericMiddlewares: Middlewares
|
|
37
|
-
) => DynamicMiddlewareMakerrsss<RequestContextMap, never, Middlewares, never> = () => (...genericMiddlewares) => {
|
|
38
|
-
const dynamicMiddlewares: Record<string, any> = {} as any
|
|
108
|
+
>() => DynamicMiddlewareMakerrsss<RequestContextMap> = () => {
|
|
39
109
|
const make = makeMiddleware<any>()
|
|
110
|
+
let capturedMiddlewares: (DynamicMiddlewareMaker<any> | GenericMiddlewareMaker)[] = []
|
|
40
111
|
const it = {
|
|
41
|
-
|
|
42
|
-
for (const
|
|
43
|
-
|
|
44
|
-
|
|
112
|
+
middleware: (...middlewares: any[]) => {
|
|
113
|
+
for (const mw of middlewares) {
|
|
114
|
+
capturedMiddlewares = [mw, ...capturedMiddlewares]
|
|
115
|
+
if (mw.dynamic) {
|
|
116
|
+
console.log("Adding dynamic middleware", mw.key, mw.dynamic.key)
|
|
117
|
+
} else {
|
|
118
|
+
console.log("Adding generic middleware", mw.key)
|
|
119
|
+
}
|
|
45
120
|
}
|
|
46
|
-
|
|
121
|
+
const [genericMiddlewares, dyn] = Array.partitionMap(
|
|
122
|
+
capturedMiddlewares,
|
|
123
|
+
(mw) =>
|
|
124
|
+
"dynamic" in mw && mw.dynamic
|
|
125
|
+
? Either.right(mw as DynamicMiddlewareMaker<any>)
|
|
126
|
+
: Either.left(mw as GenericMiddlewareMaker)
|
|
127
|
+
)
|
|
128
|
+
const dynamicMiddlewares = dyn.reduce(
|
|
129
|
+
(prev, cur) => ({ ...prev, [cur.dynamic.key]: cur }),
|
|
130
|
+
{} as Record<string, any>
|
|
131
|
+
)
|
|
132
|
+
// TODO: support dynamic and generic intertwined. treat them as one
|
|
133
|
+
return Object.assign(make({ genericMiddlewares, dynamicMiddlewares }), it)
|
|
47
134
|
}
|
|
48
135
|
}
|
|
49
136
|
return it as any
|
|
@@ -1,24 +1,32 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
-
import { Cause, Context, Effect, ParseResult } from "effect-app"
|
|
2
|
+
import { Cause, Context, Duration, Effect, Layer, ParseResult, Request } from "effect-app"
|
|
3
3
|
import { pretty } from "effect-app/utils"
|
|
4
4
|
import { logError, reportError } from "../../../errorReporter.js"
|
|
5
5
|
import { InfraLogger } from "../../../logger.js"
|
|
6
|
-
import {
|
|
6
|
+
import { Tag } from "../middleware.js"
|
|
7
7
|
|
|
8
8
|
const logRequestError = logError("Request")
|
|
9
9
|
const reportRequestError = reportError("Request")
|
|
10
10
|
|
|
11
|
+
export const RequestCacheLayers = Layer.mergeAll(
|
|
12
|
+
Layer.setRequestCache(
|
|
13
|
+
Request.makeCache({ capacity: 500, timeToLive: Duration.hours(8) })
|
|
14
|
+
),
|
|
15
|
+
Layer.setRequestCaching(true),
|
|
16
|
+
Layer.setRequestBatching(true)
|
|
17
|
+
)
|
|
18
|
+
|
|
11
19
|
export class DevMode extends Context.Reference<DevMode>()("DevMode", { defaultValue: () => false }) {}
|
|
12
20
|
|
|
13
21
|
export class RequestCacheMiddleware extends Tag<RequestCacheMiddleware>()("RequestCacheMiddleware", { wrap: true })({
|
|
14
|
-
effect: Effect.succeed((
|
|
22
|
+
effect: Effect.succeed(({ next }) => next.pipe(Effect.provide(RequestCacheLayers)))
|
|
15
23
|
}) {
|
|
16
24
|
}
|
|
17
25
|
|
|
18
26
|
export class ConfigureInterruptibility
|
|
19
27
|
extends Tag<ConfigureInterruptibility>()("ConfigureInterruptibility", { wrap: true })({
|
|
20
|
-
effect: Effect.succeed((
|
|
21
|
-
|
|
28
|
+
effect: Effect.succeed(({ next }) =>
|
|
29
|
+
next.pipe(
|
|
22
30
|
// TODO: make this depend on query/command, and consider if middleware also should be affected. right now it's not.
|
|
23
31
|
Effect.uninterruptible
|
|
24
32
|
)
|
package/src/api/routing.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
5
5
|
import { determineMethod, isCommand } from "@effect-app/infra/api/routing/utils"
|
|
6
6
|
import { Rpc, RpcGroup, RpcServer } from "@effect/rpc"
|
|
7
|
-
import { type Array,
|
|
7
|
+
import { type Array, Effect, Layer, type NonEmptyReadonlyArray, Predicate, S, Schedule, Schema, type Scope } from "effect-app"
|
|
8
8
|
import type { GetEffectContext, GetEffectError, RPCContextMap } from "effect-app/client/req"
|
|
9
9
|
import { type HttpHeaders, HttpRouter } from "effect-app/http"
|
|
10
10
|
import { typedKeysOf, typedValuesOf } from "effect-app/utils"
|
|
@@ -819,11 +819,3 @@ export type MakeHandlers<Make, Handlers extends Record<string, any>> = Make exte
|
|
|
819
819
|
* @since 3.9.0
|
|
820
820
|
*/
|
|
821
821
|
export type MakeDepsOut<Make> = Contravariant.Type<MakeDeps<Make>[Layer.LayerTypeId]["_ROut"]>
|
|
822
|
-
|
|
823
|
-
export const RequestCacheLayers = Layer.mergeAll(
|
|
824
|
-
Layer.setRequestCache(
|
|
825
|
-
Request.makeCache({ capacity: 500, timeToLive: Duration.hours(8) })
|
|
826
|
-
),
|
|
827
|
-
Layer.setRequestCaching(true),
|
|
828
|
-
Layer.setRequestBatching(true)
|
|
829
|
-
)
|
|
@@ -3,8 +3,7 @@
|
|
|
3
3
|
import { expectTypeOf } from "@effect/vitest"
|
|
4
4
|
import { Context, Effect, Scope } from "effect-app"
|
|
5
5
|
import { ContextProvider, mergeContextProviders, MergedContextProvider } from "../src/api/routing.js"
|
|
6
|
-
import { CustomError1, Some, SomeElse } from "./
|
|
7
|
-
import { SomeService } from "./query.test.js"
|
|
6
|
+
import { CustomError1, Some, SomeElse, SomeService } from "./fixtures.js"
|
|
8
7
|
|
|
9
8
|
// @effect-diagnostics-next-line missingEffectServiceDependency:off
|
|
10
9
|
class MyContextProvider extends Effect.Service<MyContextProvider>()("MyContextProvider", {
|
package/test/controller.test.ts
CHANGED
|
@@ -1,46 +1,24 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
2
|
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
|
3
3
|
import { type MakeContext, type MakeErrors, makeRouter } from "@effect-app/infra/api/routing"
|
|
4
|
-
import type { RequestContext } from "@effect-app/infra/RequestContext"
|
|
5
4
|
import { expect, expectTypeOf, it } from "@effect/vitest"
|
|
6
|
-
import {
|
|
7
|
-
import { InvalidStateError, makeRpcClient,
|
|
8
|
-
import {
|
|
9
|
-
import { contextMap, DefaultGenericMiddlewares, implementMiddleware, makeMiddleware, makeNewMiddleware, Middleware, Tag } from "../src/api/routing/middleware.js"
|
|
5
|
+
import { Context, Effect, Layer, S, Scope } from "effect-app"
|
|
6
|
+
import { InvalidStateError, makeRpcClient, NotLoggedInError, UnauthorizedError } from "effect-app/client"
|
|
7
|
+
import { DefaultGenericMiddlewares, implementMiddleware, makeMiddleware, makeNewMiddleware, Middleware, Tag } from "../src/api/routing/middleware.js"
|
|
10
8
|
import { sort } from "../src/api/routing/tsort.js"
|
|
11
|
-
import { SomeService } from "./
|
|
12
|
-
|
|
13
|
-
export class UserProfile extends Context.assignTag<UserProfile, UserProfile>("UserProfile")(
|
|
14
|
-
Class<UserProfile>("UserProfile")({
|
|
15
|
-
id: S.String,
|
|
16
|
-
roles: S.Array(S.String)
|
|
17
|
-
})
|
|
18
|
-
) {
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export class NotLoggedInError extends TaggedError<NotLoggedInError>()("NotLoggedInError", {
|
|
22
|
-
message: S.String
|
|
23
|
-
}) {}
|
|
24
|
-
|
|
25
|
-
export class CustomError1 extends TaggedError<NotLoggedInError>()("CustomError1", {}) {}
|
|
26
|
-
export class CustomError2 extends TaggedError<NotLoggedInError>()("CustomError1", {}) {}
|
|
27
|
-
|
|
28
|
-
export interface CTX {
|
|
29
|
-
context: RequestContext
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export class Some extends Context.TagMakeId("Some", Effect.succeed({ a: 1 }))<Some>() {}
|
|
33
|
-
export class SomeElse extends Context.TagMakeId("SomeElse", Effect.succeed({ b: 2 }))<SomeElse>() {}
|
|
9
|
+
import { AllowAnonymous, CustomError1, type RequestContextMap, RequireRoles, Some, SomeElse, SomeService, Test } from "./fixtures.js"
|
|
34
10
|
|
|
35
11
|
// @effect-diagnostics-next-line missingEffectServiceDependency:off
|
|
36
12
|
class MyContextProvider extends Middleware.Tag<MyContextProvider>()("MyContextProvider", {
|
|
37
|
-
provides: [Some]
|
|
13
|
+
provides: [Some],
|
|
14
|
+
requires: [SomeElse]
|
|
38
15
|
})({
|
|
39
16
|
effect: Effect.gen(function*() {
|
|
40
17
|
yield* SomeService
|
|
41
18
|
if (Math.random() > 0.5) return yield* new CustomError1()
|
|
42
19
|
|
|
43
20
|
return Effect.fnUntraced(function*() {
|
|
21
|
+
yield* SomeElse
|
|
44
22
|
// the only requirements you can have are the one provided by HttpRouter.HttpRouter.Provided
|
|
45
23
|
yield* Scope.Scope
|
|
46
24
|
|
|
@@ -74,81 +52,19 @@ class MyContextProvider2 extends Middleware.Tag<MyContextProvider2>()("MyContext
|
|
|
74
52
|
|
|
75
53
|
//
|
|
76
54
|
|
|
77
|
-
export type RequestContextMap = {
|
|
78
|
-
allowAnonymous: RPCContextMap.Inverted<UserProfile, typeof NotLoggedInError>
|
|
79
|
-
requireRoles: RPCContextMap.Custom<never, typeof UnauthorizedError, Array<string>>
|
|
80
|
-
test: RPCContextMap<never, typeof S.Never>
|
|
81
|
-
}
|
|
82
|
-
|
|
83
55
|
const Str = Context.GenericTag<"str", "str">("str")
|
|
84
56
|
const Str2 = Context.GenericTag<"str2", "str">("str2")
|
|
85
57
|
|
|
86
|
-
class AllowAnonymous extends Middleware.Tag<AllowAnonymous>()("AllowAnonymous", {
|
|
87
|
-
dynamic: contextMap<RequestContextMap>()("allowAnonymous")
|
|
88
|
-
})({
|
|
89
|
-
effect: Effect.gen(function*() {
|
|
90
|
-
return Effect.fnUntraced(
|
|
91
|
-
function*(options) {
|
|
92
|
-
yield* Scope.Scope // provided by HttpRouter.HttpRouter.Provided
|
|
93
|
-
const isLoggedIn = !!options.headers["x-user"]
|
|
94
|
-
if (!isLoggedIn) {
|
|
95
|
-
if (!options.config.allowAnonymous) {
|
|
96
|
-
return yield* new NotLoggedInError({ message: "Not logged in" })
|
|
97
|
-
}
|
|
98
|
-
return Option.none()
|
|
99
|
-
}
|
|
100
|
-
return Option.some(Context.make(
|
|
101
|
-
UserProfile,
|
|
102
|
-
{ id: "whatever", roles: ["user", "manager"] }
|
|
103
|
-
))
|
|
104
|
-
}
|
|
105
|
-
)
|
|
106
|
-
})
|
|
107
|
-
}) {
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
// @effect-diagnostics-next-line missingEffectServiceDependency:off
|
|
111
|
-
class RequireRoles extends Middleware.Tag<RequireRoles>()("RequireRoles", {
|
|
112
|
-
dynamic: contextMap<RequestContextMap>()("requireRoles"),
|
|
113
|
-
// had to move this in here, because once you put it manually as a readonly static property on the class,
|
|
114
|
-
// there's a weird issue where the fluent api stops behaving properly after adding this middleware via `addDynamicMiddleware`
|
|
115
|
-
dependsOn: [AllowAnonymous]
|
|
116
|
-
})({
|
|
117
|
-
effect: Effect.gen(function*() {
|
|
118
|
-
yield* Some
|
|
119
|
-
return Effect.fnUntraced(
|
|
120
|
-
function*(options) {
|
|
121
|
-
// we don't know if the service will be provided or not, so we use option..
|
|
122
|
-
const userProfile = yield* Effect.serviceOption(UserProfile)
|
|
123
|
-
const { requireRoles } = options.config
|
|
124
|
-
if (requireRoles && !userProfile.value?.roles?.some((role) => requireRoles.includes(role))) {
|
|
125
|
-
return yield* new UnauthorizedError({ message: "don't have the right roles" })
|
|
126
|
-
}
|
|
127
|
-
return Option.none<Context<never>>()
|
|
128
|
-
}
|
|
129
|
-
)
|
|
130
|
-
})
|
|
131
|
-
}) {
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
class Test extends Middleware.Tag<Test>()("Test", { dynamic: contextMap<RequestContextMap>()("test") })({
|
|
135
|
-
effect: Effect.gen(function*() {
|
|
136
|
-
return Effect.fn(function*(_options) {
|
|
137
|
-
return Option.none<Context<never>>()
|
|
138
|
-
})
|
|
139
|
-
})
|
|
140
|
-
}) {}
|
|
141
|
-
|
|
142
58
|
export class BogusMiddleware extends Tag<BogusMiddleware>()("BogusMiddleware", {
|
|
143
59
|
provides: SomeService,
|
|
144
60
|
wrap: true
|
|
145
61
|
})({
|
|
146
62
|
effect: Effect.gen(function*() {
|
|
147
63
|
// yield* Effect.context<"test-dep">()
|
|
148
|
-
return (
|
|
64
|
+
return ({ next }) =>
|
|
149
65
|
Effect.gen(function*() {
|
|
150
66
|
// yield* Effect.context<"test-dep2">()
|
|
151
|
-
return yield*
|
|
67
|
+
return yield* next.pipe(Effect.provideService(SomeService, null as any))
|
|
152
68
|
})
|
|
153
69
|
})
|
|
154
70
|
}) {
|
|
@@ -204,13 +120,13 @@ const middleware2 = makeMiddleware<RequestContextMap>()({
|
|
|
204
120
|
}
|
|
205
121
|
})
|
|
206
122
|
|
|
207
|
-
export const middleware3 = makeNewMiddleware<RequestContextMap>()
|
|
208
|
-
...genericMiddlewares
|
|
209
|
-
)
|
|
210
|
-
.
|
|
211
|
-
|
|
123
|
+
export const middleware3 = makeNewMiddleware<RequestContextMap>()
|
|
124
|
+
.middleware(...genericMiddlewares)
|
|
125
|
+
.middleware(AllowAnonymous, RequireRoles)
|
|
126
|
+
.middleware(Test)
|
|
127
|
+
// .middleware(BogusMiddleware)
|
|
212
128
|
|
|
213
|
-
expectTypeOf(middleware3).
|
|
129
|
+
// expectTypeOf(middleware3).toExtend<typeof middleware2>()
|
|
214
130
|
|
|
215
131
|
export type RequestConfig = {
|
|
216
132
|
/** Disable authentication requirement */
|
|
@@ -360,7 +276,7 @@ it("sorts based on requirements", () => {
|
|
|
360
276
|
|
|
361
277
|
// eslint-disable-next-line unused-imports/no-unused-vars
|
|
362
278
|
const matched = matchAll({ router })
|
|
363
|
-
expectTypeOf({} as Layer.Context<typeof matched>).toEqualTypeOf<SomeService | "str">()
|
|
279
|
+
expectTypeOf({} as Layer.Context<typeof matched>).toEqualTypeOf<SomeService | Some | "str">()
|
|
364
280
|
|
|
365
281
|
type makeContext = MakeContext<typeof router.make>
|
|
366
282
|
expectTypeOf({} as MakeErrors<typeof router.make>).toEqualTypeOf<InvalidStateError>()
|
|
@@ -432,7 +348,7 @@ const router2 = r2.Router(Something)({
|
|
|
432
348
|
|
|
433
349
|
// eslint-disable-next-line unused-imports/no-unused-vars
|
|
434
350
|
const matched2 = matchAll({ router: router2 })
|
|
435
|
-
expectTypeOf({} as Layer.Context<typeof matched2>).toEqualTypeOf<SomeService>()
|
|
351
|
+
expectTypeOf({} as Layer.Context<typeof matched2>).toEqualTypeOf<Some | SomeService>()
|
|
436
352
|
|
|
437
353
|
type makeContext2 = MakeContext<typeof router2.make>
|
|
438
354
|
expectTypeOf({} as MakeErrors<typeof router2.make>).toEqualTypeOf<InvalidStateError>()
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contextProvider.test.d.ts","sourceRoot":"","sources":["../contextProvider.test.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAEnD,OAAO,EAAE,YAAY,EAAE,IAAI,EAAE,QAAQ,EAAE,
|
|
1
|
+
{"version":3,"file":"contextProvider.test.d.ts","sourceRoot":"","sources":["../contextProvider.test.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAEnD,OAAO,EAAE,YAAY,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AA8EzE,eAAO,MAAM,mBAAmB;;CAkB9B,CAAA;AACF,eAAO,MAAM,sBAAsB;;CAkBjC,CAAA;AAMF,eAAO,MAAM,gBAAgB;;CAA0B,CAAA;AACvD,eAAO,MAAM,gBAAgB,kMAA2C,CAAA;AAIxE,eAAO,MAAM,mBAAmB;;CAA6B,CAAA;AAC7D,eAAO,MAAM,mBAAmB,kMAA8C,CAAA;AAQ9E,eAAO,MAAM,iBAAiB;;CAA2B,CAAA;AACzD,eAAO,MAAM,iBAAiB,6MAA+D,CAAA;AAI7F,eAAO,MAAM,oBAAoB;;CAA8B,CAAA;AAC/D,eAAO,MAAM,oBAAoB,6MAAqE,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"controller.test.d.ts","sourceRoot":"","sources":["../controller.test.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,WAAW,EAAE,KAAK,UAAU,EAAc,MAAM,+BAA+B,CAAA;
|
|
1
|
+
{"version":3,"file":"controller.test.d.ts","sourceRoot":"","sources":["../controller.test.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,WAAW,EAAE,KAAK,UAAU,EAAc,MAAM,+BAA+B,CAAA;AAE7F,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAC7D,OAAO,EAAoC,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AACzG,OAAO,EAAqF,UAAU,EAAO,MAAM,kCAAkC,CAAA;AAErJ,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,YAAY,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,eAAe,CAAA;;;;;;;AAGrI,cAAM,iBAAkB,SAAQ,sBA0B9B;CAAG;;;;;;AAGL,cAAM,kBAAmB,SAAQ,uBAU/B;CAAG;;;;;;;AAOL,qBAAa,eAAgB,SAAQ,oBAYnC;CACD;AAoDD,eAAO,MAAM,WAAW;;;;;YAGL,CAAA;AAKnB,MAAM,MAAM,aAAa,GAAG;IAC1B,yCAAyC;IACzC,cAAc,CAAC,EAAE,IAAI,CAAA;IACrB,iEAAiE;IACjE,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CAC/B,CAAA;AACD,eAAO,MAAuB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAI/B,CAAA;;;;;;;;;;AAEF,qBAAa,GAAI,SAAQ,QAA0C;CAAG;;;;;;;;;;AACtE,qBAAa,GAAI,SAAQ,QAA0C;CAAG;;;;;;;;;;;;AAEtE,qBAAa,WAAY,SAAQ,gBAEV;CAAG;;;;;;;;;;;;AAgB1B,qBAAa,YAAa,SAAQ,iBAET;CAAG;;;;;;;;;;;;AAE5B,qBAAa,aAAc,SAAQ,kBAEA;CAAG;;;;;AAItC,qBAAa,gBAAiB,SAAQ,qBAKpC;CAAG;;;;;AASL,qBAAa,aAAc,SAAQ,kBAOjC;CAAG;;;;;AAEL,qBAAa,iBAAkB,SAAQ,sBAKrC;CAAG;AAEL,eAAO,MAAQ,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAAE,QAAQ;;;;;2HAAE,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;uCAAiC,CAAA;AAE1E,eAAO,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAAgC,CAAA;AAyJ/C,eAAO,MAAM,kBAAkB;;;;;;;;;;CAI7B,CAAA"}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { Context, Effect, S, Scope } from "effect-app";
|
|
2
|
+
import { NotLoggedInError, type RPCContextMap, UnauthorizedError } from "effect-app/client";
|
|
3
|
+
import { Middleware } from "../src/api/routing.js";
|
|
4
|
+
declare const UserProfile_base: S.EnhancedClass<UserProfile, {
|
|
5
|
+
id: typeof S.String;
|
|
6
|
+
roles: S.Array$<typeof S.String> & {
|
|
7
|
+
withDefault: S.PropertySignature<":", readonly string[], never, ":", readonly string[], true, never>;
|
|
8
|
+
};
|
|
9
|
+
}, {
|
|
10
|
+
readonly id: string;
|
|
11
|
+
readonly roles: readonly string[];
|
|
12
|
+
}, never, {
|
|
13
|
+
readonly id: string;
|
|
14
|
+
readonly roles: readonly string[];
|
|
15
|
+
}, {}, {}> & Context.Tag<UserProfile, UserProfile>;
|
|
16
|
+
export declare class UserProfile extends UserProfile_base {
|
|
17
|
+
}
|
|
18
|
+
declare const Some_base: (abstract new (service: {
|
|
19
|
+
a: number;
|
|
20
|
+
}) => Readonly<{
|
|
21
|
+
a: number;
|
|
22
|
+
}> & Context.TagClassShape<"Some", {
|
|
23
|
+
a: number;
|
|
24
|
+
}>) & {
|
|
25
|
+
toLayer: {
|
|
26
|
+
(): import("effect/Layer").Layer<Some, never, never>;
|
|
27
|
+
<E_1, R_1>(eff: Effect.Effect<Omit<Some, keyof Context.TagClassShape<any, any>>, E_1, R_1>): import("effect/Layer").Layer<Some, E_1, R_1>;
|
|
28
|
+
};
|
|
29
|
+
toLayerScoped: {
|
|
30
|
+
(): import("effect/Layer").Layer<Some, never, never>;
|
|
31
|
+
<E_1, R_2>(eff: Effect.Effect<Context.TagClassShape<any, any>, E_1, R_2>): import("effect/Layer").Layer<Some, E_1, Exclude<R_2, Scope.Scope>>;
|
|
32
|
+
};
|
|
33
|
+
of: (service: Context.TagClassShape<any, any>) => Some;
|
|
34
|
+
make: Effect.Effect<Some, never, never>;
|
|
35
|
+
} & Context.Tag<Some, Some> & {
|
|
36
|
+
a: Effect.Effect<number, never, Some>;
|
|
37
|
+
} & {
|
|
38
|
+
use: <X>(body: (_: {
|
|
39
|
+
a: number;
|
|
40
|
+
}) => X) => X extends Effect.Effect<infer A, infer E_1, infer R_3> ? Effect.Effect<A, E_1, Some | R_3> : Effect.Effect<X, never, Some>;
|
|
41
|
+
};
|
|
42
|
+
export declare class Some extends Some_base {
|
|
43
|
+
}
|
|
44
|
+
declare const SomeElse_base: (abstract new (service: {
|
|
45
|
+
b: number;
|
|
46
|
+
}) => Readonly<{
|
|
47
|
+
b: number;
|
|
48
|
+
}> & Context.TagClassShape<"SomeElse", {
|
|
49
|
+
b: number;
|
|
50
|
+
}>) & {
|
|
51
|
+
toLayer: {
|
|
52
|
+
(): import("effect/Layer").Layer<SomeElse, never, never>;
|
|
53
|
+
<E_1, R_1>(eff: Effect.Effect<Omit<SomeElse, keyof Context.TagClassShape<any, any>>, E_1, R_1>): import("effect/Layer").Layer<SomeElse, E_1, R_1>;
|
|
54
|
+
};
|
|
55
|
+
toLayerScoped: {
|
|
56
|
+
(): import("effect/Layer").Layer<SomeElse, never, never>;
|
|
57
|
+
<E_1, R_2>(eff: Effect.Effect<Context.TagClassShape<any, any>, E_1, R_2>): import("effect/Layer").Layer<SomeElse, E_1, Exclude<R_2, Scope.Scope>>;
|
|
58
|
+
};
|
|
59
|
+
of: (service: Context.TagClassShape<any, any>) => SomeElse;
|
|
60
|
+
make: Effect.Effect<SomeElse, never, never>;
|
|
61
|
+
} & Context.Tag<SomeElse, SomeElse> & {
|
|
62
|
+
b: Effect.Effect<number, never, SomeElse>;
|
|
63
|
+
} & {
|
|
64
|
+
use: <X>(body: (_: {
|
|
65
|
+
b: number;
|
|
66
|
+
}) => X) => X extends Effect.Effect<infer A, infer E_1, infer R_3> ? Effect.Effect<A, E_1, R_3 | SomeElse> : Effect.Effect<X, never, SomeElse>;
|
|
67
|
+
};
|
|
68
|
+
export declare class SomeElse extends SomeElse_base {
|
|
69
|
+
}
|
|
70
|
+
export type RequestContextMap = {
|
|
71
|
+
allowAnonymous: RPCContextMap.Inverted<UserProfile, typeof NotLoggedInError>;
|
|
72
|
+
requireRoles: RPCContextMap.Custom<never, typeof UnauthorizedError, Array<string>>;
|
|
73
|
+
test: RPCContextMap<never, typeof S.Never>;
|
|
74
|
+
};
|
|
75
|
+
declare const AllowAnonymous_base: Middleware.TagClass<AllowAnonymous, "AllowAnonymous", {
|
|
76
|
+
readonly dynamic: {
|
|
77
|
+
key: "allowAnonymous";
|
|
78
|
+
settings: RPCContextMap.Inverted<UserProfile, typeof NotLoggedInError>;
|
|
79
|
+
};
|
|
80
|
+
readonly requires: typeof SomeElse;
|
|
81
|
+
}> & {
|
|
82
|
+
Default: import("effect/Layer").Layer<AllowAnonymous, never, never>;
|
|
83
|
+
};
|
|
84
|
+
export declare class AllowAnonymous extends AllowAnonymous_base {
|
|
85
|
+
}
|
|
86
|
+
declare const RequireRoles_base: Middleware.TagClass<RequireRoles, "RequireRoles", {
|
|
87
|
+
readonly dynamic: {
|
|
88
|
+
key: "requireRoles";
|
|
89
|
+
settings: RPCContextMap.Custom<never, typeof UnauthorizedError, string[]>;
|
|
90
|
+
};
|
|
91
|
+
readonly dependsOn: readonly [typeof AllowAnonymous];
|
|
92
|
+
}> & {
|
|
93
|
+
Default: import("effect/Layer").Layer<RequireRoles, never, Some>;
|
|
94
|
+
};
|
|
95
|
+
export declare class RequireRoles extends RequireRoles_base {
|
|
96
|
+
}
|
|
97
|
+
declare const Test_base: Middleware.TagClass<Test, "Test", {
|
|
98
|
+
readonly dynamic: {
|
|
99
|
+
key: "test";
|
|
100
|
+
settings: RPCContextMap<never, typeof S.Never>;
|
|
101
|
+
};
|
|
102
|
+
}> & {
|
|
103
|
+
Default: import("effect/Layer").Layer<Test, never, never>;
|
|
104
|
+
};
|
|
105
|
+
export declare class Test extends Test_base {
|
|
106
|
+
}
|
|
107
|
+
declare const CustomError1_base: S.TaggedErrorClass<NotLoggedInError, "CustomError1", {
|
|
108
|
+
readonly _tag: S.tag<"CustomError1">;
|
|
109
|
+
}>;
|
|
110
|
+
export declare class CustomError1 extends CustomError1_base {
|
|
111
|
+
}
|
|
112
|
+
declare const CustomError2_base: S.TaggedErrorClass<NotLoggedInError, "CustomError1", {
|
|
113
|
+
readonly _tag: S.tag<"CustomError1">;
|
|
114
|
+
}>;
|
|
115
|
+
export declare class CustomError2 extends CustomError2_base {
|
|
116
|
+
}
|
|
117
|
+
declare const SomeService_base: (abstract new (service: {
|
|
118
|
+
a: number;
|
|
119
|
+
}) => Readonly<{
|
|
120
|
+
a: number;
|
|
121
|
+
}> & Context.TagClassShape<"SomeService", {
|
|
122
|
+
a: number;
|
|
123
|
+
}>) & {
|
|
124
|
+
toLayer: {
|
|
125
|
+
(): import("effect/Layer").Layer<SomeService, never, never>;
|
|
126
|
+
<E_1, R_1>(eff: Effect.Effect<Omit<SomeService, keyof Context.TagClassShape<any, any>>, E_1, R_1>): import("effect/Layer").Layer<SomeService, E_1, R_1>;
|
|
127
|
+
};
|
|
128
|
+
toLayerScoped: {
|
|
129
|
+
(): import("effect/Layer").Layer<SomeService, never, never>;
|
|
130
|
+
<E_1, R_2>(eff: Effect.Effect<Context.TagClassShape<any, any>, E_1, R_2>): import("effect/Layer").Layer<SomeService, E_1, Exclude<R_2, Scope.Scope>>;
|
|
131
|
+
};
|
|
132
|
+
of: (service: Context.TagClassShape<any, any>) => SomeService;
|
|
133
|
+
make: Effect.Effect<SomeService, never, never>;
|
|
134
|
+
} & Context.Tag<SomeService, SomeService> & {
|
|
135
|
+
a: Effect.Effect<number, never, SomeService>;
|
|
136
|
+
} & {
|
|
137
|
+
use: <X>(body: (_: {
|
|
138
|
+
a: number;
|
|
139
|
+
}) => X) => X extends Effect.Effect<infer A, infer E_1, infer R_3> ? Effect.Effect<A, E_1, R_3 | SomeService> : Effect.Effect<X, never, SomeService>;
|
|
140
|
+
};
|
|
141
|
+
export declare class SomeService extends SomeService_base {
|
|
142
|
+
}
|
|
143
|
+
export {};
|
|
144
|
+
//# sourceMappingURL=fixtures.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fixtures.d.ts","sourceRoot":"","sources":["../fixtures.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAU,CAAC,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAC9D,OAAO,EAAE,gBAAgB,EAAE,KAAK,aAAa,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AAE3F,OAAO,EAAc,UAAU,EAAE,MAAM,uBAAuB,CAAA;;;;;;;;;;;;;AAE9D,qBAAa,WAAY,SAAQ,gBAKhC;CACA;;;;;;;;;;;;;;;;;;;;;;;;;AAED,qBAAa,IAAK,SAAQ,SAA2D;CAAG;;;;;;;;;;;;;;;;;;;;;;;;;AACxF,qBAAa,QAAS,SAAQ,aAAmE;CAAG;AAEpG,MAAM,MAAM,iBAAiB,GAAG;IAC9B,cAAc,EAAE,aAAa,CAAC,QAAQ,CAAC,WAAW,EAAE,OAAO,gBAAgB,CAAC,CAAA;IAC5E,YAAY,EAAE,aAAa,CAAC,MAAM,CAAC,KAAK,EAAE,OAAO,iBAAiB,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAA;IAClF,IAAI,EAAE,aAAa,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,KAAK,CAAC,CAAA;CAC3C,CAAA;;;;;;;;;;AAED,qBAAa,cAAe,SAAQ,mBAuBlC;CACD;;;;;;;;;;AAGD,qBAAa,YAAa,SAAQ,iBAoBhC;CACD;;;;;;;;;AAED,qBAAa,IAAK,SAAQ,SAMxB;CAAG;;;;AAEL,qBAAa,YAAa,SAAQ,iBAAmD;CAAG;;;;AACxF,qBAAa,YAAa,SAAQ,iBAAmD;CAAG;;;;;;;;;;;;;;;;;;;;;;;;;AAGxF,qBAAa,WAAY,SAAQ,gBAAgE;CAAG"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { Context, Effect, Option, S, Scope } from "effect-app";
|
|
2
|
+
import { NotLoggedInError, UnauthorizedError } from "effect-app/client";
|
|
3
|
+
import { TaggedError } from "effect-app/Schema";
|
|
4
|
+
import { contextMap, Middleware } from "../src/api/routing.js";
|
|
5
|
+
export class UserProfile extends Context.assignTag("UserProfile")(S.Class("UserProfile")({
|
|
6
|
+
id: S.String,
|
|
7
|
+
roles: S.Array(S.String)
|
|
8
|
+
})) {
|
|
9
|
+
}
|
|
10
|
+
export class Some extends Context.TagMakeId("Some", Effect.succeed({ a: 1 }))() {
|
|
11
|
+
}
|
|
12
|
+
export class SomeElse extends Context.TagMakeId("SomeElse", Effect.succeed({ b: 2 }))() {
|
|
13
|
+
}
|
|
14
|
+
export class AllowAnonymous extends Middleware.Tag()("AllowAnonymous", {
|
|
15
|
+
dynamic: contextMap()("allowAnonymous"),
|
|
16
|
+
requires: SomeElse
|
|
17
|
+
})({
|
|
18
|
+
effect: Effect.gen(function* () {
|
|
19
|
+
return Effect.fnUntraced(function* ({ config, headers }) {
|
|
20
|
+
yield* SomeElse;
|
|
21
|
+
yield* Scope.Scope; // provided by HttpRouter.HttpRouter.Provided
|
|
22
|
+
const isLoggedIn = !!headers["x-user"];
|
|
23
|
+
if (!isLoggedIn) {
|
|
24
|
+
if (!config.allowAnonymous) {
|
|
25
|
+
return yield* new NotLoggedInError({ message: "Not logged in" });
|
|
26
|
+
}
|
|
27
|
+
return Option.none();
|
|
28
|
+
}
|
|
29
|
+
return Option.some(Context.make(UserProfile, { id: "whatever", roles: ["user", "manager"] }));
|
|
30
|
+
});
|
|
31
|
+
})
|
|
32
|
+
}) {
|
|
33
|
+
}
|
|
34
|
+
// @effect-diagnostics-next-line missingEffectServiceDependency:off
|
|
35
|
+
export class RequireRoles extends Middleware.Tag()("RequireRoles", {
|
|
36
|
+
dynamic: contextMap()("requireRoles"),
|
|
37
|
+
// had to move this in here, because once you put it manually as a readonly static property on the class,
|
|
38
|
+
// there's a weird issue where the fluent api stops behaving properly after adding this middleware via `addDynamicMiddleware`
|
|
39
|
+
dependsOn: [AllowAnonymous]
|
|
40
|
+
})({
|
|
41
|
+
effect: Effect.gen(function* () {
|
|
42
|
+
yield* Some;
|
|
43
|
+
return Effect.fnUntraced(function* ({ config }) {
|
|
44
|
+
// we don't know if the service will be provided or not, so we use option..
|
|
45
|
+
const userProfile = yield* Effect.serviceOption(UserProfile);
|
|
46
|
+
const { requireRoles } = config;
|
|
47
|
+
if (requireRoles && !userProfile.value?.roles?.some((role) => requireRoles.includes(role))) {
|
|
48
|
+
return yield* new UnauthorizedError({ message: "don't have the right roles" });
|
|
49
|
+
}
|
|
50
|
+
return Option.none();
|
|
51
|
+
});
|
|
52
|
+
})
|
|
53
|
+
}) {
|
|
54
|
+
}
|
|
55
|
+
export class Test extends Middleware.Tag()("Test", { dynamic: contextMap()("test") })({
|
|
56
|
+
effect: Effect.gen(function* () {
|
|
57
|
+
return Effect.fn(function* () {
|
|
58
|
+
return Option.none();
|
|
59
|
+
});
|
|
60
|
+
})
|
|
61
|
+
}) {
|
|
62
|
+
}
|
|
63
|
+
export class CustomError1 extends TaggedError()("CustomError1", {}) {
|
|
64
|
+
}
|
|
65
|
+
export class CustomError2 extends TaggedError()("CustomError1", {}) {
|
|
66
|
+
}
|
|
67
|
+
const MakeSomeService = Effect.succeed({ a: 1 });
|
|
68
|
+
export class SomeService extends Context.TagMakeId("SomeService", MakeSomeService)() {
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZml4dHVyZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9maXh0dXJlcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLEVBQUUsQ0FBQyxFQUFFLEtBQUssRUFBRSxNQUFNLFlBQVksQ0FBQTtBQUM5RCxPQUFPLEVBQUUsZ0JBQWdCLEVBQXNCLGlCQUFpQixFQUFFLE1BQU0sbUJBQW1CLENBQUE7QUFDM0YsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLG1CQUFtQixDQUFBO0FBQy9DLE9BQU8sRUFBRSxVQUFVLEVBQUUsVUFBVSxFQUFFLE1BQU0sdUJBQXVCLENBQUE7QUFFOUQsTUFBTSxPQUFPLFdBQVksU0FBUSxPQUFPLENBQUMsU0FBUyxDQUEyQixhQUFhLENBQUMsQ0FDekYsQ0FBQyxDQUFDLEtBQUssQ0FBYyxhQUFhLENBQUMsQ0FBQztJQUNsQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLE1BQU07SUFDWixLQUFLLEVBQUUsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDO0NBQ3pCLENBQUMsQ0FDSDtDQUNBO0FBRUQsTUFBTSxPQUFPLElBQUssU0FBUSxPQUFPLENBQUMsU0FBUyxDQUFDLE1BQU0sRUFBRSxNQUFNLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLENBQUMsRUFBUTtDQUFHO0FBQ3hGLE1BQU0sT0FBTyxRQUFTLFNBQVEsT0FBTyxDQUFDLFNBQVMsQ0FBQyxVQUFVLEVBQUUsTUFBTSxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQVk7Q0FBRztBQVFwRyxNQUFNLE9BQU8sY0FBZSxTQUFRLFVBQVUsQ0FBQyxHQUFHLEVBQWtCLENBQUMsZ0JBQWdCLEVBQUU7SUFDckYsT0FBTyxFQUFFLFVBQVUsRUFBcUIsQ0FBQyxnQkFBZ0IsQ0FBQztJQUMxRCxRQUFR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
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"layerUtils.test.d.ts","sourceRoot":"","sources":["../layerUtils.test.ts"],"names":[],"mappings":""}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query.test.d.ts","sourceRoot":"","sources":["../query.test.ts"],"names":[],"mappings":"AAGA,OAAO,
|
|
1
|
+
{"version":3,"file":"query.test.d.ts","sourceRoot":"","sources":["../query.test.ts"],"names":[],"mappings":"AAGA,OAAO,EAAqC,CAAC,EAAU,MAAM,YAAY,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAazE,qBAAa,SAAU,SAAQ,cAM7B;CAAG;AACL,MAAM,CAAC,OAAO,WAAW,SAAS,CAAC;IAEjC,UAAiB,OAAQ,SAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,SAAS,CAAC;KAAG;CACvE"}
|