@authup/access 1.0.0-beta.65 → 1.0.0-beta.67

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 (50) hide show
  1. package/dist/index.d.mts +557 -65
  2. package/dist/index.d.mts.map +1 -1
  3. package/dist/index.mjs +838 -30
  4. package/dist/index.mjs.map +1 -1
  5. package/dist/permission/authorization/check-schema.d.ts +23 -0
  6. package/dist/permission/authorization/check-schema.d.ts.map +1 -0
  7. package/dist/permission/authorization/check.d.ts +7 -0
  8. package/dist/permission/authorization/check.d.ts.map +1 -0
  9. package/dist/permission/authorization/constants.d.ts +14 -0
  10. package/dist/permission/authorization/constants.d.ts.map +1 -0
  11. package/dist/permission/authorization/error.d.ts +18 -0
  12. package/dist/permission/authorization/error.d.ts.map +1 -0
  13. package/dist/permission/authorization/index.d.ts +9 -0
  14. package/dist/permission/authorization/index.d.ts.map +1 -0
  15. package/dist/permission/authorization/module.d.ts +77 -0
  16. package/dist/permission/authorization/module.d.ts.map +1 -0
  17. package/dist/permission/authorization/policy.d.ts +31 -0
  18. package/dist/permission/authorization/policy.d.ts.map +1 -0
  19. package/dist/permission/authorization/schema.d.ts +107 -0
  20. package/dist/permission/authorization/schema.d.ts.map +1 -0
  21. package/dist/permission/authorization/types.d.ts +136 -0
  22. package/dist/permission/authorization/types.d.ts.map +1 -0
  23. package/dist/permission/evaluator/module.d.ts.map +1 -1
  24. package/dist/permission/evaluator/types.d.ts +16 -1
  25. package/dist/permission/evaluator/types.d.ts.map +1 -1
  26. package/dist/permission/index.d.ts +1 -0
  27. package/dist/permission/index.d.ts.map +1 -1
  28. package/dist/permission/realm-scope/helpers.d.ts +1 -1
  29. package/dist/permission/realm-scope/helpers.d.ts.map +1 -1
  30. package/dist/policy/built-in/date/evaluator.d.ts.map +1 -1
  31. package/dist/policy/built-in/permission-binding/identity-evaluator.d.ts +21 -0
  32. package/dist/policy/built-in/permission-binding/identity-evaluator.d.ts.map +1 -0
  33. package/dist/policy/built-in/permission-binding/index.d.ts +1 -0
  34. package/dist/policy/built-in/permission-binding/index.d.ts.map +1 -1
  35. package/dist/policy/built-in/permission-binding/validator.d.ts.map +1 -1
  36. package/dist/policy/built-in/time/evaluator.d.ts.map +1 -1
  37. package/dist/policy/constants.d.ts +11 -0
  38. package/dist/policy/constants.d.ts.map +1 -1
  39. package/dist/policy/data.d.ts +2 -0
  40. package/dist/policy/data.d.ts.map +1 -1
  41. package/dist/policy/evaluation/context/define.d.ts.map +1 -1
  42. package/dist/policy/evaluation/context/index.d.ts +1 -0
  43. package/dist/policy/evaluation/context/index.d.ts.map +1 -1
  44. package/dist/policy/evaluation/context/transition.d.ts +13 -0
  45. package/dist/policy/evaluation/context/transition.d.ts.map +1 -0
  46. package/dist/policy/evaluation/context/types.d.ts +27 -0
  47. package/dist/policy/evaluation/context/types.d.ts.map +1 -1
  48. package/dist/policy/types.d.ts +5 -0
  49. package/dist/policy/types.d.ts.map +1 -1
  50. package/package.json +8 -8
package/dist/index.d.mts CHANGED
@@ -3,12 +3,14 @@ import { DecisionStrategy } from "@authup/kit";
3
3
  import { ICondition } from "@rapiq/core";
4
4
  import { Issue, IssueGroup, IssueItem } from "@ebec/core";
5
5
  import { Container } from "validup";
6
+ import { z } from "zod";
6
7
  import { MongoFiltersParser, MongoFiltersParserInput } from "@rapiq/parser-mongo";
7
8
  //#region src/policy/data.d.ts
