@nmnmcc/ability 2.1.2 → 2.1.4

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 (43) hide show
  1. package/dist/Authorizer.d.ts +11 -11
  2. package/dist/Authorizer.d.ts.map +1 -1
  3. package/dist/Authorizer.js.map +1 -1
  4. package/dist/Condition.d.ts +1 -1
  5. package/dist/HttpApi.js +1 -1
  6. package/dist/Policy.d.ts +16 -6
  7. package/dist/Policy.d.ts.map +1 -1
  8. package/dist/Policy.js.map +1 -1
  9. package/dist/internal/algebra.js +8 -5
  10. package/dist/internal/algebra.js.map +1 -1
  11. package/dist/internal/authorizer.d.ts.map +1 -1
  12. package/dist/internal/authorizer.js +35 -9
  13. package/dist/internal/authorizer.js.map +1 -1
  14. package/dist/internal/bind.js +37 -27
  15. package/dist/internal/bind.js.map +1 -1
  16. package/dist/internal/catalog.d.ts +0 -31
  17. package/dist/internal/catalog.d.ts.map +1 -1
  18. package/dist/internal/catalog.js +39 -17
  19. package/dist/internal/catalog.js.map +1 -1
  20. package/dist/internal/decide.js +1 -1
  21. package/dist/internal/decide.js.map +1 -1
  22. package/dist/internal/domain.js +8 -5
  23. package/dist/internal/domain.js.map +1 -1
  24. package/dist/internal/patterns.js +1 -1
  25. package/dist/internal/policy-json.js +2 -2
  26. package/dist/internal/policy-json.js.map +1 -1
  27. package/dist/internal/policy-nodes.js +21 -12
  28. package/dist/internal/policy-nodes.js.map +1 -1
  29. package/dist/internal/policy.js +1 -1
  30. package/dist/internal/search.js +39 -27
  31. package/dist/internal/search.js.map +1 -1
  32. package/package.json +1 -1
  33. package/src/Authorizer.ts +10 -10
  34. package/src/Policy.ts +16 -5
  35. package/src/internal/algebra.ts +12 -8
  36. package/src/internal/authorizer.ts +77 -34
  37. package/src/internal/bind.ts +43 -36
  38. package/src/internal/catalog.ts +69 -40
  39. package/src/internal/decide.ts +5 -1
  40. package/src/internal/domain.ts +6 -11
  41. package/src/internal/policy-json.ts +24 -8
  42. package/src/internal/policy-nodes.ts +19 -13
  43. package/src/internal/search.ts +31 -21
