@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.
Files changed (66) hide show
  1. package/README.md +199 -31
  2. package/dist/Authorizer.d.ts +64 -39
  3. package/dist/Authorizer.d.ts.map +1 -1
  4. package/dist/Authorizer.js +291 -6
  5. package/dist/Authorizer.js.map +1 -1
  6. package/dist/Condition.d.ts +444 -65
  7. package/dist/Condition.d.ts.map +1 -1
  8. package/dist/Condition.js +1007 -25
  9. package/dist/Condition.js.map +1 -1
  10. package/dist/Domain.d.ts +27 -17
  11. package/dist/Domain.d.ts.map +1 -1
  12. package/dist/Domain.js +52 -10
  13. package/dist/Domain.js.map +1 -1
  14. package/dist/HttpApi.d.ts +84 -40
  15. package/dist/HttpApi.d.ts.map +1 -1
  16. package/dist/HttpApi.js +103 -13
  17. package/dist/HttpApi.js.map +1 -1
  18. package/dist/Policy.d.ts +314 -56
  19. package/dist/Policy.d.ts.map +1 -1
  20. package/dist/Policy.js +1215 -38
  21. package/dist/Policy.js.map +1 -1
  22. package/dist/Principal.js +2 -2
  23. package/dist/Principal.js.map +1 -1
  24. package/dist/Resource.d.ts +171 -20
  25. package/dist/Resource.d.ts.map +1 -1
  26. package/dist/Resource.js +788 -15
  27. package/dist/Resource.js.map +1 -1
  28. package/dist/Rule.d.ts +115 -29
  29. package/dist/Rule.d.ts.map +1 -1
  30. package/dist/Rule.js +219 -12
  31. package/dist/Rule.js.map +1 -1
  32. package/dist/index.js +4 -4
  33. package/package.json +2 -2
  34. package/src/Authorizer.ts +625 -61
  35. package/src/Condition.ts +2403 -112
  36. package/src/Domain.ts +80 -23
  37. package/src/HttpApi.ts +225 -25
  38. package/src/Policy.ts +2836 -96
  39. package/src/Principal.ts +2 -2
  40. package/src/Resource.ts +1544 -29
  41. package/src/Rule.ts +463 -45
  42. package/dist/internal/authorizer.d.ts +0 -28
  43. package/dist/internal/authorizer.d.ts.map +0 -1
  44. package/dist/internal/authorizer.js +0 -153
  45. package/dist/internal/authorizer.js.map +0 -1
  46. package/dist/internal/condition.d.ts +0 -11
  47. package/dist/internal/condition.d.ts.map +0 -1
  48. package/dist/internal/condition.js +0 -393
  49. package/dist/internal/condition.js.map +0 -1
  50. package/dist/internal/domain.js +0 -34
  51. package/dist/internal/domain.js.map +0 -1
  52. package/dist/internal/httpApi.js +0 -41
  53. package/dist/internal/httpApi.js.map +0 -1
  54. package/dist/internal/policy.js +0 -524
  55. package/dist/internal/policy.js.map +0 -1
  56. package/dist/internal/resource.js +0 -66
  57. package/dist/internal/resource.js.map +0 -1
  58. package/dist/internal/rule.js +0 -131
  59. package/dist/internal/rule.js.map +0 -1
  60. package/src/internal/authorizer.ts +0 -271
  61. package/src/internal/condition.ts +0 -607
  62. package/src/internal/domain.ts +0 -56
  63. package/src/internal/httpApi.ts +0 -84
  64. package/src/internal/policy.ts +0 -815
  65. package/src/internal/resource.ts +0 -98
  66. package/src/internal/rule.ts +0 -203
@@ -1,6 +1,56 @@
1
1
  import { __exportAll } from "./_virtual/_rolldown/runtime.js";
2
- import { Forbidden as Forbidden$1, Pending as Pending$1, PolicyUnavailable as PolicyUnavailable$1, Service as Service$1, layer as layer$1 } from "./internal/authorizer.js";
2
+ import { kindOf } from "./Resource.js";
3
+ import { satisfiable } from "./Condition.js";
4
+ import { Allow, Deny, NotApplicable, reason } from "./Decision.js";
5
+ import { descriptorOf } from "./Domain.js";
6
+ import { coverage, decide, fitsKind, permittedFields, provideContext, residual, residuals, scopeHasValue } from "./Policy.js";
7
+ import * as Arr from "effect/Array";
8
+ import * as Cache from "effect/Cache";
9
+ import * as Context from "effect/Context";
10
+ import * as Effect from "effect/Effect";
11
+ import * as Equal from "effect/Equal";
12
+ import * as Hash from "effect/Hash";
13
+ import * as Layer from "effect/Layer";
14
+ import * as MutableHashMap from "effect/MutableHashMap";
15
+ import * as Option from "effect/Option";
16
+ import * as Schema from "effect/Schema";
3
17
  // src/Authorizer.ts
