@zenstackhq/server 3.0.0-beta.18 → 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/api.d.cts CHANGED
@@ -108,7 +108,7 @@ declare class RestApiHandler<Schema extends SchemaDef> implements ApiHandler<Sch
108
108
  private buildRelationSelect;
109
109
  private makeFilterValue;
110
110
  private injectRelationQuery;
111
- private handleZenStackError;
111
+ private handleORMError;
112
112
  private makeError;
113
113
  private makeUnsupportedModelError;
114
114
  private makeUnsupportedRelationshipError;
@@ -139,7 +139,7 @@ declare class RPCApiHandler<Schema extends SchemaDef> implements ApiHandler<Sche
139
139
  private isValidModel;
140
140
  private makeBadInputErrorResponse;
141
141
  private makeGenericErrorResponse;
142
- private makeZenStackErrorResponse;
142
+ private makeORMErrorResponse;
143
143
  private processRequestPayload;
144
144
  private unmarshalQ;
145
145
  }
package/dist/api.d.ts CHANGED
@@ -108,7 +108,7 @@ declare class RestApiHandler<Schema extends SchemaDef> implements ApiHandler<Sch
108
108
  private buildRelationSelect;
109
109
  private makeFilterValue;
110
110
  private injectRelationQuery;
111
- private handleZenStackError;
111
+ private handleORMError;
112
112
  private makeError;
113
113
  private makeUnsupportedModelError;
114
114
  private makeUnsupportedRelationshipError;
@@ -139,7 +139,7 @@ declare class RPCApiHandler<Schema extends SchemaDef> implements ApiHandler<Sche
139
139
  private isValidModel;
140
140
  private makeBadInputErrorResponse;
141
141
  private makeGenericErrorResponse;
142
- private makeZenStackErrorResponse;
142
+ private makeORMErrorResponse;
143
143
  private processRequestPayload;
144
144
  private unmarshalQ;
145
145
  }
