@nmnmcc/ability 2.0.7 → 2.1.2

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 (87) hide show
  1. package/README.md +52 -29
  2. package/dist/Authorizer.d.ts +21 -12
  3. package/dist/Authorizer.d.ts.map +1 -1
  4. package/dist/Authorizer.js.map +1 -1
  5. package/dist/Condition.d.ts +121 -19
  6. package/dist/Condition.d.ts.map +1 -1
  7. package/dist/Condition.js +32 -21
  8. package/dist/Condition.js.map +1 -1
  9. package/dist/Domain.d.ts +9 -0
  10. package/dist/Domain.d.ts.map +1 -1
  11. package/dist/Domain.js +5 -0
  12. package/dist/Domain.js.map +1 -1
  13. package/dist/Limits.d.ts +44 -13
  14. package/dist/Limits.d.ts.map +1 -1
  15. package/dist/Limits.js +52 -22
  16. package/dist/Limits.js.map +1 -1
  17. package/dist/Policy.d.ts +102 -18
  18. package/dist/Policy.d.ts.map +1 -1
  19. package/dist/Policy.js +7 -6
  20. package/dist/Policy.js.map +1 -1
  21. package/dist/index.d.ts +1 -1
  22. package/dist/internal/algebra.js +2 -2
  23. package/dist/internal/analysis.js +81 -75
  24. package/dist/internal/analysis.js.map +1 -1
  25. package/dist/internal/authorizer.d.ts.map +1 -1
  26. package/dist/internal/authorizer.js +11 -7
  27. package/dist/internal/authorizer.js.map +1 -1
  28. package/dist/internal/bind.js +86 -64
  29. package/dist/internal/bind.js.map +1 -1
  30. package/dist/internal/catalog.d.ts +33 -10
  31. package/dist/internal/catalog.d.ts.map +1 -1
  32. package/dist/internal/catalog.js +170 -77
  33. package/dist/internal/catalog.js.map +1 -1
  34. package/dist/internal/decide.js +27 -31
  35. package/dist/internal/decide.js.map +1 -1
  36. package/dist/internal/domain.js +19 -5
  37. package/dist/internal/domain.js.map +1 -1
  38. package/dist/internal/json.js +120 -76
  39. package/dist/internal/json.js.map +1 -1
  40. package/dist/internal/limits.d.ts +28 -0
  41. package/dist/internal/limits.d.ts.map +1 -1
  42. package/dist/internal/limits.js +75 -16
  43. package/dist/internal/limits.js.map +1 -1
  44. package/dist/internal/nodes.d.ts.map +1 -1
  45. package/dist/internal/nodes.js +53 -44
  46. package/dist/internal/nodes.js.map +1 -1
  47. package/dist/internal/patterns.js +50 -15
  48. package/dist/internal/patterns.js.map +1 -1
  49. package/dist/internal/policy-json.js +169 -127
  50. package/dist/internal/policy-json.js.map +1 -1
  51. package/dist/internal/policy-nodes.d.ts.map +1 -1
  52. package/dist/internal/policy-nodes.js +16 -13
  53. package/dist/internal/policy-nodes.js.map +1 -1
  54. package/dist/internal/policy.d.ts.map +1 -1
  55. package/dist/internal/policy.js +38 -22
  56. package/dist/internal/policy.js.map +1 -1
  57. package/dist/internal/resource.js +1 -1
  58. package/dist/internal/rule.d.ts.map +1 -1
  59. package/dist/internal/rule.js +6 -5
  60. package/dist/internal/rule.js.map +1 -1
  61. package/dist/internal/search.d.ts.map +1 -1
  62. package/dist/internal/search.js +106 -92
  63. package/dist/internal/search.js.map +1 -1
  64. package/dist/internal/trampoline.js +19 -5
  65. package/dist/internal/trampoline.js.map +1 -1
  66. package/package.json +1 -1
  67. package/src/Authorizer.ts +30 -20
  68. package/src/Condition.ts +317 -86
  69. package/src/Domain.ts +9 -0
  70. package/src/Limits.ts +69 -29
  71. package/src/Policy.ts +143 -21
  72. package/src/internal/analysis.ts +154 -124
  73. package/src/internal/authorizer.ts +29 -14
  74. package/src/internal/bind.ts +193 -136
  75. package/src/internal/catalog.ts +320 -118
  76. package/src/internal/decide.ts +61 -50
  77. package/src/internal/domain.ts +39 -3
  78. package/src/internal/json.ts +212 -117
  79. package/src/internal/limits.ts +101 -31
  80. package/src/internal/nodes.ts +65 -47
  81. package/src/internal/patterns.ts +79 -25
  82. package/src/internal/policy-json.ts +266 -197
  83. package/src/internal/policy-nodes.ts +31 -23
  84. package/src/internal/policy.ts +63 -23
  85. package/src/internal/rule.ts +16 -3
  86. package/src/internal/search.ts +186 -136
  87. package/src/internal/trampoline.ts +51 -4
