@zenstackhq/plugin-policy 3.0.0-beta.19 → 3.0.0-beta.20

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.js CHANGED
@@ -8,7 +8,7 @@ import { ExpressionWrapper as ExpressionWrapper2, ValueNode as ValueNode4 } from
8
8
 
9
9
  // src/policy-handler.ts
10
10
  import { invariant as invariant3 } from "@zenstackhq/common-helpers";
11
- import { getCrudDialect as getCrudDialect2, InternalError as InternalError2, QueryError as QueryError2, QueryUtils as QueryUtils2, RejectedByPolicyError, RejectedByPolicyReason, SchemaUtils } from "@zenstackhq/orm";
11
+ import { getCrudDialect as getCrudDialect2, QueryUtils as QueryUtils2, RejectedByPolicyReason, SchemaUtils } from "@zenstackhq/orm";
12
12
  import { ExpressionUtils as ExpressionUtils4 } from "@zenstackhq/orm/schema";
13
13
  import { AliasNode as AliasNode3, BinaryOperationNode as BinaryOperationNode3, ColumnNode as ColumnNode2, DeleteQueryNode, expressionBuilder as expressionBuilder2, ExpressionWrapper, FromNode as FromNode2, FunctionNode as FunctionNode3, IdentifierNode as IdentifierNode2, InsertQueryNode, OperationNodeTransformer, OperatorNode as OperatorNode3, ParensNode as ParensNode2, PrimitiveValueListNode, RawNode, ReferenceNode as ReferenceNode3, ReturningNode, SelectAllNode, SelectionNode as SelectionNode2, SelectQueryNode as SelectQueryNode2, sql, TableNode as TableNode3, UpdateQueryNode, ValueListNode as ValueListNode2, ValueNode as ValueNode3, ValuesNode, WhereNode as WhereNode2 } from "kysely";
14
14
  import { match as match3 } from "ts-pattern";