package/dist/api.js CHANGED
@@ -3,10 +3,11 @@ var __name = (target, value) => __defProp(target, "name", { value, configurable:
3
3
 
4
4
  // src/api/rest/index.ts
5
5
  import { clone, enumerate, lowerCaseFirst, paramCase } from "@zenstackhq/common-helpers";
6
- import { InputValidationError, NotFoundError, QueryError, RejectedByPolicyError, ZenStackError } from "@zenstackhq/orm";
6
+ import { ORMError, ORMErrorReason } from "@zenstackhq/orm";
7
7
  import { Decimal as Decimal2 } from "decimal.js";
8
8
  import SuperJSON2 from "superjson";
9
9
  import tsjapi from "ts-japi";
10
+ import { match as match2 } from "ts-pattern";
10
11
  import UrlPattern from "url-pattern";
11
12
  import z from "zod";
12
13
 
@@ -292,17 +293,17 @@ var RestApiHandler = class {
292
293
  if (!pattern) {
293
294
  throw new InvalidValueError(`Unknown route type: ${routeType}`);
294
295
  }
295
- const match2 = pattern.match(path);
296
- if (!match2) {
296
+ const match4 = pattern.match(path);
297
+ if (!match4) {
297
298
  return;
298
299
  }
299
- if (match2.type in this.modelNameMapping) {
300
- throw new InvalidValueError(`use the mapped model name: ${this.modelNameMapping[match2.type]} and not ${match2.type}`);
300
+ if (match4.type in this.modelNameMapping) {
301
+ throw new InvalidValueError(`use the mapped model name: ${this.modelNameMapping[match4.type]} and not ${match4.type}`);
301
302
  }
302
- if (match2.type in this.reverseModelNameMapping) {
303
- match2.type = this.reverseModelNameMapping[match2.type];
303
+ if (match4.type in this.reverseModelNameMapping) {
304
+ match4.type = this.reverseModelNameMapping[match4.type];
304
305
  }
305
- return match2;
306
+ return match4;
306
307
  }
307
308
  async handleRequest({ client, method, path, query, requestBody }) {
308
309
  method = method.toUpperCase();
@@ -312,21 +313,21 @@ var RestApiHandler = class {
312
313
  try {
313
314
  switch (method) {
314
315
  case "GET": {
315
- let match2 = this.matchUrlPattern(path, "single");
316
- if (match2) {
317
- return await this.processSingleRead(client, match2.type, match2.id, query);
316
+ let match4 = this.matchUrlPattern(path, "single");
317
+ if (match4) {
318
+ return await this.processSingleRead(client, match4.type, match4.id, query);
318
319
  }
319
- match2 = this.matchUrlPattern(path, "fetchRelationship");
320
- if (match2) {
321
- return await this.processFetchRelated(client, match2.type, match2.id, match2.relationship, query);
320
+ match4 = this.matchUrlPattern(path, "fetchRelationship");
321
+ if (match4) {
322
+ return await this.processFetchRelated(client, match4.type, match4.id, match4.relationship, query);
322
323
  }
323
- match2 = this.matchUrlPattern(path, "relationship");
324
- if (match2) {
325
- return await this.processReadRelationship(client, match2.type, match2.id, match2.relationship, query);
324
+ match4 = this.matchUrlPattern(path, "relationship");
325
+ if (match4) {
326
+ return await this.processReadRelationship(client, match4.type, match4.id, match4.relationship, query);
326
327
  }
327
- match2 = this.matchUrlPattern(path, "collection");
328
- if (match2) {
329
- return await this.processCollectionRead(client, match2.type, query);
328
+ match4 = this.matchUrlPattern(path, "collection");
329
+ if (match4) {
330
+ return await this.processCollectionRead(client, match4.type, query);
330
331
  }
331
332
  return this.makeError("invalidPath");
332
333
  }
@@ -334,19 +335,19 @@ var RestApiHandler = class {
334
335
  if (!requestBody) {
335
336
  return this.makeError("invalidPayload");
336
337
  }
337
- let match2 = this.matchUrlPattern(path, "collection");
338
- if (match2) {
338
+ let match4 = this.matchUrlPattern(path, "collection");
339
+ if (match4) {
339
340
  const body = requestBody;
340
341
  const upsertMeta = this.upsertMetaSchema.safeParse(body);
341
342
  if (upsertMeta.success) {
342
- return await this.processUpsert(client, match2.type, query, requestBody);
343
+ return await this.processUpsert(client, match4.type, query, requestBody);
343
344
  } else {
344
- return await this.processCreate(client, match2.type, query, requestBody);
345
+ return await this.processCreate(client, match4.type, query, requestBody);
345
346
  }
346
347
  }
347
- match2 = this.matchUrlPattern(path, "relationship");
348
- if (match2) {
349
- return await this.processRelationshipCRUD(client, "create", match2.type, match2.id, match2.relationship, query, requestBody);
348
+ match4 = this.matchUrlPattern(path, "relationship");
349
+ if (match4) {
350
+ return await this.processRelationshipCRUD(client, "create", match4.type, match4.id, match4.relationship, query, requestBody);
350
351
  }
351
352
  return this.makeError("invalidPath");
352
353
  }
@@ -356,24 +357,24 @@ var RestApiHandler = class {
356
357
  if (!requestBody) {
357
358
  return this.makeError("invalidPayload");
358
359
  }
359
- let match2 = this.matchUrlPattern(path, "single");
360
- if (match2) {
361
- return await this.processUpdate(client, match2.type, match2.id, query, requestBody);
360
+ let match4 = this.matchUrlPattern(path, "single");
361
+ if (match4) {
362
+ return await this.processUpdate(client, match4.type, match4.id, query, requestBody);
362
363
  }
363
- match2 = this.matchUrlPattern(path, "relationship");
364
- if (match2) {
365
- return await this.processRelationshipCRUD(client, "update", match2.type, match2.id, match2.relationship, query, requestBody);
364
+ match4 = this.matchUrlPattern(path, "relationship");
365
+ if (match4) {
366
+ return await this.processRelationshipCRUD(client, "update", match4.type, match4.id, match4.relationship, query, requestBody);
366
367
  }
367
368
  return this.makeError("invalidPath");
368
369
  }
369
370
  case "DELETE": {
370
- let match2 = this.matchUrlPattern(path, "single");
371
- if (match2) {
372
- return await this.processDelete(client, match2.type, match2.id);
371
+ let match4 = this.matchUrlPattern(path, "single");
372
+ if (match4) {
373
+ return await this.processDelete(client, match4.type, match4.id);
373
374
  }
374
- match2 = this.matchUrlPattern(path, "relationship");
375
- if (match2) {
376
- return await this.processRelationshipCRUD(client, "delete", match2.type, match2.id, match2.relationship, query, requestBody);
375
+ match4 = this.matchUrlPattern(path, "relationship");
376
+ if (match4) {
377
+ return await this.processRelationshipCRUD(client, "delete", match4.type, match4.id, match4.relationship, query, requestBody);
377
378
  }
378
379
  return this.makeError("invalidPath");
379
380
  }
@@ -383,8 +384,8 @@ var RestApiHandler = class {
383
384
  } catch (err) {
384
385
  if (err instanceof InvalidValueError) {
385
386
  return this.makeError("invalidValue", err.message);
386
- } else if (err instanceof ZenStackError) {
387
- return this.handleZenStackError(err);
387
+ } else if (err instanceof ORMError) {
388
+ return this.handleORMError(err);
388
389
  } else {
389
390
  return this.handleGenericError(err);
390
391
  }
@@ -1410,11 +1411,11 @@ ${err.stack}` : "Unknown error");
1410
1411
  if (!value) {
1411
1412
  continue;
1412
1413
  }
1413
- const match2 = key.match(this.filterParamPattern);
1414
- if (!match2 || !match2.groups || !match2.groups["match"]) {
1414
+ const match4 = key.match(this.filterParamPattern);
1415
+ if (!match4 || !match4.groups || !match4.groups["match"]) {
1415
1416
  continue;
1416
1417
  }
1417
- const filterKeys = match2.groups["match"].replaceAll(/[[\]]/g, " ").split(" ").filter((i) => i);
1418
+ const filterKeys = match4.groups["match"].replaceAll(/[[\]]/g, " ").split(" ").filter((i) => i);
1418
1419
  if (!filterKeys.length) {
1419
1420
  continue;
1420
1421
  }
@@ -1737,20 +1738,24 @@ ${err.stack}` : "Unknown error");
1737
1738
  };
1738
1739
  }
1739
1740
  }
1740
- handleZenStackError(err) {
1741
- if (err instanceof InputValidationError) {
1742
- return this.makeError("validationError", err.message, 422, err.cause instanceof Error ? err.cause.message : void 0);
1743
- } else if (err instanceof RejectedByPolicyError) {
1744
- return this.makeError("forbidden", err.message, 403, err.reason);
1745
- } else if (err instanceof NotFoundError) {
1746
- return this.makeError("notFound", err.message);
1747
- } else if (err instanceof QueryError) {
1748
- return this.makeError("queryError", err.message, 400, err.cause instanceof Error ? err.cause.message : void 0);
1749
- } else {
1741
+ handleORMError(err) {
1742
+ return match2(err.reason).with(ORMErrorReason.INVALID_INPUT, () => {
1743
+ return this.makeError("validationError", err.message, 422);
1744
+ }).with(ORMErrorReason.REJECTED_BY_POLICY, () => {
1745
+ return this.makeError("forbidden", err.message, 403, {
1746
+ reason: err.rejectedByPolicyReason
1747
+ });
1748
+ }).with(ORMErrorReason.NOT_FOUND, () => {
1749
+ return this.makeError("notFound", err.message, 404);
1750
+ }).with(ORMErrorReason.DB_QUERY_ERROR, () => {
1751
+ return this.makeError("queryError", err.message, 400, {
1752
+ dbErrorCode: err.dbErrorCode
1753
+ });
1754
+ }).otherwise(() => {
1750
1755
  return this.makeError("unknownError", err.message);
1751
- }
1756
+ });
1752
1757
  }
1753
- makeError(code, detail, status, reason) {
1758
+ makeError(code, detail, status, otherFields = {}) {
1754
1759
  status = status ?? this.errors[code]?.status ?? 500;
1755
1760
  const error = {
1756
1761
  status,
@@ -1760,9 +1765,7 @@ ${err.stack}` : "Unknown error");
1760
1765
  if (detail) {
1761
1766
  error.detail = detail;
1762
1767
  }
1763
- if (reason) {
1764
- error.reason = reason;
1765
- }
1768
+ Object.assign(error, otherFields);
1766
1769
  return {
1767
1770
  status,
1768
1771
  body: {
@@ -1782,8 +1785,9 @@ ${err.stack}` : "Unknown error");
1782
1785
 
1783
1786
  // src/api/rpc/index.ts
1784
1787
  import { lowerCaseFirst as lowerCaseFirst2, safeJSONStringify } from "@zenstackhq/common-helpers";
1785
- import { InputValidationError as InputValidationError2, NotFoundError as NotFoundError2, RejectedByPolicyError as RejectedByPolicyError2, ZenStackError as ZenStackError2 } from "@zenstackhq/orm";
1788
+ import { ORMError as ORMError2, ORMErrorReason as ORMErrorReason2 } from "@zenstackhq/orm";
1786
1789
  import SuperJSON3 from "superjson";
1790
+ import { match as match3 } from "ts-pattern";
1787
1791
  registerCustomSerializers();
1788
1792
  var RPCApiHandler = class {
1789
1793
  static {
@@ -1896,8 +1900,8 @@ var RPCApiHandler = class {
1896
1900
  return response;
1897
1901
  } catch (err) {
1898
1902
  log(this.options.log, "error", `error occurred when handling "${model}.${op}" request`, err);
1899
- if (err instanceof ZenStackError2) {
1900
- return this.makeZenStackErrorResponse(err);
1903
+ if (err instanceof ORMError2) {
1904
+ return this.makeORMErrorResponse(err);
1901
1905
  } else {
1902
1906
  return this.makeGenericErrorResponse(err);
1903
1907
  }
@@ -1930,27 +1934,29 @@ var RPCApiHandler = class {
1930
1934
  log(this.options.log, "debug", () => `sending error response: ${safeJSONStringify(resp)}${err instanceof Error ? "\n" + err.stack : ""}`);
1931
1935
  return resp;
1932
1936
  }
1933
- makeZenStackErrorResponse(err) {
1937
+ makeORMErrorResponse(err) {
1934
1938
  let status = 400;
1935
1939
  const error = {
1936
- message: err.message
1940
+ message: err.message,
1941
+ reason: err.reason
1937
1942
  };
1938
- if (err.cause && err.cause instanceof Error) {
1939
- error.cause = err.cause.message;
1940
- }
1941
- if (err instanceof NotFoundError2) {
1943
+ match3(err.reason).with(ORMErrorReason2.NOT_FOUND, () => {
1942
1944
  status = 404;
1943
1945
  error.model = err.model;
1944
- } else if (err instanceof InputValidationError2) {
1946
+ }).with(ORMErrorReason2.INVALID_INPUT, () => {
1945
1947
  status = 422;
1946
1948
  error.rejectedByValidation = true;
1947
1949
  error.model = err.model;
1948
- } else if (err instanceof RejectedByPolicyError2) {
1950
+ }).with(ORMErrorReason2.REJECTED_BY_POLICY, () => {
1949
1951
  status = 403;
1950
1952
  error.rejectedByPolicy = true;
1951
- error.rejectReason = err.reason;
1953
+ error.rejectReason = err.rejectedByPolicyReason;
1952
1954
  error.model = err.model;
1953
- }
1955
+ }).with(ORMErrorReason2.DB_QUERY_ERROR, () => {
1956
+ status = 400;
1957
+ error.dbErrorCode = err.dbErrorCode;
1958
+ }).otherwise(() => {
1959
+ });
1954
1960
  const resp = {
1955
1961
  status,
1956
1962
  body: {