package/src/Condition.ts CHANGED
@@ -49,6 +49,7 @@ import * as Catalog from "./internal/catalog.ts"
49
49
  import * as Json from "./internal/json.ts"
50
50
  import * as Nodes from "./internal/nodes.ts"
51
51
  import * as Search from "./internal/search.ts"
52
+ import * as Trampoline from "./internal/trampoline.ts"
52
53
  import * as Resource from "./Resource.ts"
53
54
 
54
55
  /**
@@ -412,8 +413,7 @@ type ObjectPaths<
412
413
  > = [O] extends [never]
413
414
  ? never
414
415
  : // A record is one field to a rule or a request, as `permittedFields`
415
- // lists it. So is a struct at the last part that a path may have, since
416
- // a path does not go below it.
416
+ // lists it.
417
417
  | (Parents extends true
418
418
  ? K
419
419
  : Arrays extends true
@@ -421,9 +421,7 @@ type ObjectPaths<
421
421
  ? K
422
422
  : number extends keyof O
423
423
  ? K
424
- : [Depth] extends [0]
425
- ? K
426
- : never
424
+ : never
427
425
  : never)
428
426
  | `${K}.${FieldPathInternal<O, PreviousDepth[Depth], Arrays, Parents>}`
429
427
 
@@ -503,16 +501,31 @@ type Normalize<A> = Exclude<A, undefined> | (undefined extends A ? null : never)
503
501
  * @category utility types
504
502
  * @since 0.3.0
505
503
  */
506
- export type PathValue<T, Path extends string> = T extends unknown
507
- ? PathValueIn<T, Path>
504
+ export type PathValue<T, Path extends string> = ValueWalk<T, Path>
505
+
506
+ /**
507
+ * The values of the part `Name` of each type of `U`. A part below a value
508
+ * that is not an object, as below a string or `null`, is `null`.
509
+ */
510
+ type StepValue<U, Name extends string> = U extends unknown
511
+ ? U extends object
512
+ ? ChildOf<U, Name>
513
+ : null
508
514
  : never
509
515
 
510
- /** The type of the field at `Path` of `T`, which is not a union. */
511
- type PathValueIn<T, Path extends string> = T extends object
512
- ? Path extends `${infer Head}.${infer Rest}`
513
- ? PathValue<ChildOf<T, Head>, Rest>
514
- : Normalize<ChildOf<T, Path>>
515
- : null
516
+ /**
517
+ * Walks a path two parts at a time, with the values of each step. The type
518
+ * checker takes at most about 1000 steps of a type that calls itself, so a
519
+ * walk of one part at a time would stop before a path of 1000 parts.
520
+ */
521
+ type ValueWalk<
522
+ U,
523
+ Path extends string,
524
+ > = Path extends `${infer A}.${infer B}.${infer Rest}`
525
+ ? ValueWalk<StepValue<StepValue<U, A>, B>, Rest>
526
+ : Path extends `${infer A}.${infer B}`
527
+ ? Normalize<StepValue<StepValue<U, A>, B>>
528
+ : Normalize<StepValue<U, Path>>
516
529
 
