@effect-app/infra 2.85.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 +17 -0
- package/dist/api/layerUtils.d.ts +4 -8
- package/dist/api/layerUtils.d.ts.map +1 -1
- package/dist/api/layerUtils.js +3 -11
- 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/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 +3 -13
- 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 +15 -22
- 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 +55 -8
- package/dist/api/routing/middleware/middleware-api.d.ts.map +1 -1
- package/dist/api/routing/middleware/middleware-api.js +50 -14
- package/dist/api/routing/middleware/middleware.d.ts +8 -7
- package/dist/api/routing/middleware/middleware.d.ts.map +1 -1
- package/dist/api/routing/middleware/middleware.js +6 -5
- 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/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 +9 -5
- package/src/api/layerUtils.ts +7 -21
- package/src/api/routing/middleware/ContextProvider.ts +5 -5
- 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 +9 -54
- package/src/api/routing/middleware/generic-middleware.ts +33 -33
- package/src/api/routing/middleware/middleware-api.ts +202 -32
- package/src/api/routing/middleware/middleware.ts +13 -5
- package/src/api/routing/middleware.ts +2 -1
- package/src/api/routing/tsort.ts +2 -2
- package/src/api/routing.ts +1 -9
- package/test/contextProvider.test.ts +1 -2
- package/test/controller.test.ts +35 -155
- 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 +146 -0
- package/test/dist/fixtures.d.ts.map +1 -0
- package/test/dist/fixtures.js +82 -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 +102 -0
- package/test/layerUtils.test.ts +19 -0
- package/test/query.test.ts +2 -4
- package/test/requires.test.ts +156 -0
- package/dist/api/routing/middleware/DynamicMiddleware.d.ts +0 -215
- 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 -693
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, type Layer, S, Scope } from "effect-app"
|
|
6
|
+
import { InvalidStateError, makeRpcClient, NotLoggedInError, UnauthorizedError } from "effect-app/client"
|
|
7
|
+
import { DefaultGenericMiddlewares, makeMiddleware, 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
|
-
const Str2 = Context.GenericTag<"str2", "str">("str2")
|
|
85
|
-
|
|
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
56
|
|
|
142
57
|
export class BogusMiddleware extends Tag<BogusMiddleware>()("BogusMiddleware", {
|
|
143
58
|
provides: SomeService,
|
|
144
59
|
wrap: true
|
|
145
60
|
})({
|
|
146
61
|
effect: Effect.gen(function*() {
|
|
62
|
+
yield* Str
|
|
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
|
}) {
|
|
@@ -156,61 +72,31 @@ export class BogusMiddleware extends Tag<BogusMiddleware>()("BogusMiddleware", {
|
|
|
156
72
|
|
|
157
73
|
const genericMiddlewares = [
|
|
158
74
|
...DefaultGenericMiddlewares,
|
|
159
|
-
|
|
160
|
-
MyContextProvider2
|
|
161
|
-
MyContextProvider
|
|
75
|
+
BogusMiddleware,
|
|
76
|
+
MyContextProvider2
|
|
162
77
|
] as const
|
|
163
78
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
// and what ContextProvider provides too
|
|
186
|
-
// const someElse = yield* SomeElse
|
|
187
|
-
yield* Some // provided by ContextProvider
|
|
188
|
-
yield* Scope.Scope // provided by HttpRouter.HttpRouter.Provided
|
|
189
|
-
|
|
190
|
-
return yield* handler(req, headers)
|
|
191
|
-
})
|
|
192
|
-
)
|
|
193
|
-
})
|
|
194
|
-
})
|
|
195
|
-
|
|
196
|
-
const middleware2 = makeMiddleware<RequestContextMap>()({
|
|
197
|
-
// TODO: I guess it makes sense to support just passing array of context providers too, like dynamicMiddlewares?
|
|
198
|
-
genericMiddlewares: [...DefaultGenericMiddlewares, BogusMiddleware, MyContextProvider2, MyContextProvider],
|
|
199
|
-
// or is the better api to use constructors outside, like how contextProvider is used now?
|
|
200
|
-
dynamicMiddlewares: {
|
|
201
|
-
requireRoles: RequireRoles,
|
|
202
|
-
allowAnonymous: AllowAnonymous,
|
|
203
|
-
test: Test
|
|
204
|
-
}
|
|
205
|
-
})
|
|
206
|
-
|
|
207
|
-
export const middleware3 = makeNewMiddleware<RequestContextMap>()(
|
|
208
|
-
...genericMiddlewares
|
|
209
|
-
)
|
|
210
|
-
.addDynamicMiddleware(AllowAnonymous, RequireRoles)
|
|
211
|
-
.addDynamicMiddleware(Test)
|
|
212
|
-
|
|
213
|
-
expectTypeOf(middleware3).toEqualTypeOf<typeof middleware2>()
|
|
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)],
|
|
88
|
+
|
|
89
|
+
const middleware2 = makeMiddleware<RequestContextMap>()
|
|
90
|
+
.middleware(MyContextProvider)
|
|
91
|
+
.middleware(RequireRoles, Test)
|
|
92
|
+
.middleware(AllowAnonymous)
|
|
93
|
+
.middleware(...DefaultGenericMiddlewares, BogusMiddleware, MyContextProvider2)
|
|
94
|
+
|
|
95
|
+
export const middleware3 = makeMiddleware<RequestContextMap>()
|
|
96
|
+
.middleware(...genericMiddlewares)
|
|
97
|
+
.middleware(AllowAnonymous, RequireRoles)
|
|
98
|
+
.middleware(Test)
|
|
99
|
+
.middleware(BogusMiddleware)
|
|
214
100
|
|
|
215
101
|
export type RequestConfig = {
|
|
216
102
|
/** Disable authentication requirement */
|
|
@@ -360,7 +246,7 @@ it("sorts based on requirements", () => {
|
|
|
360
246
|
|
|
361
247
|
// eslint-disable-next-line unused-imports/no-unused-vars
|
|
362
248
|
const matched = matchAll({ router })
|
|
363
|
-
expectTypeOf({} as Layer.Context<typeof matched>).toEqualTypeOf<SomeService | "str">()
|
|
249
|
+
expectTypeOf({} as Layer.Context<typeof matched>).toEqualTypeOf<SomeService | Some | "str">()
|
|
364
250
|
|
|
365
251
|
type makeContext = MakeContext<typeof router.make>
|
|
366
252
|
expectTypeOf({} as MakeErrors<typeof router.make>).toEqualTypeOf<InvalidStateError>()
|
|
@@ -432,16 +318,10 @@ const router2 = r2.Router(Something)({
|
|
|
432
318
|
|
|
433
319
|
// eslint-disable-next-line unused-imports/no-unused-vars
|
|
434
320
|
const matched2 = matchAll({ router: router2 })
|
|
435
|
-
expectTypeOf({} as Layer.Context<typeof matched2>).toEqualTypeOf<SomeService>()
|
|
321
|
+
expectTypeOf({} as Layer.Context<typeof matched2>).toEqualTypeOf<Some | SomeService | "str">()
|
|
436
322
|
|
|
437
323
|
type makeContext2 = MakeContext<typeof router2.make>
|
|
438
324
|
expectTypeOf({} as MakeErrors<typeof router2.make>).toEqualTypeOf<InvalidStateError>()
|
|
439
325
|
expectTypeOf({} as makeContext2).toEqualTypeOf<
|
|
440
326
|
SomethingService | SomethingRepo | SomethingService2
|
|
441
327
|
>()
|
|
442
|
-
|
|
443
|
-
export const dynamicMiddlewares = implementMiddleware<RequestContextMap>()({
|
|
444
|
-
requireRoles: RequireRoles,
|
|
445
|
-
allowAnonymous: AllowAnonymous,
|
|
446
|
-
test: Test
|
|
447
|
-
})
|
|
@@ -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,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"}
|
|
@@ -0,0 +1,146 @@
|
|
|
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<[typeof 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<[typeof 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 wrap: true;
|
|
92
|
+
readonly dependsOn: readonly [typeof AllowAnonymous];
|
|
93
|
+
}> & {
|
|
94
|
+
Default: import("effect/Layer").Layer<RequireRoles, never, Some>;
|
|
95
|
+
};
|
|
96
|
+
export declare class RequireRoles extends RequireRoles_base {
|
|
97
|
+
}
|
|
98
|
+
declare const Test_base: Middleware.TagClass<Test, "Test", {
|
|
99
|
+
readonly wrap: true;
|
|
100
|
+
readonly dynamic: {
|
|
101
|
+
key: "test";
|
|
102
|
+
settings: RPCContextMap<never, typeof S.Never>;
|
|
103
|
+
};
|
|
104
|
+
}> & {
|
|
105
|
+
Default: import("effect/Layer").Layer<Test, never, never>;
|
|
106
|
+
};
|
|
107
|
+
export declare class Test extends Test_base {
|
|
108
|
+
}
|
|
109
|
+
declare const CustomError1_base: S.TaggedErrorClass<NotLoggedInError, "CustomError1", {
|
|
110
|
+
readonly _tag: S.tag<"CustomError1">;
|
|
111
|
+
}>;
|
|
112
|
+
export declare class CustomError1 extends CustomError1_base {
|
|
113
|
+
}
|
|
114
|
+
declare const CustomError2_base: S.TaggedErrorClass<NotLoggedInError, "CustomError1", {
|
|
115
|
+
readonly _tag: S.tag<"CustomError1">;
|
|
116
|
+
}>;
|
|
117
|
+
export declare class CustomError2 extends CustomError2_base {
|
|
118
|
+
}
|
|
119
|
+
declare const SomeService_base: (abstract new (service: {
|
|
120
|
+
a: number;
|
|
121
|
+
}) => Readonly<{
|
|
122
|
+
a: number;
|
|
123
|
+
}> & Context.TagClassShape<"SomeService", {
|
|
124
|
+
a: number;
|
|
125
|
+
}>) & {
|
|
126
|
+
toLayer: {
|
|
127
|
+
(): import("effect/Layer").Layer<SomeService, never, never>;
|
|
128
|
+
<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>;
|
|
129
|
+
};
|
|
130
|
+
toLayerScoped: {
|
|
131
|
+
(): import("effect/Layer").Layer<SomeService, never, never>;
|
|
132
|
+
<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>>;
|
|
133
|
+
};
|
|
134
|
+
of: (service: Context.TagClassShape<any, any>) => SomeService;
|
|
135
|
+
make: Effect.Effect<SomeService, never, never>;
|
|
136
|
+
} & Context.Tag<SomeService, SomeService> & {
|
|
137
|
+
a: Effect.Effect<number, never, SomeService>;
|
|
138
|
+
} & {
|
|
139
|
+
use: <X>(body: (_: {
|
|
140
|
+
a: number;
|
|
141
|
+
}) => 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>;
|
|
142
|
+
};
|
|
143
|
+
export declare class SomeService extends SomeService_base {
|
|
144
|
+
}
|
|
145
|
+
export {};
|
|
146
|
+
//# 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,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"}
|
|
@@ -0,0 +1,82 @@
|
|
|
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", [UserProfile]),
|
|
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, new UserProfile({
|
|
30
|
+
id: "whatever",
|
|
31
|
+
roles: ["user", ...headers["x-is-manager"] === "true" ? ["manager"] : []]
|
|
32
|
+
})));
|
|
33
|
+
});
|
|
34
|
+
})
|
|
35
|
+
}) {
|
|
36
|
+
}
|
|
37
|
+
// @effect-diagnostics-next-line missingEffectServiceDependency:off
|
|
38
|
+
export class RequireRoles extends Middleware.Tag()("RequireRoles", {
|
|
39
|
+
dynamic: contextMap()("requireRoles", null), // TODO
|
|
40
|
+
wrap: true,
|
|
41
|
+
// wrap: true,
|
|
42
|
+
// had to move this in here, because once you put it manually as a readonly static property on the class,
|
|
43
|
+
// there's a weird issue where the fluent api stops behaving properly after adding this middleware via `addDynamicMiddleware`
|
|
44
|
+
dependsOn: [AllowAnonymous]
|
|
45
|
+
})({
|
|
46
|
+
effect: Effect.gen(function* () {
|
|
47
|
+
yield* Some;
|
|
48
|
+
return Effect.fnUntraced(function* ({ config, next }) {
|
|
49
|
+
// we don't know if the service will be provided or not, so we use option..
|
|
50
|
+
const userProfile = yield* Effect.serviceOption(UserProfile);
|
|
51
|
+
const { requireRoles } = config;
|
|
52
|
+
console.dir({
|
|
53
|
+
userProfile,
|
|
54
|
+
requireRoles
|
|
55
|
+
}, { depth: 5 });
|
|
56
|
+
if (requireRoles && !userProfile.value?.roles?.some((role) => requireRoles.includes(role))) {
|
|
57
|
+
return yield* new UnauthorizedError({ message: "don't have the right roles" });
|
|
58
|
+
}
|
|
59
|
+
return yield* next;
|
|
60
|
+
});
|
|
61
|
+
})
|
|
62
|
+
}) {
|
|
63
|
+
}
|
|
64
|
+
export class Test extends Middleware.Tag()("Test", {
|
|
65
|
+
wrap: true,
|
|
66
|
+
dynamic: contextMap()("test", null) // TODO
|
|
67
|
+
})({
|
|
68
|
+
effect: Effect.gen(function* () {
|
|
69
|
+
return Effect.fn(function* ({ next }) {
|
|
70
|
+
return yield* next;
|
|
71
|
+
});
|
|
72
|
+
})
|
|
73
|
+
}) {
|
|
74
|
+
}
|
|
75
|
+
export class CustomError1 extends TaggedError()("CustomError1", {}) {
|
|
76
|
+
}
|
|
77
|
+
export class CustomError2 extends TaggedError()("CustomError1", {}) {
|
|
78
|
+
}
|
|
79
|
+
const MakeSomeService = Effect.succeed({ a: 1 });
|
|
80
|
+
export class SomeService extends Context.TagMakeId("SomeService", MakeSomeService)() {
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZml4dHVyZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9maXh0dXJlcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLEVBQUUsQ0FBQyxFQUFFLEtBQUssRUFBRSxNQUFNLFlBQVksQ0FBQTtBQUM5RCxPQUFPLEVBQUUsZ0JBQWdCLEVBQXNCLGlCQUFpQixFQUFFLE1BQU0sbUJBQW1CLENBQUE7QUFDM0YsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLG1CQUFtQixDQUFBO0FBQy9DLE9BQU8sRUFBRSxVQUFVLEVBQUUsVUFBVSxFQUFFLE1BQU0sdUJBQXVCLENBQUE7QUFFOUQsTUFBTSxPQUFPLFdBQVksU0FBUSxPQUFPLENBQUMsU0FBUyxDQUEyQixhQUFhLENBQUMsQ0FDekYsQ0FBQyxDQUFDLEtBQUssQ0FBYyxhQUFhLENBQUMsQ0FBQztJQUNsQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLE1BQU07SUFDWixLQUFLLEVBQUUsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDO0NBQ3pCLENBQUMsQ0FDSDtDQUNBO0FBRUQsTUFBTSxPQUFPLElBQUssU0FBUSxPQUFPLENBQUMsU0FBUyxDQUFDLE1BQU0sRUFBRSxNQUFNLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLENBQUMsRUFBUTtDQUFHO0FBQ3hGLE1BQU0sT0FBTyxRQUFTLFNBQVEsT0FBTyxDQUFDLFNBQVMsQ0FBQyxVQUFVLEVBQUUsTUFBTSxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQVk7Q0FBRztBQVFwRyxNQUFNLE9BQU8sY0FBZSxTQUFRLFVBQVUsQ0FBQyxHQUFHLEVBQWtCLENBQUMsZ0JBQWdCLEVBQUU7SUFDckYsT0FBTyxFQUFFLFVBQVUsRUFBcUIsQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDLFdBQVcs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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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type RPCContextMap } from "effect-app/client";
|
|
2
|
+
import { type DynamicMiddlewareMaker, type GenericMiddlewareMaker, type makeMiddlewareBasic, type RequestContextMapProvider } from "../src/api/routing.js";
|
|
3
|
+
export interface MiddlewareM<RequestContext extends Record<string, RPCContextMap.Any>, Provided extends keyof RequestContext, Middlewares extends ReadonlyArray<GenericMiddlewareMaker>, DynamicMiddlewareProviders, MiddlewareR = never> {
|
|
4
|
+
middleware: <MW extends GenericMiddlewareMaker>(mw: MW) => DynamicMiddlewareMakerrsss<RequestContext, Provided, [
|
|
5
|
+
...Middlewares,
|
|
6
|
+
MW
|
|
7
|
+
], DynamicMiddlewareProviders, GenericMiddlewareMaker.ApplyServices<MW, MiddlewareR>>;
|
|
8
|
+
}
|
|
9
|
+
export interface Dynamic<RequestContext extends Record<string, RPCContextMap.Any>, Provided extends keyof RequestContext, Middlewares extends ReadonlyArray<GenericMiddlewareMaker>, DynamicMiddlewareProviders, out MiddlewareR> extends MiddlewareM<RequestContext, Provided, Middlewares, DynamicMiddlewareProviders, MiddlewareR> {
|
|
10
|
+
middleware: <MW extends DynamicMiddlewareMaker<RequestContext> | GenericMiddlewareMaker>(mw: MW) => MW extends DynamicMiddlewareMaker<RequestContext> ? DynamicMiddlewareMakerrsss<RequestContext, Provided | MW["dynamic"]["key"], Middlewares, DynamicMiddlewareProviders & {
|
|
11
|
+
[K in MW["dynamic"]["key"]]: MW;
|
|
12
|
+
}, GenericMiddlewareMaker.ApplyServices<MW, MiddlewareR>> : DynamicMiddlewareMakerrsss<RequestContext, Provided, [
|
|
13
|
+
...Middlewares,
|
|
14
|
+
MW
|
|
15
|
+
], DynamicMiddlewareProviders, GenericMiddlewareMaker.ApplyServices<MW, MiddlewareR>>;
|
|
16
|
+
}
|
|
17
|
+
type GetDynamicMiddleware<T, RequestContext extends Record<string, RPCContextMap.Any>> = T extends RequestContextMapProvider<RequestContext> ? T : never;
|
|
18
|
+
type DynamicMiddlewareMakerrsss<RequestContext extends Record<string, RPCContextMap.Any>, Provided extends keyof RequestContext = never, Middlewares extends ReadonlyArray<GenericMiddlewareMaker> = [], DynamicMiddlewareProviders = unknown, MiddlewareR = never> = keyof Omit<RequestContext, Provided> extends never ? [MiddlewareR] extends [never] ? ReturnType<typeof makeMiddlewareBasic<RequestContext, GetDynamicMiddleware<DynamicMiddlewareProviders, RequestContext>, Middlewares>> & MiddlewareM<RequestContext, Provided, Middlewares, DynamicMiddlewareProviders, MiddlewareR> : MiddlewareM<RequestContext, Provided, Middlewares, DynamicMiddlewareProviders, MiddlewareR> : Dynamic<RequestContext, Provided, Middlewares, DynamicMiddlewareProviders, MiddlewareR>;
|
|
19
|
+
export declare const makeNewMiddleware: <RequestContextMap extends Record<string, RPCContextMap.Any>>() => DynamicMiddlewareMakerrsss<RequestContextMap>;
|
|
20
|
+
export {};
|
|
21
|
+
//# sourceMappingURL=requires.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"requires.d.ts","sourceRoot":"","sources":["../requires.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Array, Either } from "effect-app";
|
|
2
|
+
import { makeMiddleware } from "../src/api/routing.js";
|
|
3
|
+
export const makeNewMiddleware = () => {
|
|
4
|
+
const make = makeMiddleware();
|
|
5
|
+
let capturedMiddlewares = [];
|
|
6
|
+
const it = {
|
|
7
|
+
middleware: (...middlewares) => {
|
|
8
|
+
for (const mw of middlewares) {
|
|
9
|
+
capturedMiddlewares = [mw, ...capturedMiddlewares];
|
|
10
|
+
if (mw.dynamic) {
|
|
11
|
+
console.log("Adding dynamic middleware", mw.key, mw.dynamic.key);
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
console.log("Adding generic middleware", mw.key);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
const [genericMiddlewares, dyn] = Array.partitionMap(capturedMiddlewares, (mw) => "dynamic" in mw && mw.dynamic
|
|
18
|
+
? Either.right(mw)
|
|
19
|
+
: Either.left(mw));
|
|
20
|
+
const dynamicMiddlewares = dyn.reduce((prev, cur) => ({ ...prev, [cur.dynamic.key]: cur }), {});
|
|
21
|
+
// TODO: support dynamic and generic intertwined. treat them as one
|
|
22
|
+
return Object.assign(make({ genericMiddlewares, dynamicMiddlewares }), it);
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
return it;
|
|
26
|
+
};
|
|
27
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVxdWlyZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9yZXF1aXJlcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBRSxNQUFNLFlBQVksQ0FBQTtBQUUxQyxPQUFPLEVBQTRELGNBQWMsRUFBNEQsTUFBTSx1QkFBdUIsQ0FBQTtBQWtIMUssTUFBTSxDQUFDLE1BQU0saUJBQWlCLEdBRXlCLEdBQUcsRUFBRTtJQUMxRCxNQUFNLElBQUksR0FBRyxjQUFjLEVBQU8sQ0FBQTtJQUNsQyxJQUFJLG1CQUFtQixHQUE2RCxFQUFFLENBQUE7SUFDdEYsTUFBTSxFQUFFLEdBQUc7UUFDVCxVQUFVLEVBQUUsQ0FBQyxHQUFHLFdBQWtCLEVBQUUsRUFBRTtZQUNwQyxLQUFLLE1BQU0sRUFBRSxJQUFJLFdBQVcsRUFBRSxDQUFDO2dCQUM3QixtQkFBbUIsR0FBRyxDQUFDLEVBQUUsRUFBRSxHQUFHLG1CQUFtQixDQUFDLENBQUE7Z0JBQ2xELElBQUksRUFBRSxDQUFDLE9BQU8sRUFBRSxDQUFDO29CQUNmLE9BQU8sQ0FBQyxHQUFHLENBQUMsMkJBQTJCLEVBQUUsRUFBRSxDQUFDLEdBQUcsRUFBRSxFQUFFLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFBO2dCQUNsRSxDQUFDO3FCQUFNLENBQUM7b0JBQ04sT0FBTyxDQUFDLEdBQUcsQ0FBQywyQkFBMkIsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUE7Z0JBQ2xELENBQUM7WUFDSCxDQUFDO1lBQ0QsTUFBTSxDQUFDLGtCQUFrQixFQUFFLEdBQUcsQ0FBQyxHQUFHLEtBQUssQ0FBQyxZQUFZLENBQ2xELG1CQUFtQixFQUNuQixDQUFDLEVBQUUsRUFBRSxFQUFFLENBQ0wsU0FBUyxJQUFJLEVBQUUsSUFBSSxFQUFFLENBQUMsT0FBTztnQkFDM0IsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsRUFBaUMsQ0FBQztnQkFDakQsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsRUFBNEIsQ0FBQyxDQUNoRCxDQUFBO1lBQ0QsTUFBTSxrQkFBa0IsR0FBRyxHQUFHLENBQUMsTUFBTSxDQUNuQyxDQUFDLElBQUksRUFBRSxHQUFHLEVBQUUsRUFBRSxDQUFDLENBQUMsRUFBRSxHQUFHLElBQUksRUFBRSxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLEVBQUUsR0FBRyxFQUFFLENBQUMsRUFDcEQsRUFBeUIsQ0FDMUIsQ0FBQTtZQUNELG1FQUFtRTtZQUNuRSxPQUFPLE1BQU0sQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLEVBQUUsa0JBQWtCLEVBQUUsa0JBQWtCLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFBO1FBQzVFLENBQUM7S0FDRixDQUFBO0lBQ0QsT0FBTyxFQUFTLENBQUE7QUFDbEIsQ0FBQyxDQUFBIn0=
|
|
@@ -0,0 +1 @@
|
|
|
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"}
|