8
9
  export interface IPolicyData {
9
10
  set(key: string, value: unknown): void;
10
11
  has(key: string): boolean;
11
12
  get<T = unknown>(key: string): T;
13
+ delete(key: string): void;
12
14
  isValidated(key: string): boolean;
13
15
  setValidated(key: string): void;
14
16
  clone(): IPolicyData;
@@ -20,12 +22,25 @@ export declare class PolicyData implements IPolicyData {
20
22
  set<T = unknown>(key: string, value: T): void;
21
23
  get<T = unknown>(key: string): T;
22
24
  has(key: string): boolean;
25
+ delete(key: string): void;
23
26
  setValidated(key: string): void;
24
27
  isValidated(key: string): boolean;
25
28
  clone(): PolicyData;
26
29
  }
27
30
  //#endregion
28
31
  //#region src/policy/evaluation/context/types.d.ts
32
+ /**
33
+ * Receives the instants at which a clock-dependent verdict could change.
34
+ *
35
+ * A `date` or `time` policy that fell back to the real clock (no `date` / `time`
36
+ * key in the bag) reports the next strictly-future instant its own verdict could
37
+ * flip, from inside the evaluation walk that already runs. A caller that caches
38
+ * an answer derived from such a walk learns when to stop trusting it. Reports may
39
+ * be early (conservative) but never late, and `invert` does not move them.
40
+ */
41
+ export type PolicyTransitionSink = {
42
+ report(at: Date): void;
43
+ };
29
44
  export type PolicyEvaluationContext = {
30
45
  readonly evaluators: Record<string, IPolicyEvaluator>;
31
46
  readonly path: (string | number)[];
@@ -39,12 +54,40 @@ export type PolicyEvaluationContext = {
39
54
  * query-build callers opt in.
40
55
  */
41
56
  readonly withConditions: boolean;
57
+ /**
58
+ * Row column the realm reach is LOWERED onto, for a caller whose rows carry the
59
+ * realm under another name (a junction's `roleRealmId` / `clientRealmId` / …).
60
+ * Default `realmId`. It reaches `RealmMatchPolicyEvaluator` scope mode as
61
+ * `attributeName`, which that mode reads only while lowering — settled
62
+ * evaluation takes the resource realm from the `realmMatch` data key and never
63
+ * consults a column name, so this can never change an evaluate() outcome.
64
+ */
65
+ readonly realmAttributeName?: string;
66
+ /**
67
+ * Optional receiver of clock transitions (see {@link PolicyTransitionSink}).
68
+ * Nested evaluations inherit it, since every walk propagates the context by
69
+ * spread.
70
+ */
71
+ readonly transitions?: PolicyTransitionSink;
42
72
  };
43
73
  export type PolicyEvaluationContextInput = Partial<PolicyEvaluationContext>;
44
74
  //#endregion
45
75
  //#region src/policy/evaluation/context/define.d.ts
46
76
  export declare function definePolicyEvaluationContext(input?: PolicyEvaluationContextInput): PolicyEvaluationContext;
47
77
  //#endregion
78
+ //#region src/policy/evaluation/context/transition.d.ts
79
+ export type PolicyTransitionCollector = PolicyTransitionSink & {
80
+ /**
81
+ * The earliest reported instant, or undefined when nothing reported one.
82
+ */
83
+ readonly next: Date | undefined;
84
+ };
85
+ /**
86
+ * A sink keeping the earliest reported instant, which is the moment an answer
87
+ * built from every evaluation it was handed to stops being current.
88
+ */
89
+ export declare function createPolicyTransitionCollector(): PolicyTransitionCollector;
90
+ //#endregion
48
91
  //#region src/policy/evaluation/types.d.ts
49
92
  export type PolicyEvaluators = Record<string, IPolicyEvaluator>;
50
93
  export type PolicyEvaluationResult = {
@@ -100,6 +143,10 @@ export interface IPolicyEvaluator {
100
143
  }
101
144
  //#endregion
102
145
  //#region src/policy/types.d.ts
146
+ /**
147
+ * A policy type's configuration validator, keyed by the type it validates.
148
+ */
149
+ export type PolicyValidators = Record<string, Container<Record<string, any>>>;
103
150
  export type BasePolicy<T extends string = string> = {
104
151
  /**
105
152
  * Type describing the policy.
@@ -322,22 +369,6 @@ export declare class IdentityPolicyEvaluator implements IPolicyEvaluator {
322
369
  evaluate(value: Record<string, any>, ctx: PolicyEvaluationContext): Promise<PolicyEvaluationResult>;
323
370
  }
324
371
  //#endregion
325
- //#region src/policy/built-in/permission-binding/types.d.ts
326
- export interface PermissionBindingPolicy extends BasePolicy {}
327
- //#endregion
328
- //#region src/policy/built-in/permission-binding/validator.d.ts
329
- export declare class PermissionBindingPolicyValidator extends Container<PermissionBindingPolicy> {
330
- initialize(): void;
331
- }
332
- //#endregion
333
- //#region src/policy/built-in/permission-binding/module.d.ts
334
- export declare class PermissionBindingPolicyEvaluator implements IPolicyEvaluator {
335
- protected validator: PermissionBindingPolicyValidator;
336
- constructor();
337
- requires(): string[];
338
- evaluate(value: Record<string, any>): Promise<PolicyEvaluationResult>;
339
- }
340
- //#endregion
341
372
  //#region src/permission/realm-scope/constants.d.ts
342
373
  /**
343
374
  * Actor-relative realm reach of a permission grant.
@@ -380,7 +411,55 @@ export declare function minRealmScope(values: Array<`${RealmScope}` | null | und
380
411
  * multiple realms) requires the scope to reach EVERY listed realm (unanimous, fail-closed),
381
412
  * so any app/entity can express its realm via one or many keys under the canonical contract.
382
413
  */
383
- export declare function realmScopeMatches(scope: `${RealmScope}` | null | undefined, resourceRealmId: string | string[] | null | undefined, identityRealmId: string | null | undefined, identityRealmName?: string | null): boolean;
414
+ export declare function realmScopeMatches(scope: `${RealmScope}` | null | undefined, resourceRealmId: string | Array<string | null> | null | undefined, identityRealmId: string | null | undefined, identityRealmName?: string | null): boolean;
415
+ //#endregion
416
+ //#region src/permission/types.d.ts
417
+ export type BasePermission = {
418
+ name: string;
419
+ clientId?: string | null;
420
+ realmId?: string | null;
421
+ decisionStrategy?: `${DecisionStrategy}` | null;
422
+ };
423
+ /**
424
+ * A raw permission grant: one permission with its policies and realm reach, as loaded from a
425
+ * role/identity junction. `aggregatePermissionPolicyBindings` groups these per permission into
426
+ * a `PermissionPolicyBindingAggregated` (the lossless disjunction of grants).
427
+ */
428
+ export type PermissionPolicyBinding = {
429
+ permission: BasePermission;
430
+ policies?: BasePolicy[];
431
+ /**
432
+ * Relative realm reach of this grant (none/own/ownOrNull/any). Absent coerces to the
433
+ * most restrictive `own` (fail-closed). NOT part of the binding identity key
434
+ * (see isPermissionPolicyBindingEqual).
435
+ */
436
+ realmScope?: `${RealmScope}`;
437
+ };
438
+ /**
439
+ * One disjunction term of an aggregated binding: a single grant's realm reach paired with its
440
+ * own (single) policy. A disjunction-aware consumer ORs `realmScopeMatches(realmScope) ∧ policy`
441
+ * across the grants of a permission.
442
+ */
443
+ export type PermissionGrant = {
444
+ /** Relative realm reach (none/own/ownOrNull/any), normalized — fail-closed default `own`. */
445
+ realmScope: `${RealmScope}`;
446
+ /**
447
+ * The grant's policy: the raw junction policy (its `id` preserved, for propagation) for a
448
+ * single-policy grant, a composite for a multi-policy (Layer-1) binding, or `undefined`
449
+ * when the grant carries no restriction.
450
+ */
451
+ policy?: BasePolicy;
452
+ };
453
+ /**
454
+ * A permission together with the actor's disjunction of grants for it. Output of
455
+ * `aggregatePermissionPolicyBindings` — the honest, lossless replacement for the collapsed
456
+ * `PermissionPolicyBinding` (no top-level realmScope/policies; the access decision is the
457
+ * OR over `grants`).
458
+ */
459
+ export type PermissionPolicyBindingAggregated = {
460
+ permission: BasePermission;
461
+ grants: PermissionGrant[];
462
+ };
384
463
  //#endregion
385
464
  //#region src/policy/built-in/realm-match/types.d.ts
386
465
  export interface RealmMatchPolicy extends BasePolicy {
@@ -438,6 +517,37 @@ export declare class RealmMatchPolicyEvaluator implements IPolicyEvaluator {
438
517
  evaluate(value: Record<string, any>, ctx: PolicyEvaluationContext): Promise<PolicyEvaluationResult>;
439
518
  }
440
519
  //#endregion
520
+ //#region src/policy/built-in/permission-binding/types.d.ts
521
+ export interface PermissionBindingPolicy extends BasePolicy {}
522
+ //#endregion
523
+ //#region src/policy/built-in/permission-binding/validator.d.ts
524
+ export declare class PermissionBindingPolicyValidator extends Container<PermissionBindingPolicy> {
525
+ initialize(): void;
526
+ }
527
+ //#endregion
528
+ //#region src/policy/built-in/permission-binding/identity-evaluator.d.ts
529
+ type IdentityPermissionProvider = {
530
+ getFor(identity: IdentityPolicyData): Promise<PermissionPolicyBinding[]>;
531
+ };
532
+ export declare class IdentityPermissionBindingPolicyEvaluator implements IPolicyEvaluator {
533
+ protected validator: PermissionBindingPolicyValidator;
534
+ protected identityEvaluator: IdentityPolicyEvaluator;
535
+ protected realmMatchEvaluator: RealmMatchPolicyEvaluator;
536
+ protected identityPermissionProvider: IdentityPermissionProvider;
537
+ constructor(identityPermissionProvider: IdentityPermissionProvider);
538
+ requires(): string[];
539
+ accessData(ctx: PolicyEvaluationContext): Promise<PermissionPolicyBindingAggregated | null>;
540
+ evaluate(value: Record<string, any>, ctx: PolicyEvaluationContext): Promise<PolicyEvaluationResult>;
541
+ }
542
+ //#endregion
543
+ //#region src/policy/built-in/permission-binding/module.d.ts
544
+ export declare class PermissionBindingPolicyEvaluator implements IPolicyEvaluator {
545
+ protected validator: PermissionBindingPolicyValidator;
546
+ constructor();
547
+ requires(): string[];
548
+ evaluate(value: Record<string, any>): Promise<PolicyEvaluationResult>;
549
+ }
550
+ //#endregion
441
551
  //#region src/policy/built-in/time/constants.d.ts
442
552
  export declare enum TimePolicyInterval {
443
553
  DAILY = "daily",
@@ -565,6 +675,16 @@ export declare const PolicyDefaultEvaluators: {
565
675
  readonly realmMatch: RealmMatchPolicyEvaluator;
566
676
  readonly time: TimePolicyEvaluator;
567
677
  };
678
+ /**
679
+ * The configuration validator of every built-in policy type, keyed like
680
+ * `PolicyDefaultEvaluators`. It is what `projectAuthorizationPolicy` runs a
681
+ * node through, so a type absent here cannot travel in the authorization
682
+ * catalog. The registry is open like the evaluator one (#3635): spread it and
683
+ * add a custom type's validator to let that type travel. It is frozen, since
684
+ * a write into it would make the type projectable for every caller in the
685
+ * process.
686
+ */
687
+ export declare const PolicyDefaultValidators: Readonly<PolicyValidators>;
568
688
  //#endregion
569
689
  //#region src/policy/input.d.ts
570
690
  /**
@@ -603,54 +723,6 @@ export declare class PermissionError extends AuthupError {
603
723
  //#region src/permission/error/check.d.ts
604
724
  export declare function isPermissionError(input: unknown): input is PermissionError;
605
725
  //#endregion
606
- //#region src/permission/types.d.ts
607
- export type BasePermission = {
608
- name: string;
609
- clientId?: string | null;
610
- realmId?: string | null;
611
- decisionStrategy?: `${DecisionStrategy}` | null;
612
- };
613
- /**
614
- * A raw permission grant: one permission with its policies and realm reach, as loaded from a
615
- * role/identity junction. `aggregatePermissionPolicyBindings` groups these per permission into
616
- * a `PermissionPolicyBindingAggregated` (the lossless disjunction of grants).
617
- */
618
- export type PermissionPolicyBinding = {
619
- permission: BasePermission;
620
- policies?: BasePolicy[];
621
- /**
622
- * Relative realm reach of this grant (none/own/ownOrNull/any). Absent coerces to the
623
- * most restrictive `own` (fail-closed). NOT part of the binding identity key
624
- * (see isPermissionPolicyBindingEqual).
625
- */
626
- realmScope?: `${RealmScope}`;
627
- };
628
- /**
629
- * One disjunction term of an aggregated binding: a single grant's realm reach paired with its
630
- * own (single) policy. A disjunction-aware consumer ORs `realmScopeMatches(realmScope) ∧ policy`
631
- * across the grants of a permission.
632
- */
633
- export type PermissionGrant = {
634
- /** Relative realm reach (none/own/ownOrNull/any), normalized — fail-closed default `own`. */
635
- realmScope: `${RealmScope}`;
636
- /**
637
- * The grant's policy: the raw junction policy (its `id` preserved, for propagation) for a
638
- * single-policy grant, a composite for a multi-policy (Layer-1) binding, or `undefined`
639
- * when the grant carries no restriction.
640
- */
641
- policy?: BasePolicy;
642
- };
643
- /**
644
- * A permission together with the actor's disjunction of grants for it. Output of
645
- * `aggregatePermissionPolicyBindings` — the honest, lossless replacement for the collapsed
646
- * `PermissionPolicyBinding` (no top-level realmScope/policies; the access decision is the
647
- * OR over `grants`).
648
- */
649
- export type PermissionPolicyBindingAggregated = {
650
- permission: BasePermission;
651
- grants: PermissionGrant[];
652
- };
653
- //#endregion
654
726
  //#region src/permission/helpers/aggregate.d.ts
655
727
  /**
656
728
  * Group raw permission-policy bindings by permission key into the actor's disjunction of
@@ -726,6 +798,13 @@ export type PermissionEvaluationOptions = {
726
798
  * (`preEvaluate()`): only a tree that settles false with the current bag denies.
727
799
  */
728
800
  pendingPolicies?: 'deny' | 'permit';
801
+ /**
802
+ * Receives the instants at which a clock-dependent policy (`date`, `time`)
803
+ * in an evaluated tree could change its verdict, so a caller caching the
804
+ * outcome knows when it expires. Handed to every policy evaluation this call
805
+ * runs; a policy-free grant evaluates nothing and reports nothing.
806
+ */
807
+ transitions?: PolicyTransitionSink;
729
808
  };
730
809
  export type PermissionEvaluationContext = {
731
810
  name: string | string[];
@@ -748,6 +827,14 @@ export type PermissionCompileContext = {
748
827
  * compiled condition ranges over.
749
828
  */
750
829
  data?: PolicyData;
830
+ /**
831
+ * Row column the realm reach is lowered onto, when the rows this compilation
832
+ * ranges over carry their realm under another name — a junction's owner-realm
833
+ * key (`roleRealmId`, `clientRealmId`, …). Default `realmId`. Affects the
834
+ * `conditional` condition only; the per-row `post` fallback still reads the
835
+ * realm from the `realmMatch` data key its caller supplies.
836
+ */
837
+ realmAttributeName?: string;
751
838
  };
752
839
  /**
753
840
  * Outcome of compiling a permission's policy trees against the knowns bag
@@ -799,4 +886,409 @@ export declare class PermissionEvaluator implements IPermissionEvaluator {
799
886
  compile(ctx: PermissionCompileContext): Promise<PermissionCompileResult>;
800
887
  }
801
888
  //#endregion
889
+ //#region src/permission/authorization/error.d.ts
890
+ export declare const AUTHORIZATION_CATALOG_STALE_ERROR_INSTANCE: unique symbol;
891
+ /**
892
+ * A grant references a definition or a policy the supplied catalog does not
893
+ * carry: the caller's cached catalog predates the definition or the junction
894
+ * row and must be refetched. A definition the catalog carries with
895
+ * `policies: null`, and one whose tree this copy cannot project, are not
896
+ * stale but unevaluable, and a grant of either is dropped.
897
+ *
898
+ * Recognize it with `isAuthorizationCatalogStaleError`, never `instanceof`:
899
+ * this package is a plain caret dependency of several workspaces, so a
900
+ * consumer tree may resolve two copies of it and turn the one recoverable
901
+ * state into an unrecoverable one.
902
+ */
903
+ export declare class AuthorizationCatalogStaleError extends AuthupError {
904
+ constructor(message: string);
905
+ }
906
+ //#endregion
907
+ //#region src/permission/authorization/check.d.ts
908
+ /**
909
+ * Marker-only: the error carries no code of its own, and it never crosses a
910
+ * wire boundary, so there is no shape to fall back to.
911
+ */
912
+ export declare function isAuthorizationCatalogStaleError(input: unknown): input is AuthorizationCatalogStaleError;
913
+ //#endregion
914
+ //#region src/permission/authorization/types.d.ts
915
+ /**
916
+ * One policy tree node as it travels: the type's configuration keys (the output
917
+ * of that type's validator), `invert`, and for a composite its children inline.
918
+ */
919
+ export type AuthorizationPolicy = {
920
+ type: string;
921
+ invert?: boolean | null;
922
+ children?: AuthorizationPolicy[];
923
+ [key: string]: unknown;
924
+ };
925
+ export type AuthorizationDefinition = {
926
+ name: string;
927
+ realm_id: string | null;
928
+ client_id: string | null;
929
+ decision_strategy: `${DecisionStrategy}` | null;
930
+ /**
931
+ * The definition layer: the ids of the policy trees bound to the permission
932
+ * definition (`auth_permission_policies`). Empty means unrestricted at this
933
+ * layer. `null` means the server could not project one of those trees onto
934
+ * the wire (a policy type the catalog does not carry, or a configuration
935
+ * its validator refuses): the definition exists, a consumer cannot evaluate
936
+ * it and denies it, dropping every grant of it, until the policy is fixed.
937
+ */
938
+ policies: string[] | null;
939
+ };
940
+ /**
941
+ * Identity-free and cacheable: every permission definition with its policy trees.
942
+ */
943
+ export type AuthorizationCatalog = {
944
+ /**
945
+ * Every policy tree a definition or a grant can name, keyed by the tree's
946
+ * own id and present exactly once however many of them reference it.
947
+ */
948
+ policies: Record<string, AuthorizationPolicy>;
949
+ permissions: AuthorizationDefinition[];
950
+ };
951
+ /**
952
+ * One raw grant of an identity as the introspection endpoints report it: the
953
+ * permission namespace it names, its realm reach and the junction policy ids.
954
+ * Structurally the extended `OAuth2TokenPermission` of `@authup/specs` (this
955
+ * package does not depend on specs).
956
+ */
957
+ export type AuthorizationGrant = {
958
+ name: string;
959
+ realm_id?: string | null;
960
+ client_id?: string | null;
961
+ /**
962
+ * Absent or null coerces to `own`, fail-closed.
963
+ */
964
+ realm_scope?: `${RealmScope}` | null;
965
+ /**
966
+ * Absent or null means no junction policy.
967
+ */
968
+ policies?: string[] | null;
969
+ };
970
+ export type AuthorizationEvaluatorInput = {
971
+ /**
972
+ * An `AuthorizationCatalog`, validated by the schema.
973
+ */
974
+ catalog: unknown;
975
+ /**
976
+ * `AuthorizationGrant[]`, validated by the schema. Defaults to none, and
977
+ * may only be supplied together with the identity holding them.
978
+ */
979
+ grants?: unknown;
980
+ /**
981
+ * The identity the grants belong to. Omitted for an anonymous caller:
982
+ * no identity data is injected and no grant is bound, so only a
983
+ * definition whose policies need no identity can pass.
984
+ */
985
+ identity?: IdentityPolicyData;
986
+ };
987
+ export type AuthorizationEvaluatorOptions = {
988
+ /**
989
+ * The policy types a catalog tree may carry. Defaults to
990
+ * `PolicyDefaultValidators`; spread it to add a custom type.
991
+ */
992
+ validators?: PolicyValidators;
993
+ /**
994
+ * How the projected trees evaluate. Defaults to
995
+ * `PolicyDefaultEvaluators`; spread it to add a custom type. The
996
+ * permission-binding evaluator is always replaced by the one binding the
997
+ * introspected grants.
998
+ */
999
+ evaluators?: PolicyEvaluators;
1000
+ };
1001
+ /**
1002
+ * Which resource realms a batch check evaluates against.
1003
+ *
1004
+ * A string is SYMBOLIC and resolved server-side against the caller's own
1005
+ * identity: `own` is the realm the identity belongs to, `ownOrNull` is that
1006
+ * realm plus `null`, the global rows every realm shares. An array is taken
1007
+ * VERBATIM: the server resolves no realm key, so it discloses no realm's
1008
+ * existence and the caller matches the answer against its own input with no
1009
+ * resolution step of its own.
1010
+ *
1011
+ * String versus array is what discriminates the two forms, so `own` stays
1012
+ * unambiguous even though it is a legal realm name.
1013
+ */
1014
+ export type AuthorizationCheckRealms = `${RealmScope.OWN}` | `${RealmScope.OWN_OR_NULL}` | Array<string | null>;
1015
+ /**
1016
+ * One permission the identity may attempt, and the requested realms it may
1017
+ * attempt it in. Never empty: a permission reaching no requested realm is
1018
+ * absent from the answer entirely, so absent means denied.
1019
+ */
1020
+ export type AuthorizationCheckPermission = {
1021
+ name: string;
1022
+ realms: Array<string | null>;
1023
+ };
1024
+ /**
1025
+ * The answer `POST /authorization/check` serves: the caller's own verdicts,
1026
+ * paired with the realms they hold in.
1027
+ *
1028
+ * It is an upper bound on what may be ATTEMPTED rather than an entitlement,
1029
+ * the same posture the catalog and `GET /schemas` take: it is a pre-gate, so a
1030
+ * grant whose junction policy needs a resource row passes here and is still
1031
+ * decided per row on the server, which stays the enforcement point.
1032
+ */
1033
+ export type AuthorizationCheckPermissions = AuthorizationCheckPermission[];
1034
+ export type AuthorizationCheckEvaluatorInput = {
1035
+ /**
1036
+ * An `AuthorizationCheckPermissions`, validated by the schema.
1037
+ */
1038
+ permissions: unknown;
1039
+ /**
1040
+ * The identity the verdicts belong to, used to resolve a `realmMatch` of
1041
+ * `own` shape: a resource realm equal to this identity's realm id or name
1042
+ * is the identity's own realm. Omitted for an anonymous caller, which
1043
+ * holds no verdict at all.
1044
+ */
1045
+ identity?: IdentityPolicyData;
1046
+ };
1047
+ //#endregion
1048
+ //#region src/permission/authorization/check-schema.d.ts
1049
+ /**
1050
+ * The whole input `createAuthorizationCheckEvaluator` takes: the answer
1051
+ * `POST /authorization/check` served and the identity it belongs to. Same
1052
+ * validup-over-zod shape as the catalog's input, so a consumer can override
1053
+ * one member's rules instead of restating the answer.
1054
+ */
1055
+ export declare class AuthorizationCheckEvaluatorInputValidator extends Container<AuthorizationCheckEvaluatorInput> {
1056
+ initialize(): void;
1057
+ }
1058
+ export type AuthorizationCheckEvaluatorInputParsed = {
1059
+ permissions: AuthorizationCheckPermissions;
1060
+ identity: AuthorizationCheckEvaluatorInput['identity'];
1061
+ };
1062
+ /**
1063
+ * Validate the check evaluator's input, plus the one rule a per-key validator
1064
+ * cannot express: a permission namespace appears at most once. Two entries for
1065
+ * one name would make the answer depend on which the consumer looked up first,
1066
+ * and the server emits one entry per name by construction.
1067
+ */
1068
+ export declare function parseAuthorizationCheckEvaluatorInput(input: AuthorizationCheckEvaluatorInput): Promise<AuthorizationCheckEvaluatorInputParsed>;
1069
+ //#endregion
1070
+ //#region src/permission/authorization/constants.d.ts
1071
+ /**
1072
+ * The node a policy tree travels as when the server withholds it, because the
1073
+ * caller's realm reach does not cover the row it was read from.
1074
+ *
1075
+ * It is deliberately a type no consumer can project: `projectAuthorizationPolicy`
1076
+ * refuses it, which is already the state a definition referencing it denies
1077
+ * through and a grant naming it is dropped through, so withholding a body needs
1078
+ * no rule of its own on the consumer side. That is a contract between the two
1079
+ * halves rather than a server detail, which is why it is declared HERE, next to
1080
+ * the projection that has to keep refusing it, and pinned by this package's own
1081
+ * test.
1082
+ */
1083
+ export declare const AUTHORIZATION_POLICY_WITHHELD_TYPE = "withheld";
1084
+ //#endregion
1085
+ //#region src/permission/authorization/module.d.ts
1086
+ /**
1087
+ * Build a resource-server (or console) evaluator from the catalog
1088
+ * `GET /authorization` serves, the identity's grants as the introspection
1089
+ * endpoints report them, and the identity itself. Rejects legacy, incomplete
1090
+ * and unsupported input. A grant referencing a definition or a policy the
1091
+ * catalog lacks throws `AuthorizationCatalogStaleError`, the signal to
1092
+ * refetch the catalog: the grants come from a fresh introspection while the
1093
+ * catalog may predate the definition or the junction row. A definition the
1094
+ * server could not project travels with `policies: null` instead of being
1095
+ * left out, so a grant of it is dropped rather than reported stale: the
1096
+ * definition layer cannot be evaluated here, a refetch changes nothing, and
1097
+ * the permission denies until the policy is fixed.
1098
+ *
1099
+ * A tree THIS copy cannot project is the same condition read from the other
1100
+ * side, and it is per tree: a policy type the validator registry lacks (a
1101
+ * type newer than this package, or a custom one the caller did not register)
1102
+ * or a configuration its validator refuses denies the definitions that reference
1103
+ * it, exactly as `policies: null` does, and drops a grant that names it,
1104
+ * exactly as a binding check does. One such tree never takes the evaluator
1105
+ * down for the permissions that do not use it. A malformed catalog still
1106
+ * throws: a duplicate permission namespace is not a data condition.
1107
+ *
1108
+ * Both the identity and the grants are optional. Without an identity no grant
1109
+ * is bound and any IDENTITY key the caller supplied is REMOVED, so the
1110
+ * binding evaluator answers with missing data exactly as the server does for
1111
+ * an anonymous request, only a definition whose policies need no identity can
1112
+ * pass, and a caller can never inject an identity the document did not prove.
1113
+ * Grants without the identity they belong to are refused.
1114
+ *
1115
+ * The REALM_MATCH data key follows the server's own three-way rule: a
1116
+ * resource that carries a realm passes it (null for a global row, which
1117
+ * `own` denies), a resource with no realm dimension passes nothing and reach
1118
+ * neutral-passes. `preEvaluate` / `preEvaluateOneOf` are the pre-gate and
1119
+ * enforce reach only when that key is present. `compile` returns the
1120
+ * allow/deny/conditional/post contract; a `post` collection query must be
1121
+ * rejected or evaluated over every candidate before paging. The supplied
1122
+ * identity is authoritative; `options.decisionStrategy` is forwarded and the
1123
+ * policy include, exclude and pending options are refused.
1124
+ *
1125
+ * The policy type set is open (#3635): `options.validators` decides which
1126
+ * trees project and `options.evaluators` how they evaluate, the built-in
1127
+ * registries by default. A custom type needs both, the validator the server
1128
+ * projected it with and the evaluator the server decides it with; given only
1129
+ * the first it projects and then denies. The binding evaluator is always this
1130
+ * function's own, since it is what binds the introspected grants.
1131
+ */
1132
+ export declare function createAuthorizationEvaluator(input: AuthorizationEvaluatorInput, options?: AuthorizationEvaluatorOptions): Promise<IPermissionEvaluator>;
1133
+ /**
1134
+ * An `IPermissionEvaluator` over the answer `POST /authorization/check`
1135
+ * served: the caller's own verdicts, paired with the realms they hold in.
1136
+ *
1137
+ * It is what a PUBLIC client gets where the catalog is out of reach. A public
1138
+ * client holds no secret, so it can obtain no `client_credentials` token and
1139
+ * has no credential of its own for the catalog's gate to be satisfied by;
1140
+ * publishing every policy predicate to it instead would be the wrong trade.
1141
+ * The verdicts are computed by the server from the same grants and the same
1142
+ * evaluators a request runs, so this is authoritative where the name-only
1143
+ * fallback it replaces is merely coarse.
1144
+ *
1145
+ * Two properties follow from the answer being a pre-gate:
1146
+ *
1147
+ * It is an UPPER BOUND, so `evaluate` and `evaluateOneOf` answer exactly what
1148
+ * the pre-gate pair answers. A check that depends on a resource row belongs to
1149
+ * whoever holds the row, and the server decides it there; answering such a
1150
+ * check here would mean inventing a verdict. That is the same bound the
1151
+ * name-only fallback already had, so nothing that gates on it loosens.
1152
+ *
1153
+ * And a resource realm is matched against what the REQUEST asked about: a
1154
+ * `realmMatch` naming a realm the request never carried is in no entry's list
1155
+ * and therefore denies. That is fail-closed by construction rather than by a
1156
+ * rule, and it is why a caller must ask about the realms its UI will ask
1157
+ * about.
1158
+ */
1159
+ export declare function createAuthorizationCheckEvaluator(input: AuthorizationCheckEvaluatorInput): Promise<IPermissionEvaluator>;
1160
+ //#endregion
1161
+ //#region src/permission/authorization/policy.d.ts
1162
+ /**
1163
+ * The one definition of what a policy looks like on the wire, used by the server
1164
+ * to build a document and by the consumer to validate one. A node is the OUTPUT
1165
+ * of its type's validator (validup strips every unmounted key, so entity columns
1166
+ * such as `id`, `name`, `builtIn` or `createdAt` never travel), plus its type
1167
+ * and, for a composite, its projected children.
1168
+ *
1169
+ * The type set is the `validators` registry, `PolicyDefaultValidators` unless
1170
+ * the caller hands another (#3635): a type the registry lacks is refused, so
1171
+ * the server and a consumer that register the same custom type let it travel,
1172
+ * and one that does not denies it. The withheld node is refused whatever the
1173
+ * registry says, since projecting it would evaluate a tree the caller was not
1174
+ * allowed to see.
1175
+ *
1176
+ * Every refusal is a `ValidupError`, the node's head and the type's own
1177
+ * validator alike, and a child's issues are rebased onto the position it sits
1178
+ * at, so one message names the node in the tree that is wrong.
1179
+ */
1180
+ export declare function projectAuthorizationPolicy(input: unknown, validators?: PolicyValidators): Promise<AuthorizationPolicy>;
1181
+ /**
1182
+ * Whether a projected tree evaluates the permission binding at any depth. A
1183
+ * grant policy carrying one would re-enter its own permission's grants, so
1184
+ * `createAuthorizationEvaluator` drops the grant that names it and evaluates
1185
+ * the permission from the rest. Its one caller is that consumer: the tree is
1186
+ * legal in a definition, where the binding check is what reach is enforced
1187
+ * by, so the producer carries it and only the grant side is refused.
1188
+ */
1189
+ export declare function containsBindingCheck(policy: AuthorizationPolicy): boolean;
1190
+ //#endregion
1191
+ //#region src/permission/authorization/schema.d.ts
1192
+ /**
1193
+ * A policy node as it travels. Deliberately LOOSE: every key beyond `type` is
1194
+ * that type's own configuration, and `projectAuthorizationPolicy` is what
1195
+ * validates it, by running the type's own validator. Mounting a node in a
1196
+ * validup container would strip every key the container does not mount, and
1197
+ * the whole configuration would go with it.
1198
+ */
1199
+ export declare const authorizationPolicySchema: z.ZodObject<{
1200
+ type: z.ZodString;
1201
+ }, z.core.$loose>;
1202
+ /**
1203
+ * One permission definition. `policies` carries the ids of its
1204
+ * definition-layer trees, or `null` when the server could not project one.
1205
+ */
1206
+ export declare const authorizationDefinitionSchema: z.ZodObject<{
1207
+ name: z.ZodString;
1208
+ realm_id: z.ZodNullable<z.ZodString>;
1209
+ client_id: z.ZodNullable<z.ZodString>;
1210
+ decision_strategy: z.ZodNullable<z.ZodEnum<typeof DecisionStrategy>>;
1211
+ policies: z.ZodNullable<z.ZodArray<z.ZodString>>;
1212
+ }, z.core.$strip>;
1213
+ export declare const authorizationCatalogSchema: z.ZodObject<{
1214
+ policies: z.ZodRecord<z.ZodString, z.ZodObject<{
1215
+ type: z.ZodString;
1216
+ }, z.core.$loose>>;
1217
+ permissions: z.ZodArray<z.ZodObject<{
1218
+ name: z.ZodString;
1219
+ realm_id: z.ZodNullable<z.ZodString>;
1220
+ client_id: z.ZodNullable<z.ZodString>;
1221
+ decision_strategy: z.ZodNullable<z.ZodEnum<typeof DecisionStrategy>>;
1222
+ policies: z.ZodNullable<z.ZodArray<z.ZodString>>;
1223
+ }, z.core.$strip>>;
1224
+ }, z.core.$strip>;
1225
+ /**
1226
+ * One grant of the identity, as the introspection endpoints report it.
1227
+ * Whether a grant's policy ids are declared is checked against the catalog
1228
+ * the consumer holds, since the two travel separately.
1229
+ */
1230
+ export declare const authorizationGrantSchema: z.ZodObject<{
1231
+ name: z.ZodString;
1232
+ realm_id: z.ZodOptional<z.ZodNullable<z.ZodString>>;
1233
+ client_id: z.ZodOptional<z.ZodNullable<z.ZodString>>;
1234
+ realm_scope: z.ZodOptional<z.ZodNullable<z.ZodEnum<typeof RealmScope>>>;
1235
+ policies: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString>>>;
1236
+ }, z.core.$strip>;
1237
+ export declare const authorizationIdentitySchema: z.ZodObject<{
1238
+ id: z.ZodString;
1239
+ type: z.ZodEnum<{
1240
+ user: "user";
1241
+ client: "client";
1242
+ }>;
1243
+ realmId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
1244
+ realmName: z.ZodOptional<z.ZodNullable<z.ZodString>>;
1245
+ clientId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
1246
+ }, z.core.$strip>;
1247
+ /**
1248
+ * The whole input `createAuthorizationEvaluator` takes: the catalog
1249
+ * `GET /authorization` serves, the grants an introspection reports and the
1250
+ * identity it names. A validup container over zod mounts, the shape every
1251
+ * validator in this package uses, so a consumer can reuse or override one
1252
+ * member's rules instead of restating the document.
1253
+ */
1254
+ export declare class AuthorizationEvaluatorInputValidator extends Container<AuthorizationEvaluatorInput> {
1255
+ initialize(): void;
1256
+ }
1257
+ export type AuthorizationEvaluatorInputParsed = {
1258
+ catalog: AuthorizationCatalog;
1259
+ grants: AuthorizationGrant[];
1260
+ identity: AuthorizationEvaluatorInput['identity'];
1261
+ };
1262
+ /**
1263
+ * Validate the evaluator's input, plus the two rules per-key validators
1264
+ * cannot express.
1265
+ *
1266
+ * Every id a definition names must be a key of `policies`: a dangling id
1267
+ * resolves to `undefined`, which reads as "this layer carries no policy", so
1268
+ * a catalog that merely omitted a tree would grant unrestricted access rather
1269
+ * than fail. The lookup is own-property only, so an id such as `constructor`
1270
+ * cannot be answered by a member of `Object.prototype`.
1271
+ *
1272
+ * And the identity and its grants travel together: grants without an identity
1273
+ * belong to nobody, while an identity without a grant list is the shape an
1274
+ * INACTIVE introspection produces (`permissions` is absent unless the
1275
+ * credential is active), which read as "holds nothing" would authorize every
1276
+ * definition that carries no binding check. An identity holding no grant says
1277
+ * so with an empty array.
1278
+ */
1279
+ export declare function parseAuthorizationEvaluatorInput(input: AuthorizationEvaluatorInput): Promise<AuthorizationEvaluatorInputParsed>;
1280
+ /**
1281
+ * One verdict: the permission namespace and the requested realms it holds in.
1282
+ * A realm value is a realm key the caller itself supplied, or `null` for the
1283
+ * global rows, so nothing here is resolved or looked up.
1284
+ */
1285
+ export declare const authorizationCheckPermissionSchema: z.ZodObject<{
1286
+ name: z.ZodString;
1287
+ realms: z.ZodArray<z.ZodNullable<z.ZodString>>;
1288
+ }, z.core.$strip>;
1289
+ export declare const authorizationCheckPermissionsSchema: z.ZodArray<z.ZodObject<{
1290
+ name: z.ZodString;
1291
+ realms: z.ZodArray<z.ZodNullable<z.ZodString>>;
1292
+ }, z.core.$strip>>;
1293
+ //#endregion
802
1294
  //# sourceMappingURL=index.d.mts.map