18
+ /**
19
+ * An authorizer is an Effect service that makes decisions for the principal
20
+ * of the current request.
21
+ *
22
+ * You make the service class, in the same way as `Context.Service`. Give the
23
+ * services that the principal and the decider need as `requires`, and their
24
+ * errors as `error`:
25
+ *
26
+ * ```ts
27
+ * class Auth extends Authorizer.Service<Auth, { requires: Identity }>()(
28
+ * "app/Auth",
29
+ * App,
30
+ * ) {}
31
+ * ```
32
+ *
33
+ * Then give a layer with {@link layer}. It says where the principal comes
34
+ * from and how to load its policy. The policy of each principal is loaded
35
+ * once and kept in a cache for a short time.
36
+ *
37
+ * Then use the service in a handler:
38
+ *
39
+ * ```ts
40
+ * yield* Auth.check({ action: "update", resource: document })
41
+ * ```
42
+ *
43
+ * A "no" answer goes into the error channel as {@link Forbidden}. When the
44
+ * policy can not be loaded, the check fails with {@link PolicyUnavailable}.
45
+ * So the check fails closed: an error is never a "yes".
46
+ *
47
+ * When no rule gives an answer, the authorizer asks the decider, if there is
48
+ * one. A decider may answer at once, or fail with {@link Pending} when a person
49
+ * or another service must answer later.
50
+ *
51
+ * @stability stable
52
+ * @since 0.3.0
53
+ */
4
54
  var Authorizer_exports = /* @__PURE__ */ __exportAll({
5
55
  Forbidden: () => Forbidden,
6
56
  Pending: () => Pending,
@@ -15,7 +65,12 @@ var Authorizer_exports = /* @__PURE__ */ __exportAll({
15
65
  * @category errors
16
66
  * @since 0.3.0
17
67
  */
18
- const Forbidden = Forbidden$1;
68
+ var Forbidden = class extends Schema.TaggedError("@nmnmcc/ability/Authorizer/Forbidden")("Forbidden", {
69
+ action: Schema.String,
70
+ kind: Schema.String,
71
+ field: Schema.optionalKey(Schema.String),
72
+ reason: Schema.optionalKey(Schema.String)
73
+ }) {};
19
74
  /**
20
75
  * The error when the policy of the principal can not be loaded. The cause is
21
76
  * kept, but it is not shown to the client.
@@ -24,7 +79,7 @@ const Forbidden = Forbidden$1;
24
79
  * @category errors
25
80
  * @since 0.3.0
26
81
  */
27
- const PolicyUnavailable = PolicyUnavailable$1;
82
+ var PolicyUnavailable = class extends Schema.TaggedError("@nmnmcc/ability/Authorizer/PolicyUnavailable")("PolicyUnavailable", { cause: Schema.Defect() }) {};
28
83
  /**
29
84
  * The error when a decider must wait for an answer. `ticket` names the
30
85
  * request that waits, so the client can come back for the answer.
@@ -33,7 +88,10 @@ const PolicyUnavailable = PolicyUnavailable$1;
33
88
  * @category errors
34
89
  * @since 0.3.0
35
90
  */
36
- const Pending = Pending$1;
91
+ var Pending = class extends Schema.TaggedError("@nmnmcc/ability/Authorizer/Pending")("Pending", {
92
+ ticket: Schema.String,
93
+ reason: Schema.optionalKey(Schema.String)
94
+ }) {};
37
95
  /**
38
96
  * Makes an authorizer service class for a domain.
39
97
  *
@@ -41,7 +99,234 @@ const Pending = Pending$1;
41
99
  * @category constructors
42
100
  * @since 0.3.0
43
101
  */
44
- const Service = Service$1;
102
+ const Service = (() => (id, domain) => {
103
+ const Base = Context.Service()(id);
104
+ return class extends Base {
105
+ static domain = domain;
106
+ static decide = (target) => this.use((service) => service.decide(target));
107
+ static check = (target) => this.use((service) => service.check(target));
108
+ static guard = (target, options) => this.use((service) => service.guard(target, options));
109
+ static filter = (target) => this.use((service) => service.filter(target));
110
+ static coverage = (target) => this.use((service) => service.coverage(target));
111
+ static permittedFields = (target) => this.use((service) => service.permittedFields(target));
112
+ };
113
+ });
114
+ /**
115
+ * A cache key for a principal. Two keys are equal when they have the same
116
+ * text, so two principals with the same value share one policy. The key also
117
+ * keeps the principal, so the cache can load its policy. A plain `Data` value
118
+ * can not do both, so the key gives its own equality with `Equal.Equal`.
119
+ */
120
+ var PrincipalKey = class PrincipalKey {
121
+ principal;
122
+ text;
123
+ constructor(principal, text) {
124
+ this.principal = principal;
125
+ this.text = text;
126
+ }
127
+ [Equal.symbol](that) {
128
+ return that instanceof PrincipalKey && that.text === this.text;
129
+ }
130
+ [Hash.symbol]() {
131
+ return Hash.string(this.text);
132
+ }
133
+ };
134
+ /**
135
+ * Tests if an array has a plain field at each index below its length. With
136
+ * one more own key for `length`, it then has no other own keys.
137
+ */
138
+ const hasEveryIndex = (value) => Arr.every(Array.from({ length: value.length }, (_, index) => index), (index) => isPlainField(value, String(index)));
139
+ /**
140
+ * Tests if an own key of an object holds plain data that the text shows: it
141
+ * can be seen in a loop over the keys, and it is not a getter.
142
+ */
143
+ const isPlainField = (value, key) => {
144
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
145
+ return descriptor !== void 0 && descriptor.enumerable === true && "value" in descriptor;
146
+ };
147
+ const isObjectLike = (value) => typeof value === "object" && value !== null || typeof value === "function";
148
+ /** Gives a number that is only for this class, in this layer. */
149
+ const classId = (classes, constructor) => {
150
+ const id = Option.getOrElse(MutableHashMap.get(classes, constructor), () => {
151
+ const fresh = MutableHashMap.size(classes);
152
+ MutableHashMap.set(classes, constructor, fresh);
153
+ return fresh;
154
+ });
155
+ return `#${String(id)}`;
156
+ };
157
+ /** The most levels of objects in a principal that the cache takes. */
158
+ const maxKeyDepth = 256;
159
+ /**
160
+ * Gives a text that names a principal value. Two values get one text only when
161
+ * they have the same types and the same data. So a string `"1"` and a bigint
162
+ * `1n` get two texts. The text keeps the class of each object, by a number
163
+ * that is its own, because two classes may have one name.
164
+ *
165
+ * It reads only the fields of plain objects and of `Schema.Class` values, and
166
+ * only when each own key is a plain field that a loop over the keys can see.
167
+ * An object of another class may keep its data where the text can not see it,
168
+ * as a `URL` does. So it gives `undefined` for such an object, unless it is a
169
+ * plain `Date`, `URL`, array, `Map` or `Set` with no extra own keys. It also
170
+ * gives `undefined` for a function, a symbol, or a value with one object in two
171
+ * places. The text can not show that two places hold the same object, and a
172
+ * loader may test it, as `set.has(value)` does.
173
+ * The private fields (`#name`) of a class can not be seen, so a principal
174
+ * class must not keep its data in them.
175
+ *
176
+ * It also gives `undefined` for a value with more than {@link maxKeyDepth}
177
+ * levels of objects. The walk calls itself for each level, so a deeper value
178
+ * could fill the stack. Such a principal is not cached.
179
+ */
180
+ const keyText = (value, seen, classes, depth = 0) => {
181
+ const plain = (text) => text;
182
+ switch (typeof value) {
183
+ case "string": return plain(`s${JSON.stringify(value)}`);
184
+ case "number": return plain(Object.is(value, -0) ? "n-0" : `n${String(value)}`);
185
+ case "bigint": return plain(`b${String(value)}`);
186
+ case "boolean": return plain(value ? "true" : "false");
187
+ case "undefined": return plain("undefined");
188
+ case "object": break;
189
+ default: return;
190
+ }
191
+ if (value === null) return plain("null");
192
+ if (seen.has(value) || depth >= maxKeyDepth) return;
193
+ seen.add(value);
194
+ const list = (items, wrap) => {
195
+ const texts = Arr.map(items, (item) => keyText(item, seen, classes, depth + 1));
196
+ return Arr.every(texts, (text) => text !== void 0) ? wrap(texts) : void 0;
197
+ };
198
+ const prototype = Object.getPrototypeOf(value);
199
+ const own = Reflect.ownKeys(value);
200
+ if (prototype === Date.prototype && own.length === 0) return `d${String(value.getTime())}`;
201
+ if (prototype === URL.prototype && own.length === 0) return `u${JSON.stringify(value.href)}`;
202
+ if (prototype === Array.prototype && own.length === value.length + 1 && hasEveryIndex(value) && !Arr.some(value, isObjectLike)) return list(value, (texts) => `[${texts.join(",")}]`);
203
+ if (prototype === Map.prototype && own.length === 0 && !Arr.some(Array.from(value.keys()), isObjectLike)) return list(Arr.flatMap(Array.from(value), ([key, item]) => [key, item]), (texts) => `Map{${texts.join(",")}}`);
204
+ if (prototype === Set.prototype && own.length === 0 && !Arr.some(Array.from(value), isObjectLike)) return list(Array.from(value), (texts) => `Set{${texts.join(",")}}`);
205
+ if ((prototype === null || prototype === Object.prototype || Schema.isSchema(prototype.constructor) && prototype.constructor.prototype === prototype) && Arr.every(own, (key) => typeof key === "string" && isPlainField(value, key))) {
206
+ const keys = own;
207
+ const name = prototype === null ? "" : classId(classes, prototype.constructor);
208
+ return list(Arr.map(keys, (key) => value[key]), (texts) => `${name}{${Arr.map(keys, (key, index) => `${JSON.stringify(key)}:${texts[index]}`).join(",")}}`);
209
+ }
210
+ };
211
+ const forbidden = (target, kind, reason) => Forbidden.make({
212
+ action: target.action,
213
+ kind,
214
+ ...target.field === void 0 ? {} : { field: target.field },
215
+ ...reason === void 0 ? {} : { reason }
216
+ });
217
+ const makeLayer = (service, options) => {
218
+ const domain = service.domain;
219
+ const classes = MutableHashMap.empty();
220
+ const keyOf = (principal) => {
221
+ const text = keyText(principal, /* @__PURE__ */ new Set(), classes);
222
+ return text === void 0 ? void 0 : new PrincipalKey(principal, text);
223
+ };
224
+ return Layer.effect(service, Effect.gen(function* () {
225
+ const services = yield* Effect.context();
226
+ const load = (principal) => options.policy(principal).pipe(Effect.provideContext(services), Effect.filterOrFail((value) => value.domain === domain, () => new globalThis.Error("The loaded policy is not a policy of this domain")), Effect.mapError((cause) => PolicyUnavailable.make({ cause })), Effect.map((value) => provideContext(value, services)));
227
+ const cache = options.cache === false ? void 0 : yield* Cache.make({
228
+ capacity: options.cache?.capacity ?? 1e3,
229
+ timeToLive: options.cache?.timeToLive ?? "30 seconds",
230
+ lookup: (key) => load(key.principal)
231
+ });
232
+ const policyFor = (principal) => {
233
+ const key = cache === void 0 ? void 0 : keyOf(principal);
234
+ if (cache === void 0 || key === void 0) return load(principal);
235
+ return Cache.get(cache, key).pipe(Effect.tapError(() => Cache.invalidate(cache, key)));
236
+ };
237
+ const withServices = (effect) => Effect.provideContext(effect, services);
238
+ const current = Effect.gen(function* () {
239
+ const principal = yield* options.principal;
240
+ return {
241
+ principal,
242
+ policy: yield* policyFor(principal)
243
+ };
244
+ });
245
+ const decideWith = Effect.fnUntraced(function* ({ principal, policy: value }, target) {
246
+ return yield* withServices(decide(value, {
247
+ ...target,
248
+ principal
249
+ }));
250
+ });
251
+ const decide$1 = (target) => Effect.flatMap(current, (snapshot) => decideWith(snapshot, target));
252
+ const kindDecision = (value, principal, target) => {
253
+ const request = {
254
+ ...target,
255
+ principal
256
+ };
257
+ const covered = coverage(value, request);
258
+ if (covered._tag === "All") return Allow({});
259
+ if (covered._tag !== "Unknown" && scopeHasValue(value, request)) {
260
+ const deny = residuals(value, request).deny;
261
+ const schema = descriptorOf(value.domain, target.kind ?? "")?.schema;
262
+ if (deny._tag === "False" || satisfiable(deny, { schema })._tag === "Unsatisfiable") return NotApplicable;
263
+ }
264
+ return Deny({});
265
+ };
266
+ const checkWith = Effect.fnUntraced(function* ({ principal, policy: value }, target) {
267
+ const kind = target.resource === void 0 ? target.kind ?? "" : kindOf(target.resource) ?? "";
268
+ const descriptor = descriptorOf(domain, kind);
269
+ if (descriptor === void 0 || !fitsKind(descriptor, target)) return yield* forbidden(target, kind, void 0);
270
+ const fromPolicy = target.resource === void 0 ? kindDecision(value, principal, target) : yield* withServices(decide(value, {
271
+ ...target,
272
+ principal
273
+ }));
274
+ const decision = fromPolicy._tag === "NotApplicable" && options.decider !== void 0 ? yield* options.decider({
275
+ ...target,
276
+ principal
277
+ }) : fromPolicy;
278
+ if (decision._tag !== "Allow") return yield* forbidden(target, kind, reason(decision));
279
+ });
280
+ const check = (target) => Effect.flatMap(current, (snapshot) => checkWith(snapshot, target));
281
+ const guard = Effect.fnUntraced(function* (target, guardOptions) {
282
+ const snapshot = yield* current;
283
+ const read = guardOptions.read ?? "read";
284
+ const { field: _field, ...rest } = target;
285
+ if ((yield* decideWith(snapshot, {
286
+ ...rest,
287
+ action: read
288
+ }))._tag !== "Allow") return yield* Effect.fail(guardOptions.hide());
289
+ if (target.action !== read || target.field !== void 0) yield* checkWith(snapshot, target);
290
+ });
291
+ const filter = (target) => Effect.map(current, ({ principal, policy: value }) => {
292
+ const request = {
293
+ ...target,
294
+ principal
295
+ };
296
+ const covered = coverage(value, request);
297
+ return covered._tag === "Unknown" ? residual(value, request) : covered.condition;
298
+ });
299
+ const coverage$1 = (target) => Effect.map(current, ({ principal, policy: value }) => coverage(value, {
300
+ ...target,
301
+ principal
302
+ }));
303
+ const permittedFields$1 = Effect.fnUntraced(function* (target) {
304
+ const { principal, policy: value } = yield* current;
305
+ return yield* withServices(permittedFields(value, {
306
+ ...target,
307
+ principal
308
+ }));
309
+ });
310
+ const invalidate = (principal) => {
311
+ if (cache === void 0) return Effect.void;
312
+ if (principal === void 0) return Cache.invalidateAll(cache);
313
+ const key = keyOf(principal);
314
+ return key === void 0 ? Effect.void : Cache.invalidate(cache, key);
315
+ };
316
+ return {
317
+ domain,
318
+ principal: options.principal,
319
+ policy: Effect.map(current, ({ policy: value }) => value),
320
+ decide: decide$1,
321
+ check,
322
+ guard,
323
+ filter,
324
+ coverage: coverage$1,
325
+ permittedFields: permittedFields$1,
326
+ invalidate
327
+ };
328
+ }));
329
+ };
45
330
  /**
46
331
  * Makes the layer of an authorizer.
47
332
  *
@@ -49,7 +334,7 @@ const Service = Service$1;
49
334
  * @category layers
50
335
  * @since 0.3.0
51
336
  */
52
- const layer = layer$1;
337
+ const layer = makeLayer;
53
338
  export { Authorizer_exports, Forbidden, Pending, PolicyUnavailable, Service, layer };
54
339
 
55
340
  //# sourceMappingURL=Authorizer.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Authorizer.js","names":["internal.Forbidden","internal.PolicyUnavailable","internal.Pending","internal.Service","internal.layer"],"sources":["../src/Authorizer.ts"],"sourcesContent":["/**\n * An authorizer is an Effect service that makes decisions for the principal\n * of the current request.\n *\n * You make the service class, in the same way as `Context.Service`. Give the\n * services that the principal and the decider need as `requires`, and their\n * errors as `error`:\n *\n * ```ts\n * class Auth extends Authorizer.Service<Auth, { requires: Identity }>()(\n * \"app/Auth\",\n * App,\n * ) {}\n * ```\n *\n * Then give a layer with {@link layer}. It says where the principal comes\n * from and how to load its policy. The policy of each principal is loaded\n * once and kept in a cache for a short time.\n *\n * Then use the service in a handler:\n *\n * ```ts\n * yield* Auth.check({ action: \"update\", resource: bot })\n * ```\n *\n * A \"no\" answer goes into the error channel as {@link Forbidden}. When the\n * policy can not be loaded, the check fails with {@link PolicyUnavailable}.\n * So the check fails closed: an error is never a \"yes\".\n *\n * When no rule gives an answer, the authorizer asks the decider, if there is\n * one. A decider may answer at once, or fail with {@link Pending} when a person\n * or a Bot must answer later.\n *\n * @stability stable\n * @since 0.3.0\n */\nimport type * as Context from \"effect/Context\"\nimport type * as Duration from \"effect/Duration\"\nimport type * as Effect from \"effect/Effect\"\nimport type * as Layer from \"effect/Layer\"\nimport type * as Condition from \"./Condition.ts\"\nimport type * as Decision from \"./Decision.ts\"\nimport type * as Domain from \"./Domain.ts\"\nimport * as internal from \"./internal/authorizer.ts\"\nimport type * as Policy from \"./Policy.ts\"\n\n/**\n * The error when a policy says no.\n *\n * @stability stable\n * @category errors\n * @since 0.3.0\n */\nexport const Forbidden: typeof internal.Forbidden = internal.Forbidden\n\n/**\n * @stability stable\n * @category errors\n * @since 0.3.0\n */\nexport type Forbidden = internal.Forbidden\n\n/**\n * The error when the policy of the principal can not be loaded. The cause is\n * kept, but it is not shown to the client.\n *\n * @stability stable\n * @category errors\n * @since 0.3.0\n */\nexport const PolicyUnavailable: typeof internal.PolicyUnavailable =\n\tinternal.PolicyUnavailable\n\n/**\n * @stability stable\n * @category errors\n * @since 0.3.0\n */\nexport type PolicyUnavailable = internal.PolicyUnavailable\n\n/**\n * The error when a decider must wait for an answer. `ticket` names the\n * request that waits, so the client can come back for the answer.\n *\n * @stability stable\n * @category errors\n * @since 0.3.0\n */\nexport const Pending: typeof internal.Pending = internal.Pending\n\n/**\n * @stability stable\n * @category errors\n * @since 0.3.0\n */\nexport type Pending = internal.Pending\n\n/**\n * The services and the errors of the principal and the decider of an\n * authorizer.\n *\n * @stability stable\n * @category models\n * @since 0.3.0\n */\nexport interface Config {\n\treadonly requires?: unknown\n\treadonly error?: unknown\n}\n\ntype RequiresOf<C> = C extends { readonly requires: infer R } ? R : never\ntype ErrorOf<C> = C extends { readonly error: infer E } ? E : never\n\n/**\n * What a check is about: an act on a resource value, or an act on a kind of\n * resource. A check on a kind passes only when the policy allows the act on\n * every value of the kind.\n *\n * @stability stable\n * @category models\n * @since 0.3.0\n */\nexport type Target<D> = Policy.Target<D> | Policy.KindTarget<D>\n\n/**\n * A request to the decider.\n *\n * @stability stable\n * @category models\n * @since 0.3.0\n */\nexport type DeciderRequest<D> = Policy.Request<D> | Policy.KindRequest<D>\n\n/**\n * The options of a guard.\n *\n * @stability stable\n * @category models\n * @since 0.3.0\n */\nexport interface GuardOptions<D, E2> {\n\t/** The action that lets the principal see the resource. The default is `\"read\"`. */\n\treadonly read?: Domain.AnyAction<D>\n\t/** The error when the principal may not see the resource. */\n\treadonly hide: () => E2\n}\n\n/**\n * The service.\n *\n * @stability stable\n * @category models\n * @since 0.3.0\n */\nexport interface Authorizer<D extends Domain.Any, E, R> {\n\treadonly domain: D\n\t/** The principal of the current request. */\n\treadonly principal: Effect.Effect<Domain.Principal<D>, E, R>\n\t/** The policy of the principal of the current request. */\n\treadonly policy: Effect.Effect<Policy.Policy<D, E>, PolicyUnavailable | E, R>\n\t/** Gives the decision of the policy. It does not ask the decider. */\n\treadonly decide: (\n\t\ttarget: Policy.Target<D>,\n\t) => Effect.Effect<Decision.Decision, PolicyUnavailable | E, R>\n\t/** Succeeds when the principal may do the act, and fails when it may not. */\n\treadonly check: (\n\t\ttarget: Target<D>,\n\t) => Effect.Effect<void, Forbidden | Pending | PolicyUnavailable | E, R>\n\t/**\n\t * Checks the read action first, and fails with the error of `hide` when the\n\t * principal may not see the resource. Then it checks the act. Use it to\n\t * answer \"not found\" to a principal that may not know that a resource\n\t * exists.\n\t */\n\treadonly guard: <E2>(\n\t\ttarget: Policy.Target<D>,\n\t\toptions: GuardOptions<D, E2>,\n\t) => Effect.Effect<void, E2 | Forbidden | Pending | PolicyUnavailable | E, R>\n\t/**\n\t * Gives the condition on resource values that the principal may act on.\n\t * Change it into a query with `Condition.fold`.\n\t */\n\treadonly filter: (\n\t\ttarget: Policy.KindTarget<D>,\n\t) => Effect.Effect<\n\t\tCondition.Condition<E, never, Condition.Opaque>,\n\t\tPolicyUnavailable | E,\n\t\tR\n\t>\n\t/** Gives the fields of a value that the principal may use. */\n\treadonly permittedFields: (\n\t\ttarget: Omit<Policy.Target<D>, \"field\">,\n\t) => Effect.Effect<ReadonlyArray<string>, PolicyUnavailable | E, R>\n\t/**\n\t * Removes the cached policy of a principal, or of every principal. Call it\n\t * after a change to the rules or roles of a principal.\n\t */\n\treadonly invalidate: (principal?: Domain.Principal<D>) => Effect.Effect<void>\n}\n\n/**\n * The class made by {@link Service}. The static functions use the service\n * from the context.\n *\n * @stability stable\n * @category models\n * @since 0.3.0\n */\nexport interface ServiceClass<\n\tSelf,\n\tId extends string,\n\tD extends Domain.Any,\n\tE,\n\tR,\n> extends Context.ServiceClass<Self, Id, Authorizer<D, E, R>> {\n\treadonly domain: D\n\treadonly decide: (\n\t\ttarget: Policy.Target<D>,\n\t) => Effect.Effect<Decision.Decision, PolicyUnavailable | E, R | Self>\n\treadonly check: (\n\t\ttarget: Target<D>,\n\t) => Effect.Effect<\n\t\tvoid,\n\t\tForbidden | Pending | PolicyUnavailable | E,\n\t\tR | Self\n\t>\n\treadonly guard: <E2>(\n\t\ttarget: Policy.Target<D>,\n\t\toptions: GuardOptions<D, E2>,\n\t) => Effect.Effect<\n\t\tvoid,\n\t\tE2 | Forbidden | Pending | PolicyUnavailable | E,\n\t\tR | Self\n\t>\n\treadonly filter: (\n\t\ttarget: Policy.KindTarget<D>,\n\t) => Effect.Effect<\n\t\tCondition.Condition<E, never, Condition.Opaque>,\n\t\tPolicyUnavailable | E,\n\t\tR | Self\n\t>\n\treadonly permittedFields: (\n\t\ttarget: Omit<Policy.Target<D>, \"field\">,\n\t) => Effect.Effect<ReadonlyArray<string>, PolicyUnavailable | E, R | Self>\n}\n\n/**\n * Any service class made by {@link Service}.\n *\n * @stability stable\n * @category models\n * @since 0.3.0\n */\nexport type AnyServiceClass = Context.Key<any, any> & {\n\treadonly domain: Domain.Any\n}\n\n/**\n * Makes an authorizer service class for a domain.\n *\n * @stability stable\n * @category constructors\n * @since 0.3.0\n */\nexport const Service: <Self, C extends Config = {}>() => <\n\tconst Id extends string,\n\tD extends Domain.Any,\n>(\n\tid: Id,\n\tdomain: D,\n) => ServiceClass<Self, Id, D, ErrorOf<C>, RequiresOf<C>> =\n\tinternal.Service as never\n\n/**\n * The options of {@link layer}.\n *\n * @stability stable\n * @category models\n * @since 0.3.0\n */\nexport interface Options<D extends Domain.Any, E, R, EL, RL, RP> {\n\t/** Gives the principal of the current request. */\n\treadonly principal: Effect.Effect<Domain.Principal<D>, E, R>\n\t/**\n\t * Loads the policy of a principal. A failure becomes\n\t * {@link PolicyUnavailable}. The services of the predicates of the policy\n\t * are taken when the layer is built.\n\t */\n\treadonly policy: (\n\t\tprincipal: Domain.Principal<D>,\n\t) => Effect.Effect<Policy.Policy<D, E, RP, any>, EL, RL>\n\t/**\n\t * Answers when no rule gives an answer. Without a decider, such a request\n\t * fails with {@link Forbidden}.\n\t */\n\treadonly decider?: (\n\t\trequest: DeciderRequest<D>,\n\t) => Effect.Effect<Decision.Decision, Pending | E, R>\n\t/**\n\t * How the policies are kept. The default keeps 1000 policies for 30 seconds.\n\t * Give `false` to load the policy for each check.\n\t */\n\treadonly cache?:\n\t\t| {\n\t\t\t\treadonly capacity?: number\n\t\t\t\treadonly timeToLive?: Duration.Input\n\t\t }\n\t\t| false\n}\n\n/**\n * Makes the layer of an authorizer.\n *\n * @stability stable\n * @category layers\n * @since 0.3.0\n */\nexport const layer: <\n\tSelf,\n\tId extends string,\n\tD extends Domain.Any,\n\tE,\n\tR,\n\tEL = never,\n\tRL = never,\n\tRP = never,\n>(\n\tservice: ServiceClass<Self, Id, D, E, R>,\n\toptions: Options<D, NoInfer<E>, NoInfer<R>, EL, RL, RP>,\n) => Layer.Layer<Self, never, RL | RP> = internal.layer as never\n"],"mappings":";;;;;;;;;;;;;;;;;AAqDA,MAAa,YAAuCA;;;;;;;;;AAiBpD,MAAa,oBACZC;;;;;;;;;AAiBD,MAAa,UAAmCC;;;;;;;;AAgLhD,MAAa,UAOZC;;;;;;;;AA8CD,MAAa,QAY4BC"}
1
+ {"version":3,"file":"Authorizer.js","names":["Policy.provideContext","Policy.decide","decide","Policy.coverage","Decision.Allow","Policy.scopeHasValue","Policy.residuals","Domain.descriptorOf","Condition.satisfiable","Decision.NotApplicable","Decision.Deny","Resource.kindOf","Policy.fitsKind","Decision.reason","Policy.residual","coverage","permittedFields","Policy.permittedFields"],"sources":["../src/Authorizer.ts"],"sourcesContent":["/**\n * An authorizer is an Effect service that makes decisions for the principal\n * of the current request.\n *\n * You make the service class, in the same way as `Context.Service`. Give the\n * services that the principal and the decider need as `requires`, and their\n * errors as `error`:\n *\n * ```ts\n * class Auth extends Authorizer.Service<Auth, { requires: Identity }>()(\n * \"app/Auth\",\n * App,\n * ) {}\n * ```\n *\n * Then give a layer with {@link layer}. It says where the principal comes\n * from and how to load its policy. The policy of each principal is loaded\n * once and kept in a cache for a short time.\n *\n * Then use the service in a handler:\n *\n * ```ts\n * yield* Auth.check({ action: \"update\", resource: document })\n * ```\n *\n * A \"no\" answer goes into the error channel as {@link Forbidden}. When the\n * policy can not be loaded, the check fails with {@link PolicyUnavailable}.\n * So the check fails closed: an error is never a \"yes\".\n *\n * When no rule gives an answer, the authorizer asks the decider, if there is\n * one. A decider may answer at once, or fail with {@link Pending} when a person\n * or another service must answer later.\n *\n * @stability stable\n * @since 0.3.0\n */\n// The service erases the error type and the service type of predicates,\n// principals and deciders to `unknown`. The public types keep them, so the\n// language service check for `unknown` in an Effect is off here.\n// @effect-diagnostics anyUnknownInErrorContext:off\nimport * as Arr from \"effect/Array\"\nimport * as Cache from \"effect/Cache\"\nimport * as Context from \"effect/Context\"\nimport type * as Duration from \"effect/Duration\"\nimport * as Effect from \"effect/Effect\"\nimport * as Equal from \"effect/Equal\"\nimport * as Hash from \"effect/Hash\"\nimport * as Layer from \"effect/Layer\"\nimport * as MutableHashMap from \"effect/MutableHashMap\"\nimport * as Option from \"effect/Option\"\nimport * as Schema from \"effect/Schema\"\nimport * as Condition from \"./Condition.ts\"\nimport * as Decision from \"./Decision.ts\"\nimport * as Domain from \"./Domain.ts\"\nimport * as Policy from \"./Policy.ts\"\nimport * as Resource from \"./Resource.ts\"\n\n/**\n * The error when a policy says no.\n *\n * @stability stable\n * @category errors\n * @since 0.3.0\n */\nexport class Forbidden extends Schema.TaggedError<Forbidden>(\n\t\"@nmnmcc/ability/Authorizer/Forbidden\",\n)(\"Forbidden\", {\n\taction: Schema.String,\n\tkind: Schema.String,\n\tfield: Schema.optionalKey(Schema.String),\n\treason: Schema.optionalKey(Schema.String),\n}) {}\n\n/**\n * The error when the policy of the principal can not be loaded. The cause is\n * kept, but it is not shown to the client.\n *\n * @stability stable\n * @category errors\n * @since 0.3.0\n */\nexport class PolicyUnavailable extends Schema.TaggedError<PolicyUnavailable>(\n\t\"@nmnmcc/ability/Authorizer/PolicyUnavailable\",\n)(\"PolicyUnavailable\", { cause: Schema.Defect() }) {}\n\n/**\n * The error when a decider must wait for an answer. `ticket` names the\n * request that waits, so the client can come back for the answer.\n *\n * @stability stable\n * @category errors\n * @since 0.3.0\n */\nexport class Pending extends Schema.TaggedError<Pending>(\n\t\"@nmnmcc/ability/Authorizer/Pending\",\n)(\"Pending\", {\n\tticket: Schema.String,\n\treason: Schema.optionalKey(Schema.String),\n}) {}\n\n/**\n * The services and the errors of the principal and the decider of an\n * authorizer.\n *\n * @stability stable\n * @category models\n * @since 0.3.0\n */\nexport interface Config {\n\treadonly requires?: unknown\n\treadonly error?: unknown\n}\n\ntype RequiresOf<C> = C extends { readonly requires: infer R } ? R : never\ntype ErrorOf<C> = C extends { readonly error: infer E } ? E : never\n\n/**\n * What a check is about: an act on a resource value, or an act on a kind of\n * resource. A check on a kind passes only when the policy allows the act on\n * every value of the kind. With a scope (`within`), it passes when the policy\n * allows the act on every value in the scope, and the scope is not empty.\n *\n * @stability stable\n * @category models\n * @since 0.3.0\n */\nexport type Target<D> = Policy.Target<D> | Policy.KindTarget<D>\n\n/**\n * A request to the decider.\n *\n * @stability stable\n * @category models\n * @since 0.3.0\n */\nexport type DeciderRequest<D> = Policy.Request<D> | Policy.KindRequest<D>\n\n/**\n * The options of a guard.\n *\n * @stability stable\n * @category models\n * @since 0.3.0\n */\nexport type GuardOptions<D, E2, K extends string = Domain.Kind<D>> = {\n\t/** The error when the principal may not see the resource. */\n\treadonly hide: () => E2\n} & (\"read\" extends Domain.CommonAction<D, K>\n\t? {\n\t\t\t/**\n\t\t\t * The action that lets the principal see the resource. It must be an\n\t\t\t * action of every kind in `K`. The default is `\"read\"`.\n\t\t\t */\n\t\t\treadonly read?: Domain.CommonAction<D, K>\n\t\t}\n\t: {\n\t\t\t/**\n\t\t\t * The action that lets the principal see the resource. It must be an\n\t\t\t * action of every kind in `K`. Some kind in `K` has no `\"read\"`\n\t\t\t * action, so you must give it.\n\t\t\t */\n\t\t\treadonly read: Domain.CommonAction<D, K>\n\t\t})\n\n/**\n * The service.\n *\n * @stability stable\n * @category models\n * @since 0.3.0\n */\nexport interface Authorizer<D extends Domain.Any, E, R> {\n\treadonly domain: D\n\t/** The principal of the current request. */\n\treadonly principal: Effect.Effect<Domain.Principal<D>, E, R>\n\t/**\n\t * The policy of the principal of the current request. Its predicates have\n\t * the services of the layer. It may have predicates, so it is opaque.\n\t */\n\treadonly policy: Effect.Effect<\n\t\tPolicy.Policy<D, E, never, Condition.Opaque>,\n\t\tPolicyUnavailable | E,\n\t\tR\n\t>\n\t/** Gives the decision of the policy. It does not ask the decider. */\n\treadonly decide: (\n\t\ttarget: Policy.Target<D>,\n\t) => Effect.Effect<Decision.Decision, PolicyUnavailable | E, R>\n\t/** Succeeds when the principal may do the act, and fails when it may not. */\n\treadonly check: (\n\t\ttarget: Target<D>,\n\t) => Effect.Effect<void, Forbidden | Pending | PolicyUnavailable | E, R>\n\t/**\n\t * Checks the read action first, and fails with the error of `hide` when the\n\t * principal may not see the resource. Then it checks the act. Use it to\n\t * answer \"not found\" to a principal that may not know that a resource\n\t * exists.\n\t */\n\treadonly guard: <const T extends Policy.Target<D>, E2>(\n\t\ttarget: T,\n\t\toptions: GuardOptions<D, E2, T[\"resource\"][\"_tag\"]>,\n\t) => Effect.Effect<void, E2 | Forbidden | Pending | PolicyUnavailable | E, R>\n\t/**\n\t * Gives the condition on resource values that the principal may act on,\n\t * inside the scope of the target when it has one. Change it into a query\n\t * with `Condition.fold`. It is `False` when the principal may act on no\n\t * value, so the list is empty: it is not an error.\n\t */\n\treadonly filter: <const T extends Policy.KindTarget<D>>(\n\t\ttarget: T,\n\t) => Effect.Effect<\n\t\tCondition.Condition<\n\t\t\tE,\n\t\t\tnever,\n\t\t\tCondition.Opaque,\n\t\t\tPolicy.ResidualReads<D, T[\"kind\"]>\n\t\t>,\n\t\tPolicyUnavailable | E,\n\t\tR\n\t>\n\t/**\n\t * Tells if the principal may act on all, none or some of the values in\n\t * the scope of the target. See `Policy.coverage`. Use it to show a button\n\t * only when the answer is not `None`.\n\t */\n\treadonly coverage: <const T extends Policy.KindTarget<D>>(\n\t\ttarget: T,\n\t) => Effect.Effect<\n\t\tPolicy.Coverage<\n\t\t\tE,\n\t\t\tnever,\n\t\t\tCondition.Opaque,\n\t\t\tPolicy.ResidualReads<D, T[\"kind\"]>\n\t\t>,\n\t\tPolicyUnavailable | E,\n\t\tR\n\t>\n\t/** Gives the fields of a value that the principal may use. */\n\treadonly permittedFields: (\n\t\ttarget: Policy.FieldlessTarget<D>,\n\t) => Effect.Effect<ReadonlyArray<string>, PolicyUnavailable | E, R>\n\t/**\n\t * Removes the cached policy of a principal, or of every principal. Call it\n\t * after a change to the rules or roles of a principal.\n\t */\n\treadonly invalidate: (principal?: Domain.Principal<D>) => Effect.Effect<void>\n}\n\n/**\n * The class made by {@link Service}. The static functions use the service\n * from the context.\n *\n * @stability stable\n * @category models\n * @since 0.3.0\n */\nexport interface ServiceClass<\n\tSelf,\n\tId extends string,\n\tD extends Domain.Any,\n\tE,\n\tR,\n> extends Context.ServiceClass<Self, Id, Authorizer<D, E, R>> {\n\treadonly domain: D\n\treadonly decide: (\n\t\ttarget: Policy.Target<D>,\n\t) => Effect.Effect<Decision.Decision, PolicyUnavailable | E, R | Self>\n\treadonly check: (\n\t\ttarget: Target<D>,\n\t) => Effect.Effect<\n\t\tvoid,\n\t\tForbidden | Pending | PolicyUnavailable | E,\n\t\tR | Self\n\t>\n\treadonly guard: <const T extends Policy.Target<D>, E2>(\n\t\ttarget: T,\n\t\toptions: GuardOptions<D, E2, T[\"resource\"][\"_tag\"]>,\n\t) => Effect.Effect<\n\t\tvoid,\n\t\tE2 | Forbidden | Pending | PolicyUnavailable | E,\n\t\tR | Self\n\t>\n\treadonly filter: <const T extends Policy.KindTarget<D>>(\n\t\ttarget: T,\n\t) => Effect.Effect<\n\t\tCondition.Condition<\n\t\t\tE,\n\t\t\tnever,\n\t\t\tCondition.Opaque,\n\t\t\tPolicy.ResidualReads<D, T[\"kind\"]>\n\t\t>,\n\t\tPolicyUnavailable | E,\n\t\tR | Self\n\t>\n\treadonly coverage: <const T extends Policy.KindTarget<D>>(\n\t\ttarget: T,\n\t) => Effect.Effect<\n\t\tPolicy.Coverage<\n\t\t\tE,\n\t\t\tnever,\n\t\t\tCondition.Opaque,\n\t\t\tPolicy.ResidualReads<D, T[\"kind\"]>\n\t\t>,\n\t\tPolicyUnavailable | E,\n\t\tR | Self\n\t>\n\treadonly permittedFields: (\n\t\ttarget: Policy.FieldlessTarget<D>,\n\t) => Effect.Effect<ReadonlyArray<string>, PolicyUnavailable | E, R | Self>\n}\n\n/**\n * Any service class made by {@link Service}.\n *\n * @stability stable\n * @category models\n * @since 0.3.0\n */\nexport type AnyServiceClass = Context.Key<any, any> & {\n\treadonly domain: Domain.Any\n}\n\n/**\n * Makes an authorizer service class for a domain.\n *\n * @stability stable\n * @category constructors\n * @since 0.3.0\n */\nexport const Service: <Self, C extends Config = {}>() => <\n\tconst Id extends string,\n\tD extends Domain.Any,\n>(\n\tid: Id,\n\tdomain: D,\n) => ServiceClass<Self, Id, D, ErrorOf<C>, RequiresOf<C>> = (() =>\n\t(id: string, domain: Domain.Any) => {\n\t\tconst Base = Context.Service<any, any>()(id)\n\t\treturn class extends Base {\n\t\t\tstatic readonly domain = domain\n\t\t\tstatic readonly decide = (target: AnyTarget) =>\n\t\t\t\tthis.use((service: any) => service.decide(target))\n\t\t\tstatic readonly check = (target: AnyTarget) =>\n\t\t\t\tthis.use((service: any) => service.check(target))\n\t\t\tstatic readonly guard = (target: AnyTarget, options: unknown) =>\n\t\t\t\tthis.use((service: any) => service.guard(target, options))\n\t\t\tstatic readonly filter = (target: AnyTarget) =>\n\t\t\t\tthis.use((service: any) => service.filter(target))\n\t\t\tstatic readonly coverage = (target: AnyTarget) =>\n\t\t\t\tthis.use((service: any) => service.coverage(target))\n\t\t\tstatic readonly permittedFields = (target: AnyTarget) =>\n\t\t\t\tthis.use((service: any) => service.permittedFields(target))\n\t\t}\n\t}) as never\n\ntype AnyTarget = {\n\treadonly action: string\n\treadonly resource?: object\n\treadonly kind?: string\n\treadonly field?: string\n\treadonly within?: unknown\n}\n\n/**\n * The options of {@link layer}.\n *\n * @stability stable\n * @category models\n * @since 0.3.0\n */\nexport interface Options<D extends Domain.Any, E, R, EL, RL, RP> {\n\t/** Gives the principal of the current request. */\n\treadonly principal: Effect.Effect<Domain.Principal<D>, E, R>\n\t/**\n\t * Loads the policy of a principal. A failure becomes\n\t * {@link PolicyUnavailable}. The services of the predicates of the policy\n\t * are taken when the layer is built.\n\t */\n\treadonly policy: (\n\t\tprincipal: Domain.Principal<D>,\n\t) => Effect.Effect<Policy.Policy<D, E, RP, any>, EL, RL>\n\t/**\n\t * Answers when no rule gives an answer. Without a decider, such a request\n\t * fails with {@link Forbidden}.\n\t */\n\treadonly decider?: (\n\t\trequest: DeciderRequest<D>,\n\t) => Effect.Effect<Decision.Decision, Pending | E, R>\n\t/**\n\t * How the policies are kept. The default keeps 1000 policies for 30 seconds.\n\t * Give `false` to load the policy for each check.\n\t *\n\t * Two principals with the same data get one policy from the cache. So the\n\t * loader must decide by the data of the principal only. When it tests that\n\t * an object of the principal is a given object, as `role === admin` does,\n\t * give `false`. A principal with objects in an array, a set or the keys of\n\t * a map is not kept, because such tests are usual there.\n\t */\n\treadonly cache?:\n\t\t| {\n\t\t\t\treadonly capacity?: number\n\t\t\t\treadonly timeToLive?: Duration.Input\n\t\t }\n\t\t| false\n}\n\n/**\n * A cache key for a principal. Two keys are equal when they have the same\n * text, so two principals with the same value share one policy. The key also\n * keeps the principal, so the cache can load its policy. A plain `Data` value\n * can not do both, so the key gives its own equality with `Equal.Equal`.\n */\nclass PrincipalKey implements Equal.Equal {\n\treadonly principal: object\n\treadonly text: string\n\tconstructor(principal: object, text: string) {\n\t\tthis.principal = principal\n\t\tthis.text = text\n\t}\n\t[Equal.symbol](that: unknown): boolean {\n\t\treturn that instanceof PrincipalKey && that.text === this.text\n\t}\n\t[Hash.symbol](): number {\n\t\treturn Hash.string(this.text)\n\t}\n}\n\n/**\n * Tests if an array has a plain field at each index below its length. With\n * one more own key for `length`, it then has no other own keys.\n */\nconst hasEveryIndex = (value: Array<unknown>): boolean =>\n\tArr.every(\n\t\tArray.from({ length: value.length }, (_, index) => index),\n\t\t(index) => isPlainField(value, String(index)),\n\t)\n\n/**\n * Tests if an own key of an object holds plain data that the text shows: it\n * can be seen in a loop over the keys, and it is not a getter.\n */\nconst isPlainField = (value: object, key: string): boolean => {\n\tconst descriptor = Object.getOwnPropertyDescriptor(value, key)\n\treturn (\n\t\tdescriptor !== undefined &&\n\t\tdescriptor.enumerable === true &&\n\t\t\"value\" in descriptor\n\t)\n}\n\nconst isObjectLike = (value: unknown): boolean =>\n\t(typeof value === \"object\" && value !== null) || typeof value === \"function\"\n\n/**\n * The number of each class that a key has seen. Each layer has its own, so\n * no state is kept for the whole program. A class is a function, and `Equal`\n * compares functions by the function itself.\n */\ntype ClassIds = MutableHashMap.MutableHashMap<object, number>\n\n/** Gives a number that is only for this class, in this layer. */\nconst classId = (classes: ClassIds, constructor: object): string => {\n\tconst id = Option.getOrElse(MutableHashMap.get(classes, constructor), () => {\n\t\tconst fresh = MutableHashMap.size(classes)\n\t\tMutableHashMap.set(classes, constructor, fresh)\n\t\treturn fresh\n\t})\n\treturn `#${String(id)}`\n}\n\n/** The most levels of objects in a principal that the cache takes. */\nconst maxKeyDepth = 256\n\n/**\n * Gives a text that names a principal value. Two values get one text only when\n * they have the same types and the same data. So a string `\"1\"` and a bigint\n * `1n` get two texts. The text keeps the class of each object, by a number\n * that is its own, because two classes may have one name.\n *\n * It reads only the fields of plain objects and of `Schema.Class` values, and\n * only when each own key is a plain field that a loop over the keys can see.\n * An object of another class may keep its data where the text can not see it,\n * as a `URL` does. So it gives `undefined` for such an object, unless it is a\n * plain `Date`, `URL`, array, `Map` or `Set` with no extra own keys. It also\n * gives `undefined` for a function, a symbol, or a value with one object in two\n * places. The text can not show that two places hold the same object, and a\n * loader may test it, as `set.has(value)` does.\n * The private fields (`#name`) of a class can not be seen, so a principal\n * class must not keep its data in them.\n *\n * It also gives `undefined` for a value with more than {@link maxKeyDepth}\n * levels of objects. The walk calls itself for each level, so a deeper value\n * could fill the stack. Such a principal is not cached.\n */\nconst keyText = (\n\tvalue: unknown,\n\tseen: Set<object>,\n\tclasses: ClassIds,\n\tdepth: number = 0,\n): string | undefined => {\n\tconst plain = (text: string): string => text\n\tswitch (typeof value) {\n\t\tcase \"string\":\n\t\t\treturn plain(`s${JSON.stringify(value)}`)\n\t\tcase \"number\":\n\t\t\treturn plain(Object.is(value, -0) ? \"n-0\" : `n${String(value)}`)\n\t\tcase \"bigint\":\n\t\t\treturn plain(`b${String(value)}`)\n\t\tcase \"boolean\":\n\t\t\treturn plain(value ? \"true\" : \"false\")\n\t\tcase \"undefined\":\n\t\t\treturn plain(\"undefined\")\n\t\tcase \"object\":\n\t\t\tbreak\n\t\tdefault:\n\t\t\treturn undefined\n\t}\n\tif (value === null) {\n\t\treturn plain(\"null\")\n\t}\n\tif (seen.has(value) || depth >= maxKeyDepth) {\n\t\treturn undefined\n\t}\n\tseen.add(value)\n\tconst list = (\n\t\titems: ReadonlyArray<unknown>,\n\t\twrap: (texts: ReadonlyArray<string>) => string,\n\t): string | undefined => {\n\t\tconst texts = Arr.map(items, (item) =>\n\t\t\tkeyText(item, seen, classes, depth + 1),\n\t\t)\n\t\treturn Arr.every(texts, (text) => text !== undefined)\n\t\t\t? wrap(texts as ReadonlyArray<string>)\n\t\t\t: undefined\n\t}\n\tconst prototype: unknown = Object.getPrototypeOf(value)\n\t// The own keys of the value. A built-in value keeps its data inside, so it\n\t// may have no own keys, and the elements of an array are its own keys. An\n\t// extra own key is data that the text does not show.\n\tconst own = Reflect.ownKeys(value)\n\t// The entries of a map or a set keep their order, because a loader may read\n\t// the first one.\n\tif (prototype === Date.prototype && own.length === 0) {\n\t\treturn `d${String((value as Date).getTime())}`\n\t}\n\tif (prototype === URL.prototype && own.length === 0) {\n\t\treturn `u${JSON.stringify((value as URL).href)}`\n\t}\n\tif (\n\t\tprototype === Array.prototype &&\n\t\town.length === (value as Array<unknown>).length + 1 &&\n\t\thasEveryIndex(value as Array<unknown>) &&\n\t\t// An array finds an object by the object itself, as in\n\t\t// `roles.includes(admin)`.\n\t\t!Arr.some(value as Array<unknown>, isObjectLike)\n\t) {\n\t\treturn list(value as Array<unknown>, (texts) => `[${texts.join(\",\")}]`)\n\t}\n\tif (\n\t\tprototype === Map.prototype &&\n\t\town.length === 0 &&\n\t\t// A map finds an object key by the object itself, not by its data, as\n\t\t// in `map.get(role)`. The text can not show which object it is.\n\t\t!Arr.some(Array.from((value as Map<unknown, unknown>).keys()), isObjectLike)\n\t) {\n\t\t// The keys and the values go in one list, so a value that is an object\n\t\t// does not go through the test of the elements of an array.\n\t\treturn list(\n\t\t\tArr.flatMap(Array.from(value as Map<unknown, unknown>), ([key, item]) => [\n\t\t\t\tkey,\n\t\t\t\titem,\n\t\t\t]),\n\t\t\t(texts) => `Map{${texts.join(\",\")}}`,\n\t\t)\n\t}\n\tif (\n\t\tprototype === Set.prototype &&\n\t\town.length === 0 &&\n\t\t// A set finds an object by the object itself, as in `set.has(role)`.\n\t\t!Arr.some(Array.from(value as Set<unknown>), isObjectLike)\n\t) {\n\t\treturn list(\n\t\t\tArray.from(value as Set<unknown>),\n\t\t\t(texts) => `Set{${texts.join(\",\")}}`,\n\t\t)\n\t}\n\tif (\n\t\t(prototype === null ||\n\t\t\tprototype === Object.prototype ||\n\t\t\t// The prototype must be the prototype of the class itself. A value\n\t\t\t// made with `Object.create(user)` has `user` as its prototype, and\n\t\t\t// the data of `user` is not in the own keys. Such a prototype may\n\t\t\t// have its own `constructor` key, so the test compares the\n\t\t\t// prototype with the `prototype` of the class.\n\t\t\t(Schema.isSchema((prototype as object).constructor) &&\n\t\t\t\t(prototype as object).constructor.prototype === prototype)) &&\n\t\tArr.every(own, (key) => typeof key === \"string\" && isPlainField(value, key))\n\t) {\n\t\t// The keys keep their order, because a loader may read the first one.\n\t\tconst keys = own as ReadonlyArray<string>\n\t\tconst name =\n\t\t\tprototype === null\n\t\t\t\t? \"\"\n\t\t\t\t: classId(classes, (prototype as object).constructor)\n\t\treturn list(\n\t\t\tArr.map(keys, (key) => (value as Record<string, unknown>)[key]),\n\t\t\t(texts) =>\n\t\t\t\t`${name}{${Arr.map(keys, (key, index) => `${JSON.stringify(key)}:${texts[index]!}`).join(\",\")}}`,\n\t\t)\n\t}\n\treturn undefined\n}\n\nconst forbidden = (\n\ttarget: AnyTarget,\n\tkind: string,\n\treason: string | undefined,\n): Forbidden =>\n\tForbidden.make({\n\t\taction: target.action,\n\t\tkind,\n\t\t...(target.field === undefined ? {} : { field: target.field }),\n\t\t...(reason === undefined ? {} : { reason }),\n\t})\n\nconst makeLayer = (\n\tservice: AnyServiceClass,\n\toptions: {\n\t\treadonly principal: Effect.Effect<object, unknown, unknown>\n\t\treadonly policy: (\n\t\t\tprincipal: object,\n\t\t) => Effect.Effect<Policy.Any, unknown, unknown>\n\t\treadonly decider?: (\n\t\t\trequest: object,\n\t\t) => Effect.Effect<Decision.Decision, unknown, unknown>\n\t\treadonly cache?:\n\t\t\t| { readonly capacity?: number; readonly timeToLive?: Duration.Input }\n\t\t\t| false\n\t},\n) => {\n\tconst domain: Domain.Any = service.domain\n\t// It gives `undefined` when the principal has no key. Such a principal does\n\t// not use the cache.\n\tconst classes: ClassIds = MutableHashMap.empty()\n\tconst keyOf = (principal: object): PrincipalKey | undefined => {\n\t\t// One set of seen objects for the walk: the walk adds each object to it,\n\t\t// and the set goes away when the key is made.\n\t\tconst text = keyText(principal, new Set(), classes)\n\t\treturn text === undefined ? undefined : new PrincipalKey(principal, text)\n\t}\n\treturn Layer.effect(\n\t\tservice,\n\t\tEffect.gen(function* () {\n\t\t\t// The services of the policy loader and of the predicates come from the\n\t\t\t// layer, so a check does not need them.\n\t\t\tconst services = yield* Effect.context<never>()\n\n\t\t\t// The predicates of the policy get the services of the layer, so the\n\t\t\t// policy and its residual conditions need no services.\n\t\t\t// A policy of another domain may have the same types, but its resources\n\t\t\t// may have other paths. So it fails closed, as a policy that can not be\n\t\t\t// loaded.\n\t\t\tconst load = (principal: object) =>\n\t\t\t\toptions.policy(principal).pipe(\n\t\t\t\t\tEffect.provideContext(services),\n\t\t\t\t\tEffect.filterOrFail(\n\t\t\t\t\t\t(value) => value.domain === domain,\n\t\t\t\t\t\t() =>\n\t\t\t\t\t\t\tnew globalThis.Error(\n\t\t\t\t\t\t\t\t\"The loaded policy is not a policy of this domain\",\n\t\t\t\t\t\t\t),\n\t\t\t\t\t),\n\t\t\t\t\tEffect.mapError((cause) => PolicyUnavailable.make({ cause })),\n\t\t\t\t\tEffect.map((value) =>\n\t\t\t\t\t\tPolicy.provideContext(value, services as never),\n\t\t\t\t\t),\n\t\t\t\t)\n\n\t\t\tconst cache =\n\t\t\t\toptions.cache === false\n\t\t\t\t\t? undefined\n\t\t\t\t\t: yield* Cache.make({\n\t\t\t\t\t\t\tcapacity: options.cache?.capacity ?? 1000,\n\t\t\t\t\t\t\ttimeToLive: options.cache?.timeToLive ?? \"30 seconds\",\n\t\t\t\t\t\t\tlookup: (key: PrincipalKey) => load(key.principal),\n\t\t\t\t\t\t})\n\n\t\t\tconst policyFor = (principal: object) => {\n\t\t\t\tconst key = cache === undefined ? undefined : keyOf(principal)\n\t\t\t\tif (cache === undefined || key === undefined) {\n\t\t\t\t\treturn load(principal)\n\t\t\t\t}\n\t\t\t\t// A failed lookup is kept in the cache. Remove it, so the next check\n\t\t\t\t// tries again.\n\t\t\t\treturn Cache.get(cache, key).pipe(\n\t\t\t\t\tEffect.tapError(() => Cache.invalidate(cache, key)),\n\t\t\t\t)\n\t\t\t}\n\n\t\t\tconst withServices = <A, E>(\n\t\t\t\teffect: Effect.Effect<A, E, unknown>,\n\t\t\t): Effect.Effect<A, E, unknown> => Effect.provideContext(effect, services)\n\n\t\t\tconst current = Effect.gen(function* () {\n\t\t\t\tconst principal = yield* options.principal\n\t\t\t\tconst value = yield* policyFor(principal)\n\t\t\t\treturn { principal, policy: value }\n\t\t\t})\n\n\t\t\t// The principal and its policy, loaded one time. A check that asks\n\t\t\t// the policy two times, such as `guard`, uses one snapshot for both,\n\t\t\t// so the two answers come from one principal.\n\t\t\ttype Snapshot = Effect.Success<typeof current>\n\n\t\t\tconst decideWith = Effect.fnUntraced(function* (\n\t\t\t\t{ principal, policy: value }: Snapshot,\n\t\t\t\ttarget: AnyTarget,\n\t\t\t) {\n\t\t\t\tconst decision: Decision.Decision = yield* withServices(\n\t\t\t\t\tPolicy.decide(value, { ...target, principal } as never),\n\t\t\t\t)\n\t\t\t\treturn decision\n\t\t\t})\n\n\t\t\tconst decide = (target: AnyTarget) =>\n\t\t\t\tEffect.flatMap(current, (snapshot) => decideWith(snapshot, target))\n\n\t\t\tconst kindDecision = (\n\t\t\t\tvalue: Policy.Any,\n\t\t\t\tprincipal: object,\n\t\t\t\ttarget: AnyTarget,\n\t\t\t): Decision.Decision => {\n\t\t\t\tconst request = { ...target, principal } as never\n\t\t\t\tconst covered = Policy.coverage(value, request)\n\t\t\t\tif (covered._tag === \"All\") {\n\t\t\t\t\treturn Decision.Allow({})\n\t\t\t\t}\n\t\t\t\t// The decider may answer for the scope only when no value in it is\n\t\t\t\t// denied, and when no predicate may fail. Else some value may get a\n\t\t\t\t// \"no\" from the policy, so the answer for the scope is \"no\". An\n\t\t\t\t// unknown answer may hide a denied value, so it is a \"no\" too.\n\t\t\t\t// An empty scope never passes, so the decider is not asked for it.\n\t\t\t\t// A scope that the search can not say has a value may be empty, so\n\t\t\t\t// the decider is not asked for it either.\n\t\t\t\tif (\n\t\t\t\t\tcovered._tag !== \"Unknown\" &&\n\t\t\t\t\tPolicy.scopeHasValue(value, request)\n\t\t\t\t) {\n\t\t\t\t\tconst deny: Condition.Ast = Policy.residuals(value, request).deny\n\t\t\t\t\tconst schema = Domain.descriptorOf(\n\t\t\t\t\t\tvalue.domain,\n\t\t\t\t\t\ttarget.kind ?? \"\",\n\t\t\t\t\t)?.schema\n\t\t\t\t\tif (\n\t\t\t\t\t\tdeny._tag === \"False\" ||\n\t\t\t\t\t\tCondition.satisfiable(deny as Condition.Condition, { schema })\n\t\t\t\t\t\t\t._tag === \"Unsatisfiable\"\n\t\t\t\t\t) {\n\t\t\t\t\t\treturn Decision.NotApplicable\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn Decision.Deny({})\n\t\t\t}\n\n\t\t\tconst checkWith = Effect.fnUntraced(function* (\n\t\t\t\t{ principal, policy: value }: Snapshot,\n\t\t\t\ttarget: AnyTarget,\n\t\t\t) {\n\t\t\t\tconst kind =\n\t\t\t\t\ttarget.resource === undefined\n\t\t\t\t\t\t? (target.kind ?? \"\")\n\t\t\t\t\t\t: (Resource.kindOf(target.resource) ?? \"\")\n\t\t\t\t// A request that does not fit its kind gets a \"no\" at once. The\n\t\t\t\t// decider must not say yes to an action that the kind does not have.\n\t\t\t\tconst descriptor = Domain.descriptorOf(domain, kind)\n\t\t\t\tif (descriptor === undefined || !Policy.fitsKind(descriptor, target)) {\n\t\t\t\t\treturn yield* forbidden(target, kind, undefined)\n\t\t\t\t}\n\t\t\t\tconst fromPolicy: Decision.Decision =\n\t\t\t\t\ttarget.resource === undefined\n\t\t\t\t\t\t? kindDecision(value, principal, target)\n\t\t\t\t\t\t: yield* withServices(\n\t\t\t\t\t\t\t\tPolicy.decide(value, { ...target, principal } as never),\n\t\t\t\t\t\t\t)\n\t\t\t\t// When no rule gives an answer, the decider gives it.\n\t\t\t\tconst decision: Decision.Decision =\n\t\t\t\t\tfromPolicy._tag === \"NotApplicable\" && options.decider !== undefined\n\t\t\t\t\t\t? yield* options.decider({ ...target, principal })\n\t\t\t\t\t\t: fromPolicy\n\t\t\t\tif (decision._tag !== \"Allow\") {\n\t\t\t\t\treturn yield* forbidden(target, kind, Decision.reason(decision))\n\t\t\t\t}\n\t\t\t})\n\n\t\t\tconst check = (target: AnyTarget) =>\n\t\t\t\tEffect.flatMap(current, (snapshot) => checkWith(snapshot, target))\n\n\t\t\tconst guard = Effect.fnUntraced(function* (\n\t\t\t\ttarget: AnyTarget,\n\t\t\t\tguardOptions: {\n\t\t\t\t\treadonly read?: string\n\t\t\t\t\treadonly hide: () => unknown\n\t\t\t\t},\n\t\t\t) {\n\t\t\t\tconst snapshot = yield* current\n\t\t\t\tconst read = guardOptions.read ?? \"read\"\n\t\t\t\tconst { field: _field, ...rest } = target\n\t\t\t\tconst visible: Decision.Decision = yield* decideWith(snapshot, {\n\t\t\t\t\t...rest,\n\t\t\t\t\taction: read,\n\t\t\t\t})\n\t\t\t\tif (visible._tag !== \"Allow\") {\n\t\t\t\t\treturn yield* Effect.fail(guardOptions.hide())\n\t\t\t\t}\n\t\t\t\tif (target.action !== read || target.field !== undefined) {\n\t\t\t\t\tyield* checkWith(snapshot, target)\n\t\t\t\t}\n\t\t\t})\n\n\t\t\t// The filter is the condition of the coverage. When the coverage is\n\t\t\t// not known, it is the residual condition in the scope, which throws\n\t\t\t// an error when there is none, so the filter fails.\n\t\t\tconst filter = (\n\t\t\t\ttarget: AnyTarget,\n\t\t\t): Effect.Effect<Condition.Ast, unknown, unknown> =>\n\t\t\t\tEffect.map(current, ({ principal, policy: value }): Condition.Ast => {\n\t\t\t\t\tconst request = { ...target, principal } as never\n\t\t\t\t\tconst covered = Policy.coverage(value, request)\n\t\t\t\t\treturn covered._tag === \"Unknown\"\n\t\t\t\t\t\t? Policy.residual(value, request)\n\t\t\t\t\t\t: (covered.condition as Condition.Ast)\n\t\t\t\t})\n\n\t\t\tconst coverage = (\n\t\t\t\ttarget: AnyTarget,\n\t\t\t): Effect.Effect<Policy.Coverage<any, any, any, any>, unknown, unknown> =>\n\t\t\t\tEffect.map(current, ({ principal, policy: value }) =>\n\t\t\t\t\tPolicy.coverage(value, { ...target, principal } as never),\n\t\t\t\t)\n\n\t\t\tconst permittedFields = Effect.fnUntraced(function* (target: AnyTarget) {\n\t\t\t\tconst { principal, policy: value } = yield* current\n\t\t\t\treturn yield* withServices(\n\t\t\t\t\tPolicy.permittedFields(value, { ...target, principal } as never),\n\t\t\t\t)\n\t\t\t})\n\n\t\t\tconst invalidate = (principal?: object) => {\n\t\t\t\tif (cache === undefined) {\n\t\t\t\t\treturn Effect.void\n\t\t\t\t}\n\t\t\t\tif (principal === undefined) {\n\t\t\t\t\treturn Cache.invalidateAll(cache)\n\t\t\t\t}\n\t\t\t\tconst key = keyOf(principal)\n\t\t\t\treturn key === undefined ? Effect.void : Cache.invalidate(cache, key)\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tdomain,\n\t\t\t\tprincipal: options.principal,\n\t\t\t\tpolicy: Effect.map(current, ({ policy: value }) => value),\n\t\t\t\tdecide,\n\t\t\t\tcheck,\n\t\t\t\tguard,\n\t\t\t\tfilter,\n\t\t\t\tcoverage,\n\t\t\t\tpermittedFields,\n\t\t\t\tinvalidate,\n\t\t\t} as never\n\t\t}),\n\t)\n}\n\n/**\n * Makes the layer of an authorizer.\n *\n * @stability stable\n * @category layers\n * @since 0.3.0\n */\nexport const layer: <\n\tSelf,\n\tId extends string,\n\tD extends Domain.Any,\n\tE,\n\tR,\n\tEL = never,\n\tRL = never,\n\tRP = never,\n>(\n\tservice: ServiceClass<Self, Id, D, E, R>,\n\toptions: Options<D, NoInfer<E>, NoInfer<R>, EL, RL, RP>,\n) => Layer.Layer<Self, never, RL | RP> = makeLayer as never\n"],"mappings":"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"}