omni-rest 0.1.0

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/cli.mjs ADDED
@@ -0,0 +1,512 @@
1
+ #!/usr/bin/env node
2
+ import fs from 'fs';
3
+ import path from 'path';
4
+ import { Prisma } from '@prisma/client';
5
+
6
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
7
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
8
+ }) : x)(function(x) {
9
+ if (typeof require !== "undefined") return require.apply(this, arguments);
10
+ throw Error('Dynamic require of "' + x + '" is not supported');
11
+ });
12
+ function getModels(prisma) {
13
+ let raw;
14
+ if (prisma?._runtimeDataModel?.models) {
15
+ const modelsObj = prisma._runtimeDataModel.models;
16
+ raw = Object.entries(modelsObj).map(([name, model]) => ({
17
+ name,
18
+ ...model,
19
+ fields: (model.fields || []).map((f) => ({
20
+ ...f,
21
+ relationName: f.kind === "object" ? f.name : void 0
22
+ }))
23
+ }));
24
+ }
25
+ if (!raw) {
26
+ const dmmfModels = Prisma?.dmmf?.datamodel?.models || __require("@prisma/client")?.Prisma?.dmmf?.datamodel?.models;
27
+ if (dmmfModels) {
28
+ raw = dmmfModels;
29
+ }
30
+ }
31
+ if (!raw) {
32
+ throw new Error(
33
+ "[omni-rest] Could not find Prisma DMMF. Ensure Prisma client is generated and you're passing a PrismaClient instance to omni-rest."
34
+ );
35
+ }
36
+ if (!Array.isArray(raw)) {
37
+ throw new Error(
38
+ `[omni-rest] Expected models to be an array, got ${typeof raw}. Debug: prisma._runtimeDataModel.models=${!!prisma?._runtimeDataModel?.models}, raw value=${JSON.stringify(raw).slice(0, 100)}`
39
+ );
40
+ }
41
+ return raw.map((model) => {
42
+ const fields = model.fields.map((f) => ({
43
+ name: f.name,
44
+ type: f.type,
45
+ isId: f.isId,
46
+ isRequired: f.isRequired,
47
+ isList: f.isList,
48
+ isRelation: !!f.relationName
49
+ }));
50
+ const idField = model.fields.find((f) => f.isId)?.name ?? "id";
51
+ return {
52
+ name: model.name,
53
+ routeName: toRouteName(model.name),
54
+ fields,
55
+ idField
56
+ };
57
+ });
58
+ }
59
+ function toRouteName(modelName) {
60
+ return modelName.toLowerCase();
61
+ }
62
+
63
+ // src/zod-generator.ts
64
+ var PRISMA_TO_ZOD = {
65
+ String: "z.string()",
66
+ Int: "z.number().int()",
67
+ Float: "z.number()",
68
+ Decimal: "z.number()",
69
+ Boolean: "z.boolean()",
70
+ DateTime: "z.coerce.date()",
71
+ Json: "z.any()",
72
+ BigInt: "z.bigint()",
73
+ Bytes: "z.any()"
74
+ };
75
+ function fieldToZod(field) {
76
+ if (field.isRelation) return null;
77
+ let zod = PRISMA_TO_ZOD[field.type] ?? "z.any()";
78
+ if (!field.isRequired) {
79
+ zod = `${zod}.optional()`;
80
+ }
81
+ if (field.isList) {
82
+ zod = `z.array(${zod})`;
83
+ }
84
+ return zod;
85
+ }
86
+ function generateModelSchema(meta) {
87
+ const name = meta.name;
88
+ const fields = meta.fields.filter((f) => !f.isRelation && !f.isId).map((f) => {
89
+ const zodExpr = fieldToZod(f);
90
+ if (!zodExpr) return null;
91
+ return ` ${f.name}: ${zodExpr},`;
92
+ }).filter(Boolean).join("\n");
93
+ return `
94
+ // \u2500\u2500\u2500 ${name} \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
95
+
96
+ export const ${name}CreateSchema = z.object({
97
+ ${fields}
98
+ });
99
+
100
+ export const ${name}UpdateSchema = ${name}CreateSchema.partial();
101
+
102
+ export type ${name}Create = z.infer<typeof ${name}CreateSchema>;
103
+ export type ${name}Update = z.infer<typeof ${name}UpdateSchema>;
104
+ `.trim();
105
+ }
106
+ function generateZodSchemas() {
107
+ const models = getModels();
108
+ const schemas = models.map(generateModelSchema).join("\n\n");
109
+ return `/**
110
+ * Auto-generated Zod schemas from Prisma schema.
111
+ * Generated by omni-rest \u2014 do not edit manually.
112
+ * Re-run after schema changes.
113
+ */
114
+ import { z } from "zod";
115
+
116
+ ${schemas}
117
+ `;
118
+ }
119
+
120
+ // src/openapi.ts
121
+ var PRISMA_TO_OAS = {
122
+ String: { type: "string" },
123
+ Int: { type: "integer", format: "int32" },
124
+ Float: { type: "number", format: "float" },
125
+ Decimal: { type: "number" },
126
+ Boolean: { type: "boolean" },
127
+ DateTime: { type: "string", format: "date-time" },
128
+ Json: { type: "object" },
129
+ BigInt: { type: "integer", format: "int64" }
130
+ };
131
+ function fieldToOasSchema(field) {
132
+ if (field.isRelation) return null;
133
+ const base = PRISMA_TO_OAS[field.type] ?? { type: "string" };
134
+ if (field.isList) return { type: "array", items: base };
135
+ return base;
136
+ }
137
+ function buildModelSchema(meta, forCreate = false) {
138
+ const properties = {};
139
+ const required = [];
140
+ for (const field of meta.fields) {
141
+ if (field.isRelation) continue;
142
+ if (forCreate && field.isId) continue;
143
+ const schema = fieldToOasSchema(field);
144
+ if (!schema) continue;
145
+ properties[field.name] = schema;
146
+ if (field.isRequired && !field.isId && forCreate) {
147
+ required.push(field.name);
148
+ }
149
+ }
150
+ return {
151
+ type: "object",
152
+ properties,
153
+ ...required.length > 0 ? { required } : {}
154
+ };
155
+ }
156
+ function generateOpenApiSpec(prisma, options = {}) {
157
+ const {
158
+ title = "omni-rest API",
159
+ version = "1.0.0",
160
+ basePath = "/api",
161
+ allow,
162
+ servers = [{ url: "http://localhost:3000" }]
163
+ } = options;
164
+ const models = getModels(prisma).filter(
165
+ (m) => !allow || allow.includes(m.routeName)
166
+ );
167
+ const paths = {};
168
+ const schemas = {};
169
+ for (const meta of models) {
170
+ const name = meta.name;
171
+ const route = meta.routeName;
172
+ schemas[name] = buildModelSchema(meta, false);
173
+ schemas[`${name}Create`] = buildModelSchema(meta, true);
174
+ schemas[`${name}Update`] = {
175
+ ...buildModelSchema(meta, true),
176
+ required: []
177
+ // all optional for PATCH
178
+ };
179
+ paths[`${basePath}/${route}`] = {
180
+ get: {
181
+ summary: `List ${name}s`,
182
+ tags: [name],
183
+ parameters: buildListParameters(),
184
+ responses: {
185
+ 200: {
186
+ description: `List of ${name}s`,
187
+ content: {
188
+ "application/json": {
189
+ schema: {
190
+ type: "object",
191
+ properties: {
192
+ data: { type: "array", items: { $ref: `#/components/schemas/${name}` } },
193
+ meta: { $ref: "#/components/schemas/PaginationMeta" }
194
+ }
195
+ }
196
+ }
197
+ }
198
+ }
199
+ }
200
+ },
201
+ post: {
202
+ summary: `Create ${name}`,
203
+ tags: [name],
204
+ requestBody: {
205
+ required: true,
206
+ content: {
207
+ "application/json": {
208
+ schema: { $ref: `#/components/schemas/${name}Create` }
209
+ }
210
+ }
211
+ },
212
+ responses: {
213
+ 201: {
214
+ description: `Created ${name}`,
215
+ content: {
216
+ "application/json": {
217
+ schema: { $ref: `#/components/schemas/${name}` }
218
+ }
219
+ }
220
+ },
221
+ 400: { $ref: "#/components/responses/BadRequest" },
222
+ 409: { $ref: "#/components/responses/Conflict" }
223
+ }
224
+ }
225
+ };
226
+ paths[`${basePath}/${route}/{id}`] = {
227
+ parameters: [
228
+ {
229
+ name: "id",
230
+ in: "path",
231
+ required: true,
232
+ schema: { type: "string" },
233
+ description: `${name} ID`
234
+ }
235
+ ],
236
+ get: {
237
+ summary: `Get ${name} by ID`,
238
+ tags: [name],
239
+ responses: {
240
+ 200: {
241
+ description: `${name} record`,
242
+ content: {
243
+ "application/json": {
244
+ schema: { $ref: `#/components/schemas/${name}` }
245
+ }
246
+ }
247
+ },
248
+ 404: { $ref: "#/components/responses/NotFound" }
249
+ }
250
+ },
251
+ put: {
252
+ summary: `Update ${name}`,
253
+ tags: [name],
254
+ requestBody: {
255
+ required: true,
256
+ content: {
257
+ "application/json": {
258
+ schema: { $ref: `#/components/schemas/${name}Create` }
259
+ }
260
+ }
261
+ },
262
+ responses: {
263
+ 200: {
264
+ description: `Updated ${name}`,
265
+ content: {
266
+ "application/json": {
267
+ schema: { $ref: `#/components/schemas/${name}` }
268
+ }
269
+ }
270
+ },
271
+ 404: { $ref: "#/components/responses/NotFound" }
272
+ }
273
+ },
274
+ patch: {
275
+ summary: `Partially update ${name}`,
276
+ tags: [name],
277
+ requestBody: {
278
+ required: true,
279
+ content: {
280
+ "application/json": {
281
+ schema: { $ref: `#/components/schemas/${name}Update` }
282
+ }
283
+ }
284
+ },
285
+ responses: {
286
+ 200: {
287
+ description: `Updated ${name}`,
288
+ content: {
289
+ "application/json": {
290
+ schema: { $ref: `#/components/schemas/${name}` }
291
+ }
292
+ }
293
+ },
294
+ 404: { $ref: "#/components/responses/NotFound" }
295
+ }
296
+ },
297
+ delete: {
298
+ summary: `Delete ${name}`,
299
+ tags: [name],
300
+ responses: {
301
+ 204: { description: "Deleted successfully" },
302
+ 404: { $ref: "#/components/responses/NotFound" }
303
+ }
304
+ }
305
+ };
306
+ paths[`${basePath}/${route}/bulk/update`] = {
307
+ patch: {
308
+ summary: `Bulk update ${name}s`,
309
+ tags: [name],
310
+ requestBody: {
311
+ required: true,
312
+ description: `Array of ${name} objects with id field to update`,
313
+ content: {
314
+ "application/json": {
315
+ schema: {
316
+ type: "array",
317
+ items: { $ref: `#/components/schemas/${name}Update` }
318
+ }
319
+ }
320
+ }
321
+ },
322
+ responses: {
323
+ 200: {
324
+ description: `Bulk update result`,
325
+ content: {
326
+ "application/json": {
327
+ schema: {
328
+ type: "object",
329
+ properties: {
330
+ updated: { type: "integer" },
331
+ records: {
332
+ type: "array",
333
+ items: { $ref: `#/components/schemas/${name}` }
334
+ }
335
+ }
336
+ }
337
+ }
338
+ }
339
+ },
340
+ 400: { $ref: "#/components/responses/BadRequest" }
341
+ }
342
+ }
343
+ };
344
+ paths[`${basePath}/${route}/bulk/delete`] = {
345
+ delete: {
346
+ summary: `Bulk delete ${name}s`,
347
+ tags: [name],
348
+ requestBody: {
349
+ required: true,
350
+ description: `Array of IDs to delete`,
351
+ content: {
352
+ "application/json": {
353
+ schema: {
354
+ type: "array",
355
+ items: { type: "string" }
356
+ }
357
+ }
358
+ }
359
+ },
360
+ responses: {
361
+ 200: {
362
+ description: `Bulk delete result`,
363
+ content: {
364
+ "application/json": {
365
+ schema: {
366
+ type: "object",
367
+ properties: {
368
+ deleted: { type: "integer" }
369
+ }
370
+ }
371
+ }
372
+ }
373
+ },
374
+ 400: { $ref: "#/components/responses/BadRequest" }
375
+ }
376
+ }
377
+ };
378
+ }
379
+ return {
380
+ openapi: "3.0.3",
381
+ info: { title, version },
382
+ servers,
383
+ paths,
384
+ components: {
385
+ schemas: {
386
+ ...schemas,
387
+ PaginationMeta: {
388
+ type: "object",
389
+ properties: {
390
+ total: { type: "integer" },
391
+ page: { type: "integer" },
392
+ limit: { type: "integer" },
393
+ totalPages: { type: "integer" }
394
+ }
395
+ },
396
+ Error: {
397
+ type: "object",
398
+ properties: { error: { type: "string" } }
399
+ }
400
+ },
401
+ responses: {
402
+ NotFound: {
403
+ description: "Record not found",
404
+ content: {
405
+ "application/json": {
406
+ schema: { $ref: "#/components/schemas/Error" }
407
+ }
408
+ }
409
+ },
410
+ BadRequest: {
411
+ description: "Bad request",
412
+ content: {
413
+ "application/json": {
414
+ schema: { $ref: "#/components/schemas/Error" }
415
+ }
416
+ }
417
+ },
418
+ Conflict: {
419
+ description: "Unique constraint violation",
420
+ content: {
421
+ "application/json": {
422
+ schema: { $ref: "#/components/schemas/Error" }
423
+ }
424
+ }
425
+ }
426
+ }
427
+ },
428
+ tags: models.map((m) => ({ name: m.name }))
429
+ };
430
+ }
431
+ function buildListParameters() {
432
+ return [
433
+ { name: "page", in: "query", schema: { type: "integer", default: 1 }, description: "Page number" },
434
+ { name: "limit", in: "query", schema: { type: "integer", default: 20 }, description: "Items per page" },
435
+ { name: "sort", in: "query", schema: { type: "string" }, description: "e.g. createdAt:desc" },
436
+ { name: "include", in: "query", schema: { type: "string" }, description: "Comma-separated relations" },
437
+ { name: "select", in: "query", schema: { type: "string" }, description: "Comma-separated fields" }
438
+ ];
439
+ }
440
+
441
+ // src/cli.ts
442
+ var args = process.argv.slice(2);
443
+ var command = args[0] ?? "generate";
444
+ var cwd = process.cwd();
445
+ var COLORS = {
446
+ green: (s) => `\x1B[32m${s}\x1B[0m`,
447
+ cyan: (s) => `\x1B[36m${s}\x1B[0m`,
448
+ red: (s) => `\x1B[31m${s}\x1B[0m`,
449
+ bold: (s) => `\x1B[1m${s}\x1B[0m`
450
+ };
451
+ function write(filePath, content) {
452
+ const abs = path.resolve(cwd, filePath);
453
+ fs.mkdirSync(path.dirname(abs), { recursive: true });
454
+ fs.writeFileSync(abs, content, "utf-8");
455
+ console.log(COLORS.green(` \u2713 Written: ${filePath}`));
456
+ }
457
+ function run() {
458
+ console.log(COLORS.bold("\n omni-rest generator\n"));
459
+ if (command === "generate:zod" || command === "generate") {
460
+ try {
461
+ console.log(COLORS.cyan(" \u2192 Generating Zod schemas from Prisma DMMF..."));
462
+ const code = generateZodSchemas();
463
+ write("src/schemas.generated.ts", code);
464
+ } catch (e) {
465
+ console.error(COLORS.red(` \u2717 Zod generation failed: ${e.message}`));
466
+ }
467
+ }
468
+ if (command === "generate:openapi" || command === "generate") {
469
+ try {
470
+ console.log(COLORS.cyan(" \u2192 Generating OpenAPI spec from Prisma DMMF..."));
471
+ const spec = generateOpenApiSpec({
472
+ title: getPackageName(),
473
+ version: getPackageVersion()
474
+ });
475
+ write("openapi.json", JSON.stringify(spec, null, 2));
476
+ } catch (e) {
477
+ console.error(COLORS.red(` \u2717 OpenAPI generation failed: ${e.message}`));
478
+ }
479
+ }
480
+ if (!["generate", "generate:zod", "generate:openapi"].includes(command)) {
481
+ console.log(`
482
+ Usage:
483
+ npx omni-rest generate Generate both Zod schemas and OpenAPI spec
484
+ npx omni-rest generate:zod Generate Zod schemas only
485
+ npx omni-rest generate:openapi Generate OpenAPI spec only
486
+ `);
487
+ }
488
+ console.log(COLORS.bold("\n Done!\n"));
489
+ }
490
+ function getPackageName() {
491
+ try {
492
+ const pkg = JSON.parse(
493
+ fs.readFileSync(path.resolve(cwd, "package.json"), "utf-8")
494
+ );
495
+ return pkg.name ?? "My API";
496
+ } catch {
497
+ return "My API";
498
+ }
499
+ }
500
+ function getPackageVersion() {
501
+ try {
502
+ const pkg = JSON.parse(
503
+ fs.readFileSync(path.resolve(cwd, "package.json"), "utf-8")
504
+ );
505
+ return pkg.version ?? "1.0.0";
506
+ } catch {
507
+ return "1.0.0";
508
+ }
509
+ }
510
+ run();
511
+ //# sourceMappingURL=cli.mjs.map
512
+ //# sourceMappingURL=cli.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/introspect.ts","../src/zod-generator.ts","../src/openapi.ts","../src/cli.ts"],"names":[],"mappings":"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","file":"cli.mjs","sourcesContent":["import { Prisma } from \"@prisma/client\";\r\nimport type { ModelMeta, FieldMeta } from \"./types\";\r\n\r\n/**\r\n * Reads Prisma's DMMF (Data Model Meta Format) at runtime\r\n * and returns structured metadata for every model in your schema.\r\n *\r\n * No file reading. No code generation. Pure runtime introspection.\r\n */\r\nexport function getModels(prisma?: any): ModelMeta[] {\r\n let raw: any[] | undefined;\r\n\r\n // Try to get from PrismaClient instance first (new v5 format)\r\n if (prisma?._runtimeDataModel?.models) {\r\n const modelsObj = prisma._runtimeDataModel.models;\r\n // Convert object to array, adding name from key\r\n raw = Object.entries(modelsObj).map(([name, model]: [string, any]) => ({\r\n name,\r\n ...model,\r\n fields: (model.fields || []).map((f: any) => ({\r\n ...f,\r\n relationName: f.kind === \"object\" ? f.name : undefined,\r\n })),\r\n }));\r\n }\r\n\r\n // Fallback to DMMF from @prisma/client module\r\n if (!raw) {\r\n const dmmfModels =\r\n (Prisma as any)?.dmmf?.datamodel?.models ||\r\n (require(\"@prisma/client\")?.Prisma as any)?.dmmf?.datamodel?.models;\r\n\r\n if (dmmfModels) {\r\n raw = dmmfModels;\r\n }\r\n }\r\n\r\n if (!raw) {\r\n throw new Error(\r\n \"[omni-rest] Could not find Prisma DMMF. Ensure Prisma client is generated and you're passing a PrismaClient instance to omni-rest.\"\r\n );\r\n }\r\n\r\n if (!Array.isArray(raw)) {\r\n throw new Error(\r\n `[omni-rest] Expected models to be an array, got ${typeof raw}. Debug: prisma._runtimeDataModel.models=${!!prisma?._runtimeDataModel?.models}, raw value=${JSON.stringify(raw).slice(0, 100)}`\r\n );\r\n }\r\n\r\n return raw.map((model: any) => {\r\n const fields: FieldMeta[] = model.fields.map((f: any) => ({\r\n name: f.name,\r\n type: f.type,\r\n isId: f.isId,\r\n isRequired: f.isRequired,\r\n isList: f.isList,\r\n isRelation: !!f.relationName,\r\n }));\r\n\r\n const idField =\r\n model.fields.find((f: any) => f.isId)?.name ?? \"id\";\r\n\r\n return {\r\n name: model.name,\r\n routeName: toRouteName(model.name),\r\n fields,\r\n idField,\r\n };\r\n });\r\n}\r\n\r\n/**\r\n * Converts a Prisma model name to a URL-safe route segment.\r\n * \"UserProfile\" → \"userprofile\"\r\n * \"OrderItem\" → \"orderitem\"\r\n */\r\nexport function toRouteName(modelName: string): string {\r\n return modelName.toLowerCase();\r\n}\r\n\r\n/**\r\n * Returns a map of routeName → ModelMeta for O(1) lookups.\r\n */\r\nexport function buildModelMap(\r\n models: ModelMeta[],\r\n allowList?: string[]\r\n): Record<string, ModelMeta> {\r\n const filtered = allowList\r\n ? models.filter((m) => allowList.includes(m.routeName))\r\n : models;\r\n\r\n return Object.fromEntries(filtered.map((m) => [m.routeName, m]));\r\n}\r\n\r\n/**\r\n * Gets the Prisma client delegate for a model.\r\n * prisma[\"userProfile\"] or prisma[\"user\"] — handles camelCase.\r\n */\r\nexport function getDelegate(prisma: any, meta: ModelMeta): any {\r\n // Prisma client properties are camelCase of model name\r\n // \"UserProfile\" → \"userProfile\"\r\n const key =\r\n meta.name.charAt(0).toLowerCase() + meta.name.slice(1);\r\n const delegate = prisma[key];\r\n\r\n if (!delegate) {\r\n throw new Error(\r\n `Could not find Prisma delegate for model \"${meta.name}\". ` +\r\n `Expected prisma.${key} to exist.`\r\n );\r\n }\r\n\r\n return delegate;\r\n}","import { getModels } from \"./introspect\";\r\nimport type { ModelMeta, FieldMeta } from \"./types\";\r\n\r\n/**\r\n * Maps Prisma scalar types → Zod method names\r\n */\r\nconst PRISMA_TO_ZOD: Record<string, string> = {\r\n String: \"z.string()\",\r\n Int: \"z.number().int()\",\r\n Float: \"z.number()\",\r\n Decimal: \"z.number()\",\r\n Boolean: \"z.boolean()\",\r\n DateTime: \"z.coerce.date()\",\r\n Json: \"z.any()\",\r\n BigInt: \"z.bigint()\",\r\n Bytes: \"z.any()\",\r\n};\r\n\r\n/**\r\n * Converts a single Prisma field to its Zod expression string.\r\n */\r\nfunction fieldToZod(field: FieldMeta): string {\r\n if (field.isRelation) return null as any; // skip relations\r\n\r\n let zod = PRISMA_TO_ZOD[field.type] ?? \"z.any()\";\r\n\r\n // Optional fields\r\n if (!field.isRequired) {\r\n zod = `${zod}.optional()`;\r\n }\r\n\r\n // List fields\r\n if (field.isList) {\r\n zod = `z.array(${zod})`;\r\n }\r\n\r\n return zod;\r\n}\r\n\r\n/**\r\n * Generates Zod schema source code for a single model.\r\n *\r\n * Produces two schemas:\r\n * - CreateSchema — all required fields must be present\r\n * - UpdateSchema — all fields are optional (for PATCH)\r\n */\r\nfunction generateModelSchema(meta: ModelMeta): string {\r\n const name = meta.name;\r\n\r\n const fields = meta.fields\r\n .filter((f) => !f.isRelation && !f.isId) // skip relations and id (auto)\r\n .map((f) => {\r\n const zodExpr = fieldToZod(f);\r\n if (!zodExpr) return null;\r\n return ` ${f.name}: ${zodExpr},`;\r\n })\r\n .filter(Boolean)\r\n .join(\"\\n\");\r\n\r\n return `\r\n// ─── ${name} ──────────────────────────────────────────────────────────────────\r\n\r\nexport const ${name}CreateSchema = z.object({\r\n${fields}\r\n});\r\n\r\nexport const ${name}UpdateSchema = ${name}CreateSchema.partial();\r\n\r\nexport type ${name}Create = z.infer<typeof ${name}CreateSchema>;\r\nexport type ${name}Update = z.infer<typeof ${name}UpdateSchema>;\r\n`.trim();\r\n}\r\n\r\n/**\r\n * Generates a complete Zod schema file for ALL models in your Prisma schema.\r\n *\r\n * @example\r\n * ```ts\r\n * import { generateZodSchemas } from \"omni-rest\";\r\n * const code = generateZodSchemas();\r\n * fs.writeFileSync(\"src/schemas.ts\", code);\r\n * ```\r\n */\r\nexport function generateZodSchemas(): string {\r\n const models = getModels();\r\n\r\n const schemas = models.map(generateModelSchema).join(\"\\n\\n\");\r\n\r\n return `/**\r\n * Auto-generated Zod schemas from Prisma schema.\r\n * Generated by omni-rest — do not edit manually.\r\n * Re-run after schema changes.\r\n */\r\nimport { z } from \"zod\";\r\n\r\n${schemas}\r\n`;\r\n}\r\n\r\n/**\r\n * Returns Zod schema OBJECTS at runtime (not source code).\r\n * Useful for request validation in middleware.\r\n *\r\n * Requires \"zod\" to be installed in the host project.\r\n */\r\nexport function buildRuntimeSchemas(): Record<\r\n string,\r\n { create: any; update: any }\r\n> {\r\n let z: any;\r\n try {\r\n z = require(\"zod\").z;\r\n } catch {\r\n throw new Error(\r\n \"[omni-rest] zod is required for runtime validation. Run: npm install zod\"\r\n );\r\n }\r\n\r\n const ZOD_FACTORIES: Record<string, () => any> = {\r\n String: () => z.string(),\r\n Int: () => z.number().int(),\r\n Float: () => z.number(),\r\n Decimal: () => z.number(),\r\n Boolean: () => z.boolean(),\r\n DateTime: () => z.coerce.date(),\r\n Json: () => z.any(),\r\n BigInt: () => z.bigint(),\r\n Bytes: () => z.any(),\r\n };\r\n\r\n const models = getModels();\r\n const result: Record<string, { create: any; update: any }> = {};\r\n\r\n for (const meta of models) {\r\n const shape: Record<string, any> = {};\r\n\r\n for (const field of meta.fields) {\r\n if (field.isRelation || field.isId) continue;\r\n\r\n const factory = ZOD_FACTORIES[field.type] ?? (() => z.any());\r\n let schema = factory();\r\n\r\n if (!field.isRequired) schema = schema.optional();\r\n if (field.isList) schema = z.array(schema);\r\n\r\n shape[field.name] = schema;\r\n }\r\n\r\n const createSchema = z.object(shape);\r\n result[meta.routeName] = {\r\n create: createSchema,\r\n update: createSchema.partial(),\r\n };\r\n }\r\n\r\n return result;\r\n}","import { getModels } from \"./introspect\";\r\nimport type { ModelMeta, FieldMeta } from \"./types\";\r\n\r\n/**\r\n * Maps Prisma scalar types → OpenAPI schema types\r\n */\r\nconst PRISMA_TO_OAS: Record<string, { type: string; format?: string }> = {\r\n String: { type: \"string\" },\r\n Int: { type: \"integer\", format: \"int32\" },\r\n Float: { type: \"number\", format: \"float\" },\r\n Decimal: { type: \"number\" },\r\n Boolean: { type: \"boolean\" },\r\n DateTime: { type: \"string\", format: \"date-time\" },\r\n Json: { type: \"object\" },\r\n BigInt: { type: \"integer\", format: \"int64\" },\r\n};\r\n\r\nfunction fieldToOasSchema(field: FieldMeta): any {\r\n if (field.isRelation) return null;\r\n const base = PRISMA_TO_OAS[field.type] ?? { type: \"string\" };\r\n if (field.isList) return { type: \"array\", items: base };\r\n return base;\r\n}\r\n\r\nfunction buildModelSchema(meta: ModelMeta, forCreate = false): any {\r\n const properties: Record<string, any> = {};\r\n const required: string[] = [];\r\n\r\n for (const field of meta.fields) {\r\n if (field.isRelation) continue;\r\n if (forCreate && field.isId) continue; // id is auto on create\r\n\r\n const schema = fieldToOasSchema(field);\r\n if (!schema) continue;\r\n\r\n properties[field.name] = schema;\r\n\r\n if (field.isRequired && !field.isId && forCreate) {\r\n required.push(field.name);\r\n }\r\n }\r\n\r\n return {\r\n type: \"object\",\r\n properties,\r\n ...(required.length > 0 ? { required } : {}),\r\n };\r\n}\r\n\r\n/**\r\n * Generates a full OpenAPI 3.0 specification object for all exposed models.\r\n *\r\n * @example\r\n * ```ts\r\n * import { generateOpenApiSpec } from \"omni-rest\";\r\n * const spec = generateOpenApiSpec(prisma, { title: \"My API\", version: \"1.0.0\", basePath: \"/api\" });\r\n * fs.writeFileSync(\"openapi.json\", JSON.stringify(spec, null, 2));\r\n * ```\r\n */\r\nexport function generateOpenApiSpec(\r\n prisma: any,\r\n options: {\r\n title?: string;\r\n version?: string;\r\n basePath?: string;\r\n allow?: string[];\r\n servers?: { url: string; description?: string }[];\r\n } = {}\r\n): object {\r\n const {\r\n title = \"omni-rest API\",\r\n version = \"1.0.0\",\r\n basePath = \"/api\",\r\n allow,\r\n servers = [{ url: \"http://localhost:3000\" }],\r\n } = options;\r\n\r\n const models = getModels(prisma).filter(\r\n (m) => !allow || allow.includes(m.routeName)\r\n );\r\n\r\n const paths: Record<string, any> = {};\r\n const schemas: Record<string, any> = {};\r\n\r\n for (const meta of models) {\r\n const name = meta.name;\r\n const route = meta.routeName;\r\n\r\n // ── Schemas ──────────────────────────────────────────────────────────────\r\n schemas[name] = buildModelSchema(meta, false);\r\n schemas[`${name}Create`] = buildModelSchema(meta, true);\r\n schemas[`${name}Update`] = {\r\n ...buildModelSchema(meta, true),\r\n required: [], // all optional for PATCH\r\n };\r\n\r\n // ── Collection path /api/:model ───────────────────────────────────────────\r\n paths[`${basePath}/${route}`] = {\r\n get: {\r\n summary: `List ${name}s`,\r\n tags: [name],\r\n parameters: buildListParameters(),\r\n responses: {\r\n 200: {\r\n description: `List of ${name}s`,\r\n content: {\r\n \"application/json\": {\r\n schema: {\r\n type: \"object\",\r\n properties: {\r\n data: { type: \"array\", items: { $ref: `#/components/schemas/${name}` } },\r\n meta: { $ref: \"#/components/schemas/PaginationMeta\" },\r\n },\r\n },\r\n },\r\n },\r\n },\r\n },\r\n },\r\n post: {\r\n summary: `Create ${name}`,\r\n tags: [name],\r\n requestBody: {\r\n required: true,\r\n content: {\r\n \"application/json\": {\r\n schema: { $ref: `#/components/schemas/${name}Create` },\r\n },\r\n },\r\n },\r\n responses: {\r\n 201: {\r\n description: `Created ${name}`,\r\n content: {\r\n \"application/json\": {\r\n schema: { $ref: `#/components/schemas/${name}` },\r\n },\r\n },\r\n },\r\n 400: { $ref: \"#/components/responses/BadRequest\" },\r\n 409: { $ref: \"#/components/responses/Conflict\" },\r\n },\r\n },\r\n };\r\n\r\n // ── Resource path /api/:model/:id ─────────────────────────────────────────\r\n paths[`${basePath}/${route}/{id}`] = {\r\n parameters: [\r\n {\r\n name: \"id\",\r\n in: \"path\",\r\n required: true,\r\n schema: { type: \"string\" },\r\n description: `${name} ID`,\r\n },\r\n ],\r\n get: {\r\n summary: `Get ${name} by ID`,\r\n tags: [name],\r\n responses: {\r\n 200: {\r\n description: `${name} record`,\r\n content: {\r\n \"application/json\": {\r\n schema: { $ref: `#/components/schemas/${name}` },\r\n },\r\n },\r\n },\r\n 404: { $ref: \"#/components/responses/NotFound\" },\r\n },\r\n },\r\n put: {\r\n summary: `Update ${name}`,\r\n tags: [name],\r\n requestBody: {\r\n required: true,\r\n content: {\r\n \"application/json\": {\r\n schema: { $ref: `#/components/schemas/${name}Create` },\r\n },\r\n },\r\n },\r\n responses: {\r\n 200: {\r\n description: `Updated ${name}`,\r\n content: {\r\n \"application/json\": {\r\n schema: { $ref: `#/components/schemas/${name}` },\r\n },\r\n },\r\n },\r\n 404: { $ref: \"#/components/responses/NotFound\" },\r\n },\r\n },\r\n patch: {\r\n summary: `Partially update ${name}`,\r\n tags: [name],\r\n requestBody: {\r\n required: true,\r\n content: {\r\n \"application/json\": {\r\n schema: { $ref: `#/components/schemas/${name}Update` },\r\n },\r\n },\r\n },\r\n responses: {\r\n 200: {\r\n description: `Updated ${name}`,\r\n content: {\r\n \"application/json\": {\r\n schema: { $ref: `#/components/schemas/${name}` },\r\n },\r\n },\r\n },\r\n 404: { $ref: \"#/components/responses/NotFound\" },\r\n },\r\n },\r\n delete: {\r\n summary: `Delete ${name}`,\r\n tags: [name],\r\n responses: {\r\n 204: { description: \"Deleted successfully\" },\r\n 404: { $ref: \"#/components/responses/NotFound\" },\r\n },\r\n },\r\n };\r\n\r\n // ── Bulk operations paths ──────────────────────────────────────────────────\r\n paths[`${basePath}/${route}/bulk/update`] = {\r\n patch: {\r\n summary: `Bulk update ${name}s`,\r\n tags: [name],\r\n requestBody: {\r\n required: true,\r\n description: `Array of ${name} objects with id field to update`,\r\n content: {\r\n \"application/json\": {\r\n schema: {\r\n type: \"array\",\r\n items: { $ref: `#/components/schemas/${name}Update` },\r\n },\r\n },\r\n },\r\n },\r\n responses: {\r\n 200: {\r\n description: `Bulk update result`,\r\n content: {\r\n \"application/json\": {\r\n schema: {\r\n type: \"object\",\r\n properties: {\r\n updated: { type: \"integer\" },\r\n records: {\r\n type: \"array\",\r\n items: { $ref: `#/components/schemas/${name}` },\r\n },\r\n },\r\n },\r\n },\r\n },\r\n },\r\n 400: { $ref: \"#/components/responses/BadRequest\" },\r\n },\r\n },\r\n };\r\n\r\n paths[`${basePath}/${route}/bulk/delete`] = {\r\n delete: {\r\n summary: `Bulk delete ${name}s`,\r\n tags: [name],\r\n requestBody: {\r\n required: true,\r\n description: `Array of IDs to delete`,\r\n content: {\r\n \"application/json\": {\r\n schema: {\r\n type: \"array\",\r\n items: { type: \"string\" },\r\n },\r\n },\r\n },\r\n },\r\n responses: {\r\n 200: {\r\n description: `Bulk delete result`,\r\n content: {\r\n \"application/json\": {\r\n schema: {\r\n type: \"object\",\r\n properties: {\r\n deleted: { type: \"integer\" },\r\n },\r\n },\r\n },\r\n },\r\n },\r\n 400: { $ref: \"#/components/responses/BadRequest\" },\r\n },\r\n },\r\n };\r\n }\r\n\r\n return {\r\n openapi: \"3.0.3\",\r\n info: { title, version },\r\n servers,\r\n paths,\r\n components: {\r\n schemas: {\r\n ...schemas,\r\n PaginationMeta: {\r\n type: \"object\",\r\n properties: {\r\n total: { type: \"integer\" },\r\n page: { type: \"integer\" },\r\n limit: { type: \"integer\" },\r\n totalPages: { type: \"integer\" },\r\n },\r\n },\r\n Error: {\r\n type: \"object\",\r\n properties: { error: { type: \"string\" } },\r\n },\r\n },\r\n responses: {\r\n NotFound: {\r\n description: \"Record not found\",\r\n content: {\r\n \"application/json\": {\r\n schema: { $ref: \"#/components/schemas/Error\" },\r\n },\r\n },\r\n },\r\n BadRequest: {\r\n description: \"Bad request\",\r\n content: {\r\n \"application/json\": {\r\n schema: { $ref: \"#/components/schemas/Error\" },\r\n },\r\n },\r\n },\r\n Conflict: {\r\n description: \"Unique constraint violation\",\r\n content: {\r\n \"application/json\": {\r\n schema: { $ref: \"#/components/schemas/Error\" },\r\n },\r\n },\r\n },\r\n },\r\n },\r\n tags: models.map((m) => ({ name: m.name })),\r\n };\r\n}\r\n\r\nfunction buildListParameters() {\r\n return [\r\n { name: \"page\", in: \"query\", schema: { type: \"integer\", default: 1 }, description: \"Page number\" },\r\n { name: \"limit\", in: \"query\", schema: { type: \"integer\", default: 20 }, description: \"Items per page\" },\r\n { name: \"sort\", in: \"query\", schema: { type: \"string\" }, description: \"e.g. createdAt:desc\" },\r\n { name: \"include\", in: \"query\", schema: { type: \"string\" }, description: \"Comma-separated relations\" },\r\n { name: \"select\", in: \"query\", schema: { type: \"string\" }, description: \"Comma-separated fields\" },\r\n ];\r\n}","#!/usr/bin/env node\r\n/**\r\n * omni-rest CLI\r\n *\r\n * Usage:\r\n * npx omni-rest generate:zod → generates src/schemas.generated.ts\r\n * npx omni-rest generate:openapi → generates openapi.json\r\n * npx omni-rest generate → generates both\r\n */\r\n\r\nimport fs from \"fs\";\r\nimport path from \"path\";\r\nimport { generateZodSchemas } from \"./zod-generator\";\r\nimport { generateOpenApiSpec } from \"./openapi\";\r\n\r\nconst args = process.argv.slice(2);\r\nconst command = args[0] ?? \"generate\";\r\nconst cwd = process.cwd();\r\n\r\nconst COLORS = {\r\n green: (s: string) => `\\x1b[32m${s}\\x1b[0m`,\r\n cyan: (s: string) => `\\x1b[36m${s}\\x1b[0m`,\r\n red: (s: string) => `\\x1b[31m${s}\\x1b[0m`,\r\n bold: (s: string) => `\\x1b[1m${s}\\x1b[0m`,\r\n};\r\n\r\nfunction write(filePath: string, content: string) {\r\n const abs = path.resolve(cwd, filePath);\r\n fs.mkdirSync(path.dirname(abs), { recursive: true });\r\n fs.writeFileSync(abs, content, \"utf-8\");\r\n console.log(COLORS.green(` ✓ Written: ${filePath}`));\r\n}\r\n\r\nfunction run() {\r\n console.log(COLORS.bold(\"\\n omni-rest generator\\n\"));\r\n\r\n if (command === \"generate:zod\" || command === \"generate\") {\r\n try {\r\n console.log(COLORS.cyan(\" → Generating Zod schemas from Prisma DMMF...\"));\r\n const code = generateZodSchemas();\r\n write(\"src/schemas.generated.ts\", code);\r\n } catch (e: any) {\r\n console.error(COLORS.red(` ✗ Zod generation failed: ${e.message}`));\r\n }\r\n }\r\n\r\n if (command === \"generate:openapi\" || command === \"generate\") {\r\n try {\r\n console.log(COLORS.cyan(\" → Generating OpenAPI spec from Prisma DMMF...\"));\r\n const spec = generateOpenApiSpec({\r\n title: getPackageName(),\r\n version: getPackageVersion(),\r\n });\r\n write(\"openapi.json\", JSON.stringify(spec, null, 2));\r\n } catch (e: any) {\r\n console.error(COLORS.red(` ✗ OpenAPI generation failed: ${e.message}`));\r\n }\r\n }\r\n\r\n if (![\"generate\", \"generate:zod\", \"generate:openapi\"].includes(command)) {\r\n console.log(`\r\n Usage:\r\n npx omni-rest generate Generate both Zod schemas and OpenAPI spec\r\n npx omni-rest generate:zod Generate Zod schemas only\r\n npx omni-rest generate:openapi Generate OpenAPI spec only\r\n `);\r\n }\r\n\r\n console.log(COLORS.bold(\"\\n Done!\\n\"));\r\n}\r\n\r\nfunction getPackageName(): string {\r\n try {\r\n const pkg = JSON.parse(\r\n fs.readFileSync(path.resolve(cwd, \"package.json\"), \"utf-8\")\r\n );\r\n return pkg.name ?? \"My API\";\r\n } catch {\r\n return \"My API\";\r\n }\r\n}\r\n\r\nfunction getPackageVersion(): string {\r\n try {\r\n const pkg = JSON.parse(\r\n fs.readFileSync(path.resolve(cwd, \"package.json\"), \"utf-8\")\r\n );\r\n return pkg.version ?? \"1.0.0\";\r\n } catch {\r\n return \"1.0.0\";\r\n }\r\n}\r\n\r\nrun();"]}