@@ -34,7 +34,7 @@ var ColumnCollector = class extends KyselyUtils.DefaultOperationNodeVisitor {
34
34
 
35
35
  // src/expression-transformer.ts
36
36
  import { invariant as invariant2 } from "@zenstackhq/common-helpers";
37
- import { getCrudDialect, InternalError, QueryError, QueryUtils } from "@zenstackhq/orm";
37
+ import { getCrudDialect, QueryUtils } from "@zenstackhq/orm";
38
38
  import { ExpressionUtils as ExpressionUtils3 } from "@zenstackhq/orm/schema";
39
39
  import { AliasNode as AliasNode2, BinaryOperationNode as BinaryOperationNode2, ColumnNode, expressionBuilder, 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";
@@ -111,6 +111,7 @@ var ExpressionEvaluator = class {
111
111
  };
112
112
 
113
113
  // src/utils.ts
114
+ import { ORMError, ORMErrorReason } from "@zenstackhq/orm";
114
115
  import { ExpressionUtils as ExpressionUtils2 } from "@zenstackhq/orm/schema";
115
116
  import { AliasNode, AndNode, BinaryOperationNode, FunctionNode, OperatorNode, OrNode, ParensNode, ReferenceNode, TableNode, UnaryOperationNode, ValueNode } from "kysely";
116
117
  function trueNode(dialect) {
@@ -212,6 +213,17 @@ function isBeforeInvocation(expr2) {
212
213
  return ExpressionUtils2.isCall(expr2) && expr2.function === "before";
213
214
  }
214
215
  __name(isBeforeInvocation, "isBeforeInvocation");
216
+ function createRejectedByPolicyError(model, reason, message) {
217
+ const err = new ORMError(ORMErrorReason.REJECTED_BY_POLICY, message ?? "operation is rejected by access policies");
218
+ err.rejectedByPolicyReason = reason;
219
+ err.model = model;
220
+ return err;
221
+ }
222
+ __name(createRejectedByPolicyError, "createRejectedByPolicyError");
223
+ function createUnsupportedError(message) {
224
+ return new ORMError(ORMErrorReason.NOT_SUPPORTED, message);
225
+ }
226
+ __name(createUnsupportedError, "createUnsupportedError");
215
227
 
216
228
  // src/expression-transformer.ts
217
229
  function _ts_decorate(decorators, target, key, desc) {
@@ -256,7 +268,7 @@ var ExpressionTransformer = class {
256
268
  }
257
269
  get authType() {
258
270
  if (!this.schema.authType) {
259
- throw new InternalError('Schema does not have an "authType" specified');
271
+ invariant2(false, 'Schema does not have an "authType" specified');
260
272
  }
261
273
  return this.schema.authType;
262
274
  }
@@ -424,7 +436,7 @@ var ExpressionTransformer = class {
424
436
  }
425
437
  transformAuthBinary(expr2, context) {
426
438
  if (expr2.op !== "==" && expr2.op !== "!=") {
427
- throw new QueryError(`Unsupported operator for \`auth()\` in policy of model "${context.model}": ${expr2.op}`);
439
+ throw createUnsupportedError(`Unsupported operator for \`auth()\` in policy of model "${context.model}": ${expr2.op}`);
428
440
  }
429
441
  let authExpr;
430
442
  let other;
@@ -440,7 +452,7 @@ var ExpressionTransformer = class {
440
452
  } else {
441
453
  const authModel = QueryUtils.getModel(this.schema, this.authType);
442
454
  if (!authModel) {
443
- throw new QueryError(`Unsupported use of \`auth()\` in policy of model "${context.model}", comparing with \`auth()\` is only possible when auth type is a model`);
455
+ throw createUnsupportedError(`Unsupported use of \`auth()\` in policy of model "${context.model}", comparing with \`auth()\` is only possible when auth type is a model`);
444
456
  }
445
457
  const idFields = Object.values(authModel.fields).filter((f) => f.id).map((f) => f.name);
446
458
  invariant2(idFields.length > 0, "auth type model must have at least one id field");
@@ -490,7 +502,7 @@ var ExpressionTransformer = class {
490
502
  transformCall(expr2, context) {
491
503
  const func = this.getFunctionImpl(expr2.function);
492
504
  if (!func) {
493
- throw new QueryError(`Function not implemented: ${expr2.function}`);
505
+ throw createUnsupportedError(`Function not implemented: ${expr2.function}`);
494
506
  }
495
507
  const eb = expressionBuilder();
496
508
  return func(eb, (expr2.args ?? []).map((arg) => this.transformCallArg(eb, arg, context)), {
@@ -527,7 +539,7 @@ var ExpressionTransformer = class {
527
539
  const valNode = this.valueMemberAccess(this.auth, arg, this.authType);
528
540
  return valNode ? eb.val(valNode.value) : eb.val(null);
529
541
  }
530
- throw new InternalError(`Unsupported argument expression: ${arg.kind}`);
542
+ throw createUnsupportedError(`Unsupported argument expression: ${arg.kind}`);
531
543
  }
532
544
  _member(expr2, context) {
533
545
  if (this.isAuthCall(expr2.receiver)) {
@@ -799,7 +811,7 @@ var PolicyHandler = class extends OperationNodeTransformer {
799
811
  }
800
812
  async handle(node, proceed) {
801
813
  if (!this.isCrudQueryNode(node)) {
802
- throw new RejectedByPolicyError(void 0, RejectedByPolicyReason.OTHER, "non-CRUD queries are not allowed");
814
+ throw createRejectedByPolicyError(void 0, RejectedByPolicyReason.OTHER, "non-CRUD queries are not allowed");
803
815
  }
804
816
  if (!this.isMutationQueryNode(node)) {
805
817
  return proceed(this.transformNode(node));
@@ -813,7 +825,7 @@ var PolicyHandler = class extends OperationNodeTransformer {
813
825
  if (constCondition === true) {
814
826
  needCheckPreCreate = false;
815
827
  } else if (constCondition === false) {
816
- throw new RejectedByPolicyError(mutationModel, RejectedByPolicyReason.NO_ACCESS);
828
+ throw createRejectedByPolicyError(mutationModel, RejectedByPolicyReason.NO_ACCESS);
817
829
  }
818
830
  }
819
831
  if (needCheckPreCreate) {
@@ -833,7 +845,7 @@ var PolicyHandler = class extends OperationNodeTransformer {
833
845
  for (const postRow of result.rows) {
834
846
  const beforeRow = beforeUpdateInfo.rows.find((r) => idFields.every((f) => r[f] === postRow[f]));
835
847
  if (!beforeRow) {
836
- throw new QueryError2("Before-update and after-update rows do not match by id. If you have post-update policies on a model, updating id fields is not supported.");
848
+ throw createRejectedByPolicyError(mutationModel, RejectedByPolicyReason.OTHER, "Before-update and after-update rows do not match by id. If you have post-update policies on a model, updating id fields is not supported.");
837
849
  }
838
850
  }
839
851
  }
@@ -864,7 +876,7 @@ var PolicyHandler = class extends OperationNodeTransformer {
864
876
  }));
865
877
  const postUpdateResult = await proceed(postUpdateQuery.toOperationNode());
866
878
  if (!postUpdateResult.rows[0]?.$condition) {
867
- throw new RejectedByPolicyError(mutationModel, RejectedByPolicyReason.NO_ACCESS, "some or all updated rows failed to pass post-update policy check");
879
+ throw createRejectedByPolicyError(mutationModel, RejectedByPolicyReason.NO_ACCESS, "some or all updated rows failed to pass post-update policy check");
868
880
  }
869
881
  }
870
882
  if (!node.returning || this.onlyReturningId(node)) {
@@ -872,7 +884,7 @@ var PolicyHandler = class extends OperationNodeTransformer {
872
884
  } else {
873
885
  const readBackResult = await this.processReadBack(node, result, proceed);
874
886
  if (readBackResult.rows.length !== result.rows.length) {
875
- throw new RejectedByPolicyError(mutationModel, RejectedByPolicyReason.CANNOT_READ_BACK, "result is not allowed to be read back");
887
+ throw createRejectedByPolicyError(mutationModel, RejectedByPolicyReason.CANNOT_READ_BACK, "result is not allowed to be read back");
876
888
  }
877
889
  return readBackResult;
878
890
  }
@@ -1131,10 +1143,10 @@ var PolicyHandler = class extends OperationNodeTransformer {
1131
1143
  };
1132
1144
  const result = await proceed(queryNode);
1133
1145
  if (!result.rows[0]?.$conditionA) {
1134
- throw new RejectedByPolicyError(m2m.firstModel, RejectedByPolicyReason.CANNOT_READ_BACK, `many-to-many relation participant model "${m2m.firstModel}" not updatable`);
1146
+ throw createRejectedByPolicyError(m2m.firstModel, RejectedByPolicyReason.CANNOT_READ_BACK, `many-to-many relation participant model "${m2m.firstModel}" not updatable`);
1135
1147
  }
1136
1148
  if (!result.rows[0]?.$conditionB) {
1137
- throw new RejectedByPolicyError(m2m.secondModel, RejectedByPolicyReason.NO_ACCESS, `many-to-many relation participant model "${m2m.secondModel}" not updatable`);
1149
+ throw createRejectedByPolicyError(m2m.secondModel, RejectedByPolicyReason.NO_ACCESS, `many-to-many relation participant model "${m2m.secondModel}" not updatable`);
1138
1150
  }
1139
1151
  }
1140
1152
  async enforcePreCreatePolicyForOne(model, fields, values, proceed) {
@@ -1176,7 +1188,7 @@ var PolicyHandler = class extends OperationNodeTransformer {
1176
1188
  };
1177
1189
  const result = await proceed(preCreateCheck);
1178
1190
  if (!result.rows[0]?.$condition) {
1179
- throw new RejectedByPolicyError(model, RejectedByPolicyReason.NO_ACCESS);
1191
+ throw createRejectedByPolicyError(model, RejectedByPolicyReason.NO_ACCESS);
1180
1192
  }
1181
1193
  }
1182
1194
  unwrapCreateValueRows(node, model, fields, isManyToManyJoinTable) {
@@ -1187,7 +1199,7 @@ var PolicyHandler = class extends OperationNodeTransformer {
1187
1199
  this.unwrapCreateValueRow(node.values, model, fields, isManyToManyJoinTable)
1188
1200
  ];
1189
1201
  } else {
1190
- throw new InternalError2(`Unexpected node kind: ${node.kind} for unwrapping create values`);
1202
+ invariant3(false, `Unexpected node kind: ${node.kind} for unwrapping create values`);
1191
1203
  }
1192
1204
  }
1193
1205
  unwrapCreateValueRow(data, model, fields, isImplicitManyToManyJoinTable) {
@@ -1278,7 +1290,7 @@ var PolicyHandler = class extends OperationNodeTransformer {
1278
1290
  alias: void 0
1279
1291
  })).when(UpdateQueryNode.is, (node2) => {
1280
1292
  if (!node2.table) {
1281
- throw new QueryError2("Update query must have a table");
1293
+ invariant3(false, "Update query must have a table");
1282
1294
  }
1283
1295
  const r2 = this.extractTableName(node2.table);
1284
1296
  return r2 ? {
@@ -1287,7 +1299,7 @@ var PolicyHandler = class extends OperationNodeTransformer {
1287
1299
  } : void 0;
1288
1300
  }).when(DeleteQueryNode.is, (node2) => {
1289
1301
  if (node2.from.froms.length !== 1) {
1290
- throw new QueryError2("Only one from table is supported for delete");
1302
+ throw createUnsupportedError("Only one from table is supported for delete");
1291
1303
  }
1292
1304
  const r2 = this.extractTableName(node2.from.froms[0]);
1293
1305
  return r2 ? {
@@ -1296,7 +1308,7 @@ var PolicyHandler = class extends OperationNodeTransformer {
1296
1308
  } : void 0;
1297
1309
  }).exhaustive();
1298
1310
  if (!r) {
1299
- throw new InternalError2(`Unable to get table name for query node: ${node}`);
1311
+ invariant3(false, `Unable to get table name for query node: ${node}`);
1300
1312
  }
1301
1313
  return r;
1302
1314
  }