@nmnmcc/ability 0.3.0 → 1.0.1
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/README.md +199 -31
- package/dist/Authorizer.d.ts +64 -39
- package/dist/Authorizer.d.ts.map +1 -1
- package/dist/Authorizer.js +291 -6
- package/dist/Authorizer.js.map +1 -1
- package/dist/Condition.d.ts +444 -65
- package/dist/Condition.d.ts.map +1 -1
- package/dist/Condition.js +1007 -25
- package/dist/Condition.js.map +1 -1
- package/dist/Domain.d.ts +27 -17
- package/dist/Domain.d.ts.map +1 -1
- package/dist/Domain.js +52 -10
- package/dist/Domain.js.map +1 -1
- package/dist/HttpApi.d.ts +84 -40
- package/dist/HttpApi.d.ts.map +1 -1
- package/dist/HttpApi.js +103 -13
- package/dist/HttpApi.js.map +1 -1
- package/dist/Policy.d.ts +314 -56
- package/dist/Policy.d.ts.map +1 -1
- package/dist/Policy.js +1215 -38
- package/dist/Policy.js.map +1 -1
- package/dist/Principal.js +2 -2
- package/dist/Principal.js.map +1 -1
- package/dist/Resource.d.ts +171 -20
- package/dist/Resource.d.ts.map +1 -1
- package/dist/Resource.js +788 -15
- package/dist/Resource.js.map +1 -1
- package/dist/Rule.d.ts +115 -29
- package/dist/Rule.d.ts.map +1 -1
- package/dist/Rule.js +219 -12
- package/dist/Rule.js.map +1 -1
- package/dist/index.js +4 -4
- package/package.json +2 -2
- package/src/Authorizer.ts +625 -61
- package/src/Condition.ts +2403 -112
- package/src/Domain.ts +80 -23
- package/src/HttpApi.ts +225 -25
- package/src/Policy.ts +2836 -96
- package/src/Principal.ts +2 -2
- package/src/Resource.ts +1544 -29
- package/src/Rule.ts +463 -45
- package/dist/internal/authorizer.d.ts +0 -28
- package/dist/internal/authorizer.d.ts.map +0 -1
- package/dist/internal/authorizer.js +0 -153
- package/dist/internal/authorizer.js.map +0 -1
- package/dist/internal/condition.d.ts +0 -11
- package/dist/internal/condition.d.ts.map +0 -1
- package/dist/internal/condition.js +0 -393
- package/dist/internal/condition.js.map +0 -1
- package/dist/internal/domain.js +0 -34
- package/dist/internal/domain.js.map +0 -1
- package/dist/internal/httpApi.js +0 -41
- package/dist/internal/httpApi.js.map +0 -1
- package/dist/internal/policy.js +0 -524
- package/dist/internal/policy.js.map +0 -1
- package/dist/internal/resource.js +0 -66
- package/dist/internal/resource.js.map +0 -1
- package/dist/internal/rule.js +0 -131
- package/dist/internal/rule.js.map +0 -1
- package/src/internal/authorizer.ts +0 -271
- package/src/internal/condition.ts +0 -607
- package/src/internal/domain.ts +0 -56
- package/src/internal/httpApi.ts +0 -84
- package/src/internal/policy.ts +0 -815
- package/src/internal/resource.ts +0 -98
- package/src/internal/rule.ts +0 -203
package/dist/HttpApi.d.ts
CHANGED
|
@@ -1,14 +1,29 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { AnyServiceClass } from "./Authorizer.js";
|
|
1
|
+
import { Any, CommonAction, Kind, ValueOf } from "./Domain.js";
|
|
2
|
+
import { Scope } from "./Policy.js";
|
|
3
|
+
import { AnyServiceClass, Forbidden, Pending, PolicyUnavailable } from "./Authorizer.js";
|
|
4
4
|
import * as Context from "effect/Context";
|
|
5
5
|
import * as Effect from "effect/Effect";
|
|
6
6
|
import * as Layer from "effect/Layer";
|
|
7
|
+
import * as Schema from "effect/Schema";
|
|
7
8
|
/**
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
9
|
+
* The path parameters of a request.
|
|
10
|
+
*
|
|
11
|
+
* @stability unstable
|
|
12
|
+
* @category models
|
|
13
|
+
* @since 1.0.0
|
|
14
|
+
*/
|
|
15
|
+
export type Params = Readonly<Record<string, string | undefined>>;
|
|
16
|
+
/**
|
|
17
|
+
* One check that an endpoint needs: an action on a kind of resource.
|
|
18
|
+
* - With `load`, the middleware loads the resource value from the path
|
|
19
|
+
* parameters and checks the action on that value.
|
|
20
|
+
* - With `within`, it makes a scope from the path parameters and checks the
|
|
21
|
+
* action on every value in the scope.
|
|
22
|
+
* - With `list`, the endpoint gives a list. The handler gets the list query
|
|
23
|
+
* with `Authorizer.filter`, so the middleware checks nothing, unless
|
|
24
|
+
* `nonEmpty` is true: then it fails when the principal may act on no value
|
|
25
|
+
* in the scope.
|
|
26
|
+
* - With none of them, it checks the action on every value of the kind.
|
|
12
27
|
*
|
|
13
28
|
* @stability unstable
|
|
14
29
|
* @category models
|
|
@@ -17,7 +32,11 @@ import * as Layer from "effect/Layer";
|
|
|
17
32
|
export interface Requirement {
|
|
18
33
|
readonly action: string;
|
|
19
34
|
readonly kind: string;
|
|
20
|
-
readonly load?: (params:
|
|
35
|
+
readonly load?: (params: Params) => Effect.Effect<object, unknown, unknown>;
|
|
36
|
+
readonly within?: (params: Params) => unknown;
|
|
37
|
+
readonly list?: {
|
|
38
|
+
readonly nonEmpty: boolean;
|
|
39
|
+
};
|
|
21
40
|
}
|
|
22
41
|
declare const Required_base: Context.ServiceClass<Required, "@nmnmcc/ability/HttpApi/Required", readonly Requirement[]>;
|
|
23
42
|
/**
|
|
@@ -43,10 +62,17 @@ declare const GroupRequired_base: Context.ServiceClass<GroupRequired, "@nmnmcc/a
|
|
|
43
62
|
export declare class GroupRequired extends GroupRequired_base {}
|
|
44
63
|
/**
|
|
45
64
|
* Makes a {@link Requirement} with the types of an authorizer. The action must
|
|
46
|
-
* be an action of the kind,
|
|
65
|
+
* be an action of the kind, also when the kind has a union type.
|
|
47
66
|
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
67
|
+
* The last argument is one of:
|
|
68
|
+
* - a `load` function, which must give a value of the kind. It may fail. Its
|
|
69
|
+
* errors must be errors of the middleware, and the services that it needs
|
|
70
|
+
* must be given to {@link layer}.
|
|
71
|
+
* - `{ within }`, a function from the path parameters to a scope. Use it for
|
|
72
|
+
* an act on a part of the kind, such as a new value with no id yet:
|
|
73
|
+
* `{ within: (params) => ($) => $.under("org", params.org ?? null) }`. A path
|
|
74
|
+
* parameter may be `undefined`, and a scope with `undefined` in it is a
|
|
75
|
+
* defect, so give a value for it.
|
|
50
76
|
*
|
|
51
77
|
* @stability unstable
|
|
52
78
|
* @category constructors
|
|
@@ -54,61 +80,79 @@ export declare class GroupRequired extends GroupRequired_base {}
|
|
|
54
80
|
*/
|
|
55
81
|
export declare const requires: <A extends {
|
|
56
82
|
readonly domain: Any;
|
|
57
|
-
}, const K extends Kind<A["domain"]>>(authorizer: A, action:
|
|
83
|
+
}, const K extends Kind<A["domain"]>>(authorizer: A, action: CommonAction<A["domain"], K>, kind: K, how?: ((params: Params) => Effect.Effect<ValueOf<A["domain"], K>, unknown, unknown>) | {
|
|
84
|
+
readonly within: (params: Params) => Scope<A["domain"], K>;
|
|
85
|
+
}) => Requirement;
|
|
86
|
+
/**
|
|
87
|
+
* Makes a {@link Requirement} for an endpoint that gives a list. The middleware
|
|
88
|
+
* does not check that the principal may act on every value, because the list
|
|
89
|
+
* shows only the values that it may act on. The handler gets the list query
|
|
90
|
+
* with `Authorizer.filter`, with the same scope.
|
|
91
|
+
*
|
|
92
|
+
* When the principal may act on no value, the list is empty: that is not an
|
|
93
|
+
* error, so a client does not learn that hidden values are there. With
|
|
94
|
+
* `nonEmpty: true`, the middleware fails with `Forbidden` in that case. It
|
|
95
|
+
* also fails when the coverage is `Unknown`, because then it can not say that
|
|
96
|
+
* the list has a value.
|
|
97
|
+
*
|
|
98
|
+
* @stability unstable
|
|
99
|
+
* @category constructors
|
|
100
|
+
* @since 1.0.0
|
|
101
|
+
*/
|
|
102
|
+
export declare const lists: <A extends {
|
|
103
|
+
readonly domain: Any;
|
|
104
|
+
}, const K extends Kind<A["domain"]>>(authorizer: A, action: CommonAction<A["domain"], K>, kind: K, options?: {
|
|
105
|
+
readonly within?: (params: Params) => Scope<A["domain"], K>;
|
|
106
|
+
readonly nonEmpty?: boolean;
|
|
107
|
+
}) => Requirement;
|
|
58
108
|
/**
|
|
59
109
|
* The errors of the middleware, with HTTP status codes: 403 for
|
|
60
110
|
* `Forbidden`, 503 for `PolicyUnavailable`, and 409 for `Pending`.
|
|
61
111
|
*
|
|
112
|
+
* The body of a `PolicyUnavailable` response has only its `_tag`. The cause
|
|
113
|
+
* may have private details, such as an error from the database, so it stays
|
|
114
|
+
* on the server.
|
|
115
|
+
*
|
|
62
116
|
* @stability unstable
|
|
63
117
|
* @category errors
|
|
64
118
|
* @since 0.3.0
|
|
65
119
|
*/
|
|
66
|
-
export declare const errors: readonly [
|
|
120
|
+
export declare const errors: readonly [Schema.decodeTo<Schema.declareConstructor<Forbidden, {
|
|
67
121
|
readonly _tag: "Forbidden";
|
|
68
122
|
readonly action: string;
|
|
69
123
|
readonly kind: string;
|
|
70
124
|
readonly field?: string;
|
|
71
125
|
readonly reason?: string;
|
|
72
|
-
}, readonly [
|
|
73
|
-
readonly action:
|
|
74
|
-
readonly kind:
|
|
75
|
-
readonly field:
|
|
76
|
-
readonly reason:
|
|
126
|
+
}, readonly [Schema.TaggedStruct<"Forbidden", {
|
|
127
|
+
readonly action: Schema.String;
|
|
128
|
+
readonly kind: Schema.String;
|
|
129
|
+
readonly field: Schema.optionalKey<Schema.String>;
|
|
130
|
+
readonly reason: Schema.optionalKey<Schema.String>;
|
|
77
131
|
}>], {
|
|
78
132
|
readonly _tag: "Forbidden";
|
|
79
133
|
readonly action: string;
|
|
80
134
|
readonly kind: string;
|
|
81
135
|
readonly field?: string;
|
|
82
136
|
readonly reason?: string;
|
|
83
|
-
}>,
|
|
84
|
-
readonly action:
|
|
85
|
-
readonly kind:
|
|
86
|
-
readonly field:
|
|
87
|
-
readonly reason:
|
|
88
|
-
}>, never, never>,
|
|
89
|
-
readonly _tag: "PolicyUnavailable";
|
|
90
|
-
readonly cause: import("effect/Schema").Json;
|
|
91
|
-
}, readonly [import("effect/Schema").TaggedStruct<"PolicyUnavailable", {
|
|
92
|
-
readonly cause: import("effect/Schema").Defect;
|
|
93
|
-
}>], {
|
|
94
|
-
readonly _tag: "PolicyUnavailable";
|
|
95
|
-
readonly cause: unknown;
|
|
96
|
-
}>, import("effect/Schema").TaggedStruct<"PolicyUnavailable", {
|
|
97
|
-
readonly cause: import("effect/Schema").Defect;
|
|
98
|
-
}>, never, never>, import("effect/Schema").decodeTo<import("effect/Schema").declareConstructor<Pending, {
|
|
137
|
+
}>, Schema.TaggedStruct<"Forbidden", {
|
|
138
|
+
readonly action: Schema.String;
|
|
139
|
+
readonly kind: Schema.String;
|
|
140
|
+
readonly field: Schema.optionalKey<Schema.String>;
|
|
141
|
+
readonly reason: Schema.optionalKey<Schema.String>;
|
|
142
|
+
}>, never, never>, Schema.decodeTo<Schema.declare<PolicyUnavailable, PolicyUnavailable>, Schema.TaggedStruct<"PolicyUnavailable", {}>, never, never>, Schema.decodeTo<Schema.declareConstructor<Pending, {
|
|
99
143
|
readonly _tag: "Pending";
|
|
100
144
|
readonly ticket: string;
|
|
101
145
|
readonly reason?: string;
|
|
102
|
-
}, readonly [
|
|
103
|
-
readonly ticket:
|
|
104
|
-
readonly reason:
|
|
146
|
+
}, readonly [Schema.TaggedStruct<"Pending", {
|
|
147
|
+
readonly ticket: Schema.String;
|
|
148
|
+
readonly reason: Schema.optionalKey<Schema.String>;
|
|
105
149
|
}>], {
|
|
106
150
|
readonly _tag: "Pending";
|
|
107
151
|
readonly ticket: string;
|
|
108
152
|
readonly reason?: string;
|
|
109
|
-
}>,
|
|
110
|
-
readonly ticket:
|
|
111
|
-
readonly reason:
|
|
153
|
+
}>, Schema.TaggedStruct<"Pending", {
|
|
154
|
+
readonly ticket: Schema.String;
|
|
155
|
+
readonly reason: Schema.optionalKey<Schema.String>;
|
|
112
156
|
}>, never, never>];
|
|
113
157
|
/**
|
|
114
158
|
* Makes the layer of an authorization middleware. The middleware reads the
|
package/dist/HttpApi.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HttpApi.d.ts","names":["Domain.Any","Domain.Kind","Domain.
|
|
1
|
+
{"version":3,"file":"HttpApi.d.ts","names":["Domain.Any","Domain.Kind","Domain.CommonAction","Domain.ValueOf","Policy.Scope","Authorizer.Forbidden","Authorizer.PolicyUnavailable","Authorizer.Pending","Authorizer.AnyServiceClass"],"sources":["../src/HttpApi.ts"],"mappings":";;;;;;;;;;;;;;YAyDY,SAAS,SAAS;;;;;;;;;;;;;;;;;iBAkBb;WACP;WACA;WACA,QAAQ,QAAQ,WAAW,OAAO;WAClC,UAAU,QAAQ;WAClB;aAAkB;;;;;;;;;;;qBAUf,iBAAiB;;WAgBb,MAAA,cAAc;WACb,OAAA,cAAc;;;;;;;;;;qBAJnB,sBAAsB;;;;;;;;;;;;;;;;;;;qBA0BtB,WACZ;WAAqB,QAAQA;SACvB,UAAUC,KAAY,cAE5B,YAAY,GACZ,QAAQC,aAAoB,aAAa,IACzC,MAAM,GACN,QAEG,QAAQ,WACH,OAAO,OAAOC,QAAe,aAAa;WACpC,SAAS,QAAQ,WAAWC,MAAa,aAAa;MAChE;;;;;;;;;;;;;;;;;qBAuBQ,QACZ;WAAqB,QAAQJ;SACvB,UAAUC,KAAY,cAE5B,YAAY,GACZ,QAAQC,aAAoB,aAAa,IACzC,MAAM,GACN;WACU,UAAU,QAAQ,WAAWE,MAAa,aAAa;WACvD;MAEN;;;;;;;;;;;;;qBAuCQ,kBAAM,OAAA,SAAA,OAAA,mBAAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAyHN,QACZ,MACA,mBACA,UAAUG,iBACV,WAEA,YAAY,QAAQ,aAAa,MAAM,UACvC,YAAY,MACR,MAAM,MACV,cAEC,UAAU,QAAQ,UAAU,UAAU,aAAa"}
|
package/dist/HttpApi.js
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
|
+
import { kindOf } from "./Resource.js";
|
|
1
2
|
import { Forbidden, Pending, PolicyUnavailable } from "./Authorizer.js";
|
|
2
|
-
import { layer as layer$1, requires as requires$1 } from "./internal/httpApi.js";
|
|
3
3
|
import * as Context from "effect/Context";
|
|
4
|
+
import * as Effect from "effect/Effect";
|
|
5
|
+
import * as Layer from "effect/Layer";
|
|
6
|
+
import * as Option from "effect/Option";
|
|
7
|
+
import * as Schema from "effect/Schema";
|
|
8
|
+
import * as SchemaTransformation from "effect/SchemaTransformation";
|
|
9
|
+
import { HttpRouter } from "effect/http";
|
|
4
10
|
import { HttpApiSchema } from "effect/http-api";
|
|
5
11
|
// src/HttpApi.ts
|
|
6
12
|
/**
|
|
@@ -9,9 +15,10 @@ import { HttpApiSchema } from "effect/http-api";
|
|
|
9
15
|
* Each endpoint says what it needs with the {@link Required} annotation. A
|
|
10
16
|
* group can give a default with {@link GroupRequired}: one list for GET
|
|
11
17
|
* requests and one list for all other methods. A middleware checks the
|
|
12
|
-
* requirements before the handler runs
|
|
13
|
-
* defect, so a new endpoint is closed until
|
|
14
|
-
* list means the endpoint is open.
|
|
18
|
+
* requirements before the handler runs, in each group that uses it. An
|
|
19
|
+
* endpoint with no annotation is a defect, so a new endpoint is closed until
|
|
20
|
+
* you say what it needs. An empty list means the endpoint is open. An endpoint
|
|
21
|
+
* in a group without the middleware is not checked at all.
|
|
15
22
|
*
|
|
16
23
|
* ```ts
|
|
17
24
|
* class Authorization extends HttpApiMiddleware.Service<
|
|
@@ -19,11 +26,13 @@ import { HttpApiSchema } from "effect/http-api";
|
|
|
19
26
|
* { requires: Identity }
|
|
20
27
|
* >()("app/Authorization", { error: HttpApi.errors }) {}
|
|
21
28
|
*
|
|
22
|
-
* const endpoint = HttpApiEndpoint.patch("update", "/
|
|
29
|
+
* const endpoint = HttpApiEndpoint.patch("update", "/notes/:id", { ... })
|
|
23
30
|
* .annotate(HttpApi.Required, [
|
|
24
|
-
* HttpApi.requires(Auth, "update", "
|
|
31
|
+
* HttpApi.requires(Auth, "update", "Note", (params) => Notes.find(params.id)),
|
|
25
32
|
* ])
|
|
26
33
|
*
|
|
34
|
+
* const notes = HttpApiGroup.make("notes").add(endpoint).middleware(Authorization)
|
|
35
|
+
*
|
|
27
36
|
* const AuthorizationLive = HttpApi.layer(Authorization, Auth)
|
|
28
37
|
* ```
|
|
29
38
|
*
|
|
@@ -52,29 +61,110 @@ var Required = class extends Context.Service()("@nmnmcc/ability/HttpApi/Required
|
|
|
52
61
|
var GroupRequired = class extends Context.Service()("@nmnmcc/ability/HttpApi/GroupRequired") {};
|
|
53
62
|
/**
|
|
54
63
|
* Makes a {@link Requirement} with the types of an authorizer. The action must
|
|
55
|
-
* be an action of the kind,
|
|
64
|
+
* be an action of the kind, also when the kind has a union type.
|
|
56
65
|
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
66
|
+
* The last argument is one of:
|
|
67
|
+
* - a `load` function, which must give a value of the kind. It may fail. Its
|
|
68
|
+
* errors must be errors of the middleware, and the services that it needs
|
|
69
|
+
* must be given to {@link layer}.
|
|
70
|
+
* - `{ within }`, a function from the path parameters to a scope. Use it for
|
|
71
|
+
* an act on a part of the kind, such as a new value with no id yet:
|
|
72
|
+
* `{ within: (params) => ($) => $.under("org", params.org ?? null) }`. A path
|
|
73
|
+
* parameter may be `undefined`, and a scope with `undefined` in it is a
|
|
74
|
+
* defect, so give a value for it.
|
|
59
75
|
*
|
|
60
76
|
* @stability unstable
|
|
61
77
|
* @category constructors
|
|
62
78
|
* @since 0.3.0
|
|
63
79
|
*/
|
|
64
|
-
const requires =
|
|
80
|
+
const requires = (_authorizer, action, kind, how) => how === void 0 ? {
|
|
81
|
+
action,
|
|
82
|
+
kind
|
|
83
|
+
} : typeof how === "function" ? {
|
|
84
|
+
action,
|
|
85
|
+
kind,
|
|
86
|
+
load: how
|
|
87
|
+
} : {
|
|
88
|
+
action,
|
|
89
|
+
kind,
|
|
90
|
+
within: how.within
|
|
91
|
+
};
|
|
92
|
+
/**
|
|
93
|
+
* Makes a {@link Requirement} for an endpoint that gives a list. The middleware
|
|
94
|
+
* does not check that the principal may act on every value, because the list
|
|
95
|
+
* shows only the values that it may act on. The handler gets the list query
|
|
96
|
+
* with `Authorizer.filter`, with the same scope.
|
|
97
|
+
*
|
|
98
|
+
* When the principal may act on no value, the list is empty: that is not an
|
|
99
|
+
* error, so a client does not learn that hidden values are there. With
|
|
100
|
+
* `nonEmpty: true`, the middleware fails with `Forbidden` in that case. It
|
|
101
|
+
* also fails when the coverage is `Unknown`, because then it can not say that
|
|
102
|
+
* the list has a value.
|
|
103
|
+
*
|
|
104
|
+
* @stability unstable
|
|
105
|
+
* @category constructors
|
|
106
|
+
* @since 1.0.0
|
|
107
|
+
*/
|
|
108
|
+
const lists = (_authorizer, action, kind, options) => ({
|
|
109
|
+
action,
|
|
110
|
+
kind,
|
|
111
|
+
list: { nonEmpty: options?.nonEmpty ?? false },
|
|
112
|
+
...options?.within === void 0 ? {} : { within: options.within }
|
|
113
|
+
});
|
|
114
|
+
/**
|
|
115
|
+
* The Schema of a `PolicyUnavailable` response. It encodes only the `_tag`, so
|
|
116
|
+
* the cause does not go to the client.
|
|
117
|
+
*/
|
|
118
|
+
const PolicyUnavailableResponse = Schema.TaggedStruct("PolicyUnavailable", {}).pipe(Schema.decodeTo(Schema.declare((u) => u instanceof PolicyUnavailable), SchemaTransformation.transform({
|
|
119
|
+
decode: () => PolicyUnavailable.make({ cause: void 0 }),
|
|
120
|
+
encode: () => ({ _tag: "PolicyUnavailable" })
|
|
121
|
+
})));
|
|
65
122
|
/**
|
|
66
123
|
* The errors of the middleware, with HTTP status codes: 403 for
|
|
67
124
|
* `Forbidden`, 503 for `PolicyUnavailable`, and 409 for `Pending`.
|
|
68
125
|
*
|
|
126
|
+
* The body of a `PolicyUnavailable` response has only its `_tag`. The cause
|
|
127
|
+
* may have private details, such as an error from the database, so it stays
|
|
128
|
+
* on the server.
|
|
129
|
+
*
|
|
69
130
|
* @stability unstable
|
|
70
131
|
* @category errors
|
|
71
132
|
* @since 0.3.0
|
|
72
133
|
*/
|
|
73
134
|
const errors = [
|
|
74
135
|
Forbidden.pipe(HttpApiSchema.status(403)),
|
|
75
|
-
|
|
136
|
+
PolicyUnavailableResponse.pipe(HttpApiSchema.status(503)),
|
|
76
137
|
Pending.pipe(HttpApiSchema.status(409))
|
|
77
138
|
];
|
|
139
|
+
const makeLayer = (middleware, authorizer) => Layer.effect(middleware, Effect.gen(function* () {
|
|
140
|
+
const service = yield* authorizer;
|
|
141
|
+
const services = yield* Effect.context();
|
|
142
|
+
return Effect.fnUntraced(function* (httpEffect, options) {
|
|
143
|
+
const requirements = Option.orElse(Context.getOption(options.endpoint.annotations, Required), () => Option.map(Context.getOption(options.group.annotations, GroupRequired), (rules) => options.endpoint.method === "GET" ? rules.read : rules.write));
|
|
144
|
+
if (Option.isNone(requirements)) return yield* Effect.die(/* @__PURE__ */ new Error(`The endpoint ${options.group.identifier}.${options.endpoint.name} does not say what it needs. Give it the HttpApi.Required annotation.`));
|
|
145
|
+
const endpoint = `${options.group.identifier}.${options.endpoint.name}`;
|
|
146
|
+
yield* Effect.forEach(requirements.value, ({ action, kind, load, within, list }) => {
|
|
147
|
+
if (load !== void 0) return HttpRouter.params.pipe(Effect.flatMap((params) => Effect.provideContext(load(params), services)), Effect.filterOrElse((value) => kindOf(value) === kind, () => Effect.die(/* @__PURE__ */ new Error(`The load function of ${endpoint} gave a value that is not a ${kind}`))), Effect.flatMap((value) => service.check({
|
|
148
|
+
action,
|
|
149
|
+
resource: value
|
|
150
|
+
})));
|
|
151
|
+
const target = within === void 0 ? Effect.succeed({
|
|
152
|
+
action,
|
|
153
|
+
kind
|
|
154
|
+
}) : Effect.map(HttpRouter.params, (params) => ({
|
|
155
|
+
action,
|
|
156
|
+
kind,
|
|
157
|
+
within: within(params)
|
|
158
|
+
}));
|
|
159
|
+
if (list === void 0) return Effect.flatMap(target, (value) => service.check(value));
|
|
160
|
+
return list.nonEmpty ? target.pipe(Effect.flatMap((value) => service.coverage(value)), Effect.filterOrElse((covered) => covered._tag === "All" || covered._tag === "Some", () => Effect.fail(Forbidden.make({
|
|
161
|
+
action,
|
|
162
|
+
kind
|
|
163
|
+
})))) : Effect.void;
|
|
164
|
+
}, { discard: true });
|
|
165
|
+
return yield* httpEffect;
|
|
166
|
+
});
|
|
167
|
+
}));
|
|
78
168
|
/**
|
|
79
169
|
* Makes the layer of an authorization middleware. The middleware reads the
|
|
80
170
|
* {@link Required} and {@link GroupRequired} annotations and checks each
|
|
@@ -89,7 +179,7 @@ const errors = [
|
|
|
89
179
|
* @category layers
|
|
90
180
|
* @since 0.3.0
|
|
91
181
|
*/
|
|
92
|
-
const layer =
|
|
93
|
-
export { GroupRequired, Required, errors, layer, requires };
|
|
182
|
+
const layer = makeLayer;
|
|
183
|
+
export { GroupRequired, Required, errors, layer, lists, requires };
|
|
94
184
|
|
|
95
185
|
//# sourceMappingURL=HttpApi.js.map
|
package/dist/HttpApi.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HttpApi.js","names":["internal.requires","internal.layer"],"sources":["../src/HttpApi.ts"],"sourcesContent":["/**\n * Tools to check authorization in an `effect/http-api` server.\n *\n * Each endpoint says what it needs with the {@link Required} annotation. A\n * group can give a default with {@link GroupRequired}: one list for GET\n * requests and one list for all other methods. A middleware checks the\n * requirements before the handler runs. An endpoint with no annotation is a\n * defect, so a new endpoint is closed until you say what it needs. An empty\n * list means the endpoint is open.\n *\n * ```ts\n * class Authorization extends HttpApiMiddleware.Service<\n * Authorization,\n * { requires: Identity }\n * >()(\"app/Authorization\", { error: HttpApi.errors }) {}\n *\n * const endpoint = HttpApiEndpoint.patch(\"update\", \"/bots/:id\", { ... })\n * .annotate(HttpApi.Required, [\n * HttpApi.requires(Auth, \"update\", \"Bot\", (params) => Bots.find(params.id)),\n * ])\n *\n * const AuthorizationLive = HttpApi.layer(Authorization, Auth)\n * ```\n *\n * This module is a separate entry point, `@nmnmcc/ability/HttpApi`, because\n * `effect/http-api` is not stable yet.\n *\n * @stability unstable\n * @since 0.3.0\n */\nimport * as Context from \"effect/Context\"\nimport type * as Effect from \"effect/Effect\"\nimport type * as Layer from \"effect/Layer\"\nimport { HttpApiSchema } from \"effect/http-api\"\nimport * as Authorizer from \"./Authorizer.ts\"\nimport type * as Domain from \"./Domain.ts\"\nimport * as internal from \"./internal/httpApi.ts\"\n\n/**\n * One check that an endpoint needs: an action on a kind of resource. With\n * `load`, the middleware loads the resource value from the path parameters\n * and checks the action on that value. Without `load`, it checks the action\n * on the kind.\n *\n * @stability unstable\n * @category models\n * @since 0.3.0\n */\nexport interface Requirement {\n\treadonly action: string\n\treadonly kind: string\n\treadonly load?: (\n\t\tparams: Readonly<Record<string, string | undefined>>,\n\t) => Effect.Effect<object, unknown, unknown>\n}\n\n/**\n * The checks that an endpoint needs.\n *\n * @stability unstable\n * @category annotations\n * @since 0.3.0\n */\nexport class Required extends Context.Service<\n\tRequired,\n\tReadonlyArray<Requirement>\n>()(\"@nmnmcc/ability/HttpApi/Required\") {}\n\n/**\n * The checks for every endpoint of a group with no {@link Required}\n * annotation. `read` is for GET requests. `write` is for all other methods.\n *\n * @stability unstable\n * @category annotations\n * @since 0.3.0\n */\nexport class GroupRequired extends Context.Service<\n\tGroupRequired,\n\t{\n\t\treadonly read: ReadonlyArray<Requirement>\n\t\treadonly write: ReadonlyArray<Requirement>\n\t}\n>()(\"@nmnmcc/ability/HttpApi/GroupRequired\") {}\n\n/**\n * Makes a {@link Requirement} with the types of an authorizer. The action must\n * be an action of the kind, and `load` must give a value of the kind.\n *\n * `load` may fail. Its errors must be errors of the middleware, and the\n * services that it needs must be given to {@link layer}.\n *\n * @stability unstable\n * @category constructors\n * @since 0.3.0\n */\nexport const requires: <\n\tA extends { readonly domain: Domain.Any },\n\tconst K extends Domain.Kind<A[\"domain\"]>,\n>(\n\tauthorizer: A,\n\taction: Domain.ActionOf<A[\"domain\"], K>,\n\tkind: K,\n\tload?: (\n\t\tparams: Readonly<Record<string, string | undefined>>,\n\t) => Effect.Effect<Domain.ValueOf<A[\"domain\"], K>, unknown, unknown>,\n) => Requirement = internal.requires\n\n/**\n * The errors of the middleware, with HTTP status codes: 403 for\n * `Forbidden`, 503 for `PolicyUnavailable`, and 409 for `Pending`.\n *\n * @stability unstable\n * @category errors\n * @since 0.3.0\n */\nexport const errors = [\n\tAuthorizer.Forbidden.pipe(HttpApiSchema.status(403)),\n\tAuthorizer.PolicyUnavailable.pipe(HttpApiSchema.status(503)),\n\tAuthorizer.Pending.pipe(HttpApiSchema.status(409)),\n] as const\n\n/**\n * Makes the layer of an authorization middleware. The middleware reads the\n * {@link Required} and {@link GroupRequired} annotations and checks each\n * requirement with the authorizer.\n *\n * The layer takes the authorizer when it is built. The middleware must\n * require the services of the authorizer, such as the identity of the\n * caller. `R` is the type of the services that the `load` functions need. The\n * layer takes them when it is built too.\n *\n * @stability unstable\n * @category layers\n * @since 0.3.0\n */\nexport const layer: <\n\tSelf,\n\tId extends string,\n\tA extends Authorizer.AnyServiceClass,\n\tR = never,\n>(\n\tmiddleware: Context.ServiceClass<Self, Id, any>,\n\tauthorizer: A,\n) => Layer.Layer<\n\tSelf,\n\tnever,\n\t(A extends Context.Key<infer I, any> ? I : never) | R\n> = internal.layer as never\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+DA,IAAa,WAAb,cAA8B,QAAQ,QAGpC,CAAC,CAAC,kCAAkC,CAAC,CAAC,CAAC;;;;;;;;;AAUzC,IAAa,gBAAb,cAAmC,QAAQ,QAMzC,CAAC,CAAC,uCAAuC,CAAC,CAAC,CAAC;;;;;;;;;;;;AAa9C,MAAa,WAUMA;;;;;;;;;AAUnB,MAAa,SAAS;CACA,UAAA,KAAK,cAAc,OAAO,GAAG,CAAC;CACtB,kBAAA,KAAK,cAAc,OAAO,GAAG,CAAC;CACxC,QAAA,KAAK,cAAc,OAAO,GAAG,CAAC;AAClD;;;;;;;;;;;;;;;AAgBA,MAAa,QAYTC"}
|
|
1
|
+
{"version":3,"file":"HttpApi.js","names":["Authorizer.PolicyUnavailable","Resource.kindOf"],"sources":["../src/HttpApi.ts"],"sourcesContent":["/**\n * Tools to check authorization in an `effect/http-api` server.\n *\n * Each endpoint says what it needs with the {@link Required} annotation. A\n * group can give a default with {@link GroupRequired}: one list for GET\n * requests and one list for all other methods. A middleware checks the\n * requirements before the handler runs, in each group that uses it. An\n * endpoint with no annotation is a defect, so a new endpoint is closed until\n * you say what it needs. An empty list means the endpoint is open. An endpoint\n * in a group without the middleware is not checked at all.\n *\n * ```ts\n * class Authorization extends HttpApiMiddleware.Service<\n * Authorization,\n * { requires: Identity }\n * >()(\"app/Authorization\", { error: HttpApi.errors }) {}\n *\n * const endpoint = HttpApiEndpoint.patch(\"update\", \"/notes/:id\", { ... })\n * .annotate(HttpApi.Required, [\n * HttpApi.requires(Auth, \"update\", \"Note\", (params) => Notes.find(params.id)),\n * ])\n *\n * const notes = HttpApiGroup.make(\"notes\").add(endpoint).middleware(Authorization)\n *\n * const AuthorizationLive = HttpApi.layer(Authorization, Auth)\n * ```\n *\n * This module is a separate entry point, `@nmnmcc/ability/HttpApi`, because\n * `effect/http-api` is not stable yet.\n *\n * @stability unstable\n * @since 0.3.0\n */\n// A `load` function of a requirement is kept in an annotation, so its error\n// type and its service type are erased to `unknown`. The language service\n// check for `unknown` in an Effect is off here.\n// @effect-diagnostics anyUnknownInErrorContext:off\nimport * as Context from \"effect/Context\"\nimport * as Effect from \"effect/Effect\"\nimport * as Layer from \"effect/Layer\"\nimport * as Option from \"effect/Option\"\nimport * as Schema from \"effect/Schema\"\nimport * as SchemaTransformation from \"effect/SchemaTransformation\"\nimport { HttpRouter } from \"effect/http\"\nimport { HttpApiSchema } from \"effect/http-api\"\nimport * as Authorizer from \"./Authorizer.ts\"\nimport type * as Domain from \"./Domain.ts\"\nimport type * as Policy from \"./Policy.ts\"\nimport * as Resource from \"./Resource.ts\"\n\n/**\n * The path parameters of a request.\n *\n * @stability unstable\n * @category models\n * @since 1.0.0\n */\nexport type Params = Readonly<Record<string, string | undefined>>\n\n/**\n * One check that an endpoint needs: an action on a kind of resource.\n * - With `load`, the middleware loads the resource value from the path\n * parameters and checks the action on that value.\n * - With `within`, it makes a scope from the path parameters and checks the\n * action on every value in the scope.\n * - With `list`, the endpoint gives a list. The handler gets the list query\n * with `Authorizer.filter`, so the middleware checks nothing, unless\n * `nonEmpty` is true: then it fails when the principal may act on no value\n * in the scope.\n * - With none of them, it checks the action on every value of the kind.\n *\n * @stability unstable\n * @category models\n * @since 0.3.0\n */\nexport interface Requirement {\n\treadonly action: string\n\treadonly kind: string\n\treadonly load?: (params: Params) => Effect.Effect<object, unknown, unknown>\n\treadonly within?: (params: Params) => unknown\n\treadonly list?: { readonly nonEmpty: boolean }\n}\n\n/**\n * The checks that an endpoint needs.\n *\n * @stability unstable\n * @category annotations\n * @since 0.3.0\n */\nexport class Required extends Context.Service<\n\tRequired,\n\tReadonlyArray<Requirement>\n>()(\"@nmnmcc/ability/HttpApi/Required\") {}\n\n/**\n * The checks for every endpoint of a group with no {@link Required}\n * annotation. `read` is for GET requests. `write` is for all other methods.\n *\n * @stability unstable\n * @category annotations\n * @since 0.3.0\n */\nexport class GroupRequired extends Context.Service<\n\tGroupRequired,\n\t{\n\t\treadonly read: ReadonlyArray<Requirement>\n\t\treadonly write: ReadonlyArray<Requirement>\n\t}\n>()(\"@nmnmcc/ability/HttpApi/GroupRequired\") {}\n\n/**\n * Makes a {@link Requirement} with the types of an authorizer. The action must\n * be an action of the kind, also when the kind has a union type.\n *\n * The last argument is one of:\n * - a `load` function, which must give a value of the kind. It may fail. Its\n * errors must be errors of the middleware, and the services that it needs\n * must be given to {@link layer}.\n * - `{ within }`, a function from the path parameters to a scope. Use it for\n * an act on a part of the kind, such as a new value with no id yet:\n * `{ within: (params) => ($) => $.under(\"org\", params.org ?? null) }`. A path\n * parameter may be `undefined`, and a scope with `undefined` in it is a\n * defect, so give a value for it.\n *\n * @stability unstable\n * @category constructors\n * @since 0.3.0\n */\nexport const requires: <\n\tA extends { readonly domain: Domain.Any },\n\tconst K extends Domain.Kind<A[\"domain\"]>,\n>(\n\tauthorizer: A,\n\taction: Domain.CommonAction<A[\"domain\"], K>,\n\tkind: K,\n\thow?:\n\t\t| ((\n\t\t\t\tparams: Params,\n\t\t ) => Effect.Effect<Domain.ValueOf<A[\"domain\"], K>, unknown, unknown>)\n\t\t| { readonly within: (params: Params) => Policy.Scope<A[\"domain\"], K> },\n) => Requirement = (_authorizer, action, kind, how) =>\n\thow === undefined\n\t\t? { action: action as string, kind }\n\t\t: typeof how === \"function\"\n\t\t\t? { action: action as string, kind, load: how }\n\t\t\t: { action: action as string, kind, within: how.within }\n\n/**\n * Makes a {@link Requirement} for an endpoint that gives a list. The middleware\n * does not check that the principal may act on every value, because the list\n * shows only the values that it may act on. The handler gets the list query\n * with `Authorizer.filter`, with the same scope.\n *\n * When the principal may act on no value, the list is empty: that is not an\n * error, so a client does not learn that hidden values are there. With\n * `nonEmpty: true`, the middleware fails with `Forbidden` in that case. It\n * also fails when the coverage is `Unknown`, because then it can not say that\n * the list has a value.\n *\n * @stability unstable\n * @category constructors\n * @since 1.0.0\n */\nexport const lists: <\n\tA extends { readonly domain: Domain.Any },\n\tconst K extends Domain.Kind<A[\"domain\"]>,\n>(\n\tauthorizer: A,\n\taction: Domain.CommonAction<A[\"domain\"], K>,\n\tkind: K,\n\toptions?: {\n\t\treadonly within?: (params: Params) => Policy.Scope<A[\"domain\"], K>\n\t\treadonly nonEmpty?: boolean\n\t},\n) => Requirement = (_authorizer, action, kind, options) => ({\n\taction: action as string,\n\tkind,\n\tlist: { nonEmpty: options?.nonEmpty ?? false },\n\t...(options?.within === undefined ? {} : { within: options.within }),\n})\n\n/**\n * The Schema of a `PolicyUnavailable` response. It encodes only the `_tag`, so\n * the cause does not go to the client.\n */\nconst PolicyUnavailableResponse = Schema.TaggedStruct(\n\t\"PolicyUnavailable\",\n\t{},\n).pipe(\n\tSchema.decodeTo(\n\t\tSchema.declare(\n\t\t\t(u): u is Authorizer.PolicyUnavailable =>\n\t\t\t\tu instanceof Authorizer.PolicyUnavailable,\n\t\t),\n\t\tSchemaTransformation.transform({\n\t\t\tdecode: () => Authorizer.PolicyUnavailable.make({ cause: undefined }),\n\t\t\tencode: () => ({ _tag: \"PolicyUnavailable\" as const }),\n\t\t}),\n\t),\n)\n\n/**\n * The errors of the middleware, with HTTP status codes: 403 for\n * `Forbidden`, 503 for `PolicyUnavailable`, and 409 for `Pending`.\n *\n * The body of a `PolicyUnavailable` response has only its `_tag`. The cause\n * may have private details, such as an error from the database, so it stays\n * on the server.\n *\n * @stability unstable\n * @category errors\n * @since 0.3.0\n */\nexport const errors = [\n\tAuthorizer.Forbidden.pipe(HttpApiSchema.status(403)),\n\tPolicyUnavailableResponse.pipe(HttpApiSchema.status(503)),\n\tAuthorizer.Pending.pipe(HttpApiSchema.status(409)),\n] as const\n\nconst makeLayer = (\n\tmiddleware: Context.ServiceClass<any, string, any>,\n\tauthorizer: Authorizer.AnyServiceClass,\n) =>\n\tLayer.effect(\n\t\tmiddleware,\n\t\tEffect.gen(function* () {\n\t\t\tconst service = yield* authorizer\n\t\t\tconst services = yield* Effect.context<never>()\n\t\t\treturn Effect.fnUntraced(function* (\n\t\t\t\thttpEffect: Effect.Effect<unknown, unknown, unknown>,\n\t\t\t\toptions: {\n\t\t\t\t\treadonly endpoint: {\n\t\t\t\t\t\treadonly name: string\n\t\t\t\t\t\treadonly method: string\n\t\t\t\t\t\treadonly annotations: Context.Context<never>\n\t\t\t\t\t}\n\t\t\t\t\treadonly group: {\n\t\t\t\t\t\treadonly identifier: string\n\t\t\t\t\t\treadonly annotations: Context.Context<never>\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t) {\n\t\t\t\tconst requirements = Option.orElse(\n\t\t\t\t\tContext.getOption(options.endpoint.annotations, Required),\n\t\t\t\t\t() =>\n\t\t\t\t\t\tOption.map(\n\t\t\t\t\t\t\tContext.getOption(options.group.annotations, GroupRequired),\n\t\t\t\t\t\t\t(rules) =>\n\t\t\t\t\t\t\t\toptions.endpoint.method === \"GET\" ? rules.read : rules.write,\n\t\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t\tif (Option.isNone(requirements)) {\n\t\t\t\t\treturn yield* Effect.die(\n\t\t\t\t\t\tnew Error(\n\t\t\t\t\t\t\t`The endpoint ${options.group.identifier}.${options.endpoint.name} does not say what it needs. Give it the HttpApi.Required annotation.`,\n\t\t\t\t\t\t),\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t\tconst endpoint = `${options.group.identifier}.${options.endpoint.name}`\n\t\t\t\t// The requirements are checked in order. The first one that fails\n\t\t\t\t// stops the request.\n\t\t\t\tyield* Effect.forEach(\n\t\t\t\t\trequirements.value,\n\t\t\t\t\t({ action, kind, load, within, list }) => {\n\t\t\t\t\t\tif (load !== undefined) {\n\t\t\t\t\t\t\treturn HttpRouter.params.pipe(\n\t\t\t\t\t\t\t\tEffect.flatMap((params) =>\n\t\t\t\t\t\t\t\t\tEffect.provideContext(load(params), services),\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t// The check is for the kind of the requirement. A value of\n\t\t\t\t\t\t\t\t// another kind is a mistake in `load`, and the check must\n\t\t\t\t\t\t\t\t// not pass with the rules of that other kind.\n\t\t\t\t\t\t\t\tEffect.filterOrElse(\n\t\t\t\t\t\t\t\t\t(value) => Resource.kindOf(value) === kind,\n\t\t\t\t\t\t\t\t\t() =>\n\t\t\t\t\t\t\t\t\t\tEffect.die(\n\t\t\t\t\t\t\t\t\t\t\tnew Error(\n\t\t\t\t\t\t\t\t\t\t\t\t`The load function of ${endpoint} gave a value that is not a ${kind}`,\n\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\tEffect.flatMap((value) =>\n\t\t\t\t\t\t\t\t\tservice.check({ action, resource: value } as never),\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst target =\n\t\t\t\t\t\t\twithin === undefined\n\t\t\t\t\t\t\t\t? Effect.succeed({ action, kind } as never)\n\t\t\t\t\t\t\t\t: Effect.map(\n\t\t\t\t\t\t\t\t\t\tHttpRouter.params,\n\t\t\t\t\t\t\t\t\t\t(params) =>\n\t\t\t\t\t\t\t\t\t\t\t({ action, kind, within: within(params) }) as never,\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\tif (list === undefined) {\n\t\t\t\t\t\t\treturn Effect.flatMap(target, (value) => service.check(value))\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// A list endpoint may give an empty list, unless it must not.\n\t\t\t\t\t\t// Only `All` and `Some` say that the list has a value. `Unknown`\n\t\t\t\t\t\t// is not a \"yes\".\n\t\t\t\t\t\treturn list.nonEmpty\n\t\t\t\t\t\t\t? target.pipe(\n\t\t\t\t\t\t\t\t\tEffect.flatMap((value) => service.coverage(value)),\n\t\t\t\t\t\t\t\t\tEffect.filterOrElse(\n\t\t\t\t\t\t\t\t\t\t(covered) =>\n\t\t\t\t\t\t\t\t\t\t\t(covered as { readonly _tag: string })._tag === \"All\" ||\n\t\t\t\t\t\t\t\t\t\t\t(covered as { readonly _tag: string })._tag === \"Some\",\n\t\t\t\t\t\t\t\t\t\t() =>\n\t\t\t\t\t\t\t\t\t\t\tEffect.fail(Authorizer.Forbidden.make({ action, kind })),\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t: Effect.void\n\t\t\t\t\t},\n\t\t\t\t\t{ discard: true },\n\t\t\t\t)\n\t\t\t\treturn yield* httpEffect\n\t\t\t})\n\t\t}),\n\t)\n\n/**\n * Makes the layer of an authorization middleware. The middleware reads the\n * {@link Required} and {@link GroupRequired} annotations and checks each\n * requirement with the authorizer.\n *\n * The layer takes the authorizer when it is built. The middleware must\n * require the services of the authorizer, such as the identity of the\n * caller. `R` is the type of the services that the `load` functions need. The\n * layer takes them when it is built too.\n *\n * @stability unstable\n * @category layers\n * @since 0.3.0\n */\nexport const layer: <\n\tSelf,\n\tId extends string,\n\tA extends Authorizer.AnyServiceClass,\n\tR = never,\n>(\n\tmiddleware: Context.ServiceClass<Self, Id, any>,\n\tauthorizer: A,\n) => Layer.Layer<\n\tSelf,\n\tnever,\n\t(A extends Context.Key<infer I, any> ? I : never) | R\n> = makeLayer as never\n"],"mappings":"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"}
|