@zenstackhq/server 2.20.0 → 3.0.0-beta.12

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.
Files changed (110) hide show
  1. package/LICENSE +1 -1
  2. package/dist/api.cjs +299 -0
  3. package/dist/api.cjs.map +1 -0
  4. package/dist/api.d.cts +28 -0
  5. package/dist/api.d.ts +28 -0
  6. package/dist/api.js +264 -0
  7. package/dist/api.js.map +1 -0
  8. package/dist/express.cjs +75 -0
  9. package/dist/express.cjs.map +1 -0
  10. package/dist/express.d.cts +31 -0
  11. package/dist/express.d.ts +31 -0
  12. package/dist/express.js +50 -0
  13. package/dist/express.js.map +1 -0
  14. package/dist/types-BH-88xJo.d.cts +68 -0
  15. package/dist/types-BH-88xJo.d.ts +68 -0
  16. package/package.json +57 -58
  17. package/README.md +0 -5
  18. package/api/base.d.ts +0 -49
  19. package/api/base.js +0 -19
  20. package/api/base.js.map +0 -1
  21. package/api/index.d.ts +0 -2
  22. package/api/index.js +0 -8
  23. package/api/index.js.map +0 -1
  24. package/api/rest/index.d.ts +0 -34
  25. package/api/rest/index.js +0 -1598
  26. package/api/rest/index.js.map +0 -1
  27. package/api/rpc/index.d.ts +0 -4
  28. package/api/rpc/index.js +0 -248
  29. package/api/rpc/index.js.map +0 -1
  30. package/api/utils.d.ts +0 -8
  31. package/api/utils.js +0 -54
  32. package/api/utils.js.map +0 -1
  33. package/elysia/handler.d.ts +0 -44
  34. package/elysia/handler.js +0 -62
  35. package/elysia/handler.js.map +0 -1
  36. package/elysia/index.d.ts +0 -1
  37. package/elysia/index.js +0 -18
  38. package/elysia/index.js.map +0 -1
  39. package/express/index.d.ts +0 -2
  40. package/express/index.js +0 -21
  41. package/express/index.js.map +0 -1
  42. package/express/middleware.d.ts +0 -27
  43. package/express/middleware.js +0 -58
  44. package/express/middleware.js.map +0 -1
  45. package/fastify/index.d.ts +0 -2
  46. package/fastify/index.js +0 -21
  47. package/fastify/index.js.map +0 -1
  48. package/fastify/plugin.d.ts +0 -18
  49. package/fastify/plugin.js +0 -48
  50. package/fastify/plugin.js.map +0 -1
  51. package/hono/handler.d.ts +0 -12
  52. package/hono/handler.js +0 -47
  53. package/hono/handler.js.map +0 -1
  54. package/hono/index.d.ts +0 -1
  55. package/hono/index.js +0 -18
  56. package/hono/index.js.map +0 -1
  57. package/nestjs/api-handler.service.d.ts +0 -15
  58. package/nestjs/api-handler.service.js +0 -72
  59. package/nestjs/api-handler.service.js.map +0 -1
  60. package/nestjs/index.d.ts +0 -3
  61. package/nestjs/index.js +0 -20
  62. package/nestjs/index.js.map +0 -1
  63. package/nestjs/interfaces/api-handler-options.interface.d.ts +0 -17
  64. package/nestjs/interfaces/api-handler-options.interface.js +0 -3
  65. package/nestjs/interfaces/api-handler-options.interface.js.map +0 -1
  66. package/nestjs/interfaces/index.d.ts +0 -2
  67. package/nestjs/interfaces/index.js +0 -19
  68. package/nestjs/interfaces/index.js.map +0 -1
  69. package/nestjs/interfaces/zenstack-module-options.interface.d.ts +0 -35
  70. package/nestjs/interfaces/zenstack-module-options.interface.js +0 -3
  71. package/nestjs/interfaces/zenstack-module-options.interface.js.map +0 -1
  72. package/nestjs/zenstack.constants.d.ts +0 -4
  73. package/nestjs/zenstack.constants.js +0 -8
  74. package/nestjs/zenstack.constants.js.map +0 -1
  75. package/nestjs/zenstack.module.d.ts +0 -12
  76. package/nestjs/zenstack.module.js +0 -61
  77. package/nestjs/zenstack.module.js.map +0 -1
  78. package/next/app-route-handler.d.ts +0 -16
  79. package/next/app-route-handler.js +0 -65
  80. package/next/app-route-handler.js.map +0 -1
  81. package/next/index.d.ts +0 -38
  82. package/next/index.js +0 -17
  83. package/next/index.js.map +0 -1
  84. package/next/pages-route-handler.d.ts +0 -9
  85. package/next/pages-route-handler.js +0 -45
  86. package/next/pages-route-handler.js.map +0 -1
  87. package/nuxt/handler.d.ts +0 -12
  88. package/nuxt/handler.js +0 -45
  89. package/nuxt/handler.js.map +0 -1
  90. package/nuxt/index.d.ts +0 -1
  91. package/nuxt/index.js +0 -18
  92. package/nuxt/index.js.map +0 -1
  93. package/shared.d.ts +0 -20
  94. package/shared.js +0 -50
  95. package/shared.js.map +0 -1
  96. package/sveltekit/handler.d.ts +0 -20
  97. package/sveltekit/handler.js +0 -68
  98. package/sveltekit/handler.js.map +0 -1
  99. package/sveltekit/index.d.ts +0 -2
  100. package/sveltekit/index.js +0 -21
  101. package/sveltekit/index.js.map +0 -1
  102. package/tanstack-start/handler.d.ts +0 -11
  103. package/tanstack-start/handler.js +0 -75
  104. package/tanstack-start/handler.js.map +0 -1
  105. package/tanstack-start/index.d.ts +0 -17
  106. package/tanstack-start/index.js +0 -16
  107. package/tanstack-start/index.js.map +0 -1
  108. package/types.d.ts +0 -49
  109. package/types.js +0 -3
  110. package/types.js.map +0 -1
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2022-2025 ZenStack
3
+ Copyright (c) 2025 ZenStack
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/dist/api.cjs ADDED
@@ -0,0 +1,299 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
9
+ var __export = (target, all) => {
10
+ for (var name in all)
11
+ __defProp(target, name, { get: all[name], enumerable: true });
12
+ };
13
+ var __copyProps = (to, from, except, desc) => {
14
+ if (from && typeof from === "object" || typeof from === "function") {
15
+ for (let key of __getOwnPropNames(from))
16
+ if (!__hasOwnProp.call(to, key) && key !== except)
17
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
18
+ }
19
+ return to;
20
+ };
21
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
22
+ // If the importer is in node compatibility mode or this is not an ESM
23
+ // file that has been converted to a CommonJS file using a Babel-
24
+ // compatible transform (i.e. "__esModule" has not been set), then set
25
+ // "default" to the CommonJS "module.exports" for node compatibility.
26
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
27
+ mod
28
+ ));
29
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
30
+
31
+ // src/api/index.ts
32
+ var api_exports = {};
33
+ __export(api_exports, {
34
+ RPCApiHandler: () => RPCApiHandler
35
+ });
36
+ module.exports = __toCommonJS(api_exports);
37
+
38
+ // src/api/rpc/index.ts
39
+ var import_common_helpers = require("@zenstackhq/common-helpers");
40
+ var import_runtime2 = require("@zenstackhq/runtime");
41
+ var import_superjson2 = __toESM(require("superjson"), 1);
42
+
43
+ // src/api/utils.ts
44
+ var import_decimal = require("decimal.js");
45
+ var import_superjson = __toESM(require("superjson"), 1);
46
+ var import_ts_pattern = require("ts-pattern");
47
+ function log(logger, level, message, error) {
48
+ if (!logger) {
49
+ return;
50
+ }
51
+ const getMessage = typeof message === "function" ? message : () => message;
52
+ if (typeof logger === "function") {
53
+ logger(level, getMessage(), error);
54
+ } else if (logger.includes(level)) {
55
+ const logFn = (0, import_ts_pattern.match)(level).with("debug", () => console.debug).with("info", () => console.info).with("warn", () => console.warn).with("error", () => console.error).exhaustive();
56
+ logFn(`@zenstackhq/server: [${level}] ${getMessage()}${error ? `
57
+ ${error}` : ""}`);
58
+ }
59
+ }
60
+ __name(log, "log");
61
+ function registerCustomSerializers() {
62
+ import_superjson.default.registerCustom({
63
+ isApplicable: /* @__PURE__ */ __name((v) => import_decimal.Decimal.isDecimal(v), "isApplicable"),
64
+ serialize: /* @__PURE__ */ __name((v) => v.toJSON(), "serialize"),
65
+ deserialize: /* @__PURE__ */ __name((v) => new import_decimal.Decimal(v), "deserialize")
66
+ }, "Decimal");
67
+ if (globalThis.Buffer) {
68
+ import_superjson.default.registerCustom({
69
+ isApplicable: /* @__PURE__ */ __name((v) => Buffer.isBuffer(v), "isApplicable"),
70
+ serialize: /* @__PURE__ */ __name((v) => v.toString("base64"), "serialize"),
71
+ deserialize: /* @__PURE__ */ __name((v) => Buffer.from(v, "base64"), "deserialize")
72
+ }, "Bytes");
73
+ }
74
+ }
75
+ __name(registerCustomSerializers, "registerCustomSerializers");
76
+
77
+ // src/api/rpc/index.ts
78
+ registerCustomSerializers();
79
+ var RPCApiHandler = class {
80
+ static {
81
+ __name(this, "RPCApiHandler");
82
+ }
83
+ options;
84
+ constructor(options) {
85
+ this.options = options;
86
+ }
87
+ get schema() {
88
+ return this.options.schema;
89
+ }
90
+ async handleRequest({ client, method, path, query, requestBody }) {
91
+ const parts = path.split("/").filter((p) => !!p);
92
+ const op = parts.pop();
93
+ let model = parts.pop();
94
+ if (parts.length !== 0 || !op || !model) {
95
+ return this.makeBadInputErrorResponse("invalid request path");
96
+ }
97
+ model = (0, import_common_helpers.lowerCaseFirst)(model);
98
+ method = method.toUpperCase();
99
+ let args;
100
+ let resCode = 200;
101
+ switch (op) {
102
+ case "create":
103
+ case "createMany":
104
+ case "createManyAndReturn":
105
+ case "upsert":
106
+ if (method !== "POST") {
107
+ return this.makeBadInputErrorResponse("invalid request method, only POST is supported");
108
+ }
109
+ if (!requestBody) {
110
+ return this.makeBadInputErrorResponse("missing request body");
111
+ }
112
+ args = requestBody;
113
+ resCode = 201;
114
+ break;
115
+ case "findFirst":
116
+ case "findUnique":
117
+ case "findMany":
118
+ case "aggregate":
119
+ case "groupBy":
120
+ case "count":
121
+ if (method !== "GET") {
122
+ return this.makeBadInputErrorResponse("invalid request method, only GET is supported");
123
+ }
124
+ try {
125
+ args = query?.["q"] ? this.unmarshalQ(query["q"], query["meta"]) : {};
126
+ } catch {
127
+ return this.makeBadInputErrorResponse('invalid "q" query parameter');
128
+ }
129
+ break;
130
+ case "update":
131
+ case "updateMany":
132
+ case "updateManyAndReturn":
133
+ if (method !== "PUT" && method !== "PATCH") {
134
+ return this.makeBadInputErrorResponse("invalid request method, only PUT or PATCH are supported");
135
+ }
136
+ if (!requestBody) {
137
+ return this.makeBadInputErrorResponse("missing request body");
138
+ }
139
+ args = requestBody;
140
+ break;
141
+ case "delete":
142
+ case "deleteMany":
143
+ if (method !== "DELETE") {
144
+ return this.makeBadInputErrorResponse("invalid request method, only DELETE is supported");
145
+ }
146
+ try {
147
+ args = query?.["q"] ? this.unmarshalQ(query["q"], query["meta"]) : {};
148
+ } catch (err) {
149
+ return this.makeBadInputErrorResponse(err instanceof Error ? err.message : 'invalid "q" query parameter');
150
+ }
151
+ break;
152
+ default:
153
+ return this.makeBadInputErrorResponse("invalid operation: " + op);
154
+ }
155
+ const { result: processedArgs, error } = await this.processRequestPayload(args);
156
+ if (error) {
157
+ return this.makeBadInputErrorResponse(error);
158
+ }
159
+ try {
160
+ if (!this.isValidModel(client, model)) {
161
+ return this.makeBadInputErrorResponse(`unknown model name: ${model}`);
162
+ }
163
+ log(this.options.log, "debug", () => `handling "${model}.${op}" request with args: ${(0, import_common_helpers.safeJSONStringify)(processedArgs)}`);
164
+ const clientResult = await client[model][op](processedArgs);
165
+ let responseBody = {
166
+ data: clientResult
167
+ };
168
+ if (clientResult) {
169
+ const { json, meta } = import_superjson2.default.serialize(clientResult);
170
+ responseBody = {
171
+ data: json
172
+ };
173
+ if (meta) {
174
+ responseBody.meta = {
175
+ serialization: meta
176
+ };
177
+ }
178
+ }
179
+ const response = {
180
+ status: resCode,
181
+ body: responseBody
182
+ };
183
+ log(this.options.log, "debug", () => `sending response for "${model}.${op}" request: ${(0, import_common_helpers.safeJSONStringify)(response)}`);
184
+ return response;
185
+ } catch (err) {
186
+ log(this.options.log, "error", `error occurred when handling "${model}.${op}" request`, err);
187
+ if (err instanceof import_runtime2.ZenStackError) {
188
+ return this.makeZenStackErrorResponse(err);
189
+ } else {
190
+ return this.makeGenericErrorResponse(err);
191
+ }
192
+ }
193
+ }
194
+ isValidModel(client, model) {
195
+ return Object.keys(client.$schema.models).some((m) => (0, import_common_helpers.lowerCaseFirst)(m) === (0, import_common_helpers.lowerCaseFirst)(model));
196
+ }
197
+ makeBadInputErrorResponse(message) {
198
+ const resp = {
199
+ status: 400,
200
+ body: {
201
+ error: {
202
+ message
203
+ }
204
+ }
205
+ };
206
+ log(this.options.log, "debug", () => `sending error response: ${(0, import_common_helpers.safeJSONStringify)(resp)}`);
207
+ return resp;
208
+ }
209
+ makeGenericErrorResponse(err) {
210
+ const resp = {
211
+ status: 500,
212
+ body: {
213
+ error: {
214
+ message: err.message || "unknown error"
215
+ }
216
+ }
217
+ };
218
+ log(this.options.log, "debug", () => `sending error response: ${(0, import_common_helpers.safeJSONStringify)(resp)}`);
219
+ return resp;
220
+ }
221
+ makeZenStackErrorResponse(err) {
222
+ let status = 400;
223
+ const error = {
224
+ message: err.message
225
+ };
226
+ if (err.cause && err.cause instanceof Error) {
227
+ error.cause = err.cause.message;
228
+ }
229
+ if (err instanceof import_runtime2.NotFoundError) {
230
+ status = 404;
231
+ error.model = err.model;
232
+ } else if (err instanceof import_runtime2.InputValidationError) {
233
+ status = 422;
234
+ error.rejectedByValidation = true;
235
+ error.model = err.model;
236
+ } else if (err instanceof import_runtime2.RejectedByPolicyError) {
237
+ status = 403;
238
+ error.rejectedByPolicy = true;
239
+ error.rejectReason = err.reason;
240
+ error.model = err.model;
241
+ }
242
+ const resp = {
243
+ status,
244
+ body: {
245
+ error
246
+ }
247
+ };
248
+ log(this.options.log, "debug", () => `sending error response: ${(0, import_common_helpers.safeJSONStringify)(resp)}`);
249
+ return resp;
250
+ }
251
+ async processRequestPayload(args) {
252
+ const { meta, ...rest } = args;
253
+ if (meta?.serialization) {
254
+ try {
255
+ args = import_superjson2.default.deserialize({
256
+ json: rest,
257
+ meta: meta.serialization
258
+ });
259
+ } catch (err) {
260
+ return {
261
+ result: void 0,
262
+ error: `failed to deserialize request payload: ${err.message}`
263
+ };
264
+ }
265
+ }
266
+ return {
267
+ result: args,
268
+ error: void 0
269
+ };
270
+ }
271
+ unmarshalQ(value, meta) {
272
+ let parsedValue;
273
+ try {
274
+ parsedValue = JSON.parse(value);
275
+ } catch {
276
+ throw new Error('invalid "q" query parameter');
277
+ }
278
+ if (meta) {
279
+ let parsedMeta;
280
+ try {
281
+ parsedMeta = JSON.parse(meta);
282
+ } catch {
283
+ throw new Error('invalid "meta" query parameter');
284
+ }
285
+ if (parsedMeta.serialization) {
286
+ return import_superjson2.default.deserialize({
287
+ json: parsedValue,
288
+ meta: parsedMeta.serialization
289
+ });
290
+ }
291
+ }
292
+ return parsedValue;
293
+ }
294
+ };
295
+ // Annotate the CommonJS export names for ESM import in node:
296
+ 0 && (module.exports = {
297
+ RPCApiHandler
298
+ });
299
+ //# sourceMappingURL=api.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/api/index.ts","../src/api/rpc/index.ts","../src/api/utils.ts"],"sourcesContent":["export { RPCApiHandler } from './rpc';\n","import { lowerCaseFirst, safeJSONStringify } from '@zenstackhq/common-helpers';\nimport {\n InputValidationError,\n NotFoundError,\n RejectedByPolicyError,\n ZenStackError,\n type ClientContract,\n} from '@zenstackhq/runtime';\nimport type { SchemaDef } from '@zenstackhq/runtime/schema';\nimport SuperJSON from 'superjson';\nimport type { ApiHandler, LogConfig, RequestContext, Response } from '../../types';\nimport { log, registerCustomSerializers } from '../utils';\n\nregisterCustomSerializers();\n\n/**\n * Options for {@link RPCApiHandler}\n */\nexport type RPCApiHandlerOptions<Schema extends SchemaDef> = {\n schema: Schema;\n log?: LogConfig;\n};\n\n/**\n * RPC style API request handler that mirrors the ZenStackClient API\n */\nexport class RPCApiHandler<Schema extends SchemaDef> implements ApiHandler<Schema> {\n constructor(private readonly options: RPCApiHandlerOptions<Schema>) {}\n\n get schema(): Schema {\n return this.options.schema;\n }\n\n async handleRequest({ client, method, path, query, requestBody }: RequestContext<Schema>): Promise<Response> {\n const parts = path.split('/').filter((p) => !!p);\n const op = parts.pop();\n let model = parts.pop();\n\n if (parts.length !== 0 || !op || !model) {\n return this.makeBadInputErrorResponse('invalid request path');\n }\n\n model = lowerCaseFirst(model);\n method = method.toUpperCase();\n let args: unknown;\n let resCode = 200;\n\n switch (op) {\n case 'create':\n case 'createMany':\n case 'createManyAndReturn':\n case 'upsert':\n if (method !== 'POST') {\n return this.makeBadInputErrorResponse('invalid request method, only POST is supported');\n }\n if (!requestBody) {\n return this.makeBadInputErrorResponse('missing request body');\n }\n\n args = requestBody;\n resCode = 201;\n break;\n\n case 'findFirst':\n case 'findUnique':\n case 'findMany':\n case 'aggregate':\n case 'groupBy':\n case 'count':\n if (method !== 'GET') {\n return this.makeBadInputErrorResponse('invalid request method, only GET is supported');\n }\n try {\n args = query?.['q']\n ? this.unmarshalQ(query['q'] as string, query['meta'] as string | undefined)\n : {};\n } catch {\n return this.makeBadInputErrorResponse('invalid \"q\" query parameter');\n }\n break;\n\n case 'update':\n case 'updateMany':\n case 'updateManyAndReturn':\n if (method !== 'PUT' && method !== 'PATCH') {\n return this.makeBadInputErrorResponse('invalid request method, only PUT or PATCH are supported');\n }\n if (!requestBody) {\n return this.makeBadInputErrorResponse('missing request body');\n }\n\n args = requestBody;\n break;\n\n case 'delete':\n case 'deleteMany':\n if (method !== 'DELETE') {\n return this.makeBadInputErrorResponse('invalid request method, only DELETE is supported');\n }\n try {\n args = query?.['q']\n ? this.unmarshalQ(query['q'] as string, query['meta'] as string | undefined)\n : {};\n } catch (err) {\n return this.makeBadInputErrorResponse(\n err instanceof Error ? err.message : 'invalid \"q\" query parameter',\n );\n }\n break;\n\n default:\n return this.makeBadInputErrorResponse('invalid operation: ' + op);\n }\n\n const { result: processedArgs, error } = await this.processRequestPayload(args);\n if (error) {\n return this.makeBadInputErrorResponse(error);\n }\n\n try {\n if (!this.isValidModel(client, model)) {\n return this.makeBadInputErrorResponse(`unknown model name: ${model}`);\n }\n\n log(\n this.options.log,\n 'debug',\n () => `handling \"${model}.${op}\" request with args: ${safeJSONStringify(processedArgs)}`,\n );\n\n const clientResult = await (client as any)[model][op](processedArgs);\n let responseBody: any = { data: clientResult };\n\n // superjson serialize response\n if (clientResult) {\n const { json, meta } = SuperJSON.serialize(clientResult);\n responseBody = { data: json };\n if (meta) {\n responseBody.meta = { serialization: meta };\n }\n }\n\n const response = { status: resCode, body: responseBody };\n log(\n this.options.log,\n 'debug',\n () => `sending response for \"${model}.${op}\" request: ${safeJSONStringify(response)}`,\n );\n return response;\n } catch (err) {\n log(this.options.log, 'error', `error occurred when handling \"${model}.${op}\" request`, err);\n if (err instanceof ZenStackError) {\n return this.makeZenStackErrorResponse(err);\n } else {\n return this.makeGenericErrorResponse(err);\n }\n }\n }\n\n private isValidModel(client: ClientContract<Schema>, model: string) {\n return Object.keys(client.$schema.models).some((m) => lowerCaseFirst(m) === lowerCaseFirst(model));\n }\n\n private makeBadInputErrorResponse(message: string) {\n const resp = {\n status: 400,\n body: { error: { message } },\n };\n log(this.options.log, 'debug', () => `sending error response: ${safeJSONStringify(resp)}`);\n return resp;\n }\n\n private makeGenericErrorResponse(err: unknown) {\n const resp = {\n status: 500,\n body: { error: { message: (err as Error).message || 'unknown error' } },\n };\n log(this.options.log, 'debug', () => `sending error response: ${safeJSONStringify(resp)}`);\n return resp;\n }\n\n private makeZenStackErrorResponse(err: ZenStackError) {\n let status = 400;\n const error: any = { message: err.message };\n if (err.cause && err.cause instanceof Error) {\n error.cause = err.cause.message;\n }\n\n if (err instanceof NotFoundError) {\n status = 404;\n error.model = err.model;\n } else if (err instanceof InputValidationError) {\n status = 422;\n error.rejectedByValidation = true;\n error.model = err.model;\n } else if (err instanceof RejectedByPolicyError) {\n status = 403;\n error.rejectedByPolicy = true;\n error.rejectReason = err.reason;\n error.model = err.model;\n }\n\n const resp = { status, body: { error } };\n log(this.options.log, 'debug', () => `sending error response: ${safeJSONStringify(resp)}`);\n return resp;\n }\n\n private async processRequestPayload(args: any) {\n const { meta, ...rest } = args;\n if (meta?.serialization) {\n try {\n // superjson deserialization\n args = SuperJSON.deserialize({ json: rest, meta: meta.serialization });\n } catch (err) {\n return { result: undefined, error: `failed to deserialize request payload: ${(err as Error).message}` };\n }\n }\n return { result: args, error: undefined };\n }\n\n private unmarshalQ(value: string, meta: string | undefined) {\n let parsedValue: any;\n try {\n parsedValue = JSON.parse(value);\n } catch {\n throw new Error('invalid \"q\" query parameter');\n }\n\n if (meta) {\n let parsedMeta: any;\n try {\n parsedMeta = JSON.parse(meta);\n } catch {\n throw new Error('invalid \"meta\" query parameter');\n }\n\n if (parsedMeta.serialization) {\n return SuperJSON.deserialize({ json: parsedValue, meta: parsedMeta.serialization });\n }\n }\n\n return parsedValue;\n }\n}\n","import { Decimal } from 'decimal.js';\nimport SuperJSON from 'superjson';\nimport { match } from 'ts-pattern';\nimport type { LogConfig, LogLevel } from '../types';\n\nexport function log(logger: LogConfig | undefined, level: LogLevel, message: string | (() => string), error?: unknown) {\n if (!logger) {\n return;\n }\n\n const getMessage = typeof message === 'function' ? message : () => message;\n\n if (typeof logger === 'function') {\n logger(level, getMessage(), error);\n } else if (logger.includes(level)) {\n const logFn = match(level)\n .with('debug', () => console.debug)\n .with('info', () => console.info)\n .with('warn', () => console.warn)\n .with('error', () => console.error)\n .exhaustive();\n logFn(`@zenstackhq/server: [${level}] ${getMessage()}${error ? `\\n${error}` : ''}`);\n }\n}\n\n/**\n * Registers custom superjson serializers.\n */\nexport function registerCustomSerializers() {\n SuperJSON.registerCustom<Decimal, string>(\n {\n isApplicable: (v): v is Decimal => Decimal.isDecimal(v),\n serialize: (v) => v.toJSON(),\n deserialize: (v) => new Decimal(v),\n },\n 'Decimal',\n );\n\n // `Buffer` is not available in edge runtime\n if (globalThis.Buffer) {\n SuperJSON.registerCustom<Buffer, string>(\n {\n isApplicable: (v): v is Buffer => Buffer.isBuffer(v),\n serialize: (v) => v.toString('base64'),\n deserialize: (v) => Buffer.from(v, 'base64'),\n },\n 'Bytes',\n );\n }\n}\n"],"mappings":"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","names":["import_runtime","import_superjson","log","logger","level","message","error","getMessage","includes","logFn","match","with","console","debug","info","warn","exhaustive","registerCustomSerializers","SuperJSON","registerCustom","isApplicable","v","Decimal","isDecimal","serialize","toJSON","deserialize","globalThis","Buffer","isBuffer","toString","from","registerCustomSerializers","RPCApiHandler","options","schema","handleRequest","client","method","path","query","requestBody","parts","split","filter","p","op","pop","model","length","makeBadInputErrorResponse","lowerCaseFirst","toUpperCase","args","resCode","unmarshalQ","err","Error","message","result","processedArgs","error","processRequestPayload","isValidModel","log","safeJSONStringify","clientResult","responseBody","data","json","meta","SuperJSON","serialize","serialization","response","status","body","ZenStackError","makeZenStackErrorResponse","makeGenericErrorResponse","Object","keys","$schema","models","some","m","resp","cause","NotFoundError","InputValidationError","rejectedByValidation","RejectedByPolicyError","rejectedByPolicy","rejectReason","reason","rest","deserialize","undefined","value","parsedValue","JSON","parse","parsedMeta"]}
package/dist/api.d.cts ADDED
@@ -0,0 +1,28 @@
1
+ import { SchemaDef } from '@zenstackhq/runtime/schema';
2
+ import { A as ApiHandler, L as LogConfig, R as RequestContext, a as Response } from './types-BH-88xJo.cjs';
3
+ import '@zenstackhq/runtime';
4
+
5
+ /**
6
+ * Options for {@link RPCApiHandler}
7
+ */
8
+ type RPCApiHandlerOptions<Schema extends SchemaDef> = {
9
+ schema: Schema;
10
+ log?: LogConfig;
11
+ };
12
+ /**
13
+ * RPC style API request handler that mirrors the ZenStackClient API
14
+ */
15
+ declare class RPCApiHandler<Schema extends SchemaDef> implements ApiHandler<Schema> {
16
+ private readonly options;
17
+ constructor(options: RPCApiHandlerOptions<Schema>);
18
+ get schema(): Schema;
19
+ handleRequest({ client, method, path, query, requestBody }: RequestContext<Schema>): Promise<Response>;
20
+ private isValidModel;
21
+ private makeBadInputErrorResponse;
22
+ private makeGenericErrorResponse;
23
+ private makeZenStackErrorResponse;
24
+ private processRequestPayload;
25
+ private unmarshalQ;
26
+ }
27
+
28
+ export { RPCApiHandler };
package/dist/api.d.ts ADDED
@@ -0,0 +1,28 @@
1
+ import { SchemaDef } from '@zenstackhq/runtime/schema';
2
+ import { A as ApiHandler, L as LogConfig, R as RequestContext, a as Response } from './types-BH-88xJo.js';
3
+ import '@zenstackhq/runtime';
4
+
5
+ /**
6
+ * Options for {@link RPCApiHandler}
7
+ */
8
+ type RPCApiHandlerOptions<Schema extends SchemaDef> = {
9
+ schema: Schema;
10
+ log?: LogConfig;
11
+ };
12
+ /**
13
+ * RPC style API request handler that mirrors the ZenStackClient API
14
+ */
15
+ declare class RPCApiHandler<Schema extends SchemaDef> implements ApiHandler<Schema> {
16
+ private readonly options;
17
+ constructor(options: RPCApiHandlerOptions<Schema>);
18
+ get schema(): Schema;
19
+ handleRequest({ client, method, path, query, requestBody }: RequestContext<Schema>): Promise<Response>;
20
+ private isValidModel;
21
+ private makeBadInputErrorResponse;
22
+ private makeGenericErrorResponse;
23
+ private makeZenStackErrorResponse;
24
+ private processRequestPayload;
25
+ private unmarshalQ;
26
+ }
27
+
28
+ export { RPCApiHandler };
package/dist/api.js ADDED
@@ -0,0 +1,264 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
+
4
+ // src/api/rpc/index.ts
5
+ import { lowerCaseFirst, safeJSONStringify } from "@zenstackhq/common-helpers";
6
+ import { InputValidationError, NotFoundError, RejectedByPolicyError, ZenStackError } from "@zenstackhq/runtime";
7
+ import SuperJSON2 from "superjson";
8
+
9
+ // src/api/utils.ts
10
+ import { Decimal } from "decimal.js";
11
+ import SuperJSON from "superjson";
12
+ import { match } from "ts-pattern";
13
+ function log(logger, level, message, error) {
14
+ if (!logger) {
15
+ return;
16
+ }
17
+ const getMessage = typeof message === "function" ? message : () => message;
18
+ if (typeof logger === "function") {
19
+ logger(level, getMessage(), error);
20
+ } else if (logger.includes(level)) {
21
+ const logFn = match(level).with("debug", () => console.debug).with("info", () => console.info).with("warn", () => console.warn).with("error", () => console.error).exhaustive();
22
+ logFn(`@zenstackhq/server: [${level}] ${getMessage()}${error ? `
23
+ ${error}` : ""}`);
24
+ }
25
+ }
26
+ __name(log, "log");
27
+ function registerCustomSerializers() {
28
+ SuperJSON.registerCustom({
29
+ isApplicable: /* @__PURE__ */ __name((v) => Decimal.isDecimal(v), "isApplicable"),
30
+ serialize: /* @__PURE__ */ __name((v) => v.toJSON(), "serialize"),
31
+ deserialize: /* @__PURE__ */ __name((v) => new Decimal(v), "deserialize")
32
+ }, "Decimal");
33
+ if (globalThis.Buffer) {
34
+ SuperJSON.registerCustom({
35
+ isApplicable: /* @__PURE__ */ __name((v) => Buffer.isBuffer(v), "isApplicable"),
36
+ serialize: /* @__PURE__ */ __name((v) => v.toString("base64"), "serialize"),
37
+ deserialize: /* @__PURE__ */ __name((v) => Buffer.from(v, "base64"), "deserialize")
38
+ }, "Bytes");
39
+ }
40
+ }
41
+ __name(registerCustomSerializers, "registerCustomSerializers");
42
+
43
+ // src/api/rpc/index.ts
44
+ registerCustomSerializers();
45
+ var RPCApiHandler = class {
46
+ static {
47
+ __name(this, "RPCApiHandler");
48
+ }
49
+ options;
50
+ constructor(options) {
51
+ this.options = options;
52
+ }
53
+ get schema() {
54
+ return this.options.schema;
55
+ }
56
+ async handleRequest({ client, method, path, query, requestBody }) {
57
+ const parts = path.split("/").filter((p) => !!p);
58
+ const op = parts.pop();
59
+ let model = parts.pop();
60
+ if (parts.length !== 0 || !op || !model) {
61
+ return this.makeBadInputErrorResponse("invalid request path");
62
+ }
63
+ model = lowerCaseFirst(model);
64
+ method = method.toUpperCase();
65
+ let args;
66
+ let resCode = 200;
67
+ switch (op) {
68
+ case "create":
69
+ case "createMany":
70
+ case "createManyAndReturn":
71
+ case "upsert":
72
+ if (method !== "POST") {
73
+ return this.makeBadInputErrorResponse("invalid request method, only POST is supported");
74
+ }
75
+ if (!requestBody) {
76
+ return this.makeBadInputErrorResponse("missing request body");
77
+ }
78
+ args = requestBody;
79
+ resCode = 201;
80
+ break;
81
+ case "findFirst":
82
+ case "findUnique":
83
+ case "findMany":
84
+ case "aggregate":
85
+ case "groupBy":
86
+ case "count":
87
+ if (method !== "GET") {
88
+ return this.makeBadInputErrorResponse("invalid request method, only GET is supported");
89
+ }
90
+ try {
91
+ args = query?.["q"] ? this.unmarshalQ(query["q"], query["meta"]) : {};
92
+ } catch {
93
+ return this.makeBadInputErrorResponse('invalid "q" query parameter');
94
+ }
95
+ break;
96
+ case "update":
97
+ case "updateMany":
98
+ case "updateManyAndReturn":
99
+ if (method !== "PUT" && method !== "PATCH") {
100
+ return this.makeBadInputErrorResponse("invalid request method, only PUT or PATCH are supported");
101
+ }
102
+ if (!requestBody) {
103
+ return this.makeBadInputErrorResponse("missing request body");
104
+ }
105
+ args = requestBody;
106
+ break;
107
+ case "delete":
108
+ case "deleteMany":
109
+ if (method !== "DELETE") {
110
+ return this.makeBadInputErrorResponse("invalid request method, only DELETE is supported");
111
+ }
112
+ try {
113
+ args = query?.["q"] ? this.unmarshalQ(query["q"], query["meta"]) : {};
114
+ } catch (err) {
115
+ return this.makeBadInputErrorResponse(err instanceof Error ? err.message : 'invalid "q" query parameter');
116
+ }
117
+ break;
118
+ default:
119
+ return this.makeBadInputErrorResponse("invalid operation: " + op);
120
+ }
121
+ const { result: processedArgs, error } = await this.processRequestPayload(args);
122
+ if (error) {
123
+ return this.makeBadInputErrorResponse(error);
124
+ }
125
+ try {
126
+ if (!this.isValidModel(client, model)) {
127
+ return this.makeBadInputErrorResponse(`unknown model name: ${model}`);
128
+ }
129
+ log(this.options.log, "debug", () => `handling "${model}.${op}" request with args: ${safeJSONStringify(processedArgs)}`);
130
+ const clientResult = await client[model][op](processedArgs);
131
+ let responseBody = {
132
+ data: clientResult
133
+ };
134
+ if (clientResult) {
135
+ const { json, meta } = SuperJSON2.serialize(clientResult);
136
+ responseBody = {
137
+ data: json
138
+ };
139
+ if (meta) {
140
+ responseBody.meta = {
141
+ serialization: meta
142
+ };
143
+ }
144
+ }
145
+ const response = {
146
+ status: resCode,
147
+ body: responseBody
148
+ };
149
+ log(this.options.log, "debug", () => `sending response for "${model}.${op}" request: ${safeJSONStringify(response)}`);
150
+ return response;
151
+ } catch (err) {
152
+ log(this.options.log, "error", `error occurred when handling "${model}.${op}" request`, err);
153
+ if (err instanceof ZenStackError) {
154
+ return this.makeZenStackErrorResponse(err);
155
+ } else {
156
+ return this.makeGenericErrorResponse(err);
157
+ }
158
+ }
159
+ }
160
+ isValidModel(client, model) {
161
+ return Object.keys(client.$schema.models).some((m) => lowerCaseFirst(m) === lowerCaseFirst(model));
162
+ }
163
+ makeBadInputErrorResponse(message) {
164
+ const resp = {
165
+ status: 400,
166
+ body: {
167
+ error: {
168
+ message
169
+ }
170
+ }
171
+ };
172
+ log(this.options.log, "debug", () => `sending error response: ${safeJSONStringify(resp)}`);
173
+ return resp;
174
+ }
175
+ makeGenericErrorResponse(err) {
176
+ const resp = {
177
+ status: 500,
178
+ body: {
179
+ error: {
180
+ message: err.message || "unknown error"
181
+ }
182
+ }
183
+ };
184
+ log(this.options.log, "debug", () => `sending error response: ${safeJSONStringify(resp)}`);
185
+ return resp;
186
+ }
187
+ makeZenStackErrorResponse(err) {
188
+ let status = 400;
189
+ const error = {
190
+ message: err.message
191
+ };
192
+ if (err.cause && err.cause instanceof Error) {
193
+ error.cause = err.cause.message;
194
+ }
195
+ if (err instanceof NotFoundError) {
196
+ status = 404;
197
+ error.model = err.model;
198
+ } else if (err instanceof InputValidationError) {
199
+ status = 422;
200
+ error.rejectedByValidation = true;
201
+ error.model = err.model;
202
+ } else if (err instanceof RejectedByPolicyError) {
203
+ status = 403;
204
+ error.rejectedByPolicy = true;
205
+ error.rejectReason = err.reason;
206
+ error.model = err.model;
207
+ }
208
+ const resp = {
209
+ status,
210
+ body: {
211
+ error
212
+ }
213
+ };
214
+ log(this.options.log, "debug", () => `sending error response: ${safeJSONStringify(resp)}`);
215
+ return resp;
216
+ }
217
+ async processRequestPayload(args) {
218
+ const { meta, ...rest } = args;
219
+ if (meta?.serialization) {
220
+ try {
221
+ args = SuperJSON2.deserialize({
222
+ json: rest,
223
+ meta: meta.serialization
224
+ });
225
+ } catch (err) {
226
+ return {
227
+ result: void 0,
228
+ error: `failed to deserialize request payload: ${err.message}`
229
+ };
230
+ }
231
+ }
232
+ return {
233
+ result: args,
234
+ error: void 0
235
+ };
236
+ }
237
+ unmarshalQ(value, meta) {
238
+ let parsedValue;
239
+ try {
240
+ parsedValue = JSON.parse(value);
241
+ } catch {
242
+ throw new Error('invalid "q" query parameter');
243
+ }
244
+ if (meta) {
245
+ let parsedMeta;
246
+ try {
247
+ parsedMeta = JSON.parse(meta);
248
+ } catch {
249
+ throw new Error('invalid "meta" query parameter');
250
+ }
251
+ if (parsedMeta.serialization) {
252
+ return SuperJSON2.deserialize({
253
+ json: parsedValue,
254
+ meta: parsedMeta.serialization
255
+ });
256
+ }
257
+ }
258
+ return parsedValue;
259
+ }
260
+ };
261
+ export {
262
+ RPCApiHandler
263
+ };
264
+ //# sourceMappingURL=api.js.map