@@ -1 +1 @@
1
- {"version":3,"file":"algebra.js","names":["Nodes","Nodes.And","Nodes.Or","Nodes.Compare","Nodes.Not","Trampoline.run","Nodes.isScalar","Trampoline.loop","Trampoline.toEffect","Nodes.runOf","Nodes.literal","Nodes.In","Nodes.Predicate"],"sources":["../../src/internal/algebra.ts"],"sourcesContent":["/**\n * The work on condition nodes: smart constructors, simplification, the step\n * that puts the principal in, tests on a value, and folds.\n *\n * The constructors of the nodes keep each condition small, so each walk here\n * has no memo. A shared child is walked again for each place, and the limits\n * of the nodes keep that work small. A walk takes the steps of a trampoline,\n * so a deep condition does not fill the stack: see `Trampoline`.\n */\n// A predicate gives an Effect with an error type and a service type that this\n// code does not know, so they are `unknown` here.\n// @effect-diagnostics anyUnknownInErrorContext:off\nimport * as Arr from \"effect/Array\"\nimport type * as Context from \"effect/Context\"\nimport * as Effect from \"effect/Effect\"\nimport * as Option from \"effect/Option\"\nimport type * as Resource from \"../Resource.ts\"\nimport * as Nodes from \"./nodes.ts\"\nimport { readPath } from \"./read.ts\"\nimport * as Trampoline from \"./trampoline.ts\"\n\ntype Node = Nodes.Node\n\nconst { always, never } = Nodes\n\n// Keys of structure\n\n/** The text of an operand. The type is in it, so `\"1\"` is not `1`. */\nconst operandText = (operand: Nodes.Operand): ReadonlyArray<string> =>\n\toperand._tag === \"Literal\"\n\t\t? [typeof operand.value, String(operand.value)]\n\t\t: [\"principal\", operand.path]\n\n/** The parts of the text of a condition with no predicate. */\nconst shapeOf = (node: Node): unknown => {\n\tswitch (node._tag) {\n\t\tcase \"True\":\n\t\tcase \"False\":\n\t\t\treturn [node._tag]\n\t\tcase \"Compare\":\n\t\t\treturn [node._tag, node.op, node.field, operandText(node.value)]\n\t\tcase \"In\":\n\t\t\treturn [node._tag, node.field, Arr.map(node.values, operandText)]\n\t\tcase \"Exists\":\n\t\t\treturn [node._tag, node.field]\n\t\tcase \"Under\":\n\t\t\treturn [node._tag, Arr.map(node.prefix, operandText)]\n\t\tcase \"And\":\n\t\tcase \"Or\":\n\t\t\treturn [node._tag, Arr.map(node.conditions, shapeOf)]\n\t\tcase \"Not\":\n\t\t\treturn [node._tag, shapeOf(node.condition)]\n\t\tcase \"Predicate\":\n\t\t\t// A smart constructor and a search do not ask for the text of a\n\t\t\t// predicate: it is equal only to itself.\n\t\t\tthrow new Error(\"A predicate has no text of structure\")\n\t}\n}\n\n/**\n * The text of the structure of a condition with no predicate. Two conditions\n * with one text give the same answer for every value. It reads all of the\n * condition, so a search counts its size in the budget.\n */\nconst structureText = (node: Node): string => JSON.stringify(shapeOf(node))\n\n/**\n * The work of the text of the structure of a condition: each node, and each\n * value of an `In` test or an `Under` test. A node counts as one in `size`,\n * also an `In` test with very many values. This walk reads the nodes only,\n * so it takes `size` steps.\n */\nconst weightOf = (node: Node): number => {\n\tswitch (node._tag) {\n\t\tcase \"In\":\n\t\t\treturn 1 + node.values.length\n\t\tcase \"Under\":\n\t\t\treturn 1 + node.prefix.length\n\t\tcase \"And\":\n\t\tcase \"Or\":\n\t\t\treturn Arr.reduce(\n\t\t\t\tnode.conditions,\n\t\t\t\t1,\n\t\t\t\t(total, child) => total + weightOf(child),\n\t\t\t)\n\t\tcase \"Not\":\n\t\t\treturn 1 + weightOf(node.condition)\n\t\tdefault:\n\t\t\treturn 1\n\t}\n}\n\n/**\n * The most nodes of a condition that a smart constructor reads for its key,\n * and the most children of a child that it puts into a node. A larger child\n * is its own key, and it stays one child, so the work of a constructor stays\n * small. A deep chain of `And` nodes, for one, does not copy all its leaves\n * at each level.\n */\nconst keyNodes = 64\n\n/** The most work of a key, with the values of its tests: see {@link weightOf}. */\nconst keyWeight = 256\n\n/**\n * The key of a child in a smart constructor: the text of its structure, or\n * the node itself when it is large. The keys go into a native `Set`, not a\n * `HashSet` of Effect. The hash of a string in Effect has no random seed, so\n * a policy could hold very many strings with one hash, and each test of the\n * set would read all of them. A native `Set` finds a node by the node itself,\n * and it hashes a string with the random seed of the engine.\n */\nexport const keyOf = (node: Node): string | Node =>\n\tnode.size > keyNodes || weightOf(node) > keyWeight\n\t\t? node\n\t\t: structureText(node)\n\n/**\n * Keeps the first node of each structure, in order. A large node is a copy\n * only of itself.\n */\nconst dedupe = (nodes: ReadonlyArray<Node>): ReadonlyArray<Node> => {\n\t// The set belongs to this call.\n\tconst seen = new Set<string | Node>()\n\treturn Arr.filter(nodes, (node) => {\n\t\tconst key = keyOf(node)\n\t\tif (seen.has(key)) {\n\t\t\treturn false\n\t\t}\n\t\tseen.add(key)\n\t\treturn true\n\t})\n}\n\n/**\n * Removes the children that the other children make useless. In an `Or`,\n * `a OR (a AND b)` is `a`. In an `And`, `a AND (a OR b)` is `a`.\n */\nconst absorb = (\n\tinner: \"And\" | \"Or\",\n\tnodes: ReadonlyArray<Node>,\n): ReadonlyArray<Node> => {\n\t// A native `Set`, as in `dedupe`.\n\tconst all = new Set(Arr.map(nodes, keyOf))\n\treturn Arr.filter(\n\t\tnodes,\n\t\t(node) =>\n\t\t\tnode._tag !== inner ||\n\t\t\t!Arr.some(node.conditions, (part) => all.has(keyOf(part))),\n\t)\n}\n\n// Smart constructors\n\n/**\n * Gives the result of an `And` with a `False` child, or of an `Or` with a\n * `True` child. The children are tested in order, so a predicate before the\n * constant still runs, and it may fail. When there is such a predicate, the\n * children before the constant stay, so the failure is not lost.\n */\nconst shortCircuit = (\n\ttag: \"And\" | \"Or\",\n\tchildren: ReadonlyArray<Node>,\n\tindex: number,\n): Node => {\n\tconst constant = tag === \"And\" ? never : always\n\tconst neutral = tag === \"And\" ? \"True\" : \"False\"\n\tconst before = Arr.filter(\n\t\tArr.take(children, index),\n\t\t(child) => child._tag !== neutral,\n\t)\n\tif (!Arr.some(before, (child) => child.opaque)) {\n\t\treturn constant\n\t}\n\treturn tag === \"And\"\n\t\t? new Nodes.And([...before, constant])\n\t\t: new Nodes.Or([...before, constant])\n}\n\n/**\n * Makes an `And` or an `Or` of simple children, and makes it simple. It looks\n * one level down only:\n * - it puts the children of a child of the same kind into the node, when\n * the child has at most `keyNodes` of them;\n * - it stops at a `False` in an `And`, or at a `True` in an `Or`;\n * - it removes `True` from an `And`, `False` from an `Or`, copies, and the\n * children that other children make useless.\n *\n * A predicate may fail, and it may give another answer when it runs again. So\n * when a child has a predicate, the children stay as they are, and each one\n * runs in its place. A child with a predicate is not put into the node either.\n */\nconst junction = (tag: \"And\" | \"Or\", children: ReadonlyArray<Node>): Node => {\n\tconst constant = tag === \"And\" ? \"False\" : \"True\"\n\tconst neutral = tag === \"And\" ? \"True\" : \"False\"\n\tconst flat = Arr.flatMap(children, (child) =>\n\t\tchild._tag === tag && !child.opaque && child.conditions.length <= keyNodes\n\t\t\t? child.conditions\n\t\t\t: [child],\n\t)\n\treturn Option.match(\n\t\tArr.findFirstIndex(flat, (child) => child._tag === constant),\n\t\t{\n\t\t\tonSome: (stop) => shortCircuit(tag, flat, stop),\n\t\t\tonNone: () => {\n\t\t\t\tconst kept = Arr.filter(flat, (child) => child._tag !== neutral)\n\t\t\t\tconst unique = Arr.some(kept, (child) => child.opaque)\n\t\t\t\t\t? kept\n\t\t\t\t\t: absorb(tag === \"And\" ? \"Or\" : \"And\", dedupe(kept))\n\t\t\t\treturn unique.length === 0\n\t\t\t\t\t? tag === \"And\"\n\t\t\t\t\t\t? always\n\t\t\t\t\t\t: never\n\t\t\t\t\t: unique.length === 1\n\t\t\t\t\t\t? unique[0]!\n\t\t\t\t\t\t: tag === \"And\"\n\t\t\t\t\t\t\t? new Nodes.And(unique)\n\t\t\t\t\t\t\t: new Nodes.Or(unique)\n\t\t\t},\n\t\t},\n\t)\n}\n\n/** An `And` of simple children, made simple. */\nexport const and = (children: ReadonlyArray<Node>): Node =>\n\tjunction(\"And\", children)\n\n/** An `Or` of simple children, made simple. */\nexport const or = (children: ReadonlyArray<Node>): Node =>\n\tjunction(\"Or\", children)\n\n/** A `Not` of a simple child, made simple. */\nexport const not = (child: Node): Node => {\n\tswitch (child._tag) {\n\t\tcase \"True\":\n\t\t\treturn never\n\t\tcase \"False\":\n\t\t\treturn always\n\t\tcase \"Not\":\n\t\t\treturn child.condition\n\t\tcase \"Compare\":\n\t\t\t// A principal field with no value makes `eq` and `ne` both false, so\n\t\t\t// only a fixed value lets `not eq` become `ne`.\n\t\t\treturn child.value._tag === \"Literal\" &&\n\t\t\t\t(child.op === \"eq\" || child.op === \"ne\")\n\t\t\t\t? new Nodes.Compare({\n\t\t\t\t\t\top: child.op === \"eq\" ? \"ne\" : \"eq\",\n\t\t\t\t\t\tfield: child.field,\n\t\t\t\t\t\tvalue: child.value,\n\t\t\t\t\t})\n\t\t\t\t: new Nodes.Not(child)\n\t\tdefault:\n\t\t\treturn new Nodes.Not(child)\n\t}\n}\n\ntype Step<A> = Trampoline.Step<A>\n\n/** The children of a node, each walked by `go` as a step of `R`. */\nconst eachChild = <A>(\n\tR: Trampoline.Runner,\n\tchildren: ReadonlyArray<Node>,\n\tgo: (child: Node) => Step<A>,\n): Step<ReadonlyArray<A>> =>\n\tR.forEach(children, (child) => R.suspend(() => go(child)))\n\n/** Makes a condition simple, from its leaves up. */\nexport const simplify = (node: Node): Node =>\n\tTrampoline.run(node.depth, (R) => {\n\t\tconst go = (current: Node): Step<Node> => {\n\t\t\tswitch (current._tag) {\n\t\t\t\tcase \"And\":\n\t\t\t\tcase \"Or\": {\n\t\t\t\t\tconst tag = current._tag\n\t\t\t\t\treturn R.map(eachChild(R, current.conditions, go), (children) =>\n\t\t\t\t\t\tjunction(tag, children),\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t\tcase \"Not\":\n\t\t\t\t\treturn R.map(\n\t\t\t\t\t\tR.suspend(() => go(current.condition)),\n\t\t\t\t\t\tnot,\n\t\t\t\t\t)\n\t\t\t\tcase \"In\":\n\t\t\t\t\treturn R.succeed(current.values.length === 0 ? never : current)\n\t\t\t\tdefault:\n\t\t\t\t\treturn R.succeed(current)\n\t\t\t}\n\t\t}\n\t\treturn go(node)\n\t})\n\n// Tests on a value\n\n/** The data that a condition needs for a test. */\nexport interface Input {\n\treadonly value: object\n\treadonly principal?: object | undefined\n\treadonly path?: ReadonlyArray<Resource.PathSegment> | undefined\n}\n\n/**\n * Gets a field of a value by a path with dots. It reads only plain data: see\n * `readPart`. A missing field, or a field under a value that is not an object,\n * gives `null`.\n */\nconst getField = (value: unknown, path: string): unknown =>\n\treadPath(value, path.split(\".\"))\n\n/**\n * Gives the value of an operand. A principal field that is `null`, missing, or\n * not a scalar gives `undefined`. No field of a resource is `undefined`, so a\n * test with it is never true. This keeps the check closed: a principal with no\n * id never matches a resource with no owner.\n */\nconst resolve = (operand: Nodes.Operand, principal: unknown): unknown => {\n\tif (operand._tag === \"Literal\") {\n\t\treturn operand.value\n\t}\n\tconst value = getField(principal, operand.path)\n\treturn value !== null && Nodes.isScalar(value) ? value : undefined\n}\n\nexport const testCompare = (\n\top: Nodes.CompareOperator,\n\tleft: unknown,\n\tright: unknown,\n): boolean => {\n\tif (right === undefined) {\n\t\treturn false\n\t}\n\tswitch (op) {\n\t\tcase \"eq\":\n\t\t\treturn left === right\n\t\tcase \"ne\":\n\t\t\treturn left !== right\n\t\tdefault: {\n\t\t\tconst ordered =\n\t\t\t\t(typeof left === \"number\" && typeof right === \"number\") ||\n\t\t\t\t(typeof left === \"string\" && typeof right === \"string\")\n\t\t\tif (!ordered) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tconst a = left as number | string\n\t\t\tconst b = right as number | string\n\t\t\tswitch (op) {\n\t\t\t\tcase \"lt\":\n\t\t\t\t\treturn a < b\n\t\t\t\tcase \"lte\":\n\t\t\t\t\treturn a <= b\n\t\t\t\tcase \"gt\":\n\t\t\t\t\treturn a > b\n\t\t\t\tcase \"gte\":\n\t\t\t\t\treturn a >= b\n\t\t\t}\n\t\t}\n\t}\n}\n\n/** Gives the values of the path of a resource, or `undefined` for no path. */\nconst pathValues = (\n\tvalue: unknown,\n\tpath: ReadonlyArray<Resource.PathSegment> | undefined,\n): ReadonlyArray<unknown> | undefined =>\n\tpath?.map((segment) =>\n\t\ttypeof segment === \"string\" ? segment : getField(value, segment.field),\n\t)\n\nconst testUnder = (\n\tprefix: ReadonlyArray<Nodes.Operand>,\n\tinput: Input,\n): boolean => {\n\tconst values = pathValues(input.value, input.path)\n\tif (values === undefined || prefix.length > values.length) {\n\t\treturn false\n\t}\n\t// An operand with no value never matches, also a hole in a path that gives\n\t// `undefined` too.\n\treturn prefix.every((operand, index) => {\n\t\tconst value = resolve(operand, input.principal)\n\t\treturn value !== undefined && value === values[index]\n\t})\n}\n\n/**\n * The test of a simple condition with no predicate on a value, as a walk.\n * The children of `And` and `Or` run in order, and they stop at the first\n * child that gives the answer.\n */\nconst testWith = (input: Input) => (R: Trampoline.Runner) => {\n\tconst go = (node: Node): Step<boolean> => {\n\t\tswitch (node._tag) {\n\t\t\tcase \"True\":\n\t\t\t\treturn R.succeed(true)\n\t\t\tcase \"False\":\n\t\t\t\treturn R.succeed(false)\n\t\t\tcase \"Compare\":\n\t\t\t\treturn R.succeed(\n\t\t\t\t\ttestCompare(\n\t\t\t\t\t\tnode.op,\n\t\t\t\t\t\tgetField(input.value, node.field),\n\t\t\t\t\t\tresolve(node.value, input.principal),\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\tcase \"In\": {\n\t\t\t\tconst field = getField(input.value, node.field)\n\t\t\t\treturn R.succeed(\n\t\t\t\t\tnode.values.some(\n\t\t\t\t\t\t(operand) => resolve(operand, input.principal) === field,\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t}\n\t\t\tcase \"Exists\":\n\t\t\t\treturn R.succeed(getField(input.value, node.field) !== null)\n\t\t\tcase \"Under\":\n\t\t\t\treturn R.succeed(testUnder(node.prefix, input))\n\t\t\tcase \"And\":\n\t\t\t\treturn R.every(node.conditions, (child) => R.suspend(() => go(child)))\n\t\t\tcase \"Or\":\n\t\t\t\treturn R.some(node.conditions, (child) => R.suspend(() => go(child)))\n\t\t\tcase \"Not\":\n\t\t\t\treturn R.map(\n\t\t\t\t\tR.suspend(() => go(node.condition)),\n\t\t\t\t\t(value) => !value,\n\t\t\t\t)\n\t\t\tcase \"Predicate\":\n\t\t\t\t// The types stop this. A predicate needs `evaluate`.\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`The predicate \"${node.name}\" needs an Effect. Use Condition.evaluate.`,\n\t\t\t\t)\n\t\t}\n\t}\n\treturn go\n}\n\n/** Tests a simple condition with no predicate on a value. */\nconst testSync = (node: Node, input: Input): boolean =>\n\tTrampoline.run(node.depth, (R) => testWith(input)(R)(node))\n\n/**\n * Tests a simple condition on a value. The children of `And` and `Or` run in\n * order, and they stop at the first child that gives the answer. Each call\n * for a child is a step of the Effect, so a deep condition does not fill the\n * stack. A part with no predicate runs as a walk in the same loop.\n */\nconst test = (\n\tnode: Node,\n\tinput: Input,\n): Effect.Effect<boolean, unknown, unknown> => {\n\tif (!node.opaque) {\n\t\treturn node.depth <= Trampoline.directDepth\n\t\t\t? Effect.sync(() => testSync(node, input))\n\t\t\t: node.pipe(testWith(input)(Trampoline.loop), Trampoline.toEffect)\n\t}\n\tswitch (node._tag) {\n\t\tcase \"Predicate\":\n\t\t\treturn Nodes.runOf(node)(input.value, input.principal)\n\t\tcase \"Not\":\n\t\t\treturn Effect.map(\n\t\t\t\tEffect.suspend(() => test(node.condition, input)),\n\t\t\t\t(value) => !value,\n\t\t\t)\n\t\tcase \"And\":\n\t\t\treturn Effect.map(\n\t\t\t\tEffect.findFirst(node.conditions, (child) =>\n\t\t\t\t\tEffect.map(\n\t\t\t\t\t\tEffect.suspend(() => test(child, input)),\n\t\t\t\t\t\t(value) => !value,\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t\tOption.isNone,\n\t\t\t)\n\t\tcase \"Or\":\n\t\t\treturn Effect.map(\n\t\t\t\tEffect.findFirst(node.conditions, (child) =>\n\t\t\t\t\tEffect.suspend(() => test(child, input)),\n\t\t\t\t),\n\t\t\t\tOption.isSome,\n\t\t\t)\n\t\tdefault:\n\t\t\treturn Effect.sync(() => testSync(node, input))\n\t}\n}\n\n/**\n * Tests a condition with no predicate on a value. The test runs on the\n * simple form of the condition with the principal in it, as a residual does.\n * So a test reads only the fields that the residual reads: a read of a field\n * that is not plain data is a defect, and a field that the answer does not\n * need, as in `x AND False`, is not read.\n */\nexport const evaluateSync = (node: Node, input: Input): boolean =>\n\ttestSync(partial(node, input), input)\n\n/** Tests a condition on a value, as {@link evaluateSync} does. */\nexport const evaluate = (\n\tnode: Node,\n\tinput: Input,\n): Effect.Effect<boolean, unknown, unknown> =>\n\tEffect.suspend(() => test(partial(node, input), input))\n\n// The principal and the path\n\n/**\n * Puts the value of the principal into an operand. It gives `undefined` for a\n * principal field with no value. See {@link resolve}.\n */\nconst bindOperand = (\n\toperand: Nodes.Operand,\n\tprincipal: unknown,\n): Nodes.Literal | undefined => {\n\tif (operand._tag === \"Literal\") {\n\t\treturn operand\n\t}\n\tconst value = resolve(operand, principal)\n\treturn value === undefined ? undefined : Nodes.literal(value as Nodes.Scalar)\n}\n\nconst expandUnder = (\n\tprefix: ReadonlyArray<Nodes.Operand>,\n\tprincipal: unknown,\n\tpath: ReadonlyArray<Resource.PathSegment> | undefined,\n): Node => {\n\tif (path === undefined || prefix.length > path.length) {\n\t\treturn never\n\t}\n\treturn and(\n\t\tArr.map(prefix, (operand, index): Node => {\n\t\t\tconst value = resolve(operand, principal)\n\t\t\tconst segment = path[index]!\n\t\t\treturn value === undefined\n\t\t\t\t? never\n\t\t\t\t: typeof segment === \"string\"\n\t\t\t\t\t? segment === value\n\t\t\t\t\t\t? always\n\t\t\t\t\t\t: never\n\t\t\t\t\t: new Nodes.Compare({\n\t\t\t\t\t\t\top: \"eq\",\n\t\t\t\t\t\t\tfield: segment.field,\n\t\t\t\t\t\t\tvalue: Nodes.literal(value as Nodes.Scalar),\n\t\t\t\t\t\t})\n\t\t}),\n\t)\n}\n\n/** The principal and the path of the resource, for {@link partial}. */\nexport interface PartialInput {\n\treadonly principal?: object | undefined\n\treadonly path?: ReadonlyArray<Resource.PathSegment> | undefined\n}\n\n/**\n * Puts the principal into a condition and expands `Under` with the path of the\n * resource. The result is simple. It has no principal fields and no `Under`\n * nodes. A predicate keeps the principal.\n */\nexport const partial = (node: Node, input: PartialInput): Node =>\n\tTrampoline.run(node.depth, (R) => {\n\t\tconst bind = (current: Node): Step<Node> => {\n\t\t\tswitch (current._tag) {\n\t\t\t\tcase \"Compare\": {\n\t\t\t\t\tconst value = bindOperand(current.value, input.principal)\n\t\t\t\t\treturn R.succeed(\n\t\t\t\t\t\tvalue === undefined\n\t\t\t\t\t\t\t? never\n\t\t\t\t\t\t\t: value === current.value\n\t\t\t\t\t\t\t\t? current\n\t\t\t\t\t\t\t\t: new Nodes.Compare({\n\t\t\t\t\t\t\t\t\t\top: current.op,\n\t\t\t\t\t\t\t\t\t\tfield: current.field,\n\t\t\t\t\t\t\t\t\t\tvalue,\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t\tcase \"In\": {\n\t\t\t\t\tconst values = Arr.flatMap(current.values, (operand) =>\n\t\t\t\t\t\tOption.toArray(\n\t\t\t\t\t\t\tOption.fromUndefinedOr(bindOperand(operand, input.principal)),\n\t\t\t\t\t\t),\n\t\t\t\t\t)\n\t\t\t\t\treturn R.succeed(\n\t\t\t\t\t\tvalues.length === 0\n\t\t\t\t\t\t\t? never\n\t\t\t\t\t\t\t: new Nodes.In({ field: current.field, values }),\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t\tcase \"Under\":\n\t\t\t\t\treturn R.succeed(\n\t\t\t\t\t\texpandUnder(current.prefix, input.principal, input.path),\n\t\t\t\t\t)\n\t\t\t\tcase \"And\":\n\t\t\t\t\treturn R.map(eachChild(R, current.conditions, bind), and)\n\t\t\t\tcase \"Or\":\n\t\t\t\t\treturn R.map(eachChild(R, current.conditions, bind), or)\n\t\t\t\tcase \"Not\":\n\t\t\t\t\treturn R.map(\n\t\t\t\t\t\tR.suspend(() => bind(current.condition)),\n\t\t\t\t\t\tnot,\n\t\t\t\t\t)\n\t\t\t\tcase \"Predicate\": {\n\t\t\t\t\tconst run = Nodes.runOf(current)\n\t\t\t\t\treturn R.succeed(\n\t\t\t\t\t\tnew Nodes.Predicate({\n\t\t\t\t\t\t\tname: current.name,\n\t\t\t\t\t\t\trun: (value) => run(value, input.principal),\n\t\t\t\t\t\t}),\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t\treturn R.succeed(current)\n\t\t\t}\n\t\t}\n\t\treturn bind(node)\n\t})\n\n/** Gives the services in `context` to every predicate of a condition. */\nexport const provide = (node: Node, context: Context.Context<never>): Node =>\n\tTrampoline.run(node.depth, (R) => {\n\t\tconst go = (current: Node): Step<Node> => {\n\t\t\tif (!current.opaque) {\n\t\t\t\treturn R.succeed(current)\n\t\t\t}\n\t\t\tswitch (current._tag) {\n\t\t\t\tcase \"Predicate\": {\n\t\t\t\t\tconst run = Nodes.runOf(current)\n\t\t\t\t\treturn R.succeed(\n\t\t\t\t\t\tnew Nodes.Predicate({\n\t\t\t\t\t\t\tname: current.name,\n\t\t\t\t\t\t\trun: (value, principal) =>\n\t\t\t\t\t\t\t\tEffect.provideContext(run(value, principal), context),\n\t\t\t\t\t\t}),\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t\tcase \"And\":\n\t\t\t\t\treturn R.map(\n\t\t\t\t\t\teachChild(R, current.conditions, go),\n\t\t\t\t\t\t(children) => new Nodes.And(children),\n\t\t\t\t\t)\n\t\t\t\tcase \"Or\":\n\t\t\t\t\treturn R.map(\n\t\t\t\t\t\teachChild(R, current.conditions, go),\n\t\t\t\t\t\t(children) => new Nodes.Or(children),\n\t\t\t\t\t)\n\t\t\t\tcase \"Not\":\n\t\t\t\t\treturn R.map(\n\t\t\t\t\t\tR.suspend(() => go(current.condition)),\n\t\t\t\t\t\t(child) => new Nodes.Not(child),\n\t\t\t\t\t)\n\t\t\t\tdefault:\n\t\t\t\t\treturn R.succeed(current)\n\t\t\t}\n\t\t}\n\t\treturn go(node)\n\t})\n\n/** The fields that a condition tests, in the order that they first come. */\nexport const fields = (node: Node): ReadonlyArray<string> => {\n\tconst all = Trampoline.run(node.depth, (R) => {\n\t\tconst go = (current: Node): Step<ReadonlyArray<string>> => {\n\t\t\tswitch (current._tag) {\n\t\t\t\tcase \"Compare\":\n\t\t\t\tcase \"In\":\n\t\t\t\tcase \"Exists\":\n\t\t\t\t\treturn R.succeed([current.field])\n\t\t\t\tcase \"And\":\n\t\t\t\tcase \"Or\":\n\t\t\t\t\treturn R.map(eachChild(R, current.conditions, go), Arr.flatten)\n\t\t\t\tcase \"Not\":\n\t\t\t\t\treturn R.suspend(() => go(current.condition))\n\t\t\t\tdefault:\n\t\t\t\t\treturn R.succeed([])\n\t\t\t}\n\t\t}\n\t\treturn go(node)\n\t})\n\t// A native `Set`, as in `dedupe`: a field of a condition that is not bound\n\t// to a domain may be any string.\n\treturn Array.from(new Set(all))\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"algebra.js","names":["Nodes","Nodes.And","Nodes.Or","Nodes.Compare","Nodes.Not","Trampoline.run","Nodes.isScalar","Trampoline.loop","Trampoline.toEffect","Nodes.runOf","Nodes.literal","Nodes.In","Nodes.Predicate"],"sources":["../../src/internal/algebra.ts"],"sourcesContent":["/**\n * The work on condition nodes: smart constructors, simplification, the step\n * that puts the principal in, tests on a value, and folds.\n *\n * The constructors of the nodes keep each condition small, so each walk here\n * has no memo. A shared child is walked again for each place, and the limits\n * of the nodes keep that work small. A walk takes the steps of a trampoline,\n * so a deep condition does not fill the stack: see `Trampoline`.\n */\n// A predicate gives an Effect with an error type and a service type that this\n// code does not know, so they are `unknown` here.\n// @effect-diagnostics anyUnknownInErrorContext:off\nimport * as Arr from \"effect/Array\"\nimport type * as Context from \"effect/Context\"\nimport * as Effect from \"effect/Effect\"\nimport * as Option from \"effect/Option\"\nimport type * as Resource from \"../Resource.ts\"\nimport * as Nodes from \"./nodes.ts\"\nimport { readPath } from \"./read.ts\"\nimport * as Trampoline from \"./trampoline.ts\"\n\ntype Node = Nodes.Node\n\nconst { always, never } = Nodes\n\n// Keys of structure\n\n/** The text of an operand. The type is in it, so `\"1\"` is not `1`. */\nconst operandText = (operand: Nodes.Operand): ReadonlyArray<string> =>\n\toperand._tag === \"Literal\"\n\t\t? [typeof operand.value, String(operand.value)]\n\t\t: [\"principal\", operand.path]\n\n/** The parts of the text of a condition with no predicate. */\nconst shapeOf = (node: Node): unknown => {\n\tswitch (node._tag) {\n\t\tcase \"True\":\n\t\tcase \"False\":\n\t\t\treturn [node._tag]\n\t\tcase \"Compare\":\n\t\t\treturn [node._tag, node.op, node.field, operandText(node.value)]\n\t\tcase \"In\":\n\t\t\treturn [node._tag, node.field, Arr.map(node.values, operandText)]\n\t\tcase \"Exists\":\n\t\t\treturn [node._tag, node.field]\n\t\tcase \"Under\":\n\t\t\treturn [node._tag, Arr.map(node.prefix, operandText)]\n\t\tcase \"And\":\n\t\tcase \"Or\":\n\t\t\treturn [node._tag, Arr.map(node.conditions, shapeOf)]\n\t\tcase \"Not\":\n\t\t\treturn [node._tag, shapeOf(node.condition)]\n\t\tcase \"Predicate\":\n\t\t\t// A smart constructor and a search do not ask for the text of a\n\t\t\t// predicate: it is equal only to itself.\n\t\t\tthrow new Error(\"A predicate has no text of structure\")\n\t}\n}\n\n/**\n * The text of the structure of a condition with no predicate. Two conditions\n * with one text give the same answer for every value. It reads all of the\n * condition, so a search counts its size in the budget.\n */\nconst structureText = (node: Node): string => JSON.stringify(shapeOf(node))\n\n/**\n * The work of the text of the structure of a condition: each node, and each\n * value of an `In` test or an `Under` test. A node counts as one in `size`,\n * also an `In` test with very many values. This walk reads the nodes only,\n * so it takes `size` steps.\n */\nconst weightOf = (node: Node): number => {\n\tswitch (node._tag) {\n\t\tcase \"In\":\n\t\t\treturn 1 + node.values.length\n\t\tcase \"Under\":\n\t\t\treturn 1 + node.prefix.length\n\t\tcase \"And\":\n\t\tcase \"Or\":\n\t\t\treturn Arr.reduce(\n\t\t\t\tnode.conditions,\n\t\t\t\t1,\n\t\t\t\t(total, child) => total + weightOf(child),\n\t\t\t)\n\t\tcase \"Not\":\n\t\t\treturn 1 + weightOf(node.condition)\n\t\tdefault:\n\t\t\treturn 1\n\t}\n}\n\n/**\n * The most nodes of a condition that a smart constructor reads for its key,\n * and the most children of a child that it puts into a node. A larger child\n * is its own key, and it stays one child, so the work of a constructor stays\n * small. A deep chain of `And` nodes, for one, does not copy all its leaves\n * at each level.\n */\nconst keyNodes = 64\n\n/** The most work of a key, with the values of its tests: see {@link weightOf}. */\nconst keyWeight = 256\n\n/**\n * The key of a child in a smart constructor: the text of its structure, or\n * the node itself when it is large. The keys go into a native `Set`, not a\n * `HashSet` of Effect. The hash of a string in Effect has no random seed, so\n * a policy could hold very many strings with one hash, and each test of the\n * set would read all of them. A native `Set` finds a node by the node itself,\n * and it hashes a string with the random seed of the engine.\n */\nexport const keyOf = (node: Node): string | Node =>\n\tnode.size > keyNodes || weightOf(node) > keyWeight\n\t\t? node\n\t\t: structureText(node)\n\n/**\n * Keeps the first node of each structure, in order. A large node is a copy\n * only of itself.\n */\nconst dedupe = (nodes: ReadonlyArray<Node>): ReadonlyArray<Node> => {\n\t// The set belongs to this call.\n\tconst seen = new Set<string | Node>()\n\treturn Arr.filter(nodes, (node) => {\n\t\tconst key = keyOf(node)\n\t\tif (seen.has(key)) {\n\t\t\treturn false\n\t\t}\n\t\tseen.add(key)\n\t\treturn true\n\t})\n}\n\n/**\n * Removes the children that the other children make useless. In an `Or`,\n * `a OR (a AND b)` is `a`. In an `And`, `a AND (a OR b)` is `a`.\n */\nconst absorb = (\n\tinner: \"And\" | \"Or\",\n\tnodes: ReadonlyArray<Node>,\n): ReadonlyArray<Node> => {\n\t// A native `Set`, as in `dedupe`.\n\tconst all = new Set(Arr.map(nodes, keyOf))\n\treturn Arr.filter(\n\t\tnodes,\n\t\t(node) =>\n\t\t\tnode._tag !== inner ||\n\t\t\t!Arr.some(node.conditions, (part) => all.has(keyOf(part))),\n\t)\n}\n\n// Smart constructors\n\n/**\n * Gives the result of an `And` with a `False` child, or of an `Or` with a\n * `True` child. The children are tested in order, so a predicate before the\n * constant still runs, and it may fail. When there is such a predicate, the\n * children before the constant stay, so the failure is not lost.\n */\nconst shortCircuit = (\n\ttag: \"And\" | \"Or\",\n\tchildren: ReadonlyArray<Node>,\n\tindex: number,\n): Node => {\n\tconst constant = tag === \"And\" ? never : always\n\tconst neutral = tag === \"And\" ? \"True\" : \"False\"\n\tconst before = Arr.filter(\n\t\tArr.take(children, index),\n\t\t(child) => child._tag !== neutral,\n\t)\n\tif (!Arr.some(before, (child) => child.opaque)) {\n\t\treturn constant\n\t}\n\treturn tag === \"And\"\n\t\t? new Nodes.And([...before, constant])\n\t\t: new Nodes.Or([...before, constant])\n}\n\n/**\n * Makes an `And` or an `Or` of simple children, and makes it simple. It looks\n * one level down only:\n * - it puts the children of a child of the same kind into the node, when\n * the child has at most `keyNodes` of them;\n * - it stops at a `False` in an `And`, or at a `True` in an `Or`;\n * - it removes `True` from an `And`, `False` from an `Or`, copies, and the\n * children that other children make useless.\n *\n * A predicate may fail, and it may give another answer when it runs again. So\n * when a child has a predicate, the children stay as they are, and each one\n * runs in its place. A child with a predicate is not put into the node either.\n */\nconst junction = (tag: \"And\" | \"Or\", children: ReadonlyArray<Node>): Node => {\n\tconst constant = tag === \"And\" ? \"False\" : \"True\"\n\tconst neutral = tag === \"And\" ? \"True\" : \"False\"\n\tconst flat = Arr.flatMap(children, (child) =>\n\t\tchild._tag === tag && !child.opaque && child.conditions.length <= keyNodes\n\t\t\t? child.conditions\n\t\t\t: [child],\n\t)\n\treturn Option.match(\n\t\tArr.findFirstIndex(flat, (child) => child._tag === constant),\n\t\t{\n\t\t\tonSome: (stop) => shortCircuit(tag, flat, stop),\n\t\t\tonNone: () => {\n\t\t\t\tconst kept = Arr.filter(flat, (child) => child._tag !== neutral)\n\t\t\t\tconst unique = Arr.some(kept, (child) => child.opaque)\n\t\t\t\t\t? kept\n\t\t\t\t\t: absorb(tag === \"And\" ? \"Or\" : \"And\", dedupe(kept))\n\t\t\t\treturn unique.length === 0\n\t\t\t\t\t? tag === \"And\"\n\t\t\t\t\t\t? always\n\t\t\t\t\t\t: never\n\t\t\t\t\t: unique.length === 1\n\t\t\t\t\t\t? unique[0]!\n\t\t\t\t\t\t: tag === \"And\"\n\t\t\t\t\t\t\t? new Nodes.And(unique)\n\t\t\t\t\t\t\t: new Nodes.Or(unique)\n\t\t\t},\n\t\t},\n\t)\n}\n\n/** An `And` of simple children, made simple. */\nexport const and = (children: ReadonlyArray<Node>): Node =>\n\tjunction(\"And\", children)\n\n/** An `Or` of simple children, made simple. */\nexport const or = (children: ReadonlyArray<Node>): Node =>\n\tjunction(\"Or\", children)\n\n/** A `Not` of a simple child, made simple. */\nexport const not = (child: Node): Node => {\n\tswitch (child._tag) {\n\t\tcase \"True\":\n\t\t\treturn never\n\t\tcase \"False\":\n\t\t\treturn always\n\t\tcase \"Not\":\n\t\t\treturn child.condition\n\t\tcase \"Compare\":\n\t\t\t// A principal field with no value makes `eq` and `ne` both false, so\n\t\t\t// only a fixed value lets `not eq` become `ne`.\n\t\t\treturn child.value._tag === \"Literal\" &&\n\t\t\t\t(child.op === \"eq\" || child.op === \"ne\")\n\t\t\t\t? new Nodes.Compare({\n\t\t\t\t\t\top: child.op === \"eq\" ? \"ne\" : \"eq\",\n\t\t\t\t\t\tfield: child.field,\n\t\t\t\t\t\tvalue: child.value,\n\t\t\t\t\t})\n\t\t\t\t: new Nodes.Not(child)\n\t\tdefault:\n\t\t\treturn new Nodes.Not(child)\n\t}\n}\n\ntype Step<A> = Trampoline.Step<A>\n\n/** The children of a node, each walked by `go` as a step of `R`. */\nconst eachChild = <A>(\n\tR: Trampoline.Runner,\n\tchildren: ReadonlyArray<Node>,\n\tgo: (child: Node) => Step<A>,\n): Step<ReadonlyArray<A>> =>\n\tR.forEach(children, (child) => R.suspend(() => go(child)))\n\n/** Makes a condition simple, from its leaves up. */\nexport const simplify = (node: Node): Node =>\n\tTrampoline.run(node.depth, (R) => {\n\t\tconst go = (current: Node): Step<Node> => {\n\t\t\tswitch (current._tag) {\n\t\t\t\tcase \"And\":\n\t\t\t\tcase \"Or\": {\n\t\t\t\t\tconst tag = current._tag\n\t\t\t\t\treturn R.map(eachChild(R, current.conditions, go), (children) =>\n\t\t\t\t\t\tjunction(tag, children),\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t\tcase \"Not\":\n\t\t\t\t\treturn R.map(\n\t\t\t\t\t\tR.suspend(() => go(current.condition)),\n\t\t\t\t\t\tnot,\n\t\t\t\t\t)\n\t\t\t\tcase \"In\":\n\t\t\t\t\treturn R.succeed(current.values.length === 0 ? never : current)\n\t\t\t\tdefault:\n\t\t\t\t\treturn R.succeed(current)\n\t\t\t}\n\t\t}\n\t\treturn go(node)\n\t})\n\n// Tests on a value\n\n/** The data that a condition needs for a test. */\nexport interface Input {\n\treadonly value: object\n\treadonly principal?: object | undefined\n\treadonly path?: ReadonlyArray<Resource.PathSegment> | undefined\n}\n\n/**\n * Gets a field of a value by a path with dots. It reads only plain data: see\n * `readPart`. A missing field, or a field under a value that is not an object,\n * gives `null`.\n */\nconst getField = (value: unknown, path: string): unknown =>\n\treadPath(value, path.split(\".\"))\n\n/**\n * Gives the value of an operand. A principal field that is `null`, missing, or\n * not a scalar gives `undefined`. No field of a resource is `undefined`, so a\n * test with it is never true. This keeps the check closed: a principal with no\n * id never matches a resource with no owner.\n */\nconst resolve = (operand: Nodes.Operand, principal: unknown): unknown => {\n\tif (operand._tag === \"Literal\") {\n\t\treturn operand.value\n\t}\n\tconst value = getField(principal, operand.path)\n\treturn value !== null && Nodes.isScalar(value) ? value : undefined\n}\n\nexport const testCompare = (\n\top: Nodes.CompareOperator,\n\tleft: unknown,\n\tright: unknown,\n): boolean => {\n\tif (right === undefined) {\n\t\treturn false\n\t}\n\tswitch (op) {\n\t\tcase \"eq\":\n\t\t\treturn left === right\n\t\tcase \"ne\":\n\t\t\treturn left !== right\n\t\tdefault: {\n\t\t\tconst ordered =\n\t\t\t\t(typeof left === \"number\" && typeof right === \"number\") ||\n\t\t\t\t(typeof left === \"string\" && typeof right === \"string\")\n\t\t\tif (!ordered) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tconst a = left as number | string\n\t\t\tconst b = right as number | string\n\t\t\tswitch (op) {\n\t\t\t\tcase \"lt\":\n\t\t\t\t\treturn a < b\n\t\t\t\tcase \"lte\":\n\t\t\t\t\treturn a <= b\n\t\t\t\tcase \"gt\":\n\t\t\t\t\treturn a > b\n\t\t\t\tcase \"gte\":\n\t\t\t\t\treturn a >= b\n\t\t\t}\n\t\t}\n\t}\n}\n\n/** Gives the values of the path of a resource, or `undefined` for no path. */\nconst pathValues = (\n\tvalue: unknown,\n\tpath: ReadonlyArray<Resource.PathSegment> | undefined,\n): ReadonlyArray<unknown> | undefined =>\n\tpath?.map((segment) =>\n\t\ttypeof segment === \"string\" ? segment : getField(value, segment.field),\n\t)\n\nconst testUnder = (\n\tprefix: ReadonlyArray<Nodes.Operand>,\n\tinput: Input,\n): boolean => {\n\tconst values = pathValues(input.value, input.path)\n\tif (values === undefined || prefix.length > values.length) {\n\t\treturn false\n\t}\n\t// An operand with no value never matches, also a hole in a path that gives\n\t// `undefined` too.\n\treturn prefix.every((operand, index) => {\n\t\tconst value = resolve(operand, input.principal)\n\t\treturn value !== undefined && value === values[index]\n\t})\n}\n\n/**\n * The test of a simple condition with no predicate on a value, as a walk.\n * The children of `And` and `Or` run in order, and they stop at the first\n * child that gives the answer.\n */\nconst testWith = (input: Input) => (R: Trampoline.Runner) => {\n\tconst go = (node: Node): Step<boolean> => {\n\t\tswitch (node._tag) {\n\t\t\tcase \"True\":\n\t\t\t\treturn R.succeed(true)\n\t\t\tcase \"False\":\n\t\t\t\treturn R.succeed(false)\n\t\t\tcase \"Compare\":\n\t\t\t\treturn R.succeed(\n\t\t\t\t\ttestCompare(\n\t\t\t\t\t\tnode.op,\n\t\t\t\t\t\tgetField(input.value, node.field),\n\t\t\t\t\t\tresolve(node.value, input.principal),\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\tcase \"In\": {\n\t\t\t\tconst field = getField(input.value, node.field)\n\t\t\t\treturn R.succeed(\n\t\t\t\t\tnode.values.some(\n\t\t\t\t\t\t(operand) => resolve(operand, input.principal) === field,\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t}\n\t\t\tcase \"Exists\":\n\t\t\t\treturn R.succeed(getField(input.value, node.field) !== null)\n\t\t\tcase \"Under\":\n\t\t\t\treturn R.succeed(testUnder(node.prefix, input))\n\t\t\tcase \"And\":\n\t\t\t\treturn R.every(node.conditions, (child) => R.suspend(() => go(child)))\n\t\t\tcase \"Or\":\n\t\t\t\treturn R.some(node.conditions, (child) => R.suspend(() => go(child)))\n\t\t\tcase \"Not\":\n\t\t\t\treturn R.map(\n\t\t\t\t\tR.suspend(() => go(node.condition)),\n\t\t\t\t\t(value) => !value,\n\t\t\t\t)\n\t\t\tcase \"Predicate\":\n\t\t\t\t// The types stop this. A predicate needs `evaluate`.\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`The predicate \"${node.name}\" needs an Effect. Use Condition.evaluate.`,\n\t\t\t\t)\n\t\t}\n\t}\n\treturn go\n}\n\n/** Tests a simple condition with no predicate on a value. */\nconst testSync = (node: Node, input: Input): boolean =>\n\tTrampoline.run(node.depth, (R) => testWith(input)(R)(node))\n\n/**\n * Tests a simple condition on a value. The children of `And` and `Or` run in\n * order, and they stop at the first child that gives the answer. Each call\n * for a child is a step of the Effect, so a deep condition does not fill the\n * stack. A part with no predicate runs as a walk in the same loop.\n */\nconst test = (\n\tnode: Node,\n\tinput: Input,\n): Effect.Effect<boolean, unknown, unknown> => {\n\tif (!node.opaque) {\n\t\treturn node.depth <= Trampoline.directDepth\n\t\t\t? Effect.sync(() => testSync(node, input))\n\t\t\t: node.pipe(testWith(input)(Trampoline.loop), Trampoline.toEffect)\n\t}\n\tswitch (node._tag) {\n\t\tcase \"Predicate\":\n\t\t\treturn Nodes.runOf(node)(input.value, input.principal)\n\t\tcase \"Not\":\n\t\t\treturn Effect.map(\n\t\t\t\tEffect.suspend(() => test(node.condition, input)),\n\t\t\t\t(value) => !value,\n\t\t\t)\n\t\tcase \"And\":\n\t\t\treturn Effect.map(\n\t\t\t\tEffect.findFirst(node.conditions, (child) =>\n\t\t\t\t\tEffect.map(\n\t\t\t\t\t\tEffect.suspend(() => test(child, input)),\n\t\t\t\t\t\t(value) => !value,\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t\tOption.isNone,\n\t\t\t)\n\t\tcase \"Or\":\n\t\t\treturn Effect.map(\n\t\t\t\tEffect.findFirst(node.conditions, (child) =>\n\t\t\t\t\tEffect.suspend(() => test(child, input)),\n\t\t\t\t),\n\t\t\t\tOption.isSome,\n\t\t\t)\n\t\tdefault:\n\t\t\treturn Effect.sync(() => testSync(node, input))\n\t}\n}\n\n/**\n * Tests a condition with no predicate on a value. The test runs on the\n * simple form of the condition with the principal in it, as a residual does.\n * So a test reads only the fields that the residual reads: a read of a field\n * that is not plain data is a defect, and a field that the answer does not\n * need, as in `x AND False`, is not read.\n */\nexport const evaluateSync = (node: Node, input: Input): boolean =>\n\ttestSync(partial(node, input), input)\n\n/** Tests a condition on a value, as {@link evaluateSync} does. */\nexport const evaluate = (\n\tnode: Node,\n\tinput: Input,\n): Effect.Effect<boolean, unknown, unknown> =>\n\tEffect.suspend(() => test(partial(node, input), input))\n\n// The principal and the path\n\n/**\n * Puts the value of the principal into an operand. It gives `undefined` for a\n * principal field with no value. See {@link resolve}.\n */\nconst bindOperand = (\n\toperand: Nodes.Operand,\n\tprincipal: unknown,\n): Nodes.Literal | undefined => {\n\tif (operand._tag === \"Literal\") {\n\t\treturn operand\n\t}\n\tconst value = resolve(operand, principal)\n\treturn value === undefined ? undefined : Nodes.literal(value as Nodes.Scalar)\n}\n\nconst expandUnder = (\n\tprefix: ReadonlyArray<Nodes.Operand>,\n\tprincipal: unknown,\n\tpath: ReadonlyArray<Resource.PathSegment> | undefined,\n): Node => {\n\tif (path === undefined || prefix.length > path.length) {\n\t\treturn never\n\t}\n\treturn and(\n\t\tArr.map(prefix, (operand, index): Node => {\n\t\t\tconst value = resolve(operand, principal)\n\t\t\tconst segment = path[index]!\n\t\t\treturn value === undefined\n\t\t\t\t? never\n\t\t\t\t: typeof segment === \"string\"\n\t\t\t\t\t? segment === value\n\t\t\t\t\t\t? always\n\t\t\t\t\t\t: never\n\t\t\t\t\t: new Nodes.Compare({\n\t\t\t\t\t\t\top: \"eq\",\n\t\t\t\t\t\t\tfield: segment.field,\n\t\t\t\t\t\t\tvalue: Nodes.literal(value as Nodes.Scalar),\n\t\t\t\t\t\t})\n\t\t}),\n\t)\n}\n\n/** The principal and the path of the resource, for {@link partial}. */\nexport interface PartialInput {\n\treadonly principal?: object | undefined\n\treadonly path?: ReadonlyArray<Resource.PathSegment> | undefined\n}\n\n/**\n * Puts the principal into a condition and expands `Under` with the path of the\n * resource. The result is simple. It has no principal fields and no `Under`\n * nodes. A predicate keeps the principal.\n */\nexport const partial = (node: Node, input: PartialInput): Node =>\n\tTrampoline.run(node.depth, (R) => {\n\t\tconst bind = (current: Node): Step<Node> => {\n\t\t\tswitch (current._tag) {\n\t\t\t\tcase \"Compare\": {\n\t\t\t\t\tconst value = bindOperand(current.value, input.principal)\n\t\t\t\t\treturn R.succeed(\n\t\t\t\t\t\tvalue === undefined\n\t\t\t\t\t\t\t? never\n\t\t\t\t\t\t\t: value === current.value\n\t\t\t\t\t\t\t\t? current\n\t\t\t\t\t\t\t\t: new Nodes.Compare({\n\t\t\t\t\t\t\t\t\t\top: current.op,\n\t\t\t\t\t\t\t\t\t\tfield: current.field,\n\t\t\t\t\t\t\t\t\t\tvalue,\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t\tcase \"In\": {\n\t\t\t\t\tconst values = Arr.flatMap(current.values, (operand) =>\n\t\t\t\t\t\tOption.toArray(\n\t\t\t\t\t\t\tOption.fromUndefinedOr(bindOperand(operand, input.principal)),\n\t\t\t\t\t\t),\n\t\t\t\t\t)\n\t\t\t\t\treturn R.succeed(\n\t\t\t\t\t\tvalues.length === 0\n\t\t\t\t\t\t\t? never\n\t\t\t\t\t\t\t: new Nodes.In({ field: current.field, values }),\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t\tcase \"Under\":\n\t\t\t\t\treturn R.succeed(\n\t\t\t\t\t\texpandUnder(current.prefix, input.principal, input.path),\n\t\t\t\t\t)\n\t\t\t\tcase \"And\":\n\t\t\t\t\treturn R.map(eachChild(R, current.conditions, bind), and)\n\t\t\t\tcase \"Or\":\n\t\t\t\t\treturn R.map(eachChild(R, current.conditions, bind), or)\n\t\t\t\tcase \"Not\":\n\t\t\t\t\treturn R.map(\n\t\t\t\t\t\tR.suspend(() => bind(current.condition)),\n\t\t\t\t\t\tnot,\n\t\t\t\t\t)\n\t\t\t\tcase \"Predicate\": {\n\t\t\t\t\tconst run = Nodes.runOf(current)\n\t\t\t\t\treturn R.succeed(\n\t\t\t\t\t\tnew Nodes.Predicate({\n\t\t\t\t\t\t\tname: current.name,\n\t\t\t\t\t\t\trun: (value) => run(value, input.principal),\n\t\t\t\t\t\t}),\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t\treturn R.succeed(current)\n\t\t\t}\n\t\t}\n\t\treturn bind(node)\n\t})\n\n/** Gives the services in `context` to every predicate of a condition. */\nexport const provide = (node: Node, context: Context.Context<never>): Node =>\n\tTrampoline.run(node.depth, (R) => {\n\t\tconst go = (current: Node): Step<Node> => {\n\t\t\tif (!current.opaque) {\n\t\t\t\treturn R.succeed(current)\n\t\t\t}\n\t\t\tswitch (current._tag) {\n\t\t\t\tcase \"Predicate\": {\n\t\t\t\t\tconst run = Nodes.runOf(current)\n\t\t\t\t\treturn R.succeed(\n\t\t\t\t\t\tnew Nodes.Predicate({\n\t\t\t\t\t\t\tname: current.name,\n\t\t\t\t\t\t\trun: (value, principal) =>\n\t\t\t\t\t\t\t\tEffect.provideContext(run(value, principal), context),\n\t\t\t\t\t\t}),\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t\tcase \"And\":\n\t\t\t\t\treturn R.map(\n\t\t\t\t\t\teachChild(R, current.conditions, go),\n\t\t\t\t\t\t(children) => new Nodes.And(children),\n\t\t\t\t\t)\n\t\t\t\tcase \"Or\":\n\t\t\t\t\treturn R.map(\n\t\t\t\t\t\teachChild(R, current.conditions, go),\n\t\t\t\t\t\t(children) => new Nodes.Or(children),\n\t\t\t\t\t)\n\t\t\t\tcase \"Not\":\n\t\t\t\t\treturn R.map(\n\t\t\t\t\t\tR.suspend(() => go(current.condition)),\n\t\t\t\t\t\t(child) => new Nodes.Not(child),\n\t\t\t\t\t)\n\t\t\t\tdefault:\n\t\t\t\t\treturn R.succeed(current)\n\t\t\t}\n\t\t}\n\t\treturn go(node)\n\t})\n\n/** The fields that a condition tests, in the order that they first come. */\nexport const fields = (node: Node): ReadonlyArray<string> => {\n\t// The fields go into one native `Set`, in order, as in `dedupe`: a field\n\t// of a condition that is not bound to a domain may be any string. A walk\n\t// that joined the lists of the children would copy the list of a deep\n\t// condition at each level. The set belongs to this walk.\n\tconst seen = new Set<string>()\n\tTrampoline.run(node.depth, (R) => {\n\t\tconst go = (current: Node): Step<undefined> => {\n\t\t\tswitch (current._tag) {\n\t\t\t\tcase \"Compare\":\n\t\t\t\tcase \"In\":\n\t\t\t\tcase \"Exists\":\n\t\t\t\t\tseen.add(current.field)\n\t\t\t\t\treturn R.succeed(undefined)\n\t\t\t\tcase \"And\":\n\t\t\t\tcase \"Or\":\n\t\t\t\t\treturn R.map(eachChild(R, current.conditions, go), () => undefined)\n\t\t\t\tcase \"Not\":\n\t\t\t\t\treturn R.suspend(() => go(current.condition))\n\t\t\t\tdefault:\n\t\t\t\t\treturn R.succeed(undefined)\n\t\t\t}\n\t\t}\n\t\treturn go(node)\n\t})\n\treturn Array.from(seen)\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"authorizer.d.ts","names":[],"sources":["../../src/internal/authorizer.ts"],"mappings":";;;;;;;;;;;;;;;;qBAoCa,kBAAkB;;;;;qBAUlB,0BAA0B;;;;;;qBAK1B,gBAAgB"}
1
+ {"version":3,"file":"authorizer.d.ts","names":[],"sources":["../../src/internal/authorizer.ts"],"mappings":";;;;;;;;;;;;;;;;qBAqCa,kBAAkB;;;;;qBAUlB,0BAA0B;;;;;;qBAK1B,gBAAgB"}
@@ -15,6 +15,7 @@ import * as Hash from "effect/Hash";
15
15
  import * as HashMap from "effect/HashMap";
16
16
  import * as HashSet from "effect/HashSet";
17
17
  import * as Layer from "effect/Layer";
18
+ import * as Option from "effect/Option";
18
19
  import * as Result from "effect/Result";
19
20
  import * as Schema from "effect/Schema";
20
21
  // src/internal/authorizer.ts
@@ -87,16 +88,41 @@ var PrincipalKey = class PrincipalKey {
87
88
  * the order that a loop sees them. `Equal` does not see the order of the
88
89
  * fields of an object or of the items of a map, but a loader may read it, as
89
90
  * `Object.values` does. So two keys need the same order too. A scalar is in
90
- * the text with its type, so the items of a set or a map show their order.
91
+ * the text with its type, so the items of a set or a map show their order,
92
+ * and `-0` is not `0`: `Equal` takes them as one, but a loader may not.
93
+ *
94
+ * Each object gets a number at its first visit, and a later visit of it, as
95
+ * of a part that the value shares or of a loop back to a part above, writes
96
+ * `#` and the number. So the walk ends for a value with a loop, and a shared
97
+ * part does not make the text very long. The numbers are in a native `Map`,
98
+ * because the walk must find an object by the object itself. The map belongs
99
+ * to one walk.
100
+ *
101
+ * A value that keeps its data inside, with no own fields, as a `Date`, a
102
+ * `URL` or a `RegExp`, is in the text with its data, and so is an `Option`.
103
+ * For another such value, the walk can not see the data, so it throws, and
104
+ * the principal gets no key: it is not kept.
91
105
  */
92
- const orderOf = adaptive((R, child) => (value, depth) => {
93
- if (typeof value !== "object" || value === null) return R.succeed(typeof value === "string" ? JSON.stringify(value) : `${typeof value}:${String(value)}`);
94
- const items = (list) => R.forEach(list, (item) => child(item, depth + 1));
95
- if (Array.isArray(value)) return R.map(items(value), (texts) => `[${texts.join(",")}]`);
96
- if (value instanceof Map || value instanceof Set || HashMap.isHashMap(value) || HashSet.isHashSet(value) || Chunk.isChunk(value)) return R.map(items(Array.from(value)), (texts) => `<${texts.join(",")}>`);
97
- const names = Object.keys(value);
98
- return R.map(items(Arr.map(names, (name) => value[name])), (texts) => `{${Arr.map(names, (name, index) => `${JSON.stringify(name)}:${texts[index]}`).join(",")}}`);
99
- });
106
+ const orderOf = (root) => {
107
+ const ids = /* @__PURE__ */ new Map();
108
+ return adaptive((R, child) => (value, depth) => {
109
+ if (typeof value !== "object" || value === null) return R.succeed(typeof value === "string" ? JSON.stringify(value) : Object.is(value, -0) ? "number:-0" : `${typeof value}:${String(value)}`);
110
+ const known = ids.get(value);
111
+ if (known !== void 0) return R.succeed(`#${String(known)}`);
112
+ ids.set(value, ids.size);
113
+ const items = (list) => R.forEach(list, (item) => child(item, depth + 1));
114
+ if (value instanceof Date) return R.succeed(`date:${String(value.getTime())}`);
115
+ if (value instanceof URL) return R.succeed(`url:${JSON.stringify(value.href)}`);
116
+ if (value instanceof RegExp) return R.succeed(`regexp:${JSON.stringify(String(value))}`);
117
+ if (Option.isOption(value)) return Option.isSome(value) ? R.map(child(value.value, depth + 1), (text) => `some(${text})`) : R.succeed("none");
118
+ if (Array.isArray(value)) return R.map(items(value), (texts) => `[${texts.join(",")}]`);
119
+ if (value instanceof Map || value instanceof Set || HashMap.isHashMap(value) || HashSet.isHashSet(value) || Chunk.isChunk(value)) return R.map(items(Array.from(value)), (texts) => `<${texts.join(",")}>`);
120
+ const names = Object.keys(value);
121
+ const prototype = Object.getPrototypeOf(value);
122
+ if (names.length === 0 && prototype !== Object.prototype && prototype !== null) throw new Error("The data of a part of the principal is not in fields");
123
+ return R.map(items(Arr.map(names, (name) => value[name])), (texts) => `{${Arr.map(names, (name, index) => `${JSON.stringify(name)}:${texts[index]}`).join(",")}}`);
124
+ })(root);
125
+ };
100
126
  /**
101
127
  * Gives the JSON codec of a Schema, or `undefined` when the Schema has no JSON
102
128
  * form, as a struct with a symbol key has none.
@@ -1 +1 @@
1
- {"version":3,"file":"authorizer.js","names":["Trampoline.adaptive","Policies.provideContext","Decide.decideAny","ResourceData.kindOf","DomainData.descriptorOf","Decide.fitsKind","Analysis.decideKind","Decision.reason","Analysis.coverageAny","permittedFields","Decide.permittedFields"],"sources":["../../src/internal/authorizer.ts"],"sourcesContent":["/**\n * The values of authorizers: the errors, the service class and the layer.\n * The types are in `Authorizer.ts`.\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 Chunk from \"effect/Chunk\"\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 HashMap from \"effect/HashMap\"\nimport * as HashSet from \"effect/HashSet\"\nimport * as Layer from \"effect/Layer\"\nimport * as Result from \"effect/Result\"\nimport * as Schema from \"effect/Schema\"\nimport type * as Authorizer from \"../Authorizer.ts\"\nimport type * as Condition from \"../Condition.ts\"\nimport * as Decision from \"../Decision.ts\"\nimport type * as Domain from \"../Domain.ts\"\nimport type * as Policy from \"../Policy.ts\"\nimport * as Analysis from \"./analysis.ts\"\nimport * as Decide from \"./decide.ts\"\nimport * as DomainData from \"./domain.ts\"\nimport * as Policies from \"./policy.ts\"\nimport * as ResourceData from \"./resource.ts\"\nimport * as Trampoline from \"./trampoline.ts\"\n\ntype AnyServiceClass = Authorizer.AnyServiceClass\n\n/** The error when a policy says no. */\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/** The error when the policy of the principal can not be loaded. */\nexport class PolicyUnavailable extends Schema.TaggedError<PolicyUnavailable>(\n\t\"@nmnmcc/ability/Authorizer/PolicyUnavailable\",\n)(\"PolicyUnavailable\", { cause: Schema.Defect() }) {}\n\n/** The error when a decider must wait for an answer. */\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/** Makes an authorizer service class for a domain. */\nexport const Service =\n\t() =>\n\t(\n\t\tid: string,\n\t\toptions: {\n\t\t\treadonly domain: Domain.Any\n\t\t\treadonly principal: Effect.Effect<any, any, any>\n\t\t},\n\t\t// The class has no name, and its type uses types of Effect that a\n\t\t// declaration file can not name. So this function gives a `Context.Key`.\n\t\t// The public module gives the full type.\n\t): Context.Key<any, any> => {\n\t\tconst Base = Context.Service<any, any>()(id)\n\t\treturn class extends Base {\n\t\t\tstatic readonly domain = options.domain\n\t\t\tstatic readonly principal = options.principal\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}\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 * A cache key for a principal. Two keys are equal when they have the same\n * text, so two principals with the same key share one policy. A key from the\n * JSON form also needs equal decoded principals: a Schema may make data when\n * it decodes, as `expired` from a time, so one text may give two principals.\n * The key also keeps the principal, so the cache can load its policy. A plain\n * `Data` value can not do all this, so the key gives its own equality with\n * `Equal.Equal`.\n */\nclass PrincipalKey implements Equal.Equal {\n\treadonly principal: object\n\treadonly text: string\n\t/**\n\t * The order of the parts of the decoded principal, from {@link orderOf},\n\t * when the key is the JSON form. The decoded principals must be equal\n\t * too, with their parts in the same order. `undefined` for a key from\n\t * `cache.key`.\n\t */\n\treadonly order: string | undefined\n\tconstructor(principal: object, text: string, order: string | undefined) {\n\t\tthis.principal = principal\n\t\tthis.text = text\n\t\tthis.order = order\n\t}\n\t[Equal.symbol](that: unknown): boolean {\n\t\treturn (\n\t\t\tthat instanceof PrincipalKey &&\n\t\t\tthat.text === this.text &&\n\t\t\tthat.order === this.order &&\n\t\t\t(this.order === undefined || Equal.equals(that.principal, this.principal))\n\t\t)\n\t}\n\t[Hash.symbol](): number {\n\t\treturn Hash.string(this.text)\n\t}\n}\n\n/**\n * The text of the order of the parts of a value: the names of the fields of\n * each object, and the items of each list, set and map, with each scalar, in\n * the order that a loop sees them. `Equal` does not see the order of the\n * fields of an object or of the items of a map, but a loader may read it, as\n * `Object.values` does. So two keys need the same order too. A scalar is in\n * the text with its type, so the items of a set or a map show their order.\n */\nconst orderOf: (value: unknown) => string = Trampoline.adaptive<\n\tunknown,\n\tstring\n>((R, child) => (value, depth) => {\n\tif (typeof value !== \"object\" || value === null) {\n\t\treturn R.succeed(\n\t\t\ttypeof value === \"string\"\n\t\t\t\t? JSON.stringify(value)\n\t\t\t\t: `${typeof value}:${String(value)}`,\n\t\t)\n\t}\n\tconst items = (list: ReadonlyArray<unknown>) =>\n\t\tR.forEach(list, (item) => child(item, depth + 1))\n\tif (Array.isArray(value)) {\n\t\treturn R.map(items(value), (texts) => `[${texts.join(\",\")}]`)\n\t}\n\tif (\n\t\tvalue instanceof Map ||\n\t\tvalue instanceof Set ||\n\t\tHashMap.isHashMap(value) ||\n\t\tHashSet.isHashSet(value) ||\n\t\tChunk.isChunk(value)\n\t) {\n\t\treturn R.map(\n\t\t\titems(Array.from(value as Iterable<unknown>)),\n\t\t\t(texts) => `<${texts.join(\",\")}>`,\n\t\t)\n\t}\n\tconst names = Object.keys(value)\n\treturn R.map(\n\t\titems(Arr.map(names, (name) => (value as Record<string, unknown>)[name])),\n\t\t(texts) =>\n\t\t\t`{${Arr.map(names, (name, index) => `${JSON.stringify(name)}:${texts[index]!}`).join(\",\")}}`,\n\t)\n})\n\n/**\n * Gives the JSON codec of a Schema, or `undefined` when the Schema has no JSON\n * form, as a struct with a symbol key has none.\n */\nconst jsonCodecOf = (\n\tschema: Schema.Top,\n): Schema.Codec<unknown, unknown> | undefined => {\n\ttry {\n\t\treturn Schema.toCodecJson(schema) as unknown as Schema.Codec<\n\t\t\tunknown,\n\t\t\tunknown\n\t\t>\n\t} catch {\n\t\treturn undefined\n\t}\n}\n\n/**\n * Makes the cache key of a principal from its JSON form. The key keeps the\n * principal that the Schema decodes from that form, so the loader sees only\n * the data that the key shows. A principal gets no key when it does not\n * encode, or when the decoded value is not `Equal` to it. Two classes, or a\n * string and a number, may have one JSON form, as in a union, and `Equal`\n * tells them apart. A Schema may make data when it decodes, as the order of\n * the fields of a record, so the key keeps that order too. So two\n * principals with one key are equal, and the cache can not give one the\n * policy of the other.\n */\nconst jsonKey = (\n\tschema: Schema.Top,\n): ((principal: object) => PrincipalKey | undefined) => {\n\tconst codec = jsonCodecOf(schema)\n\t// A principal with no JSON form is never kept.\n\tif (codec === undefined) {\n\t\treturn () => undefined\n\t}\n\tconst encode = Schema.encodeUnknownResult(codec)\n\tconst decode = Schema.decodeUnknownResult(codec)\n\tconst keyOf = (principal: object): PrincipalKey | undefined =>\n\t\tResult.match(encode(principal), {\n\t\t\tonFailure: () => undefined,\n\t\t\tonSuccess: (json) => {\n\t\t\t\t// The key is the text, so the check decodes the text. The encoded\n\t\t\t\t// value may hold more than its text shows, as an object of a\n\t\t\t\t// `Schema.Any` field does: `JSON.stringify` leaves out a map.\n\t\t\t\tconst text = JSON.stringify(json)\n\t\t\t\treturn Result.match(decode(JSON.parse(text)), {\n\t\t\t\t\tonFailure: () => undefined,\n\t\t\t\t\tonSuccess: (decoded) =>\n\t\t\t\t\t\tEqual.equals(decoded, principal)\n\t\t\t\t\t\t\t? new PrincipalKey(decoded as object, text, orderOf(decoded))\n\t\t\t\t\t\t\t: undefined,\n\t\t\t\t})\n\t\t\t},\n\t\t})\n\treturn (principal) => {\n\t\t// A very deep principal may fill the stack of the encoder or of\n\t\t// `Equal`. Such a principal is not kept.\n\t\ttry {\n\t\t\treturn keyOf(principal)\n\t\t} catch {\n\t\t\treturn undefined\n\t\t}\n\t}\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\n/** Makes the layer of an authorizer. */\nexport const makeLayer = (\n\tservice: AnyServiceClass,\n\toptions: {\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| {\n\t\t\t\t\treadonly capacity?: number\n\t\t\t\t\treadonly timeToLive?: Duration.Input\n\t\t\t\t\treadonly key?: (principal: object) => string | undefined\n\t\t\t }\n\t\t\t| false\n\t},\n) => {\n\tconst domain: Domain.Any = service.domain\n\t// The JSON form of a principal, and the copy that the Schema decodes from\n\t// it. The loader always gets the copy, with a cache or not, so a cache can\n\t// not change an answer: a form may lose data that `Equal` does not see,\n\t// as `-0` becomes `0`. A principal with no such form gives `undefined`.\n\tconst canonicalOf = jsonKey(domain.principal)\n\tconst custom = options.cache === false ? undefined : options.cache?.key\n\t// It gives `undefined` when the principal has no key. Such a principal does\n\t// not use the cache.\n\tconst keyOf = (\n\t\tprincipal: object,\n\t\tcanonical: PrincipalKey | undefined,\n\t): PrincipalKey | undefined => {\n\t\tif (custom === undefined) {\n\t\t\treturn canonical\n\t\t}\n\t\tconst text = custom(principal)\n\t\treturn text === undefined\n\t\t\t? undefined\n\t\t\t: new PrincipalKey(canonical?.principal ?? principal, text, undefined)\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\tPolicies.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 canonical = canonicalOf(principal)\n\t\t\t\tconst key =\n\t\t\t\t\tcache === undefined ? undefined : keyOf(principal, canonical)\n\t\t\t\tif (cache === undefined || key === undefined) {\n\t\t\t\t\treturn load(canonical?.principal ?? 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* service.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\tDecide.decideAny(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 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: (ResourceData.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 = DomainData.descriptorOf(domain, kind)\n\t\t\t\tif (\n\t\t\t\t\tdescriptor === undefined ||\n\t\t\t\t\t!Decide.fitsKind(descriptor, target, domain.limits.fieldPathParts)\n\t\t\t\t) {\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? Analysis.decideKind(value, { ...target, principal } as never)\n\t\t\t\t\t\t: yield* withServices(\n\t\t\t\t\t\t\t\tDecide.decideAny(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: the scope for `All`,\n\t\t\t// `False` for `None`, and else the residual condition in the scope.\n\t\t\t// The residual throws an error when it is too large, so the filter\n\t\t\t// 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(\n\t\t\t\t\tcurrent,\n\t\t\t\t\t({ principal, policy: value }): Condition.Ast =>\n\t\t\t\t\t\tAnalysis.coverageAny(value, { ...target, principal } as never)\n\t\t\t\t\t\t\t.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<Analysis.AnyCoverage, unknown, unknown> =>\n\t\t\t\tEffect.map(current, ({ principal, policy: value }) =>\n\t\t\t\t\tAnalysis.coverageAny(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\tDecide.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, canonicalOf(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: service.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"],"mappings":"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"}
1
+ {"version":3,"file":"authorizer.js","names":["Trampoline.adaptive","Policies.provideContext","Decide.decideAny","ResourceData.kindOf","DomainData.descriptorOf","Decide.fitsKind","Analysis.decideKind","Decision.reason","Analysis.coverageAny","permittedFields","Decide.permittedFields"],"sources":["../../src/internal/authorizer.ts"],"sourcesContent":["/**\n * The values of authorizers: the errors, the service class and the layer.\n * The types are in `Authorizer.ts`.\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 Chunk from \"effect/Chunk\"\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 HashMap from \"effect/HashMap\"\nimport * as HashSet from \"effect/HashSet\"\nimport * as Layer from \"effect/Layer\"\nimport * as Option from \"effect/Option\"\nimport * as Result from \"effect/Result\"\nimport * as Schema from \"effect/Schema\"\nimport type * as Authorizer from \"../Authorizer.ts\"\nimport type * as Condition from \"../Condition.ts\"\nimport * as Decision from \"../Decision.ts\"\nimport type * as Domain from \"../Domain.ts\"\nimport type * as Policy from \"../Policy.ts\"\nimport * as Analysis from \"./analysis.ts\"\nimport * as Decide from \"./decide.ts\"\nimport * as DomainData from \"./domain.ts\"\nimport * as Policies from \"./policy.ts\"\nimport * as ResourceData from \"./resource.ts\"\nimport * as Trampoline from \"./trampoline.ts\"\n\ntype AnyServiceClass = Authorizer.AnyServiceClass\n\n/** The error when a policy says no. */\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/** The error when the policy of the principal can not be loaded. */\nexport class PolicyUnavailable extends Schema.TaggedError<PolicyUnavailable>(\n\t\"@nmnmcc/ability/Authorizer/PolicyUnavailable\",\n)(\"PolicyUnavailable\", { cause: Schema.Defect() }) {}\n\n/** The error when a decider must wait for an answer. */\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/** Makes an authorizer service class for a domain. */\nexport const Service =\n\t() =>\n\t(\n\t\tid: string,\n\t\toptions: {\n\t\t\treadonly domain: Domain.Any\n\t\t\treadonly principal: Effect.Effect<any, any, any>\n\t\t},\n\t\t// The class has no name, and its type uses types of Effect that a\n\t\t// declaration file can not name. So this function gives a `Context.Key`.\n\t\t// The public module gives the full type.\n\t): Context.Key<any, any> => {\n\t\tconst Base = Context.Service<any, any>()(id)\n\t\treturn class extends Base {\n\t\t\tstatic readonly domain = options.domain\n\t\t\tstatic readonly principal = options.principal\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}\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 * A cache key for a principal. Two keys are equal when they have the same\n * text, so two principals with the same key share one policy. A key from the\n * JSON form also needs equal decoded principals: a Schema may make data when\n * it decodes, as `expired` from a time, so one text may give two principals.\n * The key also keeps the principal, so the cache can load its policy. A plain\n * `Data` value can not do all this, so the key gives its own equality with\n * `Equal.Equal`.\n */\nclass PrincipalKey implements Equal.Equal {\n\treadonly principal: object\n\treadonly text: string\n\t/**\n\t * The order of the parts of the decoded principal, from {@link orderOf},\n\t * when the key is the JSON form. The decoded principals must be equal\n\t * too, with their parts in the same order. `undefined` for a key from\n\t * `cache.key`.\n\t */\n\treadonly order: string | undefined\n\tconstructor(principal: object, text: string, order: string | undefined) {\n\t\tthis.principal = principal\n\t\tthis.text = text\n\t\tthis.order = order\n\t}\n\t[Equal.symbol](that: unknown): boolean {\n\t\treturn (\n\t\t\tthat instanceof PrincipalKey &&\n\t\t\tthat.text === this.text &&\n\t\t\tthat.order === this.order &&\n\t\t\t(this.order === undefined || Equal.equals(that.principal, this.principal))\n\t\t)\n\t}\n\t[Hash.symbol](): number {\n\t\treturn Hash.string(this.text)\n\t}\n}\n\n/**\n * The text of the order of the parts of a value: the names of the fields of\n * each object, and the items of each list, set and map, with each scalar, in\n * the order that a loop sees them. `Equal` does not see the order of the\n * fields of an object or of the items of a map, but a loader may read it, as\n * `Object.values` does. So two keys need the same order too. A scalar is in\n * the text with its type, so the items of a set or a map show their order,\n * and `-0` is not `0`: `Equal` takes them as one, but a loader may not.\n *\n * Each object gets a number at its first visit, and a later visit of it, as\n * of a part that the value shares or of a loop back to a part above, writes\n * `#` and the number. So the walk ends for a value with a loop, and a shared\n * part does not make the text very long. The numbers are in a native `Map`,\n * because the walk must find an object by the object itself. The map belongs\n * to one walk.\n *\n * A value that keeps its data inside, with no own fields, as a `Date`, a\n * `URL` or a `RegExp`, is in the text with its data, and so is an `Option`.\n * For another such value, the walk can not see the data, so it throws, and\n * the principal gets no key: it is not kept.\n */\nconst orderOf = (root: unknown): string => {\n\tconst ids = new Map<object, number>()\n\treturn Trampoline.adaptive<unknown, string>((R, child) => (value, depth) => {\n\t\tif (typeof value !== \"object\" || value === null) {\n\t\t\treturn R.succeed(\n\t\t\t\ttypeof value === \"string\"\n\t\t\t\t\t? JSON.stringify(value)\n\t\t\t\t\t: Object.is(value, -0)\n\t\t\t\t\t\t? \"number:-0\"\n\t\t\t\t\t\t: `${typeof value}:${String(value)}`,\n\t\t\t)\n\t\t}\n\t\tconst known = ids.get(value)\n\t\tif (known !== undefined) {\n\t\t\treturn R.succeed(`#${String(known)}`)\n\t\t}\n\t\tids.set(value, ids.size)\n\t\tconst items = (list: ReadonlyArray<unknown>) =>\n\t\t\tR.forEach(list, (item) => child(item, depth + 1))\n\t\tif (value instanceof Date) {\n\t\t\treturn R.succeed(`date:${String(value.getTime())}`)\n\t\t}\n\t\tif (value instanceof URL) {\n\t\t\treturn R.succeed(`url:${JSON.stringify(value.href)}`)\n\t\t}\n\t\tif (value instanceof RegExp) {\n\t\t\treturn R.succeed(`regexp:${JSON.stringify(String(value))}`)\n\t\t}\n\t\tif (Option.isOption(value)) {\n\t\t\treturn Option.isSome(value)\n\t\t\t\t? R.map(child(value.value, depth + 1), (text) => `some(${text})`)\n\t\t\t\t: R.succeed(\"none\")\n\t\t}\n\t\tif (Array.isArray(value)) {\n\t\t\treturn R.map(items(value), (texts) => `[${texts.join(\",\")}]`)\n\t\t}\n\t\tif (\n\t\t\tvalue instanceof Map ||\n\t\t\tvalue instanceof Set ||\n\t\t\tHashMap.isHashMap(value) ||\n\t\t\tHashSet.isHashSet(value) ||\n\t\t\tChunk.isChunk(value)\n\t\t) {\n\t\t\treturn R.map(\n\t\t\t\titems(Array.from(value as Iterable<unknown>)),\n\t\t\t\t(texts) => `<${texts.join(\",\")}>`,\n\t\t\t)\n\t\t}\n\t\tconst names = Object.keys(value)\n\t\tconst prototype: unknown = Object.getPrototypeOf(value)\n\t\tif (\n\t\t\tnames.length === 0 &&\n\t\t\tprototype !== Object.prototype &&\n\t\t\tprototype !== null\n\t\t) {\n\t\t\tthrow new Error(\"The data of a part of the principal is not in fields\")\n\t\t}\n\t\treturn R.map(\n\t\t\titems(Arr.map(names, (name) => (value as Record<string, unknown>)[name])),\n\t\t\t(texts) =>\n\t\t\t\t`{${Arr.map(names, (name, index) => `${JSON.stringify(name)}:${texts[index]!}`).join(\",\")}}`,\n\t\t)\n\t})(root)\n}\n\n/**\n * Gives the JSON codec of a Schema, or `undefined` when the Schema has no JSON\n * form, as a struct with a symbol key has none.\n */\nconst jsonCodecOf = (\n\tschema: Schema.Top,\n): Schema.Codec<unknown, unknown> | undefined => {\n\ttry {\n\t\treturn Schema.toCodecJson(schema) as unknown as Schema.Codec<\n\t\t\tunknown,\n\t\t\tunknown\n\t\t>\n\t} catch {\n\t\treturn undefined\n\t}\n}\n\n/**\n * Makes the cache key of a principal from its JSON form. The key keeps the\n * principal that the Schema decodes from that form, so the loader sees only\n * the data that the key shows. A principal gets no key when it does not\n * encode, or when the decoded value is not `Equal` to it. Two classes, or a\n * string and a number, may have one JSON form, as in a union, and `Equal`\n * tells them apart. A Schema may make data when it decodes, as the order of\n * the fields of a record, so the key keeps that order too. So two\n * principals with one key are equal, and the cache can not give one the\n * policy of the other.\n */\nconst jsonKey = (\n\tschema: Schema.Top,\n): ((principal: object) => PrincipalKey | undefined) => {\n\tconst codec = jsonCodecOf(schema)\n\t// A principal with no JSON form is never kept.\n\tif (codec === undefined) {\n\t\treturn () => undefined\n\t}\n\tconst encode = Schema.encodeUnknownResult(codec)\n\tconst decode = Schema.decodeUnknownResult(codec)\n\tconst keyOf = (principal: object): PrincipalKey | undefined =>\n\t\tResult.match(encode(principal), {\n\t\t\tonFailure: () => undefined,\n\t\t\tonSuccess: (json) => {\n\t\t\t\t// The key is the text, so the check decodes the text. The encoded\n\t\t\t\t// value may hold more than its text shows, as an object of a\n\t\t\t\t// `Schema.Any` field does: `JSON.stringify` leaves out a map.\n\t\t\t\tconst text = JSON.stringify(json)\n\t\t\t\treturn Result.match(decode(JSON.parse(text)), {\n\t\t\t\t\tonFailure: () => undefined,\n\t\t\t\t\tonSuccess: (decoded) =>\n\t\t\t\t\t\tEqual.equals(decoded, principal)\n\t\t\t\t\t\t\t? new PrincipalKey(decoded as object, text, orderOf(decoded))\n\t\t\t\t\t\t\t: undefined,\n\t\t\t\t})\n\t\t\t},\n\t\t})\n\treturn (principal) => {\n\t\t// A very deep principal may fill the stack of the encoder or of\n\t\t// `Equal`. Such a principal is not kept.\n\t\ttry {\n\t\t\treturn keyOf(principal)\n\t\t} catch {\n\t\t\treturn undefined\n\t\t}\n\t}\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\n/** Makes the layer of an authorizer. */\nexport const makeLayer = (\n\tservice: AnyServiceClass,\n\toptions: {\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| {\n\t\t\t\t\treadonly capacity?: number\n\t\t\t\t\treadonly timeToLive?: Duration.Input\n\t\t\t\t\treadonly key?: (principal: object) => string | undefined\n\t\t\t }\n\t\t\t| false\n\t},\n) => {\n\tconst domain: Domain.Any = service.domain\n\t// The JSON form of a principal, and the copy that the Schema decodes from\n\t// it. The loader always gets the copy, with a cache or not, so a cache can\n\t// not change an answer: a form may lose data that `Equal` does not see,\n\t// as `-0` becomes `0`. A principal with no such form gives `undefined`.\n\tconst canonicalOf = jsonKey(domain.principal)\n\tconst custom = options.cache === false ? undefined : options.cache?.key\n\t// It gives `undefined` when the principal has no key. Such a principal does\n\t// not use the cache.\n\tconst keyOf = (\n\t\tprincipal: object,\n\t\tcanonical: PrincipalKey | undefined,\n\t): PrincipalKey | undefined => {\n\t\tif (custom === undefined) {\n\t\t\treturn canonical\n\t\t}\n\t\tconst text = custom(principal)\n\t\treturn text === undefined\n\t\t\t? undefined\n\t\t\t: new PrincipalKey(canonical?.principal ?? principal, text, undefined)\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\tPolicies.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 canonical = canonicalOf(principal)\n\t\t\t\tconst key =\n\t\t\t\t\tcache === undefined ? undefined : keyOf(principal, canonical)\n\t\t\t\tif (cache === undefined || key === undefined) {\n\t\t\t\t\treturn load(canonical?.principal ?? 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* service.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\tDecide.decideAny(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 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: (ResourceData.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 = DomainData.descriptorOf(domain, kind)\n\t\t\t\tif (\n\t\t\t\t\tdescriptor === undefined ||\n\t\t\t\t\t!Decide.fitsKind(descriptor, target, domain.limits.fieldPathParts)\n\t\t\t\t) {\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? Analysis.decideKind(value, { ...target, principal } as never)\n\t\t\t\t\t\t: yield* withServices(\n\t\t\t\t\t\t\t\tDecide.decideAny(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: the scope for `All`,\n\t\t\t// `False` for `None`, and else the residual condition in the scope.\n\t\t\t// The residual throws an error when it is too large, so the filter\n\t\t\t// 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(\n\t\t\t\t\tcurrent,\n\t\t\t\t\t({ principal, policy: value }): Condition.Ast =>\n\t\t\t\t\t\tAnalysis.coverageAny(value, { ...target, principal } as never)\n\t\t\t\t\t\t\t.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<Analysis.AnyCoverage, unknown, unknown> =>\n\t\t\t\tEffect.map(current, ({ principal, policy: value }) =>\n\t\t\t\t\tAnalysis.coverageAny(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\tDecide.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, canonicalOf(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: service.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"],"mappings":"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"}
@@ -1,13 +1,13 @@
1
1
  import { adaptive, run } from "./trampoline.js";
2
2
  import { isNode } from "./nodes.js";
3
- import { accepts, anyKinds, lookup } from "./catalog.js";
3
+ import { accepts, anyKinds, fieldsOf, lookup } from "./catalog.js";
4
4
  import { at, pathOf } from "./place.js";
5
5
  import { fitsCatalog, parse } from "./patterns.js";
6
6
  import { withSuggestion } from "./suggest.js";
7
7
  import * as Arr from "effect/Array";
8
8
  import * as HashMap from "effect/HashMap";
9
- import * as Result from "effect/Result";
10
9
  import * as Option from "effect/Option";
10
+ import * as Result from "effect/Result";
11
11
  // src/internal/bind.ts
12
12
  /**
13
13
  * The binding of rules to a domain. It is the one check of a rule, for a rule
@@ -64,8 +64,12 @@ const hasNumbers = (kinds) => kinds.number !== "none" || Arr.some(kinds.literals
64
64
  const isOrdered = (kinds) => hasStrings(kinds) || hasNumbers(kinds);
65
65
  /** Tests if two fields may hold values of one ordered type. */
66
66
  const orderedMeet = (left, right) => hasStrings(left) && hasStrings(right) || hasNumbers(left) && hasNumbers(right);
67
- /** The texts of the fields of a catalog that have only names, for suggestions. */
68
- const namesOf = (catalog) => Arr.map(Arr.filter(catalog.fields, (field) => Arr.every(field.path, (segment) => typeof segment === "string")), (field) => field.text);
67
+ /**
68
+ * The texts of the fields of a catalog that have only names, for
69
+ * suggestions, with the limits of the domain. The domain checked the size of
70
+ * the list when it was made.
71
+ */
72
+ const namesOf = (catalog, limits) => Arr.map(Arr.filter(fieldsOf(catalog, limits.fieldPathParts, limits.catalogFields), (field) => Arr.every(field.path, (segment) => typeof segment === "string")), (field) => field.text);
69
73
  /** The issue of a field that is not a field of every resource of the rule. */
70
74
  const fieldIssue = (context, field, at) => {
71
75
  const parts = context.memo.limits.fieldPathParts;
@@ -81,7 +85,7 @@ const fieldIssue = (context, field, at) => {
81
85
  const without = Arr.filter(context.named, (descriptor) => lookup(descriptor.catalog, field, parts) === void 0);
82
86
  return without.length === 0 ? [] : [{
83
87
  path: at,
84
- issue: suggestIn(context.memo, message, field, without[0].kind, () => namesOf(without[0].catalog))
88
+ issue: suggestIn(context.memo, message, field, without[0].kind, () => namesOf(without[0].catalog, context.memo.limits))
85
89
  }];
86
90
  };
87
91
  /**
@@ -140,7 +144,7 @@ const principalField = (context, ref, at) => {
140
144
  };
141
145
  return found !== void 0 ? found : {
142
146
  path: at,
143
- issue: suggestIn(context.memo, `The principal has no field "${ref}"`, ref, "~principal", () => namesOf(context.domain.principalCatalog))
147
+ issue: suggestIn(context.memo, `The principal has no field "${ref}"`, ref, "~principal", () => namesOf(context.domain.principalCatalog, context.memo.limits))
144
148
  };
145
149
  };
146
150
  const isIssue = (value) => "issue" in value;
@@ -287,14 +291,14 @@ const conditionIssues = (context, root, rootAt, seen) => run(root.depth, (R) =>
287
291
  default: return [];
288
292
  }
289
293
  };
290
- const go = (node, at$1) => {
294
+ const go = (node, at$3) => {
291
295
  if (seen.has(node)) return R.succeed([]);
292
296
  seen.add(node);
293
297
  switch (node._tag) {
294
298
  case "And":
295
- case "Or": return R.map(R.forEach(node.conditions, (child, index) => R.suspend(() => go(child, at(at$1, "conditions", index)))), Arr.flatten);
296
- case "Not": return R.suspend(() => go(node.condition, at(at$1, "condition")));
297
- default: return R.succeed(leaf(node, at$1));
299
+ case "Or": return R.map(R.forEach(node.conditions, (child, index) => R.suspend(() => go(child, at(at$3, "conditions", index)))), Arr.flatten);
300
+ case "Not": return R.suspend(() => go(node.condition, at(at$3, "condition")));
301
+ default: return R.succeed(leaf(node, at$3));
298
302
  }
299
303
  };
300
304
  return go(root, rootAt);
@@ -306,8 +310,8 @@ const hasAction = (descriptor, actions) => actions.includes("*") || Arr.some(act
306
310
  * full path is made only for an issue that the binding keeps: a rule with
307
311
  * very many problems deep in a tree does not make a full path for each one.
308
312
  */
309
- const ruleIssues = (domain, rule, at$3, memo = makeMemo(domain.limits)) => {
310
- const here = (issues) => under(memo, at$3, issues);
313
+ const ruleIssues = (domain, rule, at$2, memo = makeMemo(domain.limits)) => {
314
+ const here = (issues) => under(memo, at$2, issues);
311
315
  const all = rule.resources.includes("*");
312
316
  const names = Array.from(new Set(Arr.filter(rule.resources, (kind) => kind !== "*")));
313
317
  const kinds = Array.from(HashMap.keys(domain.resources));
@@ -328,7 +332,7 @@ const ruleIssues = (domain, rule, at$3, memo = makeMemo(domain.limits)) => {
328
332
  const whenIssues = rule.when === void 0 ? [] : !isNode(rule.when) ? here([notWhole(["when"])]) : rule.when.weight > conditionNodes ? here([{
329
333
  path: ["when"],
330
334
  issue: `A condition has ${String(rule.when.weight)} nodes and values. The most is ${String(conditionNodes)}.`
331
- }]) : conditionIssues(context, rule.when, at(at$3, "when"), /* @__PURE__ */ new Set());
335
+ }]) : conditionIssues(context, rule.when, at(at$2, "when"), /* @__PURE__ */ new Set());
332
336
  const work = memo.work.steps > memo.limits.searchSteps && !memo.work.noted;
333
337
  memo.work.noted ||= work;
334
338
  return [
@@ -343,36 +347,42 @@ const ruleIssues = (domain, rule, at$3, memo = makeMemo(domain.limits)) => {
343
347
  ...fieldIssues,
344
348
  ...whenIssues,
345
349
  ...work ? [{
346
- path: pathOf(at$3),
350
+ path: pathOf(at$2),
347
351
  issue: `The policy takes more than ${String(memo.limits.searchSteps)} steps to check: its field patterns, and the fields and values of its tests on each resource. The most is ${String(memo.limits.searchSteps)}.`
348
352
  }] : []
349
353
  ];
350
354
  };
351
355
  /** Checks each rule of a policy tree against a domain. */
352
356
  const treeIssues = (domain, root) => {
353
- const rulesOf = adaptive((R, child) => ({ node, at: at$2 }, level) => {
357
+ const found = [];
358
+ adaptive((R, child) => ({ node, at: at$1 }, level) => {
359
+ const below = (parts) => R.map(R.forEach(parts, (part) => child(part, level + 1)), () => void 0);
354
360
  switch (node._tag) {
355
- case "Rules": return R.succeed(Arr.map(node.rules, (rule, index) => [rule, at(at$2, "rules", index)]));
361
+ case "Rules":
362
+ Arr.forEach(node.rules, (rule, index) => {
363
+ found.push([rule, at(at$1, "rules", index)]);
364
+ });
365
+ return R.succeed(void 0);
356
366
  case "All":
357
367
  case "Any":
358
- case "FirstOf": return R.map(R.forEach(node.policies, (inner, index) => child({
368
+ case "FirstOf": return below(Arr.map(node.policies, (inner, index) => ({
359
369
  node: inner,
360
- at: at(at$2, "policies", index)
361
- }, level + 1)), Arr.flatten);
362
- case "Ceiling": return R.map(R.forEach([{
370
+ at: at(at$1, "policies", index)
371
+ })));
372
+ case "Ceiling": return below([{
363
373
  node: node.cap,
364
- at: at(at$2, "cap")
374
+ at: at(at$1, "cap")
365
375
  }, {
366
376
  node: node.policy,
367
- at: at(at$2, "policy")
368
- }], (part) => child(part, level + 1)), Arr.flatten);
377
+ at: at(at$1, "policy")
378
+ }]);
369
379
  }
370
- });
371
- const memo = makeMemo(domain.limits);
372
- return Arr.flatMap(rulesOf({
380
+ })({
373
381
  node: root,
374
382
  at: void 0
375
- }), (found) => Array.isArray(found) ? ruleIssues(domain, found[0], found[1], memo) : [found]);
383
+ });
384
+ const memo = makeMemo(domain.limits);
385
+ return Arr.flatMap(found, ([rule, place]) => ruleIssues(domain, rule, place, memo));
376
386
  };
377
387
  export { ruleIssues, treeIssues };
378
388