@zenstackhq/plugin-policy 3.3.0-beta.3 → 3.3.0-beta.5
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/index.cjs +15 -19
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +30 -34
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1798 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +6 -6
package/dist/index.js
CHANGED
|
@@ -4,13 +4,13 @@ var __name = (target, value) => __defProp(target, "name", { value, configurable:
|
|
|
4
4
|
// src/functions.ts
|
|
5
5
|
import { invariant as invariant4 } from "@zenstackhq/common-helpers";
|
|
6
6
|
import { CRUD, QueryUtils as QueryUtils3 } from "@zenstackhq/orm";
|
|
7
|
-
import { ExpressionWrapper as
|
|
7
|
+
import { ExpressionWrapper as ExpressionWrapper3, ValueNode as ValueNode4 } from "kysely";
|
|
8
8
|
|
|
9
9
|
// src/policy-handler.ts
|
|
10
10
|
import { invariant as invariant3 } from "@zenstackhq/common-helpers";
|
|
11
11
|
import { getCrudDialect as getCrudDialect2, QueryUtils as QueryUtils2, RejectedByPolicyReason, SchemaUtils as SchemaUtils2 } from "@zenstackhq/orm";
|
|
12
12
|
import { ExpressionUtils as ExpressionUtils4 } from "@zenstackhq/orm/schema";
|
|
13
|
-
import { AliasNode as AliasNode3, BinaryOperationNode as BinaryOperationNode3, ColumnNode as ColumnNode3, DeleteQueryNode, expressionBuilder as expressionBuilder2, ExpressionWrapper, FromNode as FromNode2, IdentifierNode as IdentifierNode2, InsertQueryNode, OperationNodeTransformer, OperatorNode as OperatorNode3, ParensNode as ParensNode2, PrimitiveValueListNode, ReferenceNode as ReferenceNode3, ReturningNode, SelectAllNode, SelectionNode as SelectionNode2, SelectQueryNode as SelectQueryNode2, sql, TableNode as TableNode3, UpdateQueryNode, ValueNode as ValueNode3, ValuesNode, WhereNode as WhereNode2 } from "kysely";
|
|
13
|
+
import { AliasNode as AliasNode3, BinaryOperationNode as BinaryOperationNode3, ColumnNode as ColumnNode3, DeleteQueryNode, expressionBuilder as expressionBuilder2, ExpressionWrapper as ExpressionWrapper2, FromNode as FromNode2, IdentifierNode as IdentifierNode2, InsertQueryNode, OperationNodeTransformer, OperatorNode as OperatorNode3, ParensNode as ParensNode2, PrimitiveValueListNode, ReferenceNode as ReferenceNode3, ReturningNode, SelectAllNode, SelectionNode as SelectionNode2, SelectQueryNode as SelectQueryNode2, sql, TableNode as TableNode3, UpdateQueryNode, ValueNode as ValueNode3, ValuesNode, WhereNode as WhereNode2 } from "kysely";
|
|
14
14
|
import { match as match3 } from "ts-pattern";
|
|
15
15
|
|
|
16
16
|
// src/column-collector.ts
|
|
@@ -36,7 +36,7 @@ var ColumnCollector = class extends KyselyUtils.DefaultOperationNodeVisitor {
|
|
|
36
36
|
import { invariant as invariant2 } from "@zenstackhq/common-helpers";
|
|
37
37
|
import { getCrudDialect, QueryUtils, SchemaUtils } from "@zenstackhq/orm";
|
|
38
38
|
import { ExpressionUtils as ExpressionUtils3 } from "@zenstackhq/orm/schema";
|
|
39
|
-
import { AliasNode as AliasNode2, BinaryOperationNode as BinaryOperationNode2, ColumnNode as ColumnNode2, expressionBuilder, FromNode, FunctionNode as FunctionNode2, IdentifierNode, OperatorNode as OperatorNode2, ReferenceNode as ReferenceNode2, SelectionNode, SelectQueryNode, TableNode as TableNode2, ValueListNode, ValueNode as ValueNode2, WhereNode } from "kysely";
|
|
39
|
+
import { AliasNode as AliasNode2, BinaryOperationNode as BinaryOperationNode2, ColumnNode as ColumnNode2, expressionBuilder, ExpressionWrapper, FromNode, FunctionNode as FunctionNode2, IdentifierNode, OperatorNode as OperatorNode2, ReferenceNode as ReferenceNode2, SelectionNode, SelectQueryNode, TableNode as TableNode2, ValueListNode, ValueNode as ValueNode2, WhereNode } from "kysely";
|
|
40
40
|
import { match as match2 } from "ts-pattern";
|
|
41
41
|
|
|
42
42
|
// src/expression-evaluator.ts
|
|
@@ -287,6 +287,7 @@ var ExpressionTransformer = class {
|
|
|
287
287
|
}
|
|
288
288
|
client;
|
|
289
289
|
dialect;
|
|
290
|
+
eb = expressionBuilder();
|
|
290
291
|
constructor(client) {
|
|
291
292
|
this.client = client;
|
|
292
293
|
this.dialect = getCrudDialect(this.schema, this.clientOptions);
|
|
@@ -311,13 +312,15 @@ var ExpressionTransformer = class {
|
|
|
311
312
|
if (!handler) {
|
|
312
313
|
throw new Error(`Unsupported expression kind: ${expression.kind}`);
|
|
313
314
|
}
|
|
314
|
-
|
|
315
|
+
const result = handler.value.call(this, expression, context);
|
|
316
|
+
invariant2("kind" in result, `expression handler must return an OperationNode: transforming ${expression.kind}`);
|
|
317
|
+
return result;
|
|
315
318
|
}
|
|
316
319
|
_literal(expr2) {
|
|
317
320
|
return this.transformValue(expr2.value, typeof expr2.value === "string" ? "String" : typeof expr2.value === "boolean" ? "Boolean" : "Int");
|
|
318
321
|
}
|
|
319
322
|
_array(expr2, context) {
|
|
320
|
-
return
|
|
323
|
+
return this.dialect.buildArrayValue(expr2.items.map((item) => new ExpressionWrapper(this.transform(item, context))), expr2.type).toOperationNode();
|
|
321
324
|
}
|
|
322
325
|
_field(expr2, context) {
|
|
323
326
|
if (context.contextValue) {
|
|
@@ -604,9 +607,11 @@ var ExpressionTransformer = class {
|
|
|
604
607
|
return trueNode(this.dialect);
|
|
605
608
|
} else if (value === false) {
|
|
606
609
|
return falseNode(this.dialect);
|
|
610
|
+
} else if (Array.isArray(value)) {
|
|
611
|
+
return this.dialect.buildArrayValue(value.map((v) => new ExpressionWrapper(this.transformValue(v, type))), type).toOperationNode();
|
|
607
612
|
} else {
|
|
608
613
|
const transformed = this.dialect.transformInput(value, type, false) ?? null;
|
|
609
|
-
if (
|
|
614
|
+
if (typeof transformed !== "string") {
|
|
610
615
|
return ValueNode2.createImmediate(transformed);
|
|
611
616
|
} else {
|
|
612
617
|
return ValueNode2.create(transformed);
|
|
@@ -630,8 +635,7 @@ var ExpressionTransformer = class {
|
|
|
630
635
|
if (!func) {
|
|
631
636
|
throw createUnsupportedError(`Function not implemented: ${expr2.function}`);
|
|
632
637
|
}
|
|
633
|
-
|
|
634
|
-
return func(eb, (expr2.args ?? []).map((arg) => this.transformCallArg(eb, arg, context)), {
|
|
638
|
+
return func(this.eb, (expr2.args ?? []).map((arg) => this.transformCallArg(arg, context)), {
|
|
635
639
|
client: this.client,
|
|
636
640
|
dialect: this.dialect,
|
|
637
641
|
model: context.modelOrType,
|
|
@@ -651,21 +655,12 @@ var ExpressionTransformer = class {
|
|
|
651
655
|
}
|
|
652
656
|
return func;
|
|
653
657
|
}
|
|
654
|
-
transformCallArg(
|
|
655
|
-
if (ExpressionUtils3.isLiteral(arg)) {
|
|
656
|
-
return eb.val(arg.value);
|
|
657
|
-
}
|
|
658
|
+
transformCallArg(arg, context) {
|
|
658
659
|
if (ExpressionUtils3.isField(arg)) {
|
|
659
|
-
return eb.ref(arg.field);
|
|
660
|
-
}
|
|
661
|
-
|
|
662
|
-
return this.transformCall(arg, context);
|
|
663
|
-
}
|
|
664
|
-
if (this.isAuthMember(arg)) {
|
|
665
|
-
const valNode = this.valueMemberAccess(this.auth, arg, this.authType);
|
|
666
|
-
return valNode ? eb.val(valNode.value) : eb.val(null);
|
|
660
|
+
return this.eb.ref(arg.field);
|
|
661
|
+
} else {
|
|
662
|
+
return new ExpressionWrapper(this.transform(arg, context));
|
|
667
663
|
}
|
|
668
|
-
throw createUnsupportedError(`Unsupported argument expression: ${arg.kind}`);
|
|
669
664
|
}
|
|
670
665
|
_member(expr2, context) {
|
|
671
666
|
if (ExpressionUtils3.isBinding(expr2.receiver)) {
|
|
@@ -1068,7 +1063,7 @@ var PolicyHandler = class extends OperationNodeTransformer {
|
|
|
1068
1063
|
modelLevelFilter,
|
|
1069
1064
|
node.where?.where ?? trueNode(this.dialect)
|
|
1070
1065
|
]);
|
|
1071
|
-
const preUpdateCheckQuery = this.eb.selectFrom(mutationModel).select((eb) => eb.fn.coalesce(eb.fn.sum(this.dialect.castInt(new
|
|
1066
|
+
const preUpdateCheckQuery = this.eb.selectFrom(mutationModel).select((eb) => eb.fn.coalesce(eb.fn.sum(this.dialect.castInt(new ExpressionWrapper2(logicalNot(this.dialect, fieldLevelFilter)))), eb.lit(0)).as("$filteredCount")).where(() => new ExpressionWrapper2(updateFilter));
|
|
1072
1067
|
const preUpdateResult = await proceed(preUpdateCheckQuery.toOperationNode());
|
|
1073
1068
|
if (preUpdateResult.rows[0].$filteredCount > 0) {
|
|
1074
1069
|
throw createRejectedByPolicyError(mutationModel, RejectedByPolicyReason.NO_ACCESS, "some rows cannot be updated due to field policies");
|
|
@@ -1119,10 +1114,10 @@ var PolicyHandler = class extends OperationNodeTransformer {
|
|
|
1119
1114
|
eb(eb.fn("COUNT", [
|
|
1120
1115
|
eb.lit(1)
|
|
1121
1116
|
]), "=", Number(updateResult.numAffectedRows ?? 0)).as("$condition")
|
|
1122
|
-
]).where(() => new
|
|
1117
|
+
]).where(() => new ExpressionWrapper2(conjunction(this.dialect, [
|
|
1123
1118
|
idConditions,
|
|
1124
1119
|
postUpdateFilter
|
|
1125
|
-
]))).$if(needsBeforeUpdateJoin, (qb) => qb.leftJoin(() => new
|
|
1120
|
+
]))).$if(needsBeforeUpdateJoin, (qb) => qb.leftJoin(() => new ExpressionWrapper2(beforeUpdateTable).as("$before"), (join) => {
|
|
1126
1121
|
const idFields = QueryUtils2.requireIdFields(this.client.$schema, model);
|
|
1127
1122
|
return idFields.reduce((acc, f) => acc.onRef(`${model}.${f}`, "=", `$before.${f}`), join);
|
|
1128
1123
|
}));
|
|
@@ -1232,7 +1227,7 @@ var PolicyHandler = class extends OperationNodeTransformer {
|
|
|
1232
1227
|
if (!columnName) {
|
|
1233
1228
|
return update;
|
|
1234
1229
|
}
|
|
1235
|
-
const wrappedValue = sql`IF(${new
|
|
1230
|
+
const wrappedValue = sql`IF(${new ExpressionWrapper2(filter)}, ${new ExpressionWrapper2(update.value)}, ${sql.ref(columnName)})`.toOperationNode();
|
|
1236
1231
|
return {
|
|
1237
1232
|
...update,
|
|
1238
1233
|
value: wrappedValue
|
|
@@ -1409,7 +1404,7 @@ var PolicyHandler = class extends OperationNodeTransformer {
|
|
|
1409
1404
|
};
|
|
1410
1405
|
}
|
|
1411
1406
|
const eb = expressionBuilder2();
|
|
1412
|
-
const selection = eb.case().when(new
|
|
1407
|
+
const selection = eb.case().when(new ExpressionWrapper2(filter)).then(eb.ref(field)).else(null).end().as(field).toOperationNode();
|
|
1413
1408
|
return {
|
|
1414
1409
|
hasPolicies: true,
|
|
1415
1410
|
selection: SelectionNode2.create(selection)
|
|
@@ -1489,9 +1484,9 @@ var PolicyHandler = class extends OperationNodeTransformer {
|
|
|
1489
1484
|
invariant3(bValue !== null && bValue !== void 0, "B value cannot be null or undefined");
|
|
1490
1485
|
const eb = expressionBuilder2();
|
|
1491
1486
|
const filterA = this.buildPolicyFilter(m2m.firstModel, void 0, "update");
|
|
1492
|
-
const queryA = eb.selectFrom(m2m.firstModel).where(eb(eb.ref(`${m2m.firstModel}.${m2m.firstIdField}`), "=", aValue)).select(() => new
|
|
1487
|
+
const queryA = eb.selectFrom(m2m.firstModel).where(eb(eb.ref(`${m2m.firstModel}.${m2m.firstIdField}`), "=", aValue)).select(() => new ExpressionWrapper2(filterA).as("$t"));
|
|
1493
1488
|
const filterB = this.buildPolicyFilter(m2m.secondModel, void 0, "update");
|
|
1494
|
-
const queryB = eb.selectFrom(m2m.secondModel).where(eb(eb.ref(`${m2m.secondModel}.${m2m.secondIdField}`), "=", bValue)).select(() => new
|
|
1489
|
+
const queryB = eb.selectFrom(m2m.secondModel).where(eb(eb.ref(`${m2m.secondModel}.${m2m.secondIdField}`), "=", bValue)).select(() => new ExpressionWrapper2(filterB).as("$t"));
|
|
1495
1490
|
const queryNode = {
|
|
1496
1491
|
kind: "SelectQueryNode",
|
|
1497
1492
|
selections: [
|
|
@@ -1515,7 +1510,7 @@ var PolicyHandler = class extends OperationNodeTransformer {
|
|
|
1515
1510
|
for (const def of allFields) {
|
|
1516
1511
|
const index = fields.indexOf(def.name);
|
|
1517
1512
|
if (index >= 0) {
|
|
1518
|
-
allValues.push(new
|
|
1513
|
+
allValues.push(new ExpressionWrapper2(values[index]));
|
|
1519
1514
|
} else {
|
|
1520
1515
|
allValues.push(this.eb.lit(null));
|
|
1521
1516
|
}
|
|
@@ -1524,7 +1519,7 @@ var PolicyHandler = class extends OperationNodeTransformer {
|
|
|
1524
1519
|
allValues
|
|
1525
1520
|
]);
|
|
1526
1521
|
const filter = this.buildPolicyFilter(model, void 0, "create");
|
|
1527
|
-
const preCreateCheck = this.eb.selectFrom(valuesTable.as(model)).select(this.eb(this.eb.fn.count(this.eb.lit(1)), ">", 0).as("$condition")).where(() => new
|
|
1522
|
+
const preCreateCheck = this.eb.selectFrom(valuesTable.as(model)).select(this.eb(this.eb.fn.count(this.eb.lit(1)), ">", 0).as("$condition")).where(() => new ExpressionWrapper2(filter));
|
|
1528
1523
|
const result = await proceed(preCreateCheck.toOperationNode());
|
|
1529
1524
|
if (!result.rows[0]?.$condition) {
|
|
1530
1525
|
throw createRejectedByPolicyError(model, RejectedByPolicyReason.NO_ACCESS);
|
|
@@ -1560,8 +1555,9 @@ var PolicyHandler = class extends OperationNodeTransformer {
|
|
|
1560
1555
|
value = this.dialect.transformInput(item, fieldDef.type, !!fieldDef.array);
|
|
1561
1556
|
}
|
|
1562
1557
|
if (Array.isArray(value)) {
|
|
1558
|
+
const fieldDef = QueryUtils2.requireField(this.client.$schema, model, fields[i]);
|
|
1563
1559
|
result.push({
|
|
1564
|
-
node: this.dialect.
|
|
1560
|
+
node: this.dialect.buildArrayValue(value, fieldDef.type).toOperationNode(),
|
|
1565
1561
|
raw: value
|
|
1566
1562
|
});
|
|
1567
1563
|
} else {
|
|
@@ -1810,8 +1806,8 @@ var PolicyHandler = class extends OperationNodeTransformer {
|
|
|
1810
1806
|
}
|
|
1811
1807
|
const checkForOperation = operation === "read" ? "read" : "update";
|
|
1812
1808
|
const joinTable = alias ?? tableName;
|
|
1813
|
-
const aQuery = this.eb.selectFrom(m2m.firstModel).whereRef(`${m2m.firstModel}.${m2m.firstIdField}`, "=", `${joinTable}.A`).select(() => new
|
|
1814
|
-
const bQuery = this.eb.selectFrom(m2m.secondModel).whereRef(`${m2m.secondModel}.${m2m.secondIdField}`, "=", `${joinTable}.B`).select(() => new
|
|
1809
|
+
const aQuery = this.eb.selectFrom(m2m.firstModel).whereRef(`${m2m.firstModel}.${m2m.firstIdField}`, "=", `${joinTable}.A`).select(() => new ExpressionWrapper2(this.buildPolicyFilter(m2m.firstModel, void 0, checkForOperation)).as("$conditionA"));
|
|
1810
|
+
const bQuery = this.eb.selectFrom(m2m.secondModel).whereRef(`${m2m.secondModel}.${m2m.secondIdField}`, "=", `${joinTable}.B`).select(() => new ExpressionWrapper2(this.buildPolicyFilter(m2m.secondModel, void 0, checkForOperation)).as("$conditionB"));
|
|
1815
1811
|
return this.eb.and([
|
|
1816
1812
|
aQuery,
|
|
1817
1813
|
bQuery
|
|
@@ -1911,7 +1907,7 @@ var check = /* @__PURE__ */ __name((eb, args, { client, model, modelAlias, opera
|
|
|
1911
1907
|
const policyHandler = new PolicyHandler(client);
|
|
1912
1908
|
const op = arg2Node ? arg2Node.value : operation;
|
|
1913
1909
|
const policyCondition = policyHandler.buildPolicyFilter(relationModel, void 0, op);
|
|
1914
|
-
const result = eb.selectFrom(eb.selectFrom(relationModel).where(joinCondition).select(new
|
|
1910
|
+
const result = eb.selectFrom(eb.selectFrom(relationModel).where(joinCondition).select(new ExpressionWrapper3(policyCondition).as("$condition")).as("$sub")).selectAll();
|
|
1915
1911
|
return result;
|
|
1916
1912
|
}, "check");
|
|
1917
1913
|
|