517
530
  /**
518
531
  * The type of the part `Name` of `T`. A part of a path is text, so the part
@@ -528,6 +541,215 @@ type ChildOf<T, Name extends string> = Name extends keyof T
528
541
  : never
529
542
  : never
530
543
 
544
+ /**
545
+ * What a path may do, for one use of it: go below a list or a whole value,
546
+ * as a rule or a request may, and end at a struct, as the fields of a rule
547
+ * may. See {@link FieldPath}, {@link FieldSelector} and {@link FieldName},
548
+ * which list the short paths with the same rules.
549
+ */
550
+ interface PathRules {
551
+ readonly arrays: boolean
552
+ readonly parents: boolean
553
+ }
554
+
555
+ /** The rules of a path that a condition reads. */
556
+ interface ReadRules {
557
+ readonly arrays: false
558
+ readonly parents: false
559
+ }
560
+
561
+ /** The rules of the field of a request. */
562
+ interface SelectRules {
563
+ readonly arrays: true
564
+ readonly parents: false
565
+ }
566
+
567
+ /** The rules of a field of a rule, which may name a struct. */
568
+ interface NameRules {
569
+ readonly arrays: true
570
+ readonly parents: true
571
+ }
572
+
573
+ /** The objects below a field with the values `V`: see `PathsOf`. */
574
+ type ObjectsBelow<V, Arrays extends boolean> = Arrays extends true
575
+ ? Exclude<V, Leaf | Whole | Function | ReadonlyArray<unknown>>
576
+ : [Extract<V, Whole | Function | ReadonlyArray<unknown>>] extends [never]
577
+ ? Exclude<V, Leaf>
578
+ : never
579
+
580
+ /** Tests if `Name` names a field of every object of `O`, as `keyof` does. */
581
+ type HasPart<O, Name extends string> = Name extends keyof O
582
+ ? true
583
+ : Name extends `${infer N extends number}`
584
+ ? N extends keyof O
585
+ ? true
586
+ : number extends keyof O
587
+ ? true
588
+ : false
589
+ : false
590
+
591
+ /**
592
+ * The objects below the part `Name` of the objects `O`, for a path that goes
593
+ * on, or `never` when it can not go on.
594
+ */
595
+ type PathStep<O, Name extends string, R extends PathRules> =
596
+ HasPart<O, Name> extends true
597
+ ? ObjectsBelow<NonNullable<ChildOf<O, Name>>, R["arrays"]>
598
+ : never
599
+
600
+ /** Tests if a path may end at a field with the values `V`: see `PathsOf`. */
601
+ type EndsAt<V, R extends PathRules, Last extends boolean> = [V] extends [never]
602
+ ? true
603
+ : {} extends V
604
+ ? true
605
+ : [Extract<V, Leaf | Whole>] extends [never]
606
+ ? R["arrays"] extends true
607
+ ? [Extract<V, ReadonlyArray<unknown>>] extends [never]
608
+ ? EndsAtObjects<ObjectsBelow<V, true>, R, Last>
609
+ : true
610
+ : false
611
+ : true
612
+
613
+ /**
614
+ * Tests if a path may end at a field that holds the objects `O`: a field of a
615
+ * rule may name a struct, and a request may name a record, or a struct at
616
+ * the last part that a path may have.
617
+ */
618
+ type EndsAtObjects<O, R extends PathRules, Last extends boolean> = [O] extends [
619
+ never,
620
+ ]
621
+ ? false
622
+ : R["parents"] extends true
623
+ ? true
624
+ : string extends keyof O
625
+ ? true
626
+ : number extends keyof O
627
+ ? true
628
+ : Last
629
+
630
+ /** The paths one part below `Done`, as the names that may come next. */
631
+ type NextNames<O, Done extends string> = `${Done}${keyof O & (string | number)}`
632
+
633
+ /**
634
+ * Walks a path two parts at a time, from the objects `O`. It gives `true`
635
+ * for a path that the rules `R` take, or the names that may come next after
636
+ * the last good part. `Count` counts the parts before `F`, so the walk knows
637
+ * the last part that a path may have: part 1000, the default of
638
+ * `Limits.fieldPathParts`.
639
+ */
640
+ type PathWalk<
641
+ O,
642
+ F extends string,
643
+ Done extends string,
644
+ R extends PathRules,
645
+ Count extends ReadonlyArray<0>,
646
+ > = F extends `${infer A}.${infer B}.${infer Rest}`
647
+ ? PathStep<O, A, R> extends infer O1
648
+ ? [O1] extends [never]
649
+ ? NextNames<O, Done>
650
+ : PathStep<O1, B, R> extends infer O2
651
+ ? [O2] extends [never]
652
+ ? NextNames<O1, `${Done}${A}.`>
653
+ : PathWalk<O2, Rest, `${Done}${A}.${B}.`, R, [...Count, 0, 0]>
654
+ : never
655
+ : never
656
+ : F extends `${infer A}.${infer B}`
657
+ ? PathStep<O, A, R> extends infer O1
658
+ ? [O1] extends [never]
659
+ ? NextNames<O, Done>
660
+ : PathEnd<O1, B, `${Done}${A}.`, R, [...Count, 0]>
661
+ : never
662
+ : PathEnd<O, F, Done, R, Count>
663
+
664
+ type PathEnd<
665
+ O,
666
+ Name extends string,
667
+ Done extends string,
668
+ R extends PathRules,
669
+ Count extends ReadonlyArray<0>,
670
+ > =
671
+ HasPart<O, Name> extends true
672
+ ? EndsAt<
673
+ NonNullable<ChildOf<O, Name>>,
674
+ R,
675
+ Count["length"] extends 999 ? true : false
676
+ > extends true
677
+ ? true
678
+ : // The name is a field, but a path may not end at it, as at a struct
679
+ // for a condition: the paths below it may come next. The names of
680
+ // this place would hold the name itself.
681
+ NextNames<
682
+ ObjectsBelow<NonNullable<ChildOf<O, Name>>, R["arrays"]>,
683
+ `${Done}${Name}.`
684
+ >
685
+ : NextNames<O, Done>
686
+
687
+ /**
688
+ * Checks one field path `F` of `T`, of any length up to about 1000 parts.
689
+ * It gives `F` for a path that the rules `R` take. For another path, it gives
690
+ * the paths that may come next after its last good part, so a type error
691
+ * names them. For a union of types, a part must be in each of them.
692
+ */
693
+ type PathCheck<T, F extends string, R extends PathRules> = [T] extends [object]
694
+ ? // Each path of a union of paths, as of a field typed `FieldSelector`,
695
+ // is checked by itself.
696
+ F extends unknown
697
+ ? PathWalk<T, F, "", R, []> extends true
698
+ ? F
699
+ : // The names come from parts of `F`. Inference must not find `F`
700
+ // in them, so a call gets its `F` from the path that it gives.
701
+ NoInfer<PathWalk<T, F, "", R, []>>
702
+ : never
703
+ : never
704
+
705
+ /**
706
+ * A path of `T` that a condition may read, as one of {@link FieldPath}, of
707
+ * any length up to about 1000 parts. It is `F` when `F` is such a path, and
708
+ * the names that may come next when it is not.
709
+ *
710
+ * @stability stable
711
+ * @category utility types
712
+ * @since 2.1.0
713
+ */
714
+ export type ReadPath<T, F extends string> = PathCheck<T, F, ReadRules>
715
+
716
+ /**
717
+ * A path of `T` that a request may name, as one of {@link FieldSelector}, of
718
+ * any length up to about 1000 parts. See {@link ReadPath}.
719
+ *
720
+ * @stability stable
721
+ * @category utility types
722
+ * @since 2.1.0
723
+ */
724
+ export type SelectPath<T, F extends string> = PathCheck<T, F, SelectRules>
725
+
726
+ /**
727
+ * A path of `T` that a field of a rule may name, as one of
728
+ * {@link FieldName}, of any length up to about 1000 parts. See
729
+ * {@link ReadPath}.
730
+ *
731
+ * @stability stable
732
+ * @category utility types
733
+ * @since 2.1.0
734
+ */
735
+ export type NamePath<T, F extends string> = PathCheck<T, F, NameRules>
736
+
737
+ /** A path that a condition may read, with an ordered value. */
738
+ type OrderedReadPath<T, F extends string> =
739
+ ReadPath<T, F> extends F
740
+ ? Exclude<PathValue<T, F>, null> extends number | string
741
+ ? F
742
+ : never
743
+ : ReadPath<T, F>
744
+
745
+ /** A path that a condition may read, with a scalar value. */
746
+ type ScalarReadPath<T, F extends string> =
747
+ ReadPath<T, F> extends F
748
+ ? PathValue<T, F> extends Scalar
749
+ ? F
750
+ : never
751
+ : ReadPath<T, F>
752
+
531
753
  /**
532
754
  * A value for a field of type `A`: a fixed value, or a field of the principal
533
755
  * with the same type.
@@ -538,16 +760,6 @@ type ChildOf<T, Name extends string> = Name extends keyof T
538
760
  */
