@sequenceholdings/orm 2.3.0 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.cjs +100 -66
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +100 -66
- package/dist/cli.js.map +1 -1
- package/dist/compiler.cjs +107 -38
- package/dist/compiler.cjs.map +1 -1
- package/dist/compiler.d.cts +6 -4
- package/dist/compiler.d.ts +6 -4
- package/dist/compiler.js +107 -38
- package/dist/compiler.js.map +1 -1
- package/dist/predicate-v2.cjs +95 -19
- package/dist/predicate-v2.cjs.map +1 -1
- package/dist/predicate-v2.d.cts +40 -3
- package/dist/predicate-v2.d.ts +40 -3
- package/dist/predicate-v2.js +95 -19
- package/dist/predicate-v2.js.map +1 -1
- package/package.json +1 -1
package/dist/predicate-v2.cjs
CHANGED
|
@@ -1642,6 +1642,7 @@ var Parser2 = class {
|
|
|
1642
1642
|
return node;
|
|
1643
1643
|
}
|
|
1644
1644
|
if (this.peekKeyword("exists")) return this.parseExists();
|
|
1645
|
+
if (this.peekKeyword("visible") && this.tokens[this.index + 1]?.kind === "lparen") return this.parseVisible();
|
|
1645
1646
|
return this.parseComparison();
|
|
1646
1647
|
}
|
|
1647
1648
|
parseBooleanCall(fn) {
|
|
@@ -1661,6 +1662,13 @@ var Parser2 = class {
|
|
|
1661
1662
|
this.expect("rparen", "')' closing exists(...)");
|
|
1662
1663
|
return { kind: "exists", path, where };
|
|
1663
1664
|
}
|
|
1665
|
+
parseVisible() {
|
|
1666
|
+
this.advance();
|
|
1667
|
+
this.expect("lparen", "'(' after visible");
|
|
1668
|
+
const path = this.parsePath("a link path in visible(...)");
|
|
1669
|
+
this.expect("rparen", "')' closing visible(...)");
|
|
1670
|
+
return { kind: "visible", path };
|
|
1671
|
+
}
|
|
1664
1672
|
parseComparison() {
|
|
1665
1673
|
const left = this.parseOperand();
|
|
1666
1674
|
const operator = this.expect("operator", "a comparison operator");
|
|
@@ -1776,6 +1784,24 @@ function parsePolicy(source) {
|
|
|
1776
1784
|
|
|
1777
1785
|
// src/predicate-v2/compile.ts
|
|
1778
1786
|
var POLICY_MAX_LINK_DEPTH = 3;
|
|
1787
|
+
function scopeToNamespace(pred, namespace) {
|
|
1788
|
+
switch (pred.kind) {
|
|
1789
|
+
case "capability":
|
|
1790
|
+
case "role":
|
|
1791
|
+
return pred.namespace ? pred : { ...pred, namespace };
|
|
1792
|
+
case "and":
|
|
1793
|
+
case "or":
|
|
1794
|
+
return { ...pred, operands: pred.operands.map((operand) => scopeToNamespace(operand, namespace)) };
|
|
1795
|
+
case "not":
|
|
1796
|
+
return { ...pred, operand: scopeToNamespace(pred.operand, namespace) };
|
|
1797
|
+
case "exists":
|
|
1798
|
+
return { ...pred, where: scopeToNamespace(pred.where, namespace) };
|
|
1799
|
+
case "aggPredicate":
|
|
1800
|
+
return pred.where ? { ...pred, where: scopeToNamespace(pred.where, namespace) } : pred;
|
|
1801
|
+
default:
|
|
1802
|
+
return pred;
|
|
1803
|
+
}
|
|
1804
|
+
}
|
|
1779
1805
|
var CMP_BY_OP = {
|
|
1780
1806
|
"=": "eq",
|
|
1781
1807
|
"!=": "neq",
|
|
@@ -1809,7 +1835,7 @@ function resolveLink(info, ref) {
|
|
|
1809
1835
|
function columnCandidates(info) {
|
|
1810
1836
|
return [...info.columns.map((c) => c.name), ...info.links.map((l) => l.name)];
|
|
1811
1837
|
}
|
|
1812
|
-
var PolicyCompiler = class {
|
|
1838
|
+
var PolicyCompiler = class _PolicyCompiler {
|
|
1813
1839
|
constructor(ctx) {
|
|
1814
1840
|
this.ctx = ctx;
|
|
1815
1841
|
}
|
|
@@ -1822,13 +1848,15 @@ var PolicyCompiler = class {
|
|
|
1822
1848
|
return { kind: node.kind, operands: node.operands.map((operand) => this.compile(operand, table, depth)) };
|
|
1823
1849
|
case "not":
|
|
1824
1850
|
assertNoNegatedExternalClaim(node.operand);
|
|
1825
|
-
return { kind: "not", operand: this.compile(node.operand, table, depth) };
|
|
1851
|
+
return { kind: "not", operand: new _PolicyCompiler({ ...this.ctx, negated: true }).compile(node.operand, table, depth) };
|
|
1826
1852
|
case "capability":
|
|
1827
1853
|
return { kind: "capability", key: node.key };
|
|
1828
1854
|
case "role":
|
|
1829
1855
|
return { kind: "role", key: node.key };
|
|
1830
1856
|
case "exists":
|
|
1831
1857
|
return this.compileExists(node.path, node.where, table, depth);
|
|
1858
|
+
case "visible":
|
|
1859
|
+
return this.compileVisible(node.path, table, depth);
|
|
1832
1860
|
case "compare":
|
|
1833
1861
|
return this.compileCompare(node, table, depth);
|
|
1834
1862
|
}
|
|
@@ -1842,6 +1870,36 @@ var PolicyCompiler = class {
|
|
|
1842
1870
|
}
|
|
1843
1871
|
return pred;
|
|
1844
1872
|
}
|
|
1873
|
+
/** `visible(path)` → `exists(path, <final target's read policy>)`. */
|
|
1874
|
+
compileVisible(path, table, depth) {
|
|
1875
|
+
const { links, finalTable } = this.resolveLinkPath(path, table, depth, { toOneOnly: false });
|
|
1876
|
+
const readPolicy = this.ctx.resolver.readPolicy;
|
|
1877
|
+
if (!readPolicy) {
|
|
1878
|
+
throw new PolicyCompileError(
|
|
1879
|
+
`visible(${path.join(".")}) needs the target's read policy, which this compile context does not provide`,
|
|
1880
|
+
"visible-unresolvable"
|
|
1881
|
+
);
|
|
1882
|
+
}
|
|
1883
|
+
if (this.ctx.visiting.includes(finalTable)) {
|
|
1884
|
+
throw new PolicyCompileError(
|
|
1885
|
+
`visible(${path.join(".")}) on '${table}' reaches '${finalTable}' whose read policy is already being expanded (${[...this.ctx.visiting, finalTable].join(" \u2192 ")})`,
|
|
1886
|
+
"visible-cycle"
|
|
1887
|
+
);
|
|
1888
|
+
}
|
|
1889
|
+
const expression = readPolicy(finalTable);
|
|
1890
|
+
let pred = expression === void 0 ? { kind: "const", value: true } : compilePolicyAt({
|
|
1891
|
+
expression,
|
|
1892
|
+
table: finalTable,
|
|
1893
|
+
ctx: { ...this.ctx, visiting: [...this.ctx.visiting, finalTable] },
|
|
1894
|
+
depth: depth + links.length
|
|
1895
|
+
});
|
|
1896
|
+
const owner = this.ctx.resolver.policyNamespace?.(finalTable);
|
|
1897
|
+
if (owner) pred = scopeToNamespace(pred, owner);
|
|
1898
|
+
for (let i = links.length - 1; i >= 0; i -= 1) {
|
|
1899
|
+
pred = { kind: "exists", link: links[i].name, where: pred };
|
|
1900
|
+
}
|
|
1901
|
+
return pred;
|
|
1902
|
+
}
|
|
1845
1903
|
resolveLinkPath(path, table, depth, { toOneOnly }) {
|
|
1846
1904
|
const links = [];
|
|
1847
1905
|
let current = table;
|
|
@@ -1902,6 +1960,7 @@ var PolicyCompiler = class {
|
|
|
1902
1960
|
);
|
|
1903
1961
|
}
|
|
1904
1962
|
if (valueSide.kind === "claim" && isExternalPolicyClaimKey(valueSide.key)) {
|
|
1963
|
+
if (this.ctx.negated) throw negatedExternalClaim(valueSide.key);
|
|
1905
1964
|
assertExternalClaimComparison({ op, key: valueSide.key, column: info.columns.find((c) => c.name === column) });
|
|
1906
1965
|
}
|
|
1907
1966
|
let cmp = this.buildCmp(op, column, valueSide);
|
|
@@ -1939,22 +1998,30 @@ function assertExternalClaimComparison({ op, key, column }) {
|
|
|
1939
1998
|
);
|
|
1940
1999
|
}
|
|
1941
2000
|
}
|
|
2001
|
+
function negatedExternalClaim(key) {
|
|
2002
|
+
return new PolicyCompileError(
|
|
2003
|
+
`claim('${key}') cannot appear under not(): a negated borrower comparison admits other borrowers' rows`,
|
|
2004
|
+
"unsupported-comparison"
|
|
2005
|
+
);
|
|
2006
|
+
}
|
|
1942
2007
|
function assertNoNegatedExternalClaim(operand) {
|
|
1943
2008
|
walkPolicy(operand, (node) => {
|
|
1944
2009
|
if (node.kind !== "compare") return;
|
|
1945
2010
|
const claim = [node.left, node.right].find((side) => side.kind === "claim" && isExternalPolicyClaimKey(side.key));
|
|
1946
|
-
if (claim?.kind === "claim")
|
|
1947
|
-
throw new PolicyCompileError(
|
|
1948
|
-
`claim('${claim.key}') cannot appear under not(): a negated borrower comparison admits other borrowers' rows`,
|
|
1949
|
-
"unsupported-comparison"
|
|
1950
|
-
);
|
|
1951
|
-
}
|
|
2011
|
+
if (claim?.kind === "claim") throw negatedExternalClaim(claim.key);
|
|
1952
2012
|
});
|
|
1953
2013
|
}
|
|
1954
2014
|
function compilePredicateV2({ expression, table, resolver, maxLinkDepth }) {
|
|
2015
|
+
return compilePredicateAt({
|
|
2016
|
+
expression,
|
|
2017
|
+
table,
|
|
2018
|
+
depth: 0,
|
|
2019
|
+
ctx: { resolver, maxLinkDepth: maxLinkDepth ?? POLICY_MAX_LINK_DEPTH, visiting: [table] }
|
|
2020
|
+
});
|
|
2021
|
+
}
|
|
2022
|
+
function compilePredicateAt({ expression, table, ctx, depth }) {
|
|
1955
2023
|
const parsed = typeof expression === "string" ? parsePolicy(expression) : expression;
|
|
1956
|
-
|
|
1957
|
-
return compiler.compile(parsed.ast, table, 0);
|
|
2024
|
+
return new PolicyCompiler(ctx).compile(parsed.ast, table, depth);
|
|
1958
2025
|
}
|
|
1959
2026
|
function assertClaimsOnlyWhen(parsed) {
|
|
1960
2027
|
walkPolicy(parsed.ast, (node) => {
|
|
@@ -1971,25 +2038,34 @@ function assertClaimsOnlyWhen(parsed) {
|
|
|
1971
2038
|
"when-not-claims-only"
|
|
1972
2039
|
);
|
|
1973
2040
|
}
|
|
1974
|
-
if (node.kind === "exists") {
|
|
2041
|
+
if (node.kind === "exists" || node.kind === "visible") {
|
|
1975
2042
|
throw new PolicyCompileError(
|
|
1976
|
-
|
|
2043
|
+
`variant 'when' guards are claims-only \u2014 ${node.kind}() is not allowed`,
|
|
1977
2044
|
"when-not-claims-only"
|
|
1978
2045
|
);
|
|
1979
2046
|
}
|
|
1980
2047
|
});
|
|
1981
2048
|
}
|
|
1982
|
-
function
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
2049
|
+
function initialVisiting({ table, access }) {
|
|
2050
|
+
return (access ?? "read") === "read" ? [table] : [];
|
|
2051
|
+
}
|
|
2052
|
+
function compilePolicy({ expression, table, resolver, maxLinkDepth, access }) {
|
|
2053
|
+
return compilePolicyAt({
|
|
2054
|
+
expression,
|
|
2055
|
+
table,
|
|
2056
|
+
depth: 0,
|
|
2057
|
+
ctx: { resolver, maxLinkDepth: maxLinkDepth ?? POLICY_MAX_LINK_DEPTH, visiting: initialVisiting({ table, access }) }
|
|
2058
|
+
});
|
|
2059
|
+
}
|
|
2060
|
+
function compilePolicyAt({ expression, table, ctx, depth }) {
|
|
2061
|
+
if (typeof expression === "string") return compilePredicateAt({ expression, table, ctx, depth });
|
|
2062
|
+
const defaultPred = compilePredicateAt({ expression: expression.default, table, ctx, depth });
|
|
1987
2063
|
if (expression.variants.length === 0) return defaultPred;
|
|
1988
2064
|
const branches = expression.variants.map((variant) => {
|
|
1989
2065
|
const parsedWhen = parsePolicy(variant.when);
|
|
1990
2066
|
assertClaimsOnlyWhen(parsedWhen);
|
|
1991
|
-
const when =
|
|
1992
|
-
const grant = variant.allow === true ? { kind: "const", value: true } :
|
|
2067
|
+
const when = compilePredicateAt({ expression: parsedWhen, table, ctx, depth });
|
|
2068
|
+
const grant = variant.allow === true ? { kind: "const", value: true } : compilePredicateAt({ expression: variant.policy, table, ctx, depth });
|
|
1993
2069
|
return { kind: "and", operands: [when, grant] };
|
|
1994
2070
|
});
|
|
1995
2071
|
return { kind: "or", operands: [defaultPred, ...branches] };
|