@effect-app/infra 2.86.0 → 2.87.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 +11 -0
- package/dist/api/layerUtils.d.ts +1 -5
- package/dist/api/layerUtils.d.ts.map +1 -1
- package/dist/api/layerUtils.js +3 -11
- package/dist/api/routing/middleware/RouterMiddleware.d.ts +33 -0
- package/dist/api/routing/middleware/RouterMiddleware.d.ts.map +1 -0
- package/dist/api/routing/middleware/RouterMiddleware.js +5 -0
- package/dist/api/routing/middleware/RpcMiddleware.d.ts +199 -0
- package/dist/api/routing/middleware/RpcMiddleware.d.ts.map +1 -0
- package/dist/api/routing/middleware/RpcMiddleware.js +14 -0
- package/dist/api/routing/middleware/dynamic-middleware.d.ts +2 -12
- package/dist/api/routing/middleware/dynamic-middleware.d.ts.map +1 -1
- package/dist/api/routing/middleware/dynamic-middleware.js +2 -18
- package/dist/api/routing/middleware/generic-middleware.d.ts +4 -23
- package/dist/api/routing/middleware/generic-middleware.d.ts.map +1 -1
- package/dist/api/routing/middleware/generic-middleware.js +13 -9
- package/dist/api/routing/middleware/middleware-api.d.ts +43 -7
- package/dist/api/routing/middleware/middleware-api.d.ts.map +1 -1
- package/dist/api/routing/middleware/middleware-api.js +47 -22
- package/dist/api/routing/middleware/middleware.d.ts +3 -3
- package/dist/api/routing/middleware/middleware.js +2 -2
- package/dist/api/routing/middleware.d.ts +2 -1
- package/dist/api/routing/middleware.d.ts.map +1 -1
- package/dist/api/routing/middleware.js +3 -2
- package/dist/api/routing/tsort.d.ts +2 -2
- package/dist/api/routing/tsort.d.ts.map +1 -1
- package/dist/api/routing/tsort.js +1 -1
- package/package.json +9 -5
- package/src/api/layerUtils.ts +4 -18
- package/src/api/routing/middleware/RouterMiddleware.ts +149 -0
- package/src/api/routing/middleware/RpcMiddleware.ts +287 -0
- package/src/api/routing/middleware/dynamic-middleware.ts +5 -52
- package/src/api/routing/middleware/generic-middleware.ts +23 -34
- package/src/api/routing/middleware/middleware-api.ts +142 -59
- package/src/api/routing/middleware/middleware.ts +1 -1
- package/src/api/routing/middleware.ts +2 -1
- package/src/api/routing/tsort.ts +2 -2
- package/test/controller.test.ts +22 -58
- package/test/dist/controller.test.d.ts.map +1 -1
- package/test/dist/fixtures.d.ts +4 -2
- package/test/dist/fixtures.d.ts.map +1 -1
- package/test/dist/fixtures.js +21 -9
- package/test/dist/requires.test.d.ts.map +1 -1
- package/test/fixtures.ts +29 -12
- package/test/requires.test.ts +98 -17
- package/dist/api/routing/middleware/DynamicMiddleware.d.ts +0 -229
- package/dist/api/routing/middleware/DynamicMiddleware.d.ts.map +0 -1
- package/dist/api/routing/middleware/DynamicMiddleware.js +0 -168
- package/src/api/routing/middleware/DynamicMiddleware.ts +0 -715
|
@@ -1,13 +1,20 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Rpc } from "@effect/rpc"
|
|
2
|
+
import { Context, Effect, Layer, type NonEmptyArray, type NonEmptyReadonlyArray } from "effect-app"
|
|
2
3
|
import { type RPCContextMap } from "effect-app/client"
|
|
3
|
-
import { type
|
|
4
|
+
import { type Simplify } from "effect-app/Types"
|
|
5
|
+
import { type LayerUtils } from "../../layerUtils.js"
|
|
6
|
+
import { type GenericMiddlewareMaker, genericMiddlewareMaker } from "./generic-middleware.js"
|
|
7
|
+
import { makeRpcEffect, type MiddlewareMakerId, type RPCHandlerFactory } from "./RouterMiddleware.js"
|
|
8
|
+
import { type AnyDynamic, type RpcDynamic, type TagClassAny } from "./RpcMiddleware.js"
|
|
4
9
|
|
|
5
|
-
// TODO:
|
|
6
|
-
//
|
|
7
|
-
export const contextMap =
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
10
|
+
// TODO: don't expect service when it's wrap/never
|
|
11
|
+
// perhaps RequestContextMap should be an object, instead of an interface, so that we don't need to provide anything here
|
|
12
|
+
export const contextMap =
|
|
13
|
+
<RequestContextMap extends Record<string, RPCContextMap.Any>>() =>
|
|
14
|
+
<K extends keyof RequestContextMap>(a: K, service: RequestContextMap[K]["service"]) => ({
|
|
15
|
+
key: a,
|
|
16
|
+
settings: { service } as any as RequestContextMap[typeof a]
|
|
17
|
+
})
|
|
11
18
|
|
|
12
19
|
export interface MiddlewareM<
|
|
13
20
|
RequestContext extends Record<string, RPCContextMap.Any>,
|
|
@@ -28,6 +35,13 @@ export interface MiddlewareM<
|
|
|
28
35
|
>
|
|
29
36
|
}
|
|
30
37
|
|
|
38
|
+
type GetDependsOnKeys<MW extends GenericMiddlewareMaker> = MW extends { dependsOn: NonEmptyReadonlyArray<TagClassAny> }
|
|
39
|
+
? {
|
|
40
|
+
[K in keyof MW["dependsOn"]]: MW["dependsOn"][K] extends AnyDynamic ? MW["dependsOn"][K]["dynamic"]["key"]
|
|
41
|
+
: never
|
|
42
|
+
}[keyof MW["dependsOn"]]
|
|
43
|
+
: never
|
|
44
|
+
|
|
31
45
|
export interface MiddlewareDynamic<
|
|
32
46
|
RequestContext extends Record<string, RPCContextMap.Any>,
|
|
33
47
|
Provided extends keyof RequestContext,
|
|
@@ -35,14 +49,17 @@ export interface MiddlewareDynamic<
|
|
|
35
49
|
DynamicMiddlewareProviders,
|
|
36
50
|
out MiddlewareR
|
|
37
51
|
> {
|
|
38
|
-
|
|
39
|
-
// either have to block it, or implement the support properly.
|
|
40
|
-
middleware<MW extends NonEmptyArray<DynamicMiddlewareMaker<RequestContext>> | NonEmptyArray<GenericMiddlewareMaker>>(
|
|
52
|
+
middleware<MW extends NonEmptyArray<GenericMiddlewareMaker>>(
|
|
41
53
|
...mw: MW
|
|
42
|
-
):
|
|
54
|
+
): MW extends NonEmptyArray<{ dynamic: RpcDynamic<any, RequestContext[keyof RequestContext]> }>
|
|
55
|
+
? DynamicMiddlewareMakerrsss<
|
|
43
56
|
RequestContext,
|
|
44
|
-
|
|
45
|
-
|
|
57
|
+
// when one dynamic middleware depends on another, substract the key, to enforce the dependency to be provided after.
|
|
58
|
+
Exclude<
|
|
59
|
+
Provided | MW[number]["dynamic"]["key"],
|
|
60
|
+
{ [K in keyof MW]: GetDependsOnKeys<MW[K]> }[number]
|
|
61
|
+
>,
|
|
62
|
+
[...Middlewares, ...MW],
|
|
46
63
|
& DynamicMiddlewareProviders
|
|
47
64
|
& {
|
|
48
65
|
[U in MW[number] as U["dynamic"]["key"]]: U
|
|
@@ -58,9 +75,6 @@ export interface MiddlewareDynamic<
|
|
|
58
75
|
>
|
|
59
76
|
}
|
|
60
77
|
|
|
61
|
-
type GetDynamicMiddleware<T, RequestContext extends Record<string, RPCContextMap.Any>> = T extends
|
|
62
|
-
RequestContextMapProvider<RequestContext> ? T : never
|
|
63
|
-
|
|
64
78
|
type DynamicMiddlewareMakerrsss<
|
|
65
79
|
RequestContext extends Record<string, RPCContextMap.Any>,
|
|
66
80
|
Provided extends keyof RequestContext = never,
|
|
@@ -68,19 +82,18 @@ type DynamicMiddlewareMakerrsss<
|
|
|
68
82
|
DynamicMiddlewareProviders = unknown,
|
|
69
83
|
MiddlewareR = never
|
|
70
84
|
> = keyof Omit<RequestContext, Provided> extends never ? [MiddlewareR] extends [never] ?
|
|
85
|
+
& {
|
|
86
|
+
MiddlewareR: MiddlewareR
|
|
87
|
+
Provided: Provided
|
|
88
|
+
Middlewares: Middlewares
|
|
89
|
+
DynamicMiddlewareProviders: Simplify<DynamicMiddlewareProviders>
|
|
90
|
+
}
|
|
71
91
|
& ReturnType<
|
|
72
92
|
typeof makeMiddlewareBasic<
|
|
73
93
|
RequestContext,
|
|
74
|
-
GetDynamicMiddleware<DynamicMiddlewareProviders, RequestContext>,
|
|
75
94
|
Middlewares
|
|
76
95
|
>
|
|
77
96
|
>
|
|
78
|
-
// & {
|
|
79
|
-
// MiddlewareR: MiddlewareR
|
|
80
|
-
// Provided: Provided
|
|
81
|
-
// Middlewares: Middlewares
|
|
82
|
-
// DynamicMiddlewareProviders: Simplify<DynamicMiddlewareProviders>
|
|
83
|
-
// }
|
|
84
97
|
& MiddlewareM<
|
|
85
98
|
RequestContext,
|
|
86
99
|
Provided,
|
|
@@ -88,50 +101,120 @@ type DynamicMiddlewareMakerrsss<
|
|
|
88
101
|
DynamicMiddlewareProviders,
|
|
89
102
|
MiddlewareR
|
|
90
103
|
>
|
|
91
|
-
:
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
104
|
+
:
|
|
105
|
+
& {
|
|
106
|
+
MiddlewareR: MiddlewareR
|
|
107
|
+
Provided: Provided
|
|
108
|
+
Middlewares: Middlewares
|
|
109
|
+
DynamicMiddlewareProviders: Simplify<DynamicMiddlewareProviders>
|
|
110
|
+
}
|
|
111
|
+
& MiddlewareM<
|
|
112
|
+
RequestContext,
|
|
113
|
+
Provided,
|
|
114
|
+
Middlewares,
|
|
115
|
+
DynamicMiddlewareProviders,
|
|
116
|
+
MiddlewareR
|
|
117
|
+
>
|
|
118
|
+
:
|
|
119
|
+
& {
|
|
120
|
+
MiddlewareR: MiddlewareR
|
|
121
|
+
Provided: Provided
|
|
122
|
+
Middlewares: Middlewares
|
|
123
|
+
DynamicMiddlewareProviders: Simplify<DynamicMiddlewareProviders>
|
|
124
|
+
}
|
|
125
|
+
& MiddlewareDynamic<
|
|
126
|
+
RequestContext,
|
|
127
|
+
Provided,
|
|
128
|
+
Middlewares,
|
|
129
|
+
DynamicMiddlewareProviders,
|
|
130
|
+
MiddlewareR
|
|
131
|
+
>
|
|
105
132
|
|
|
106
|
-
export const
|
|
133
|
+
export const makeMiddleware: <
|
|
107
134
|
RequestContextMap extends Record<string, RPCContextMap.Any>
|
|
108
135
|
>() => DynamicMiddlewareMakerrsss<RequestContextMap> = () => {
|
|
109
|
-
|
|
110
|
-
let capturedMiddlewares: (DynamicMiddlewareMaker<any> | GenericMiddlewareMaker)[] = []
|
|
136
|
+
let allMiddleware: GenericMiddlewareMaker[] = []
|
|
111
137
|
const it = {
|
|
112
138
|
middleware: (...middlewares: any[]) => {
|
|
113
139
|
for (const mw of middlewares) {
|
|
114
|
-
|
|
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
|
-
}
|
|
140
|
+
allMiddleware = [mw, ...allMiddleware]
|
|
120
141
|
}
|
|
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
142
|
// TODO: support dynamic and generic intertwined. treat them as one
|
|
133
|
-
return Object.assign(
|
|
143
|
+
return Object.assign(makeMiddlewareBasic<any, any>(...allMiddleware), it)
|
|
134
144
|
}
|
|
135
145
|
}
|
|
136
146
|
return it as any
|
|
137
147
|
}
|
|
148
|
+
|
|
149
|
+
export const makeMiddlewareBasic =
|
|
150
|
+
// by setting RequestContextMap beforehand, execute contextual typing does not fuck up itself to anys
|
|
151
|
+
<
|
|
152
|
+
RequestContextMap extends Record<string, RPCContextMap.Any>,
|
|
153
|
+
// RequestContextProviders extends RequestContextMapProvider<RequestContextMap>, // how to resolve the dynamic middleware
|
|
154
|
+
GenericMiddlewareProviders extends ReadonlyArray<GenericMiddlewareMaker>
|
|
155
|
+
>(
|
|
156
|
+
...make: GenericMiddlewareProviders
|
|
157
|
+
) => {
|
|
158
|
+
const MiddlewareMaker = Context.GenericTag<
|
|
159
|
+
MiddlewareMakerId,
|
|
160
|
+
{
|
|
161
|
+
effect: RPCHandlerFactory<
|
|
162
|
+
RequestContextMap,
|
|
163
|
+
GenericMiddlewareMaker.Provided<GenericMiddlewareProviders[number]>
|
|
164
|
+
>
|
|
165
|
+
_tag: "MiddlewareMaker"
|
|
166
|
+
}
|
|
167
|
+
>(
|
|
168
|
+
"MiddlewareMaker"
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
const middlewares = genericMiddlewareMaker(...make)
|
|
172
|
+
|
|
173
|
+
const l = Layer.scoped(
|
|
174
|
+
MiddlewareMaker,
|
|
175
|
+
middlewares
|
|
176
|
+
.effect
|
|
177
|
+
.pipe(
|
|
178
|
+
Effect.map((generic) => ({
|
|
179
|
+
_tag: "MiddlewareMaker" as const,
|
|
180
|
+
effect: makeRpcEffect<
|
|
181
|
+
RequestContextMap,
|
|
182
|
+
GenericMiddlewareMaker.Provided<GenericMiddlewareProviders[number]>
|
|
183
|
+
>()(
|
|
184
|
+
(schema, next, moduleName) => {
|
|
185
|
+
return (payload, headers) =>
|
|
186
|
+
Effect
|
|
187
|
+
.gen(function*() {
|
|
188
|
+
const basic = {
|
|
189
|
+
config: schema.config ?? {},
|
|
190
|
+
payload,
|
|
191
|
+
headers,
|
|
192
|
+
clientId: 0, // TODO: get the clientId from the request context
|
|
193
|
+
rpc: {
|
|
194
|
+
...Rpc.fromTaggedRequest(schema as any),
|
|
195
|
+
key: `${moduleName}.${payload._tag}`,
|
|
196
|
+
_tag: `${moduleName}.${payload._tag}`
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
return yield* generic({
|
|
200
|
+
...basic,
|
|
201
|
+
next: next(payload, headers) as any
|
|
202
|
+
})
|
|
203
|
+
}) as any // why?
|
|
204
|
+
}
|
|
205
|
+
)
|
|
206
|
+
}))
|
|
207
|
+
)
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
const middlewareLayer = l
|
|
211
|
+
.pipe(
|
|
212
|
+
Layer.provide(middlewares.dependencies as any)
|
|
213
|
+
) as Layer.Layer<
|
|
214
|
+
MiddlewareMakerId,
|
|
215
|
+
LayerUtils.GetLayersError<typeof middlewares.dependencies>, // what could go wrong when building the dynamic middleware provider
|
|
216
|
+
LayerUtils.GetLayersContext<typeof middlewares.dependencies>
|
|
217
|
+
>
|
|
218
|
+
|
|
219
|
+
return Object.assign(MiddlewareMaker, { Default: middlewareLayer })
|
|
220
|
+
}
|
|
@@ -3,7 +3,7 @@ import { Cause, Context, Duration, Effect, Layer, ParseResult, Request } from "e
|
|
|
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 { Tag } from "
|
|
6
|
+
import { Tag } from "./RpcMiddleware.js"
|
|
7
7
|
|
|
8
8
|
const logRequestError = logError("Request")
|
|
9
9
|
const reportRequestError = reportError("Request")
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
// codegen:start {preset: barrel, include: ./middleware/*.ts, nodir: false }
|
|
2
2
|
export * from "./middleware/ContextProvider.js"
|
|
3
3
|
export * from "./middleware/dynamic-middleware.js"
|
|
4
|
-
export * from "./middleware/DynamicMiddleware.js"
|
|
5
4
|
export * from "./middleware/generic-middleware.js"
|
|
6
5
|
export * from "./middleware/middleware-api.js"
|
|
7
6
|
export * from "./middleware/middleware.js"
|
|
7
|
+
export * from "./middleware/RouterMiddleware.js"
|
|
8
|
+
export * from "./middleware/RpcMiddleware.js"
|
|
8
9
|
// codegen:end
|
|
9
10
|
|
|
10
11
|
export * as Middleware from "./middleware.js"
|
package/src/api/routing/tsort.ts
CHANGED
|
@@ -39,7 +39,7 @@ export function tsort(edges) {
|
|
|
39
39
|
return sorted
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
export const createEdges = <T extends { dependsOn?: any[] }>(dep: readonly T[]) => {
|
|
42
|
+
export const createEdges = <T extends { dependsOn?: readonly any[] }>(dep: readonly T[]) => {
|
|
43
43
|
const result = []
|
|
44
44
|
dep.forEach((key) => {
|
|
45
45
|
key.dependsOn?.forEach((n) => {
|
|
@@ -49,7 +49,7 @@ export const createEdges = <T extends { dependsOn?: any[] }>(dep: readonly T[])
|
|
|
49
49
|
return result
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
export const sort = <T>(dep: readonly (T & { dependsOn?: any[] })[]): readonly T[] => {
|
|
52
|
+
export const sort = <T>(dep: readonly (T & { dependsOn?: readonly any[] })[]): readonly T[] => {
|
|
53
53
|
const edges = createEdges(dep)
|
|
54
54
|
const result = tsort(edges)
|
|
55
55
|
return result.concat(dep.filter((v) => !result.includes(v)))
|
package/test/controller.test.ts
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
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
4
|
import { expect, expectTypeOf, it } from "@effect/vitest"
|
|
5
|
-
import { Context, Effect, Layer, S, Scope } from "effect-app"
|
|
5
|
+
import { Context, Effect, type Layer, S, Scope } from "effect-app"
|
|
6
6
|
import { InvalidStateError, makeRpcClient, NotLoggedInError, UnauthorizedError } from "effect-app/client"
|
|
7
|
-
import { DefaultGenericMiddlewares,
|
|
7
|
+
import { DefaultGenericMiddlewares, makeMiddleware, Middleware, Tag } from "../src/api/routing/middleware.js"
|
|
8
8
|
import { sort } from "../src/api/routing/tsort.js"
|
|
9
9
|
import { AllowAnonymous, CustomError1, type RequestContextMap, RequireRoles, Some, SomeElse, SomeService, Test } from "./fixtures.js"
|
|
10
10
|
|
|
@@ -53,13 +53,13 @@ class MyContextProvider2 extends Middleware.Tag<MyContextProvider2>()("MyContext
|
|
|
53
53
|
//
|
|
54
54
|
|
|
55
55
|
const Str = Context.GenericTag<"str", "str">("str")
|
|
56
|
-
const Str2 = Context.GenericTag<"str2", "str">("str2")
|
|
57
56
|
|
|
58
57
|
export class BogusMiddleware extends Tag<BogusMiddleware>()("BogusMiddleware", {
|
|
59
58
|
provides: SomeService,
|
|
60
59
|
wrap: true
|
|
61
60
|
})({
|
|
62
61
|
effect: Effect.gen(function*() {
|
|
62
|
+
yield* Str
|
|
63
63
|
// yield* Effect.context<"test-dep">()
|
|
64
64
|
return ({ next }) =>
|
|
65
65
|
Effect.gen(function*() {
|
|
@@ -72,61 +72,31 @@ export class BogusMiddleware extends Tag<BogusMiddleware>()("BogusMiddleware", {
|
|
|
72
72
|
|
|
73
73
|
const genericMiddlewares = [
|
|
74
74
|
...DefaultGenericMiddlewares,
|
|
75
|
-
|
|
76
|
-
MyContextProvider2
|
|
77
|
-
MyContextProvider
|
|
75
|
+
BogusMiddleware,
|
|
76
|
+
MyContextProvider2
|
|
78
77
|
] as const
|
|
79
78
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
},
|
|
90
|
-
|
|
91
|
-
dependencies: [Layer.effect(Str2, Str)],
|
|
92
|
-
execute: (maker) =>
|
|
93
|
-
Effect.gen(function*() {
|
|
94
|
-
return maker(
|
|
95
|
-
(_schema, handler) => (req, headers) =>
|
|
96
|
-
// contextProvider and dynamicMiddlewares are already provided here.
|
|
97
|
-
// aka this runs "last"
|
|
98
|
-
Effect
|
|
99
|
-
.gen(function*() {
|
|
100
|
-
// you can use only HttpRouter.HttpRouter.Provided here as additional context
|
|
101
|
-
// and what ContextProvider provides too
|
|
102
|
-
// const someElse = yield* SomeElse
|
|
103
|
-
yield* Some // provided by ContextProvider
|
|
104
|
-
yield* Scope.Scope // provided by HttpRouter.HttpRouter.Provided
|
|
105
|
-
|
|
106
|
-
return yield* handler(req, headers)
|
|
107
|
-
})
|
|
108
|
-
)
|
|
109
|
-
})
|
|
110
|
-
})
|
|
79
|
+
const middleware = makeMiddleware<RequestContextMap>()
|
|
80
|
+
.middleware(MyContextProvider)
|
|
81
|
+
.middleware(
|
|
82
|
+
RequireRoles,
|
|
83
|
+
Test
|
|
84
|
+
)
|
|
85
|
+
.middleware(AllowAnonymous)
|
|
86
|
+
.middleware(...genericMiddlewares)
|
|
87
|
+
// dependencies: [Layer.effect(Str2, Str)],
|
|
111
88
|
|
|
112
|
-
const middleware2 = makeMiddleware<RequestContextMap>()
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
requireRoles: RequireRoles,
|
|
118
|
-
allowAnonymous: AllowAnonymous,
|
|
119
|
-
test: Test
|
|
120
|
-
}
|
|
121
|
-
})
|
|
89
|
+
const middleware2 = makeMiddleware<RequestContextMap>()
|
|
90
|
+
.middleware(MyContextProvider)
|
|
91
|
+
.middleware(RequireRoles, Test)
|
|
92
|
+
.middleware(AllowAnonymous)
|
|
93
|
+
.middleware(...DefaultGenericMiddlewares, BogusMiddleware, MyContextProvider2)
|
|
122
94
|
|
|
123
|
-
export const middleware3 =
|
|
95
|
+
export const middleware3 = makeMiddleware<RequestContextMap>()
|
|
124
96
|
.middleware(...genericMiddlewares)
|
|
125
97
|
.middleware(AllowAnonymous, RequireRoles)
|
|
126
98
|
.middleware(Test)
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
// expectTypeOf(middleware3).toExtend<typeof middleware2>()
|
|
99
|
+
.middleware(BogusMiddleware)
|
|
130
100
|
|
|
131
101
|
export type RequestConfig = {
|
|
132
102
|
/** Disable authentication requirement */
|
|
@@ -348,16 +318,10 @@ const router2 = r2.Router(Something)({
|
|
|
348
318
|
|
|
349
319
|
// eslint-disable-next-line unused-imports/no-unused-vars
|
|
350
320
|
const matched2 = matchAll({ router: router2 })
|
|
351
|
-
expectTypeOf({} as Layer.Context<typeof matched2>).toEqualTypeOf<Some | SomeService>()
|
|
321
|
+
expectTypeOf({} as Layer.Context<typeof matched2>).toEqualTypeOf<Some | SomeService | "str">()
|
|
352
322
|
|
|
353
323
|
type makeContext2 = MakeContext<typeof router2.make>
|
|
354
324
|
expectTypeOf({} as MakeErrors<typeof router2.make>).toEqualTypeOf<InvalidStateError>()
|
|
355
325
|
expectTypeOf({} as makeContext2).toEqualTypeOf<
|
|
356
326
|
SomethingService | SomethingRepo | SomethingService2
|
|
357
327
|
>()
|
|
358
|
-
|
|
359
|
-
export const dynamicMiddlewares = implementMiddleware<RequestContextMap>()({
|
|
360
|
-
requireRoles: RequireRoles,
|
|
361
|
-
allowAnonymous: AllowAnonymous,
|
|
362
|
-
test: Test
|
|
363
|
-
})
|
|
@@ -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;AAE7F,OAAO,
|
|
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,EAAW,MAAM,EAAE,KAAK,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAElE,OAAO,EAA6C,UAAU,EAAO,MAAM,kCAAkC,CAAA;AAE7G,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,YAAY,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,eAAe,CAAA;;;;;;AAgCrI,cAAM,kBAAmB,SAAQ,uBAU/B;CAAG;;;;;;;AAML,qBAAa,eAAgB,SAAQ,oBAanC;CACD;AAwBD,eAAO,MAAM,WAAW;;;;;;;;;;;;;;YAIM,CAAA;AAE9B,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"}
|
package/test/dist/fixtures.d.ts
CHANGED
|
@@ -68,14 +68,14 @@ declare const SomeElse_base: (abstract new (service: {
|
|
|
68
68
|
export declare class SomeElse extends SomeElse_base {
|
|
69
69
|
}
|
|
70
70
|
export type RequestContextMap = {
|
|
71
|
-
allowAnonymous: RPCContextMap.Inverted<UserProfile, typeof NotLoggedInError>;
|
|
71
|
+
allowAnonymous: RPCContextMap.Inverted<[typeof UserProfile], typeof NotLoggedInError>;
|
|
72
72
|
requireRoles: RPCContextMap.Custom<never, typeof UnauthorizedError, Array<string>>;
|
|
73
73
|
test: RPCContextMap<never, typeof S.Never>;
|
|
74
74
|
};
|
|
75
75
|
declare const AllowAnonymous_base: Middleware.TagClass<AllowAnonymous, "AllowAnonymous", {
|
|
76
76
|
readonly dynamic: {
|
|
77
77
|
key: "allowAnonymous";
|
|
78
|
-
settings: RPCContextMap.Inverted<UserProfile, typeof NotLoggedInError>;
|
|
78
|
+
settings: RPCContextMap.Inverted<[typeof UserProfile], typeof NotLoggedInError>;
|
|
79
79
|
};
|
|
80
80
|
readonly requires: typeof SomeElse;
|
|
81
81
|
}> & {
|
|
@@ -88,6 +88,7 @@ declare const RequireRoles_base: Middleware.TagClass<RequireRoles, "RequireRoles
|
|
|
88
88
|
key: "requireRoles";
|
|
89
89
|
settings: RPCContextMap.Custom<never, typeof UnauthorizedError, string[]>;
|
|
90
90
|
};
|
|
91
|
+
readonly wrap: true;
|
|
91
92
|
readonly dependsOn: readonly [typeof AllowAnonymous];
|
|
92
93
|
}> & {
|
|
93
94
|
Default: import("effect/Layer").Layer<RequireRoles, never, Some>;
|
|
@@ -95,6 +96,7 @@ declare const RequireRoles_base: Middleware.TagClass<RequireRoles, "RequireRoles
|
|
|
95
96
|
export declare class RequireRoles extends RequireRoles_base {
|
|
96
97
|
}
|
|
97
98
|
declare const Test_base: Middleware.TagClass<Test, "Test", {
|
|
99
|
+
readonly wrap: true;
|
|
98
100
|
readonly dynamic: {
|
|
99
101
|
key: "test";
|
|
100
102
|
settings: RPCContextMap<never, typeof S.Never>;
|
|
@@ -1 +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;
|
|
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,CAAC,OAAO,WAAW,CAAC,EAAE,OAAO,gBAAgB,CAAC,CAAA;IACrF,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,mBA4BlC;CACD;;;;;;;;;;;AAGD,qBAAa,YAAa,SAAQ,iBA6BhC;CACD;;;;;;;;;;AAED,qBAAa,IAAK,SAAQ,SASxB;CAAG;;;;AAEL,qBAAa,YAAa,SAAQ,iBAAmD;CAAG;;;;AACxF,qBAAa,YAAa,SAAQ,iBAAmD;CAAG;;;;;;;;;;;;;;;;;;;;;;;;;AAGxF,qBAAa,WAAY,SAAQ,gBAAgE;CAAG"}
|
package/test/dist/fixtures.js
CHANGED
|
@@ -12,7 +12,7 @@ export class Some extends Context.TagMakeId("Some", Effect.succeed({ a: 1 }))()
|
|
|
12
12
|
export class SomeElse extends Context.TagMakeId("SomeElse", Effect.succeed({ b: 2 }))() {
|
|
13
13
|
}
|
|
14
14
|
export class AllowAnonymous extends Middleware.Tag()("AllowAnonymous", {
|
|
15
|
-
dynamic: contextMap()("allowAnonymous"),
|
|
15
|
+
dynamic: contextMap()("allowAnonymous", [UserProfile]),
|
|
16
16
|
requires: SomeElse
|
|
17
17
|
})({
|
|
18
18
|
effect: Effect.gen(function* () {
|
|
@@ -26,36 +26,48 @@ export class AllowAnonymous extends Middleware.Tag()("AllowAnonymous", {
|
|
|
26
26
|
}
|
|
27
27
|
return Option.none();
|
|
28
28
|
}
|
|
29
|
-
return Option.some(Context.make(UserProfile, {
|
|
29
|
+
return Option.some(Context.make(UserProfile, new UserProfile({
|
|
30
|
+
id: "whatever",
|
|
31
|
+
roles: ["user", ...headers["x-is-manager"] === "true" ? ["manager"] : []]
|
|
32
|
+
})));
|
|
30
33
|
});
|
|
31
34
|
})
|
|
32
35
|
}) {
|
|
33
36
|
}
|
|
34
37
|
// @effect-diagnostics-next-line missingEffectServiceDependency:off
|
|
35
38
|
export class RequireRoles extends Middleware.Tag()("RequireRoles", {
|
|
36
|
-
dynamic: contextMap()("requireRoles"),
|
|
39
|
+
dynamic: contextMap()("requireRoles", null), // TODO
|
|
40
|
+
wrap: true,
|
|
41
|
+
// wrap: true,
|
|
37
42
|
// had to move this in here, because once you put it manually as a readonly static property on the class,
|
|
38
43
|
// there's a weird issue where the fluent api stops behaving properly after adding this middleware via `addDynamicMiddleware`
|
|
39
44
|
dependsOn: [AllowAnonymous]
|
|
40
45
|
})({
|
|
41
46
|
effect: Effect.gen(function* () {
|
|
42
47
|
yield* Some;
|
|
43
|
-
return Effect.fnUntraced(function* ({ config }) {
|
|
48
|
+
return Effect.fnUntraced(function* ({ config, next }) {
|
|
44
49
|
// we don't know if the service will be provided or not, so we use option..
|
|
45
50
|
const userProfile = yield* Effect.serviceOption(UserProfile);
|
|
46
51
|
const { requireRoles } = config;
|
|
52
|
+
console.dir({
|
|
53
|
+
userProfile,
|
|
54
|
+
requireRoles
|
|
55
|
+
}, { depth: 5 });
|
|
47
56
|
if (requireRoles && !userProfile.value?.roles?.some((role) => requireRoles.includes(role))) {
|
|
48
57
|
return yield* new UnauthorizedError({ message: "don't have the right roles" });
|
|
49
58
|
}
|
|
50
|
-
return
|
|
59
|
+
return yield* next;
|
|
51
60
|
});
|
|
52
61
|
})
|
|
53
62
|
}) {
|
|
54
63
|
}
|
|
55
|
-
export class Test extends Middleware.Tag()("Test", {
|
|
64
|
+
export class Test extends Middleware.Tag()("Test", {
|
|
65
|
+
wrap: true,
|
|
66
|
+
dynamic: contextMap()("test", null) // TODO
|
|
67
|
+
})({
|
|
56
68
|
effect: Effect.gen(function* () {
|
|
57
|
-
return Effect.fn(function* () {
|
|
58
|
-
return
|
|
69
|
+
return Effect.fn(function* ({ next }) {
|
|
70
|
+
return yield* next;
|
|
59
71
|
});
|
|
60
72
|
})
|
|
61
73
|
}) {
|
|
@@ -67,4 +79,4 @@ export class CustomError2 extends TaggedError()("CustomError1", {}) {
|
|
|
67
79
|
const MakeSomeService = Effect.succeed({ a: 1 });
|
|
68
80
|
export class SomeService extends Context.TagMakeId("SomeService", MakeSomeService)() {
|
|
69
81
|
}
|
|
70
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
82
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZml4dHVyZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9maXh0dXJlcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLEVBQUUsQ0FBQyxFQUFFLEtBQUssRUFBRSxNQUFNLFlBQVksQ0FBQTtBQUM5RCxPQUFPLEVBQUUsZ0JBQWdCLEVBQXNCLGlCQUFpQixFQUFFLE1BQU0sbUJBQW1CLENBQUE7QUFDM0YsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLG1CQUFtQixDQUFBO0FBQy9DLE9BQU8sRUFBRSxVQUFVLEVBQUUsVUFBVSxFQUFFLE1BQU0sdUJBQXVCLENBQUE7QUFFOUQsTUFBTSxPQUFPLFdBQVksU0FBUSxPQUFPLENBQUMsU0FBUyxDQUEyQixhQUFhLENBQUMsQ0FDekYsQ0FBQyxDQUFDLEtBQUssQ0FBYyxhQUFhLENBQUMsQ0FBQztJQUNsQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLE1BQU07SUFDWixLQUFLLEVBQUUsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDO0NBQ3pCLENBQUMsQ0FDSDtDQUNBO0FBRUQsTUFBTSxPQUFPLElBQUssU0FBUSxPQUFPLENBQUMsU0FBUyxDQUFDLE1BQU0sRUFBRSxNQUFNLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLENBQUMsRUFBUTtDQUFHO0FBQ3hGLE1BQU0sT0FBTyxRQUFTLFNBQVEsT0FBTyxDQUFDLFNBQVMsQ0FBQyxVQUFVLEVBQUUsTUFBTSxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQVk7Q0FBRztBQVFwRyxNQUFNLE9BQU8sY0FBZSxTQUFRLFVBQVUsQ0FBQyxHQUFHLEVBQWtCLENBQUMsZ0JBQWdCLEVBQUU7SUFDckYsT0FBTyxFQUFFLFVBQVUsRUFBcUIsQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDLFdBQVcs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
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"requires.test.d.ts","sourceRoot":"","sources":["../requires.test.ts"],"names":[],"mappings":"AACA,OAAO,
|
|
1
|
+
{"version":3,"file":"requires.test.d.ts","sourceRoot":"","sources":["../requires.test.ts"],"names":[],"mappings":"AACA,OAAO,EAAkB,KAAK,EAAK,MAAM,YAAY,CAAA;AAErD,OAAO,EAAkB,UAAU,EAAE,MAAM,uBAAuB,CAAA;AAClE,OAAO,EAAwD,IAAI,EAAE,QAAQ,EAAQ,MAAM,eAAe,CAAA;;;;;;AAE1G,qBAAa,cAAe,SAAQ,mBAUlC;CACD;;;;;;;AAED,qBAAa,kBAAmB,SAAQ,uBAYtC;CACD;;;;;;;AAED,qBAAa,sBAAuB,SAAQ,2BAa1C;CACD"}
|
package/test/fixtures.ts
CHANGED
|
@@ -15,13 +15,13 @@ export class Some extends Context.TagMakeId("Some", Effect.succeed({ a: 1 }))<So
|
|
|
15
15
|
export class SomeElse extends Context.TagMakeId("SomeElse", Effect.succeed({ b: 2 }))<SomeElse>() {}
|
|
16
16
|
|
|
17
17
|
export type RequestContextMap = {
|
|
18
|
-
allowAnonymous: RPCContextMap.Inverted<UserProfile, typeof NotLoggedInError>
|
|
18
|
+
allowAnonymous: RPCContextMap.Inverted<[typeof UserProfile], typeof NotLoggedInError>
|
|
19
19
|
requireRoles: RPCContextMap.Custom<never, typeof UnauthorizedError, Array<string>>
|
|
20
20
|
test: RPCContextMap<never, typeof S.Never>
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
export class AllowAnonymous extends Middleware.Tag<AllowAnonymous>()("AllowAnonymous", {
|
|
24
|
-
dynamic: contextMap<RequestContextMap>()("allowAnonymous"),
|
|
24
|
+
dynamic: contextMap<RequestContextMap>()("allowAnonymous", [UserProfile]),
|
|
25
25
|
requires: SomeElse
|
|
26
26
|
})({
|
|
27
27
|
effect: Effect.gen(function*() {
|
|
@@ -36,10 +36,15 @@ export class AllowAnonymous extends Middleware.Tag<AllowAnonymous>()("AllowAnony
|
|
|
36
36
|
}
|
|
37
37
|
return Option.none()
|
|
38
38
|
}
|
|
39
|
-
return Option.some(
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
39
|
+
return Option.some(
|
|
40
|
+
Context.make(
|
|
41
|
+
UserProfile,
|
|
42
|
+
new UserProfile({
|
|
43
|
+
id: "whatever",
|
|
44
|
+
roles: ["user", ...headers["x-is-manager"] === "true" ? ["manager"] : []]
|
|
45
|
+
})
|
|
46
|
+
)
|
|
47
|
+
)
|
|
43
48
|
}
|
|
44
49
|
)
|
|
45
50
|
})
|
|
@@ -48,7 +53,9 @@ export class AllowAnonymous extends Middleware.Tag<AllowAnonymous>()("AllowAnony
|
|
|
48
53
|
|
|
49
54
|
// @effect-diagnostics-next-line missingEffectServiceDependency:off
|
|
50
55
|
export class RequireRoles extends Middleware.Tag<RequireRoles>()("RequireRoles", {
|
|
51
|
-
dynamic: contextMap<RequestContextMap>()("requireRoles"),
|
|
56
|
+
dynamic: contextMap<RequestContextMap>()("requireRoles", null as never), // TODO
|
|
57
|
+
wrap: true,
|
|
58
|
+
// wrap: true,
|
|
52
59
|
// had to move this in here, because once you put it manually as a readonly static property on the class,
|
|
53
60
|
// there's a weird issue where the fluent api stops behaving properly after adding this middleware via `addDynamicMiddleware`
|
|
54
61
|
dependsOn: [AllowAnonymous]
|
|
@@ -56,24 +63,34 @@ export class RequireRoles extends Middleware.Tag<RequireRoles>()("RequireRoles",
|
|
|
56
63
|
effect: Effect.gen(function*() {
|
|
57
64
|
yield* Some
|
|
58
65
|
return Effect.fnUntraced(
|
|
59
|
-
function*({ config }) {
|
|
66
|
+
function*({ config, next }) {
|
|
60
67
|
// we don't know if the service will be provided or not, so we use option..
|
|
61
68
|
const userProfile = yield* Effect.serviceOption(UserProfile)
|
|
62
69
|
const { requireRoles } = config
|
|
70
|
+
console.dir(
|
|
71
|
+
{
|
|
72
|
+
userProfile,
|
|
73
|
+
requireRoles
|
|
74
|
+
},
|
|
75
|
+
{ depth: 5 }
|
|
76
|
+
)
|
|
63
77
|
if (requireRoles && !userProfile.value?.roles?.some((role) => requireRoles.includes(role))) {
|
|
64
78
|
return yield* new UnauthorizedError({ message: "don't have the right roles" })
|
|
65
79
|
}
|
|
66
|
-
return
|
|
80
|
+
return yield* next
|
|
67
81
|
}
|
|
68
82
|
)
|
|
69
83
|
})
|
|
70
84
|
}) {
|
|
71
85
|
}
|
|
72
86
|
|
|
73
|
-
export class Test extends Middleware.Tag<Test>()("Test", {
|
|
87
|
+
export class Test extends Middleware.Tag<Test>()("Test", {
|
|
88
|
+
wrap: true,
|
|
89
|
+
dynamic: contextMap<RequestContextMap>()("test", null as never) // TODO
|
|
90
|
+
})({
|
|
74
91
|
effect: Effect.gen(function*() {
|
|
75
|
-
return Effect.fn(function*() {
|
|
76
|
-
return
|
|
92
|
+
return Effect.fn(function*({ next }) {
|
|
93
|
+
return yield* next
|
|
77
94
|
})
|
|
78
95
|
})
|
|
79
96
|
}) {}
|