539
761
  export type OperandOf<A, P = never> = Extract<A, Scalar> | Ref<A, P>
540
762
 
541
- type ScalarPath<T> = {
542
- [F in FieldPath<T>]: PathValue<T, F> extends Scalar ? F : never
543
- }[FieldPath<T>]
544
-
545
- type OrderedPath<T> = {
546
- [F in FieldPath<T>]: Exclude<PathValue<T, F>, null> extends number | string
547
- ? F
548
- : never
549
- }[FieldPath<T>]
550
-
551
763
  /**
552
764
  * A test made by a {@link Builder}. It runs no code, but it keeps the value
553
765
  * type of its resource, so a test on the fields of one resource can not go
@@ -584,58 +796,60 @@ type PrincipalOf<V, _P> = [Extract<V, PrincipalRef>] extends [never]
584
796
  export interface Builder<Data, Value, P> {
585
797
  /** The field is equal to the value. */
586
798
  readonly eq: <
587
- const F extends FieldPath<Data>,
799
+ const F extends string,
588
800
  const V extends OperandOf<FieldValue<Data, F>, any>,
589
801
  >(
590
- field: F,
802
+ field: ReadPath<Data, F>,
591
803
  value: V,
592
804
  ) => Test<Value, PrincipalOf<V, P>>
