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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Omni Rest Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,476 @@
1
+ # omni-rest
2
+
3
+ > **Auto-generate REST APIs from your Prisma schema** — zero-config CRUD endpoints
4
+
5
+ [![npm version](https://img.shields.io/npm/v/omni-rest.svg)](https://www.npmjs.com/package/omni-rest)
6
+ [![License](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
7
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.0+-blue.svg)](https://www.typescriptlang.org/)
8
+ [![Node.js](https://img.shields.io/badge/Node.js-18+-green.svg)](https://nodejs.org/)
9
+
10
+ ## What is omni-rest?
11
+
12
+ omni-rest automatically generates RESTful API endpoints from your Prisma schema. With zero configuration, you get:
13
+
14
+ ✅ **CRUD Operations** - Create, Read, Update, Delete any model
15
+ ✅ **Bulk Operations** - Update/delete multiple records in one request
16
+ ✅ **Advanced Queries** - Filter, sort, paginate with standard query parameters
17
+ ✅ **OpenAPI Docs** - Auto-generated Swagger UI for all endpoints
18
+ ✅ **Type Safety** - Full TypeScript support with generated types
19
+ ✅ **Framework Agnostic** - Works with Express, Next.js, Fastify, and more
20
+ ✅ **Security Guards** - Control access at operation level
21
+ ✅ **Audit Hooks** - Log operations and trigger side effects
22
+
23
+ ## Quick Start
24
+
25
+ ### Installation
26
+
27
+ ```bash
28
+ npm install omni-rest @prisma/client
29
+ npm install -D prisma
30
+ ```
31
+
32
+ ### Basic Setup
33
+
34
+ Define your schema:
35
+
36
+ ```prisma
37
+ // prisma/schema.prisma
38
+ model Product {
39
+ id Int @id @default(autoincrement())
40
+ name String @unique
41
+ price Float
42
+ inventory Int @default(0)
43
+ }
44
+ ```
45
+
46
+ Mount the API:
47
+
48
+ ```typescript
49
+ // server.ts
50
+ import express from "express";
51
+ import { PrismaClient } from "@prisma/client";
52
+ import { expressAdapter } from "omni-rest/express";
53
+
54
+ const app = express();
55
+ const prisma = new PrismaClient();
56
+
57
+ app.use(express.json());
58
+ app.use("/api", expressAdapter(prisma));
59
+
60
+ app.listen(3000);
61
+ ```
62
+
63
+ Start making requests:
64
+
65
+ ```bash
66
+ # GET all products
67
+ curl http://localhost:3000/api/product
68
+
69
+ # Create product
70
+ curl -X POST http://localhost:3000/api/product \\
71
+ -H "Content-Type: application/json" \\
72
+ -d '{"name":"Laptop","price":999.99}'
73
+
74
+ # Get product by ID
75
+ curl http://localhost:3000/api/product/1
76
+
77
+ # Update product
78
+ curl -X PATCH http://localhost:3000/api/product/1 \\
79
+ -H "Content-Type: application/json" \\
80
+ -d '{"price":899.99}'
81
+
82
+ # Delete product
83
+ curl -X DELETE http://localhost:3000/api/product/1
84
+ ```
85
+
86
+ ## Features
87
+
88
+ ### Framework Support
89
+
90
+ | Framework | Status | Example |
91
+ |-----------|--------|---------|
92
+ | **Express** | ✅ | [examples/express-app](examples/express-app) |
93
+ | **Next.js App Router** | ✅ | [examples/nextjs-app](examples/nextjs-app) |
94
+ | **Fastify** | ✅ | [Source](src/adapters/fastify.ts) |
95
+ | **Koa** | 🔵 | Planned |
96
+ | **Nest.js** | 🔵 | Planned |
97
+
98
+ ### API Endpoints
99
+
100
+ Each model automatically gets 8 REST endpoints:
101
+
102
+ ```
103
+ LIST GET /api/:model?limit=10&offset=0&filter=...
104
+ CREATE POST /api/:model
105
+ READ GET /api/:model/:id
106
+ UPDATE PUT /api/:model/:id
107
+ PATCH PATCH /api/:model/:id
108
+ DELETE DELETE /api/:model/:id
109
+ BULK_UPD PATCH /api/:model/bulk/update
110
+ BULK_DEL DELETE /api/:model/bulk/delete
111
+ ```
112
+
113
+ ### Query Parameters
114
+
115
+ The LIST endpoint supports powerful filtering and pagination:
116
+
117
+ ```javascript
118
+ // Pagination
119
+ GET /api/product?limit=10&offset=20
120
+
121
+ // Sorting
122
+ GET /api/product?orderBy=price:desc&orderBy=name:asc
123
+
124
+ // Filtering
125
+ GET /api/product?name=Laptop&price[gte]=100&price[lte]=1000&inventory[gt]=0
126
+
127
+ // Filter Operators
128
+ // eq, ne, lt, lte, gt, gte, in, nin, contains, startsWith, endsWith
129
+ ```
130
+
131
+ Full API Reference: [docs/API.md](docs/API.md)
132
+
133
+ ### Security Features
134
+
135
+ #### Authorization Guards
136
+
137
+ Control access per model and operation:
138
+
139
+ ```typescript
140
+ expressAdapter(prisma, {
141
+ guards: {
142
+ product: {
143
+ DELETE: async ({ id }) => {
144
+ const hasOrders = await prisma.order.count({
145
+ where: { items: { some: { productId: id } } },
146
+ });
147
+ if (hasOrders > 0) {
148
+ return "Cannot delete products with orders";
149
+ }
150
+ },
151
+ },
152
+ },
153
+ });
154
+ ```
155
+
156
+ #### Audit Logging
157
+
158
+ Track all operations with hooks:
159
+
160
+ ```typescript
161
+ expressAdapter(prisma, {
162
+ beforeOperation: async ({ model, method, id, body }) => {
163
+ await auditLog.create({
164
+ model, method, userId: req.user.id,
165
+ timestamp: new Date(),
166
+ });
167
+ },
168
+ });
169
+ ```
170
+
171
+ Configuration Guide: [docs/CONFIGURATION.md](docs/CONFIGURATION.md)
172
+
173
+ ### OpenAPI Documentation
174
+
175
+ Automatically generate Swagger UI:
176
+
177
+ ```typescript
178
+ import { generateOpenApiSpec } from "omni-rest";
179
+ import swaggerUi from "swagger-ui-express";
180
+
181
+ const spec = generateOpenApiSpec(prisma, {
182
+ title: "My API",
183
+ version: "1.0.0",
184
+ basePath: "/api",
185
+ });
186
+
187
+ app.use("/docs", swaggerUi.serve, swaggerUi.setup(spec));
188
+ ```
189
+
190
+ Visit http://localhost:3000/docs to explore your API!
191
+
192
+ ## Documentation
193
+
194
+ - **[📚 Documentation Site](https://omni-rest.vercel.app)** - Live documentation website
195
+ - **[Quick Start Guide](docs/QUICKSTART.md)** - 5-minute setup
196
+ - **[API Reference](docs/API.md)** - Complete endpoint documentation
197
+ - **[Configuration](docs/CONFIGURATION.md)** - Guards, hooks, pagination
198
+ - **[Contributing](docs/CONTRIBUTING.md)** - How to contribute
199
+ - **[Vercel Deployment](docs/VERCEL_DEPLOYMENT.md)** - Deploy docs to Vercel
200
+
201
+ ## Examples
202
+
203
+ ### Express.js
204
+
205
+ ```typescript
206
+ import express from "express";
207
+ import { PrismaClient } from "@prisma/client";
208
+ import { expressAdapter } from "omni-rest/express";
209
+
210
+ const app = express();
211
+ const prisma = new PrismaClient();
212
+
213
+ app.use(express.json());
214
+
215
+ app.use("/api", expressAdapter(prisma, {
216
+ allow: ["product", "category"], // Only expose these models
217
+
218
+ guards: {
219
+ product: {
220
+ DELETE: async ({ id }) => {
221
+ const count = await prisma.order.count({
222
+ where: { items: { some: { productId: id } } },
223
+ });
224
+ if (count > 0) return "Has active orders";
225
+ },
226
+ },
227
+ },
228
+
229
+ beforeOperation: async ({ model, method }) => {
230
+ console.log(\ \);
231
+ },
232
+ }));
233
+
234
+ app.listen(3000, () => console.log("🚀 Ready on :3000"));
235
+ ```
236
+
237
+ Full Express Example: [examples/express-app](examples/express-app)
238
+
239
+ ### Next.js App Router
240
+
241
+ ```typescript
242
+ // app/api/[...prismaRest]/route.ts
243
+ import { PrismaClient } from "@prisma/client";
244
+ import { nextjsAdapter } from "omni-rest/nextjs";
245
+
246
+ const prisma = new PrismaClient();
247
+
248
+ export const { GET, POST, PUT, PATCH, DELETE } = nextjsAdapter(prisma, {
249
+ allow: ["product"],
250
+ });
251
+ ```
252
+
253
+ Full Next.js Example: [examples/nextjs-app](examples/nextjs-app)
254
+
255
+ ### Fastify
256
+
257
+ ```typescript
258
+ import Fastify from "fastify";
259
+ import { PrismaClient } from "@prisma/client";
260
+ import { fastifyAdapter } from "omni-rest/fastify";
261
+
262
+ const app = Fastify();
263
+ const prisma = new PrismaClient();
264
+
265
+ fastifyAdapter(app, prisma, {
266
+ prefix: "/api",
267
+ allow: ["product"],
268
+ });
269
+
270
+ app.listen({ port: 3000 });
271
+ ```
272
+
273
+ ## Advanced Usage
274
+
275
+ ### Custom Middleware
276
+
277
+ Add authentication before omni-rest routes:
278
+
279
+ ```typescript
280
+ app.use("/api", authenticate, expressAdapter(prisma));
281
+
282
+ function authenticate(req, res, next) {
283
+ const token = req.headers.authorization?.split(" ")[1];
284
+ if (!token) return res.status(401).json({ error: "Unauthorized" });
285
+ req.user = verifyToken(token);
286
+ next();
287
+ }
288
+ ```
289
+
290
+ ### Model Filtering
291
+
292
+ Only expose certain models:
293
+
294
+ ```typescript
295
+ expressAdapter(prisma, {
296
+ allow: ["product", "category"], // Only these
297
+ });
298
+ ```
299
+
300
+ ### Pagination Limits
301
+
302
+ Control default and maximum pagination:
303
+
304
+ ```typescript
305
+ expressAdapter(prisma, {
306
+ defaultLimit: 20, // Default page size
307
+ maxLimit: 100, // Maximum allowed
308
+ });
309
+ ```
310
+
311
+ ### Lifecycle Hooks
312
+
313
+ Run code before/after operations:
314
+
315
+ ```typescript
316
+ expressAdapter(prisma, {
317
+ beforeOperation: async ({ model, method, id, body }) => {
318
+ // Log, validate, audit trail
319
+ },
320
+
321
+ afterOperation: async ({ model, method, result }) => {
322
+ // Webhook, cache invalidation, events
323
+ },
324
+ });
325
+ ```
326
+
327
+ Full Configuration: [docs/CONFIGURATION.md](docs/CONFIGURATION.md)
328
+
329
+ ## CLI
330
+
331
+ omni-rest includes a CLI for schema introspection:
332
+
333
+ ```bash
334
+ # Introspect your Prisma schema
335
+ npx omni-rest introspect
336
+
337
+ # Generate all endpoints
338
+ npx omni-rest generate
339
+
340
+ # Validate configuration
341
+ npx omni-rest validate
342
+ ```
343
+
344
+ ## How It Works
345
+
346
+ 1. **Schema Introspection** - Reads your Prisma schema using Prisma._runtimeDataModel
347
+ 2. **Route Generation** - Creates REST routes based on your models and fields
348
+ 3. **Query Building** - Parses URL parameters to build Prisma queries
349
+ 4. **Execute** - Runs queries through your PrismaClient instance
350
+ 5. **Response Formatting** - Returns standardized JSON responses
351
+
352
+ ## Type Safety
353
+
354
+ Full TypeScript support with automatically generated types:
355
+
356
+ ```typescript
357
+ import type {
358
+ RouterInstance,
359
+ PrismaRestOptions,
360
+ HandlerResult,
361
+ } from "omni-rest";
362
+ ```
363
+
364
+ ## Performance Considerations
365
+
366
+ - **Pagination defaults** - Set reasonable defaults with defaultLimit and maxLimit
367
+ - **Database indexes** - Create indexes on frequently filtered fields
368
+ - **Query optimization** - Use select and include in hooks to limit data
369
+ - **Caching** - Implement caching with afterOperation hooks
370
+
371
+ ## Security Best Practices
372
+
373
+ ✅ **Always use guards** for sensitive operations (DELETE, POST)
374
+ ✅ **Validate user permissions** in guards before allowing operations
375
+ ✅ **Enable audit logging** with beforeOperation/afterOperation hooks
376
+ ✅ **Use allow list** to expose only necessary models
377
+ ✅ **Implement authentication** middleware before mounting adapter
378
+ ✅ **Set reasonable pagination limits** to prevent abuse
379
+
380
+ Example secure setup:
381
+
382
+ ```typescript
383
+ expressAdapter(prisma, {
384
+ allow: ["product"], // Only expose needed models
385
+
386
+ guards: {
387
+ product: {
388
+ POST: async () => !isAdmin() ? "Admin only" : undefined,
389
+ DELETE: async () => !isAdmin() ? "Admin only" : undefined,
390
+ },
391
+ },
392
+
393
+ beforeOperation: async ({ model, method, user }) => {
394
+ logAuditTrail({ model, method, userId: user.id });
395
+ },
396
+ });
397
+ ```
398
+
399
+ ## Troubleshooting
400
+
401
+ ### "Cannot find module" errors
402
+
403
+ Ensure all dependencies are installed:
404
+
405
+ ```bash
406
+ npm install @prisma/client express swagger-ui-express
407
+ ```
408
+
409
+ ### CORS Issues
410
+
411
+ Add CORS middleware before mounting adapter:
412
+
413
+ ```typescript
414
+ import cors from "cors";
415
+ app.use(cors());
416
+ app.use("/api", expressAdapter(prisma));
417
+ ```
418
+
419
+ ### TypeScript Errors
420
+
421
+ Ensure you have proper types installed:
422
+
423
+ ```bash
424
+ npm install -D @types/express @types/node typescript
425
+ ```
426
+
427
+ ### Prisma Version Compatibility
428
+
429
+ omni-rest supports Prisma 4.0+. For best compatibility, use Prisma 5.0+:
430
+
431
+ ```bash
432
+ npm install @prisma/client@^5.0.0
433
+ ```
434
+
435
+ ## Contributing
436
+
437
+ Found a bug? Have a feature idea? Contributions welcome!
438
+
439
+ [Contributing Guide](docs/CONTRIBUTING.md)
440
+
441
+ ### Running Tests
442
+
443
+ ```bash
444
+ npm test # Run all tests
445
+ npm run test:watch # Watch mode
446
+ npm run build # Build distribution
447
+ ```
448
+
449
+ ## Roadmap
450
+
451
+ - [ ] GraphQL schema export
452
+ - [ ] Real-time subscriptions
453
+ - [ ] Webhook system
454
+ - [ ] Rate limiting middleware
455
+ - [ ] Additional framework support (Koa, Nest.js)
456
+ - [ ] Caching layer
457
+ - [ ] API versioning
458
+
459
+ ## License
460
+
461
+ MIT © [Omni Rest Contributors](LICENSE)
462
+
463
+ ## Support
464
+
465
+ - 📖 [Documentation](docs/)
466
+ - 🙋 [GitHub Discussions](https://github.com/omni-rest/omni-rest/discussions)
467
+ - 🐛 [Report Issues](https://github.com/omni-rest/omni-rest/issues)
468
+ - 💬 [Chat on Discord](https://discord.gg/omni-rest)
469
+
470
+ ## Acknowledgments
471
+
472
+ Inspired by PostgREST and built for the modern JavaScript/TypeScript ecosystem.
473
+
474
+ ---
475
+
476
+ **Made with ❤️ by the Omni Rest community**
@@ -0,0 +1,34 @@
1
+ import { PrismaClient } from '@prisma/client';
2
+ import { P as PrismaRestOptions } from '../types-CzjpYtyN.mjs';
3
+
4
+ /**
5
+ * Express adapter for omni-rest.
6
+ *
7
+ * @example
8
+ * ```ts
9
+ * import express from "express";
10
+ * import { PrismaClient } from "@prisma/client";
11
+ * import { expressAdapter } from "omni-rest/express";
12
+ *
13
+ * const app = express();
14
+ * const prisma = new PrismaClient();
15
+ *
16
+ * app.use(express.json());
17
+ * app.use("/api", expressAdapter(prisma, {
18
+ * allow: ["department", "category", "city"],
19
+ * }));
20
+ *
21
+ * // Auto-generates:
22
+ * // GET /api/department
23
+ * // POST /api/department
24
+ * // GET /api/department/:id
25
+ * // PUT /api/department/:id
26
+ * // PATCH /api/department/:id
27
+ * // DELETE /api/department/:id
28
+ * // PATCH /api/department/bulk/update
29
+ * // DELETE /api/department/bulk/delete
30
+ * ```
31
+ */
32
+ declare function expressAdapter(prisma: PrismaClient, options?: PrismaRestOptions): any;
33
+
34
+ export { expressAdapter };
@@ -0,0 +1,34 @@
1
+ import { PrismaClient } from '@prisma/client';
2
+ import { P as PrismaRestOptions } from '../types-CzjpYtyN.js';
3
+
4
+ /**
5
+ * Express adapter for omni-rest.
6
+ *
7
+ * @example
8
+ * ```ts
9
+ * import express from "express";
10
+ * import { PrismaClient } from "@prisma/client";
11
+ * import { expressAdapter } from "omni-rest/express";
12
+ *
13
+ * const app = express();
14
+ * const prisma = new PrismaClient();
15
+ *
16
+ * app.use(express.json());
17
+ * app.use("/api", expressAdapter(prisma, {
18
+ * allow: ["department", "category", "city"],
19
+ * }));
20
+ *
21
+ * // Auto-generates:
22
+ * // GET /api/department
23
+ * // POST /api/department
24
+ * // GET /api/department/:id
25
+ * // PUT /api/department/:id
26
+ * // PATCH /api/department/:id
27
+ * // DELETE /api/department/:id
28
+ * // PATCH /api/department/bulk/update
29
+ * // DELETE /api/department/bulk/delete
30
+ * ```
31
+ */
32
+ declare function expressAdapter(prisma: PrismaClient, options?: PrismaRestOptions): any;
33
+
34
+ export { expressAdapter };