@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.cjs +76 -70
- package/dist/api.cjs.map +1 -1
- package/dist/api.d.cts +2 -2
- package/dist/api.d.ts +2 -2
- package/dist/api.js +78 -72
- package/dist/api.js.map +1 -1
- package/package.json +7 -7
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
|
|
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
|
|
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
|
|
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
|
|
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 {
|
|
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
|
|
296
|
-
if (!
|
|
296
|
+
const match4 = pattern.match(path);
|
|
297
|
+
if (!match4) {
|
|
297
298
|
return;
|
|
298
299
|
}
|
|
299
|
-
if (
|
|
300
|
-
throw new InvalidValueError(`use the mapped model name: ${this.modelNameMapping[
|
|
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 (
|
|
303
|
-
|
|
303
|
+
if (match4.type in this.reverseModelNameMapping) {
|
|
304
|
+
match4.type = this.reverseModelNameMapping[match4.type];
|
|
304
305
|
}
|
|
305
|
-
return
|
|
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
|
|
316
|
-
if (
|
|
317
|
-
return await this.processSingleRead(client,
|
|
316
|
+
let match4 = this.matchUrlPattern(path, "single");
|
|
317
|
+
if (match4) {
|
|
318
|
+
return await this.processSingleRead(client, match4.type, match4.id, query);
|
|
318
319
|
}
|
|
319
|
-
|
|
320
|
-
if (
|
|
321
|
-
return await this.processFetchRelated(client,
|
|
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
|
-
|
|
324
|
-
if (
|
|
325
|
-
return await this.processReadRelationship(client,
|
|
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
|
-
|
|
328
|
-
if (
|
|
329
|
-
return await this.processCollectionRead(client,
|
|
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
|
|
338
|
-
if (
|
|
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,
|
|
343
|
+
return await this.processUpsert(client, match4.type, query, requestBody);
|
|
343
344
|
} else {
|
|
344
|
-
return await this.processCreate(client,
|
|
345
|
+
return await this.processCreate(client, match4.type, query, requestBody);
|
|
345
346
|
}
|
|
346
347
|
}
|
|
347
|
-
|
|
348
|
-
if (
|
|
349
|
-
return await this.processRelationshipCRUD(client, "create",
|
|
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
|
|
360
|
-
if (
|
|
361
|
-
return await this.processUpdate(client,
|
|
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
|
-
|
|
364
|
-
if (
|
|
365
|
-
return await this.processRelationshipCRUD(client, "update",
|
|
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
|
|
371
|
-
if (
|
|
372
|
-
return await this.processDelete(client,
|
|
371
|
+
let match4 = this.matchUrlPattern(path, "single");
|
|
372
|
+
if (match4) {
|
|
373
|
+
return await this.processDelete(client, match4.type, match4.id);
|
|
373
374
|
}
|
|
374
|
-
|
|
375
|
-
if (
|
|
376
|
-
return await this.processRelationshipCRUD(client, "delete",
|
|
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
|
|
387
|
-
return this.
|
|
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
|
|
1414
|
-
if (!
|
|
1414
|
+
const match4 = key.match(this.filterParamPattern);
|
|
1415
|
+
if (!match4 || !match4.groups || !match4.groups["match"]) {
|
|
1415
1416
|
continue;
|
|
1416
1417
|
}
|
|
1417
|
-
const filterKeys =
|
|
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
|
-
|
|
1741
|
-
|
|
1742
|
-
return this.makeError("validationError", err.message, 422
|
|
1743
|
-
}
|
|
1744
|
-
return this.makeError("forbidden", err.message, 403,
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
}
|
|
1748
|
-
return this.makeError("
|
|
1749
|
-
}
|
|
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,
|
|
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
|
-
|
|
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 {
|
|
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
|
|
1900
|
-
return this.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
}
|
|
1946
|
+
}).with(ORMErrorReason2.INVALID_INPUT, () => {
|
|
1945
1947
|
status = 422;
|
|
1946
1948
|
error.rejectedByValidation = true;
|
|
1947
1949
|
error.model = err.model;
|
|
1948
|
-
}
|
|
1950
|
+
}).with(ORMErrorReason2.REJECTED_BY_POLICY, () => {
|
|
1949
1951
|
status = 403;
|
|
1950
1952
|
error.rejectedByPolicy = true;
|
|
1951
|
-
error.rejectReason = err.
|
|
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: {
|