593
805
  /** The field is not equal to the value. */
594
806
  readonly ne: <
595
- const F extends FieldPath<Data>,
807
+ const F extends string,
596
808
  const V extends OperandOf<FieldValue<Data, F>, any>,
597
809
  >(
598
- field: F,
810
+ field: ReadPath<Data, F>,
599
811
  value: V,
600
812
  ) => Test<Value, PrincipalOf<V, P>>
601
813
  readonly lt: <
602
- const F extends OrderedPath<Data>,
814
+ const F extends string,
603
815
  const V extends OperandOf<Exclude<FieldValue<Data, F>, null>, any>,
604
816
  >(
605
- field: F,
817
+ field: OrderedReadPath<Data, F>,
606
818
  value: V,
607
819
  ) => Test<Value, PrincipalOf<V, P>>
608
820
  readonly lte: <
609
- const F extends OrderedPath<Data>,
821
+ const F extends string,
610
822
  const V extends OperandOf<Exclude<FieldValue<Data, F>, null>, any>,
611
823
  >(
612
- field: F,
824
+ field: OrderedReadPath<Data, F>,
613
825
  value: V,
614
826
  ) => Test<Value, PrincipalOf<V, P>>
615
827
  readonly gt: <
616
- const F extends OrderedPath<Data>,
828
+ const F extends string,
617
829
  const V extends OperandOf<Exclude<FieldValue<Data, F>, null>, any>,
618
830
  >(
619
- field: F,
831
+ field: OrderedReadPath<Data, F>,
620
832
  value: V,
621
833
  ) => Test<Value, PrincipalOf<V, P>>
622
834
  readonly gte: <
623
- const F extends OrderedPath<Data>,
835
+ const F extends string,
624
836
  const V extends OperandOf<Exclude<FieldValue<Data, F>, null>, any>,
625
837
  >(
626
- field: F,
838
+ field: OrderedReadPath<Data, F>,
627
839
  value: V,
628
840
  ) => Test<Value, PrincipalOf<V, P>>
629
841
  /** The field is equal to one of the values. */
630
842
  readonly in: <
631
- const F extends FieldPath<Data>,
843
+ const F extends string,
632
844
  const Vs extends ReadonlyArray<OperandOf<FieldValue<Data, F>, any>>,
