@effect-app/infra 2.87.2 → 2.89.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 +24 -1
- package/dist/api/{routing/middleware/ContextProvider.d.ts → ContextProvider.d.ts} +1 -1
- package/dist/api/ContextProvider.d.ts.map +1 -0
- package/dist/api/ContextProvider.js +38 -0
- package/dist/api/routing/middleware/RouterMiddleware.d.ts +15 -28
- package/dist/api/routing/middleware/RouterMiddleware.d.ts.map +1 -1
- package/dist/api/routing/middleware/RouterMiddleware.js +2 -5
- package/dist/api/routing/middleware/RpcMiddleware.d.ts +19 -23
- package/dist/api/routing/middleware/RpcMiddleware.d.ts.map +1 -1
- package/dist/api/routing/middleware/RpcMiddleware.js +1 -1
- package/dist/api/routing/middleware/dynamic-middleware.d.ts +1 -9
- package/dist/api/routing/middleware/dynamic-middleware.d.ts.map +1 -1
- package/dist/api/routing/middleware/generic-middleware.d.ts +24 -22
- package/dist/api/routing/middleware/generic-middleware.d.ts.map +1 -1
- package/dist/api/routing/middleware/generic-middleware.js +24 -8
- package/dist/api/routing/middleware/middleware-api.d.ts +68 -36
- package/dist/api/routing/middleware/middleware-api.d.ts.map +1 -1
- package/dist/api/routing/middleware/middleware-api.js +45 -45
- package/dist/api/routing/middleware/middleware.d.ts +7 -7
- package/dist/api/routing/middleware/middleware.d.ts.map +1 -1
- package/dist/api/routing/middleware/middleware.js +5 -5
- package/dist/api/routing/middleware.d.ts +0 -1
- package/dist/api/routing/middleware.d.ts.map +1 -1
- package/dist/api/routing/middleware.js +1 -2
- package/dist/api/routing.d.ts +1 -1
- package/dist/api/routing.d.ts.map +1 -1
- package/dist/api/routing.js +12 -10
- package/package.json +6 -6
- package/src/api/{routing/middleware/ContextProvider.ts → ContextProvider.ts} +1 -1
- package/src/api/routing/middleware/RouterMiddleware.ts +22 -134
- package/src/api/routing/middleware/RpcMiddleware.ts +28 -23
- package/src/api/routing/middleware/dynamic-middleware.ts +0 -47
- package/src/api/routing/middleware/generic-middleware.ts +84 -35
- package/src/api/routing/middleware/middleware-api.ts +190 -159
- package/src/api/routing/middleware/middleware.ts +5 -5
- package/src/api/routing/middleware.ts +0 -1
- package/src/api/routing.ts +22 -20
- package/test/contextProvider.test.ts +28 -25
- package/test/controller.test.ts +44 -9
- 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 +39 -45
- package/test/dist/fixtures.d.ts.map +1 -1
- package/test/dist/fixtures.js +27 -14
- package/test/dist/requires.test.d.ts.map +1 -1
- package/test/fixtures.ts +29 -18
- package/test/layerUtils.test.ts +1 -2
- package/test/requires.test.ts +146 -103
- package/dist/api/routing/middleware/ContextProvider.d.ts.map +0 -1
- package/dist/api/routing/middleware/ContextProvider.js +0 -38
package/test/controller.test.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { Context, Effect, type Layer, S, Scope } from "effect-app"
|
|
|
6
6
|
import { InvalidStateError, makeRpcClient, NotLoggedInError, UnauthorizedError } from "effect-app/client"
|
|
7
7
|
import { DefaultGenericMiddlewares, makeMiddleware, Middleware, Tag } from "../src/api/routing/middleware.js"
|
|
8
8
|
import { sort } from "../src/api/routing/tsort.js"
|
|
9
|
-
import { AllowAnonymous, CustomError1,
|
|
9
|
+
import { AllowAnonymous, CustomError1, RequestContextMap, RequireRoles, Some, SomeElse, SomeService, Test } from "./fixtures.js"
|
|
10
10
|
|
|
11
11
|
// @effect-diagnostics-next-line missingEffectServiceDependency:off
|
|
12
12
|
class MyContextProvider extends Middleware.Tag<MyContextProvider>()("MyContextProvider", {
|
|
@@ -55,7 +55,6 @@ class MyContextProvider2 extends Middleware.Tag<MyContextProvider2>()("MyContext
|
|
|
55
55
|
const Str = Context.GenericTag<"str", "str">("str")
|
|
56
56
|
|
|
57
57
|
export class BogusMiddleware extends Tag<BogusMiddleware>()("BogusMiddleware", {
|
|
58
|
-
provides: SomeService,
|
|
59
58
|
wrap: true
|
|
60
59
|
})({
|
|
61
60
|
effect: Effect.gen(function*() {
|
|
@@ -64,7 +63,7 @@ export class BogusMiddleware extends Tag<BogusMiddleware>()("BogusMiddleware", {
|
|
|
64
63
|
return ({ next }) =>
|
|
65
64
|
Effect.gen(function*() {
|
|
66
65
|
// yield* Effect.context<"test-dep2">()
|
|
67
|
-
return yield* next
|
|
66
|
+
return yield* next
|
|
68
67
|
})
|
|
69
68
|
})
|
|
70
69
|
}) {
|
|
@@ -76,23 +75,59 @@ const genericMiddlewares = [
|
|
|
76
75
|
MyContextProvider2
|
|
77
76
|
] as const
|
|
78
77
|
|
|
79
|
-
const middleware = makeMiddleware<RequestContextMap>()
|
|
78
|
+
const middleware = makeMiddleware<RequestContextMap>(RequestContextMap)
|
|
80
79
|
.middleware(MyContextProvider)
|
|
81
80
|
.middleware(
|
|
82
81
|
RequireRoles,
|
|
83
82
|
Test
|
|
84
83
|
)
|
|
84
|
+
// AllowAnonymous provided after RequireRoles so that RequireRoles can access what AllowAnonymous provides
|
|
85
85
|
.middleware(AllowAnonymous)
|
|
86
86
|
.middleware(...genericMiddlewares)
|
|
87
|
-
// dependencies: [Layer.effect(Str2, Str)],
|
|
88
87
|
|
|
89
|
-
const
|
|
88
|
+
const middlewareBis = makeMiddleware<RequestContextMap>(RequestContextMap)
|
|
89
|
+
.middleware(MyContextProvider)
|
|
90
|
+
.middleware(
|
|
91
|
+
RequireRoles,
|
|
92
|
+
Test
|
|
93
|
+
)
|
|
94
|
+
// testing sideways elimination
|
|
95
|
+
.middleware(AllowAnonymous, ...genericMiddlewares)
|
|
96
|
+
|
|
97
|
+
expectTypeOf(middleware).toEqualTypeOf<typeof middlewareBis>()
|
|
98
|
+
|
|
99
|
+
const middlewareTrisWip = makeMiddleware<RequestContextMap>(RequestContextMap)
|
|
100
|
+
.middleware(
|
|
101
|
+
MyContextProvider,
|
|
102
|
+
RequireRoles,
|
|
103
|
+
Test
|
|
104
|
+
)
|
|
105
|
+
.missing
|
|
106
|
+
|
|
107
|
+
expectTypeOf(middlewareTrisWip).toEqualTypeOf<{
|
|
108
|
+
missingDynamicMiddlewares: "allowAnonymous"
|
|
109
|
+
missingContext: SomeElse
|
|
110
|
+
}>()
|
|
111
|
+
|
|
112
|
+
// testing more sideways elimination]
|
|
113
|
+
const middlewareQuater = makeMiddleware<RequestContextMap>(RequestContextMap)
|
|
114
|
+
.middleware(
|
|
115
|
+
MyContextProvider,
|
|
116
|
+
RequireRoles,
|
|
117
|
+
Test,
|
|
118
|
+
AllowAnonymous,
|
|
119
|
+
...genericMiddlewares
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
expectTypeOf(middleware).toEqualTypeOf<typeof middlewareQuater>()
|
|
123
|
+
|
|
124
|
+
const middleware2 = makeMiddleware<RequestContextMap>(RequestContextMap)
|
|
90
125
|
.middleware(MyContextProvider)
|
|
91
126
|
.middleware(RequireRoles, Test)
|
|
92
127
|
.middleware(AllowAnonymous)
|
|
93
128
|
.middleware(...DefaultGenericMiddlewares, BogusMiddleware, MyContextProvider2)
|
|
94
129
|
|
|
95
|
-
export const middleware3 = makeMiddleware<RequestContextMap>()
|
|
130
|
+
export const middleware3 = makeMiddleware<RequestContextMap>(RequestContextMap)
|
|
96
131
|
.middleware(...genericMiddlewares)
|
|
97
132
|
.middleware(AllowAnonymous, RequireRoles)
|
|
98
133
|
.middleware(Test)
|
|
@@ -246,7 +281,7 @@ it("sorts based on requirements", () => {
|
|
|
246
281
|
|
|
247
282
|
// eslint-disable-next-line unused-imports/no-unused-vars
|
|
248
283
|
const matched = matchAll({ router })
|
|
249
|
-
expectTypeOf({} as Layer.Context<typeof matched>).toEqualTypeOf<SomeService |
|
|
284
|
+
expectTypeOf({} as Layer.Context<typeof matched>).toEqualTypeOf<SomeService | "str">()
|
|
250
285
|
|
|
251
286
|
type makeContext = MakeContext<typeof router.make>
|
|
252
287
|
expectTypeOf({} as MakeErrors<typeof router.make>).toEqualTypeOf<InvalidStateError>()
|
|
@@ -307,7 +342,7 @@ const router2 = r2.Router(Something)({
|
|
|
307
342
|
|
|
308
343
|
// eslint-disable-next-line unused-imports/no-unused-vars
|
|
309
344
|
const matched2 = matchAll({ router: router2 })
|
|
310
|
-
expectTypeOf({} as Layer.Context<typeof matched2>).toEqualTypeOf<
|
|
345
|
+
expectTypeOf({} as Layer.Context<typeof matched2>).toEqualTypeOf<SomeService | "str">()
|
|
311
346
|
|
|
312
347
|
type makeContext2 = MakeContext<typeof router2.make>
|
|
313
348
|
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,
|
|
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,EAAY,WAAW,EAAE,MAAM,eAAe,CAAA;AA8EzE,eAAO,MAAM,mBAAmB;;CAkB9B,CAAA;AACF,eAAO,MAAM,sBAAsB;;CAkBjC,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;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,
|
|
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,iBAAiB,EAAE,YAAY,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,eAAe,CAAA;;;;;;AAgChI,cAAM,kBAAmB,SAAQ,uBAU/B;CAAG;;;;;;AAML,qBAAa,eAAgB,SAAQ,oBAYnC;CACD;AA4DD,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
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Context, Effect, S, Scope } from "effect-app";
|
|
2
|
-
import { NotLoggedInError,
|
|
2
|
+
import { NotLoggedInError, RPCContextMap, UnauthorizedError } from "effect-app/client";
|
|
3
3
|
import { Middleware } from "../src/api/routing.js";
|
|
4
4
|
declare const UserProfile_base: S.EnhancedClass<UserProfile, {
|
|
5
5
|
id: typeof S.String;
|
|
@@ -37,7 +37,7 @@ declare const Some_base: (abstract new (service: {
|
|
|
37
37
|
} & {
|
|
38
38
|
use: <X>(body: (_: {
|
|
39
39
|
a: number;
|
|
40
|
-
}) => X) => X extends Effect.Effect<infer A, infer E_1, infer R_3> ? Effect.Effect<A, E_1,
|
|
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
41
|
};
|
|
42
42
|
export declare class Some extends Some_base {
|
|
43
43
|
}
|
|
@@ -67,16 +67,42 @@ declare const SomeElse_base: (abstract new (service: {
|
|
|
67
67
|
};
|
|
68
68
|
export declare class SomeElse extends SomeElse_base {
|
|
69
69
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
70
|
+
declare const SomeService_base: (abstract new (service: {
|
|
71
|
+
a: number;
|
|
72
|
+
}) => Readonly<{
|
|
73
|
+
a: number;
|
|
74
|
+
}> & Context.TagClassShape<"SomeService", {
|
|
75
|
+
a: number;
|
|
76
|
+
}>) & {
|
|
77
|
+
toLayer: {
|
|
78
|
+
(): import("effect/Layer").Layer<SomeService, never, never>;
|
|
79
|
+
<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>;
|
|
80
|
+
};
|
|
81
|
+
toLayerScoped: {
|
|
82
|
+
(): import("effect/Layer").Layer<SomeService, never, never>;
|
|
83
|
+
<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>>;
|
|
84
|
+
};
|
|
85
|
+
of: (service: Context.TagClassShape<any, any>) => SomeService;
|
|
86
|
+
make: Effect.Effect<SomeService, never, never>;
|
|
87
|
+
} & Context.Tag<SomeService, SomeService> & {
|
|
88
|
+
a: Effect.Effect<number, never, SomeService>;
|
|
89
|
+
} & {
|
|
90
|
+
use: <X>(body: (_: {
|
|
91
|
+
a: number;
|
|
92
|
+
}) => 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>;
|
|
93
|
+
};
|
|
94
|
+
export declare class SomeService extends SomeService_base {
|
|
95
|
+
}
|
|
96
|
+
export declare const RequestContextMap: {
|
|
97
|
+
readonly allowAnonymous: RPCContextMap.Inverted<[typeof UserProfile], typeof NotLoggedInError>;
|
|
98
|
+
readonly requireRoles: RPCContextMap.Custom<never, typeof UnauthorizedError, string[]>;
|
|
99
|
+
readonly test: RPCContextMap.RPCContextMap<never, typeof S.Never>;
|
|
74
100
|
};
|
|
101
|
+
type _RequestContextMap = typeof RequestContextMap;
|
|
102
|
+
export interface RequestContextMap extends _RequestContextMap {
|
|
103
|
+
}
|
|
75
104
|
declare const AllowAnonymous_base: Middleware.TagClass<AllowAnonymous, "AllowAnonymous", {
|
|
76
|
-
readonly dynamic:
|
|
77
|
-
key: "allowAnonymous";
|
|
78
|
-
settings: RPCContextMap.Inverted<[typeof UserProfile], typeof NotLoggedInError>;
|
|
79
|
-
};
|
|
105
|
+
readonly dynamic: Middleware.RpcDynamic<"allowAnonymous", RPCContextMap.Inverted<[typeof UserProfile], typeof NotLoggedInError>>;
|
|
80
106
|
readonly requires: typeof SomeElse;
|
|
81
107
|
}> & {
|
|
82
108
|
Default: import("effect/Layer").Layer<AllowAnonymous, never, never>;
|
|
@@ -84,23 +110,17 @@ declare const AllowAnonymous_base: Middleware.TagClass<AllowAnonymous, "AllowAno
|
|
|
84
110
|
export declare class AllowAnonymous extends AllowAnonymous_base {
|
|
85
111
|
}
|
|
86
112
|
declare const RequireRoles_base: Middleware.TagClass<RequireRoles, "RequireRoles", {
|
|
87
|
-
readonly dynamic:
|
|
88
|
-
key: "requireRoles";
|
|
89
|
-
settings: RPCContextMap.Custom<never, typeof UnauthorizedError, string[]>;
|
|
90
|
-
};
|
|
113
|
+
readonly dynamic: Middleware.RpcDynamic<"requireRoles", RPCContextMap.Custom<never, typeof UnauthorizedError, string[]>>;
|
|
91
114
|
readonly wrap: true;
|
|
92
115
|
readonly dependsOn: readonly [typeof AllowAnonymous];
|
|
93
116
|
}> & {
|
|
94
|
-
Default: import("effect/Layer").Layer<RequireRoles, never,
|
|
117
|
+
Default: import("effect/Layer").Layer<RequireRoles, never, SomeService>;
|
|
95
118
|
};
|
|
96
119
|
export declare class RequireRoles extends RequireRoles_base {
|
|
97
120
|
}
|
|
98
121
|
declare const Test_base: Middleware.TagClass<Test, "Test", {
|
|
99
122
|
readonly wrap: true;
|
|
100
|
-
readonly dynamic:
|
|
101
|
-
key: "test";
|
|
102
|
-
settings: RPCContextMap<never, typeof S.Never>;
|
|
103
|
-
};
|
|
123
|
+
readonly dynamic: Middleware.RpcDynamic<"test", RPCContextMap.RPCContextMap<never, typeof S.Never>>;
|
|
104
124
|
}> & {
|
|
105
125
|
Default: import("effect/Layer").Layer<Test, never, never>;
|
|
106
126
|
};
|
|
@@ -116,31 +136,5 @@ declare const CustomError2_base: S.TaggedErrorClass<NotLoggedInError, "CustomErr
|
|
|
116
136
|
}>;
|
|
117
137
|
export declare class CustomError2 extends CustomError2_base {
|
|
118
138
|
}
|
|
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, SomeService | R_3> : Effect.Effect<X, never, SomeService>;
|
|
142
|
-
};
|
|
143
|
-
export declare class SomeService extends SomeService_base {
|
|
144
|
-
}
|
|
145
139
|
export {};
|
|
146
140
|
//# sourceMappingURL=fixtures.d.ts.map
|
|
@@ -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,
|
|
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,aAAa,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AAEtF,OAAO,EAAyB,UAAU,EAAE,MAAM,uBAAuB,CAAA;;;;;;;;;;;;;AAEzE,qBAAa,WAAY,SAAQ,gBAKhC;CACA;;;;;;;;;;;;;;;;;;;;;;;;;AAED,qBAAa,IAAK,SAAQ,SAA2D;CAAG;;;;;;;;;;;;;;;;;;;;;;;;;AACxF,qBAAa,QAAS,SAAQ,aAAmE;CAAG;;;;;;;;;;;;;;;;;;;;;;;;;AAEpG,qBAAa,WAAY,SAAQ,gBAAgE;CAAG;AASpG,eAAO,MAAM,iBAAiB;;;;CAIpB,CAAA;AAEV,KAAK,kBAAkB,GAAG,OAAO,iBAAiB,CAAA;AAClD,MAAM,WAAW,iBAAkB,SAAQ,kBAAkB;CAAG;;;;;;;AAEhE,qBAAa,cAAe,SAAQ,mBA4BlC;CACD;;;;;;;;AAID,qBAAa,YAAa,SAAQ,iBA6BhC;CACD;;;;;;;AAGD,qBAAa,IAAK,SAAQ,SASxB;CAAG;;;;AAEL,qBAAa,YAAa,SAAQ,iBAAmD;CAAG;;;;AACxF,qBAAa,YAAa,SAAQ,iBAAmD;CAAG"}
|
package/test/dist/fixtures.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Context, Effect, Option, S, Scope } from "effect-app";
|
|
2
|
-
import { NotLoggedInError, UnauthorizedError } from "effect-app/client";
|
|
2
|
+
import { NotLoggedInError, RPCContextMap, UnauthorizedError } from "effect-app/client";
|
|
3
3
|
import { TaggedError } from "effect-app/Schema";
|
|
4
|
-
import { contextMap, Middleware } from "../src/api/routing.js";
|
|
4
|
+
import { contextMap, getConfig, Middleware } from "../src/api/routing.js";
|
|
5
5
|
export class UserProfile extends Context.assignTag("UserProfile")(S.Class("UserProfile")({
|
|
6
6
|
id: S.String,
|
|
7
7
|
roles: S.Array(S.String)
|
|
@@ -11,17 +11,31 @@ export class Some extends Context.TagMakeId("Some", Effect.succeed({ a: 1 }))()
|
|
|
11
11
|
}
|
|
12
12
|
export class SomeElse extends Context.TagMakeId("SomeElse", Effect.succeed({ b: 2 }))() {
|
|
13
13
|
}
|
|
14
|
+
const MakeSomeService = Effect.succeed({ a: 1 });
|
|
15
|
+
export class SomeService extends Context.TagMakeId("SomeService", MakeSomeService)() {
|
|
16
|
+
}
|
|
17
|
+
const requestConfig = getConfig();
|
|
18
|
+
// TODO: null as never sucks
|
|
19
|
+
// why [UserProfile] is needed? AllowAnonymous triggers an error if just UserProfile without []
|
|
20
|
+
// [] requires return Context, non [] requires return the Service instance
|
|
21
|
+
//
|
|
22
|
+
// consider if we want to support Context of one Service
|
|
23
|
+
export const RequestContextMap = {
|
|
24
|
+
allowAnonymous: RPCContextMap.makeInverted([UserProfile], NotLoggedInError),
|
|
25
|
+
requireRoles: RPCContextMap.makeCustom(null, UnauthorizedError, Array()),
|
|
26
|
+
test: RPCContextMap.make(null, S.Never)
|
|
27
|
+
};
|
|
14
28
|
export class AllowAnonymous extends Middleware.Tag()("AllowAnonymous", {
|
|
15
|
-
dynamic: contextMap(
|
|
29
|
+
dynamic: contextMap(RequestContextMap, "allowAnonymous"),
|
|
16
30
|
requires: SomeElse
|
|
17
31
|
})({
|
|
18
32
|
effect: Effect.gen(function* () {
|
|
19
|
-
return Effect.fnUntraced(function* ({
|
|
33
|
+
return Effect.fnUntraced(function* ({ headers, rpc }) {
|
|
20
34
|
yield* SomeElse;
|
|
21
35
|
yield* Scope.Scope; // provided by HttpRouter.HttpRouter.Provided
|
|
22
36
|
const isLoggedIn = !!headers["x-user"];
|
|
23
37
|
if (!isLoggedIn) {
|
|
24
|
-
if (!
|
|
38
|
+
if (!requestConfig(rpc).allowAnonymous) {
|
|
25
39
|
return yield* new NotLoggedInError({ message: "Not logged in" });
|
|
26
40
|
}
|
|
27
41
|
return Option.none();
|
|
@@ -34,9 +48,10 @@ export class AllowAnonymous extends Middleware.Tag()("AllowAnonymous", {
|
|
|
34
48
|
})
|
|
35
49
|
}) {
|
|
36
50
|
}
|
|
51
|
+
// TODO: don't expect service when it's wrap
|
|
37
52
|
// @effect-diagnostics-next-line missingEffectServiceDependency:off
|
|
38
53
|
export class RequireRoles extends Middleware.Tag()("RequireRoles", {
|
|
39
|
-
dynamic: contextMap(
|
|
54
|
+
dynamic: contextMap(RequestContextMap, "requireRoles"),
|
|
40
55
|
wrap: true,
|
|
41
56
|
// wrap: true,
|
|
42
57
|
// had to move this in here, because once you put it manually as a readonly static property on the class,
|
|
@@ -44,11 +59,11 @@ export class RequireRoles extends Middleware.Tag()("RequireRoles", {
|
|
|
44
59
|
dependsOn: [AllowAnonymous]
|
|
45
60
|
})({
|
|
46
61
|
effect: Effect.gen(function* () {
|
|
47
|
-
yield*
|
|
48
|
-
return Effect.fnUntraced(function* ({
|
|
62
|
+
yield* SomeService;
|
|
63
|
+
return Effect.fnUntraced(function* ({ next, rpc }) {
|
|
49
64
|
// we don't know if the service will be provided or not, so we use option..
|
|
50
65
|
const userProfile = yield* Effect.serviceOption(UserProfile);
|
|
51
|
-
const { requireRoles } =
|
|
66
|
+
const { requireRoles } = requestConfig(rpc);
|
|
52
67
|
console.dir({
|
|
53
68
|
userProfile,
|
|
54
69
|
requireRoles
|
|
@@ -61,9 +76,10 @@ export class RequireRoles extends Middleware.Tag()("RequireRoles", {
|
|
|
61
76
|
})
|
|
62
77
|
}) {
|
|
63
78
|
}
|
|
79
|
+
// TODO: don't expect service when it's wrap
|
|
64
80
|
export class Test extends Middleware.Tag()("Test", {
|
|
65
81
|
wrap: true,
|
|
66
|
-
dynamic: contextMap(
|
|
82
|
+
dynamic: contextMap(RequestContextMap, "test")
|
|
67
83
|
})({
|
|
68
84
|
effect: Effect.gen(function* () {
|
|
69
85
|
return Effect.fn(function* ({ next }) {
|
|
@@ -76,7 +92,4 @@ export class CustomError1 extends TaggedError()("CustomError1", {}) {
|
|
|
76
92
|
}
|
|
77
93
|
export class CustomError2 extends TaggedError()("CustomError1", {}) {
|
|
78
94
|
}
|
|
79
|
-
|
|
80
|
-
export class SomeService extends Context.TagMakeId("SomeService", MakeSomeService)() {
|
|
81
|
-
}
|
|
82
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZml4dHVyZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9maXh0dXJlcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLEVBQUUsQ0FBQyxFQUFFLEtBQUssRUFBRSxNQUFNLFlBQVksQ0FBQTtBQUM5RCxPQUFPLEVBQUUsZ0JBQWdCLEVBQXNCLGlCQUFpQixFQUFFLE1BQU0sbUJBQW1CLENBQUE7QUFDM0YsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLG1CQUFtQixDQUFBO0FBQy9DLE9BQU8sRUFBRSxVQUFVLEVBQUUsVUFBVSxFQUFFLE1BQU0sdUJBQXVCLENBQUE7QUFFOUQsTUFBTSxPQUFPLFdBQVksU0FBUSxPQUFPLENBQUMsU0FBUyxDQUEyQixhQUFhLENBQUMsQ0FDekYsQ0FBQyxDQUFDLEtBQUssQ0FBYyxhQUFhLENBQUMsQ0FBQztJQUNsQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLE1BQU07SUFDWixLQUFLLEVBQUUsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDO0NBQ3pCLENBQUMsQ0FDSDtDQUNBO0FBRUQsTUFBTSxPQUFPLElBQUssU0FBUSxPQUFPLENBQUMsU0FBUyxDQUFDLE1BQU0sRUFBRSxNQUFNLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLENBQUMsRUFBUTtDQUFHO0FBQ3hGLE1BQU0sT0FBTyxRQUFTLFNBQVEsT0FBTyxDQUFDLFNBQVMsQ0FBQyxVQUFVLEVBQUUsTUFBTSxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQVk7Q0FBRztBQVFwRyxNQUFNLE9BQU8sY0FBZSxTQUFRLFVBQVUsQ0FBQyxHQUFHLEVBQWtCLENBQUMsZ0JBQWdCLEVBQUU7SUFDckYsT0FBTyxFQUFFLFVBQVUsRUFBcUIsQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDLFdBQVcsQ0FBQyxDQUFDO0lBQ3pFLFFBQVEsRUFBRSxRQUFRO0NBQ25CLENBQUMsQ0FBQztJQUNELE1BQU0sRUFBRSxNQUFNLENBQUMsR0FBRyxDQUFDLFFBQVEsQ0FBQztRQUMxQixPQUFPLE1BQU0sQ0FBQyxVQUFVLENBQ3RCLFFBQVEsQ0FBQyxFQUFDLEVBQUUsTUFBTSxFQUFFLE9BQU8sRUFBRTtZQUMzQixLQUFLLENBQUMsQ0FBQyxRQUFRLENBQUE7WUFDZixLQUFLLENBQUMsQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFBLENBQUMsNkNBQTZDO1lBQ2hFLE1BQU0sVUFBVSxHQUFHLENBQUMsQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLENBQUE7WUFDdEMsSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFDO2dCQUNoQixJQUFJLENBQUMsTUFBTSxDQUFDLGNBQWMsRUFBRSxDQUFDO29CQUMzQixPQUFPLEtBQUssQ0FBQyxDQUFDLElBQUksZ0JBQWdCLENBQUMsRUFBRSxPQUFPLEVBQUUsZUFBZSxFQUFFLENBQUMsQ0FBQTtnQkFDbEUsQ0FBQztnQkFDRCxPQUFPLE1BQU0sQ0FBQyxJQUFJLEVBQUUsQ0FBQTtZQUN0QixDQUFDO1lBQ0QsT0FBTyxNQUFNLENBQUMsSUFBSSxDQUNoQixPQUFPLENBQUMsSUFBSSxDQUNWLFdBQVcsRUFDWCxJQUFJLFdBQVcsQ0FBQztnQkFDZCxFQUFFLEVBQUUsVUFBVTtnQkFDZCxLQUFLLEVBQUUsQ0FBQyxNQUFNLEVBQUUsR0FBRyxPQUFPLENBQUMsY0FBYyxDQUFDLEtBQUssTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7YUFDMUUsQ0FBQyxDQUNILENBQ0YsQ0FBQTtRQUNILENBQUMsQ0FDRixDQUFBO0lBQ0gsQ0FBQyxDQUFDO0NBQ0gsQ0FBQztDQUNEO0FBRUQsbUVBQW1FO0FBQ25FLE1BQU0sT0FBTyxZQUFhLFNBQVEsVUFBVSxDQUFDLEdBQUcsRUFBZ0IsQ0FBQyxjQUFjLEVBQUU7SUFDL0UsT0FBTyxFQUFFLFVBQVUsRUFBcUIsQ0FBQyxjQUFjLEVBQUUsSUFBYSxDQUFDLEVBQUUsT0FBTztJQUNoRixJQUFJLEVBQUUsSUFBSTtJQUNWLGNBQWM7SUFDZCx5R0FBeUc7SUFDekcsNkhBQTZIO0lBQzdILFNBQVMsRUFBRSxDQUFDLGNBQWMsQ0FBQztDQUM1QixDQUFDLENBQUM7SUFDRCxNQUFNLEVBQUUsTUFBTSxDQUFDLEdBQUcsQ0FBQyxRQUFRLENBQUM7UUFDMUIsS0FBSyxDQUFDLENBQUMsSUFBSSxDQUFBO1FBQ1gsT0FBTyxNQUFNLENBQUMsVUFBVSxDQUN0QixRQUFRLENBQUMsRUFBQyxFQUFFLE1BQU0sRUFBRSxJQUFJLEVBQUU7WUFDeEIsMkVBQTJFO1lBQzNFLE1BQU0sV0FBVyxHQUFHLEtBQUssQ0FBQyxDQUFDLE1BQU0sQ0FBQyxhQUFhLENBQUMsV0FBVyxDQUFDLENBQUE7WUFDNUQsTUFBTSxFQUFFLFlBQVksRUFBRSxHQUFHLE1BQU0sQ0FBQTtZQUMvQixPQUFPLENBQUMsR0FBRyxDQUNUO2dCQUNFLFdBQVc7Z0JBQ1gsWUFBWTthQUNiLEVBQ0QsRUFBRSxLQUFLLEVBQUUsQ0FBQyxFQUFFLENBQ2IsQ0FBQTtZQUNELElBQUksWUFBWSxJQUFJLENBQUMsV0FBVyxDQUFDLEtBQUssRUFBRSxLQUFLLEVBQUUsSUFBSSxDQUFDLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQyxZQUFZLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxDQUFDLEVBQUUsQ0FBQztnQkFDM0YsT0FBTyxLQUFLLENBQUMsQ0FBQyxJQUFJLGlCQUFpQixDQUFDLEVBQUUsT0FBTyxFQUFFLDRCQUE0QixFQUFFLENBQUMsQ0FBQTtZQUNoRixDQUFDO1lBQ0QsT0FBTyxLQUFLLENBQUMsQ0FBQyxJQUFJLENBQUE7UUFDcEIsQ0FBQyxDQUNGLENBQUE7SUFDSCxDQUFDLENBQUM7Q0FDSCxDQUFDO0NBQ0Q7QUFFRCxNQUFNLE9BQU8sSUFBSyxTQUFRLFVBQVUsQ0FBQyxHQUFHLEVBQVEsQ0FBQyxNQUFNLEVBQUU7SUFDdkQsSUFBSSxFQUFFLElBQUk7SUFDVixPQUFPLEVBQUUsVUFBVSxFQUFxQixDQUFDLE1BQU0sRUFBRSxJQUFhLENBQUMsQ0FBQyxPQUFPO0NBQ3hFLENBQUMsQ0FBQztJQUNELE1BQU0sRUFBRSxNQUFNLENBQUMsR0FBRyxDQUFDLFFBQVEsQ0FBQztRQUMxQixPQUFPLE1BQU0sQ0FBQyxFQUFFLENBQUMsUUFBUSxDQUFDLEVBQUMsRUFBRSxJQUFJLEVBQUU7WUFDakMsT0FBTyxLQUFLLENBQUMsQ0FBQyxJQUFJLENBQUE7UUFDcEIsQ0FBQyxDQUFDLENBQUE7SUFDSixDQUFDLENBQUM7Q0FDSCxDQUFDO0NBQUc7QUFFTCxNQUFNLE9BQU8sWUFBYSxTQUFRLFdBQVcsRUFBb0IsQ0FBQyxjQUFjLEVBQUUsRUFBRSxDQUFDO0NBQUc7QUFDeEYsTUFBTSxPQUFPLFlBQWEsU0FBUSxXQUFXLEVBQW9CLENBQUMsY0FBYyxFQUFFLEVBQUUsQ0FBQztDQUFHO0FBRXhGLE1BQU0sZUFBZSxHQUFHLE1BQU0sQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQTtBQUNoRCxNQUFNLE9BQU8sV0FBWSxTQUFRLE9BQU8sQ0FBQyxTQUFTLENBQUMsYUFBYSxFQUFFLGVBQWUsQ0FBQyxFQUFlO0NBQUcifQ==
|
|
95
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZml4dHVyZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9maXh0dXJlcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLEVBQUUsQ0FBQyxFQUFFLEtBQUssRUFBRSxNQUFNLFlBQVksQ0FBQTtBQUM5RCxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsYUFBYSxFQUFFLGlCQUFpQixFQUFFLE1BQU0sbUJBQW1CLENBQUE7QUFDdEYsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLG1CQUFtQixDQUFBO0FBQy9DLE9BQU8sRUFBRSxVQUFVLEVBQUUsU0FBUyxFQUFFLFVBQVUsRUFBRSxNQUFNLHVCQUF1QixDQUFBO0FBRXpFLE1BQU0sT0FBTyxXQUFZLFNBQVEsT0FBTyxDQUFDLFNBQVMsQ0FBMkIsYUFBYSxDQUFDLENBQ3pGLENBQUMsQ0FBQyxLQUFLLENBQWMsYUFBYSxDQUFDLENBQUM7SUFDbEMsRUFBRSxFQUFFLENBQUMsQ0FBQyxNQUFNO0lBQ1osS0FBSyxFQUFFLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQztDQUN6QixDQUFDLENBQ0g7Q0FDQTtBQUVELE1BQU0sT0FBTyxJQUFLLFNBQVEsT0FBTyxDQUFDLFNBQVMsQ0FBQyxNQUFNLEVBQUUsTUFBTSxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQVE7Q0FBRztBQUN4RixNQUFNLE9BQU8sUUFBUyxTQUFRLE9BQU8sQ0FBQyxTQUFTLENBQUMsVUFBVSxFQUFFLE1BQU0sQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQyxFQUFZO0NBQUc7QUFDcEcsTUFBTSxlQUFlLEdBQUcsTUFBTSxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFBO0FBQ2hELE1BQU0sT0FBTyxXQUFZLFNB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
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"requires.test.d.ts","sourceRoot":"","sources":["../requires.test.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"requires.test.d.ts","sourceRoot":"","sources":["../requires.test.ts"],"names":[],"mappings":"AAGA,OAAO,EAA2B,KAAK,EAAK,MAAM,YAAY,CAAA;AAG9D,OAAO,EAAkB,UAAU,EAAE,MAAM,uBAAuB,CAAA;AAClE,OAAO,EAAmD,IAAI,EAAE,QAAQ,EAAqB,MAAM,eAAe,CAAA;;;;;;AAElH,qBAAa,cAAe,SAAQ,mBAUlC;CACD;;;;;;;AAGD,qBAAa,kBAAmB,SAAQ,uBAQtC;CACD;;;;;;;AAED,qBAAa,kBAAmB,SAAQ,uBAYtC;CACD;;;;;;;AAED,qBAAa,sBAAuB,SAAQ,2BAa1C;CACD"}
|
package/test/fixtures.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Context, Effect, Option, S, Scope } from "effect-app"
|
|
2
|
-
import { NotLoggedInError,
|
|
2
|
+
import { NotLoggedInError, RPCContextMap, UnauthorizedError } from "effect-app/client"
|
|
3
3
|
import { TaggedError } from "effect-app/Schema"
|
|
4
|
-
import { contextMap, Middleware } from "../src/api/routing.js"
|
|
4
|
+
import { contextMap, getConfig, Middleware } from "../src/api/routing.js"
|
|
5
5
|
|
|
6
6
|
export class UserProfile extends Context.assignTag<UserProfile, UserProfile>("UserProfile")(
|
|
7
7
|
S.Class<UserProfile>("UserProfile")({
|
|
@@ -13,25 +13,37 @@ export class UserProfile extends Context.assignTag<UserProfile, UserProfile>("Us
|
|
|
13
13
|
|
|
14
14
|
export class Some extends Context.TagMakeId("Some", Effect.succeed({ a: 1 }))<Some>() {}
|
|
15
15
|
export class SomeElse extends Context.TagMakeId("SomeElse", Effect.succeed({ b: 2 }))<SomeElse>() {}
|
|
16
|
+
const MakeSomeService = Effect.succeed({ a: 1 })
|
|
17
|
+
export class SomeService extends Context.TagMakeId("SomeService", MakeSomeService)<SomeService>() {}
|
|
16
18
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
const requestConfig = getConfig<RequestContextMap>()
|
|
20
|
+
|
|
21
|
+
// TODO: null as never sucks
|
|
22
|
+
// why [UserProfile] is needed? AllowAnonymous triggers an error if just UserProfile without []
|
|
23
|
+
// [] requires return Context, non [] requires return the Service instance
|
|
24
|
+
//
|
|
25
|
+
// consider if we want to support Context of one Service
|
|
26
|
+
export const RequestContextMap = {
|
|
27
|
+
allowAnonymous: RPCContextMap.makeInverted([UserProfile], NotLoggedInError),
|
|
28
|
+
requireRoles: RPCContextMap.makeCustom(null as never, UnauthorizedError, Array<string>()),
|
|
29
|
+
test: RPCContextMap.make(null as never, S.Never)
|
|
30
|
+
} as const
|
|
31
|
+
|
|
32
|
+
type _RequestContextMap = typeof RequestContextMap
|
|
33
|
+
export interface RequestContextMap extends _RequestContextMap {}
|
|
22
34
|
|
|
23
35
|
export class AllowAnonymous extends Middleware.Tag<AllowAnonymous>()("AllowAnonymous", {
|
|
24
|
-
dynamic: contextMap
|
|
36
|
+
dynamic: contextMap(RequestContextMap, "allowAnonymous"),
|
|
25
37
|
requires: SomeElse
|
|
26
38
|
})({
|
|
27
39
|
effect: Effect.gen(function*() {
|
|
28
40
|
return Effect.fnUntraced(
|
|
29
|
-
function*({
|
|
41
|
+
function*({ headers, rpc }) {
|
|
30
42
|
yield* SomeElse
|
|
31
43
|
yield* Scope.Scope // provided by HttpRouter.HttpRouter.Provided
|
|
32
44
|
const isLoggedIn = !!headers["x-user"]
|
|
33
45
|
if (!isLoggedIn) {
|
|
34
|
-
if (!
|
|
46
|
+
if (!requestConfig(rpc).allowAnonymous) {
|
|
35
47
|
return yield* new NotLoggedInError({ message: "Not logged in" })
|
|
36
48
|
}
|
|
37
49
|
return Option.none()
|
|
@@ -51,9 +63,10 @@ export class AllowAnonymous extends Middleware.Tag<AllowAnonymous>()("AllowAnony
|
|
|
51
63
|
}) {
|
|
52
64
|
}
|
|
53
65
|
|
|
66
|
+
// TODO: don't expect service when it's wrap
|
|
54
67
|
// @effect-diagnostics-next-line missingEffectServiceDependency:off
|
|
55
68
|
export class RequireRoles extends Middleware.Tag<RequireRoles>()("RequireRoles", {
|
|
56
|
-
dynamic: contextMap
|
|
69
|
+
dynamic: contextMap(RequestContextMap, "requireRoles"),
|
|
57
70
|
wrap: true,
|
|
58
71
|
// wrap: true,
|
|
59
72
|
// had to move this in here, because once you put it manually as a readonly static property on the class,
|
|
@@ -61,12 +74,12 @@ export class RequireRoles extends Middleware.Tag<RequireRoles>()("RequireRoles",
|
|
|
61
74
|
dependsOn: [AllowAnonymous]
|
|
62
75
|
})({
|
|
63
76
|
effect: Effect.gen(function*() {
|
|
64
|
-
yield*
|
|
77
|
+
yield* SomeService
|
|
65
78
|
return Effect.fnUntraced(
|
|
66
|
-
function*({
|
|
79
|
+
function*({ next, rpc }) {
|
|
67
80
|
// we don't know if the service will be provided or not, so we use option..
|
|
68
81
|
const userProfile = yield* Effect.serviceOption(UserProfile)
|
|
69
|
-
const { requireRoles } =
|
|
82
|
+
const { requireRoles } = requestConfig(rpc)
|
|
70
83
|
console.dir(
|
|
71
84
|
{
|
|
72
85
|
userProfile,
|
|
@@ -84,9 +97,10 @@ export class RequireRoles extends Middleware.Tag<RequireRoles>()("RequireRoles",
|
|
|
84
97
|
}) {
|
|
85
98
|
}
|
|
86
99
|
|
|
100
|
+
// TODO: don't expect service when it's wrap
|
|
87
101
|
export class Test extends Middleware.Tag<Test>()("Test", {
|
|
88
102
|
wrap: true,
|
|
89
|
-
dynamic: contextMap
|
|
103
|
+
dynamic: contextMap(RequestContextMap, "test")
|
|
90
104
|
})({
|
|
91
105
|
effect: Effect.gen(function*() {
|
|
92
106
|
return Effect.fn(function*({ next }) {
|
|
@@ -97,6 +111,3 @@ export class Test extends Middleware.Tag<Test>()("Test", {
|
|
|
97
111
|
|
|
98
112
|
export class CustomError1 extends TaggedError<NotLoggedInError>()("CustomError1", {}) {}
|
|
99
113
|
export class CustomError2 extends TaggedError<NotLoggedInError>()("CustomError1", {}) {}
|
|
100
|
-
|
|
101
|
-
const MakeSomeService = Effect.succeed({ a: 1 })
|
|
102
|
-
export class SomeService extends Context.TagMakeId("SomeService", MakeSomeService)<SomeService>() {}
|
package/test/layerUtils.test.ts
CHANGED