633
845
  >(
634
- field: F,
846
+ field: ReadPath<Data, F>,
635
847
  values: Vs,
636
848
  ) => Test<Value, PrincipalOf<Vs[number], P>>
637
849
  /** The field has a value that is not `null`. */
638
- readonly exists: <const F extends FieldPath<Data>>(field: F) => Test<Value>
850
+ readonly exists: <const F extends string>(
851
+ field: ReadPath<Data, F>,
852
+ ) => Test<Value>
639
853
  /** The path of the resource starts with these parts. */
640
854
  readonly under: <
641
855
  const Ps extends ReadonlyArray<string | null | Ref<string | null, any>>,
@@ -646,8 +860,8 @@ export interface Builder<Data, Value, P> {
646
860
  * A field of the principal, to use as a value. The field must have a
647
861
  * {@link Scalar} type.
648
862
  */
649
- readonly principal: <const F extends ScalarPath<P>>(
650
- field: F,
863
+ readonly principal: <const F extends string>(
864
+ field: ScalarReadPath<P, F>,
651
865
  ) => Ref<PathValue<P, F>, P>
652
866
  readonly and: <const Cs extends ReadonlyArray<Any>>(
653
867
  ...conditions: Cs
@@ -992,50 +1206,65 @@ const literalValue = (operand: Operand, field: string): Scalar => {
992
1206
  return operand.value
993
1207
  }
994
1208
 
995
- /** Folds a condition. A shared child is folded again for each place. */
996
- const foldNode = <A>(node: Nodes.Node, interpreter: Interpreter<A>): A => {
997
- switch (node._tag) {
998
- case "True":
999
- return interpreter.true()
1000
- case "False":
1001
- return interpreter.false()
1002
- case "Compare":
1003
- return interpreter.compare(
1004
- node.op,
1005
- node.field,
1006
- literalValue(node.value, node.field),
1007
- )
1008
- case "In":
1009
- return interpreter.in(
1010
- node.field,
1011
- Arr.map(node.values, (operand) => literalValue(operand, node.field)),
1012
- )
1013
- case "Exists":
1014
- return interpreter.exists(node.field)
1015
- case "Under":
1016
- throw Untranslatable.make({
1017
- reason:
1018
- "An Under node needs the resource path. Call Condition.partial first.",
1019
- })
1020
- case "And":
1021
- return interpreter.and(
1022
- Arr.map(node.conditions, (child) => foldNode(child, interpreter)),
1023
- )
1024
- case "Or":
1025
- return interpreter.or(
1026
- Arr.map(node.conditions, (child) => foldNode(child, interpreter)),
1027
- )
1028
- case "Not":
1029
- return interpreter.not(foldNode(node.condition, interpreter))
1030
- case "Predicate":
1031
- if (interpreter.predicate === undefined) {
1032
- throw Untranslatable.make({
1033
- reason: `The predicate "${node.name}" can not become a query`,
1034
- })
1209
+ /**
1210
+ * Folds a condition. A shared child is folded again for each place. The walk
1211
+ * takes the steps of a trampoline, so a deep condition does not fill the
1212
+ * stack.
1213
+ */
1214
+ const foldNode = <A>(root: Nodes.Node, interpreter: Interpreter<A>): A =>
1215
+ Trampoline.run(root.depth, (R) => {
1216
+ const go = (node: Nodes.Node): Trampoline.Step<A> => {
1217
+ const children = (nodes: ReadonlyArray<Nodes.Node>) =>
1218
+ R.forEach(nodes, (child) => R.suspend(() => go(child)))
1219
+ switch (node._tag) {
1220
+ case "True":
1221
+ return R.succeed(interpreter.true())
1222
+ case "False":
1223
+ return R.succeed(interpreter.false())
1224
+ case "Compare":
1225
+ return R.succeed(
1226
+ interpreter.compare(
1227
+ node.op,
1228
+ node.field,
1229
+ literalValue(node.value, node.field),
1230
+ ),
1231
+ )
1232
+ case "In":
1233
+ return R.succeed(
1234
+ interpreter.in(
1235
+ node.field,
1236
+ Arr.map(node.values, (operand) =>
1237
+ literalValue(operand, node.field),
1238
+ ),
1239
+ ),
1240
+ )
1241
+ case "Exists":
1242
+ return R.succeed(interpreter.exists(node.field))
1243
+ case "Under":
1244
+ throw Untranslatable.make({
1245
+ reason:
1246
+ "An Under node needs the resource path. Call Condition.partial first.",
1247
+ })
1248
+ case "And":
1249
+ return R.map(children(node.conditions), interpreter.and)
1250
+ case "Or":
1251
+ return R.map(children(node.conditions), interpreter.or)
1252
+ case "Not":
1253
+ return R.map(
1254
+ R.suspend(() => go(node.condition)),
1255
+ interpreter.not,
1256
+ )
1257
+ case "Predicate":
1258
+ if (interpreter.predicate === undefined) {
1259
+ throw Untranslatable.make({
1260
+ reason: `The predicate "${node.name}" can not become a query`,
1261
+ })
1262
+ }
1263
+ return R.succeed(interpreter.predicate(node.name))
1035
1264
  }
1036
- return interpreter.predicate(node.name)
1037
- }
1038
- }
1265
+ }
1266
+ return go(root)
1267
+ })
1039
1268
 
1040
1269
  /**
1041
1270
  * Changes a condition into another form with an interpreter. Call
@@ -1220,9 +1449,11 @@ export type PlainCondition = Condition<any>
1220
1449
  * The Schema of a condition with no predicate. It checks the shape only. Use
1221
1450
  * `Policy.schema` to check the field names against a domain too.
1222
1451
  *
1223
- * The decoder takes at most 500 levels of conditions, and at most 1000000
1224
- * objects and array items, with a shared object counted for each place. It
1225
- * reads only the own data fields of the input.
1452
+ * The decoder takes the default limits: at most `conditionNodes` nodes,
1453
+ * 1000000, and `jsonNodes` objects and array items, 10000000, with a shared
1454
+ * object counted for each place. It stops at the first one past a limit. It
1455
+ * takes any number of levels, and it reads only the own data fields of the
1456
+ * input. Use `Policy.schema` for the limits of a domain.
1226
1457
  *
1227
1458
  * @stability stable
1228
1459
  * @category schemas
package/src/Domain.ts CHANGED
@@ -18,6 +18,7 @@ import type * as HashMap from "effect/HashMap"
18
18
  import type * as Schema from "effect/Schema"
19
19
  import type * as Catalog from "./internal/catalog.ts"
20
20
  import * as Internal from "./internal/domain.ts"
21
+ import type * as Limits from "./Limits.ts"
21
22
  import type * as Resource from "./Resource.ts"
22
23
 
23
24
  /** The Schema of a principal: a Schema of objects, such as a `Schema.Class`. */
@@ -42,6 +43,8 @@ export interface Domain<
42
43
  /** The descriptor of each resource, by its kind name. */
43
44
  readonly resources: HashMap.HashMap<string, Resource.Descriptor>
44
45
  readonly meta: Schema.Top | undefined
46
+ /** The limits of the domain: see `Limits`. */
47
+ readonly limits: Limits.Limits
45
48
  readonly "~Domain"?: {
46
49
  readonly Principal: P
47
50
  readonly Resources: Resources
@@ -174,6 +177,11 @@ export type AnyValue<D> = Resource.Value<Resources<D>>
174
177
  * may not need services, because `Policy.schema` gives a Schema that needs
175
178
  * none.
176
179
  *
180
+ * Give `limits` to set the limits of the domain, as
181
+ * `{ limits: { fieldPathParts: 2000 } }`. Each one is a whole number from 1
182
+ * up to its ceiling in `Limits.ceilings`, and a limit that you leave out has
183
+ * its default. A wrong value is a defect.
184
+ *
177
185
  * @stability stable
178
186
  * @category constructors
179
187
  * @since 0.3.0
@@ -186,4 +194,5 @@ export const make: <
186
194
  readonly principal: P
187
195
  readonly resources: Resources
188
196
  readonly meta?: M
197
+ readonly limits?: Partial<Limits.Limits>
189
198
  }) => Domain<P["Type"], Resources[number], M["Type"]> = Internal.make as never