postgresdk 0.6.17 → 0.7.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.
Files changed (4) hide show
  1. package/README.md +43 -869
  2. package/dist/cli.js +14 -292
  3. package/dist/index.js +14 -292
  4. package/package.json +1 -1
package/README.md CHANGED
@@ -1,135 +1,8 @@
1
1
  # postgresdk
2
2
 
3
- Turn your PostgreSQL database into a fully-typed, production-ready SDK in seconds.
4
-
5
- ## What You Get
6
-
7
- Start with your existing PostgreSQL database:
8
-
9
- ```sql
10
- CREATE TABLE authors (
11
- id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
12
- name TEXT NOT NULL,
13
- bio TEXT
14
- );
15
-
16
- CREATE TABLE books (
17
- id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
18
- title TEXT NOT NULL,
19
- author_id UUID REFERENCES authors(id),
20
- published_at TIMESTAMPTZ
21
- );
22
-
23
- CREATE TABLE tags (
24
- id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
25
- name TEXT UNIQUE NOT NULL
26
- );
27
-
28
- CREATE TABLE book_tags (
29
- book_id UUID REFERENCES books(id),
30
- tag_id UUID REFERENCES tags(id),
31
- PRIMARY KEY (book_id, tag_id)
32
- );
33
- ```
34
-
35
- Run one command:
36
-
37
- ```bash
38
- npx postgresdk generate
39
- ```
40
-
41
- Get a complete, type-safe SDK with:
42
-
43
- ### 🎯 Client SDK with Full TypeScript Support
44
-
45
- ```typescript
46
- import { SDK } from "./api/client";
47
-
48
- const sdk = new SDK({
49
- baseUrl: "http://localhost:3000",
50
- auth: { apiKey: "your-key" } // Optional auth
51
- });
52
-
53
- // ✅ Fully typed - autocomplete everything!
54
- const author = await sdk.authors.create({
55
- name: "Jane Austen",
56
- bio: "English novelist known for social commentary"
57
- });
58
-
59
- // ✅ Type-safe relationships with eager loading
60
- const booksWithAuthor = await sdk.books.list({
61
- include: {
62
- author: true, // 1:N relationship
63
- tags: true // M:N relationship
64
- }
65
- });
66
-
67
- // ✅ Complex nested queries
68
- const authorsWithEverything = await sdk.authors.list({
69
- include: {
70
- books: {
71
- include: {
72
- tags: true
73
- }
74
- }
75
- }
76
- });
77
-
78
- // ✅ Built-in pagination & filtering
79
- const recentBooks = await sdk.books.list({
80
- where: { published_at: { gte: "2024-01-01" } },
81
- orderBy: "published_at",
82
- order: "desc",
83
- limit: 10
84
- });
85
- ```
3
+ > ⚠️ **Active Development**: This project is under active development and is not yet stable for production use. APIs and features may change without notice.
86
4
 
87
- ### 🚀 Production-Ready REST API
88
-
89
- ```typescript
90
- import { Hono } from "hono";
91
- import { Client } from "pg";
92
- import { createRouter } from "./api/server/router";
93
-
94
- const app = new Hono();
95
- const pg = new Client({ connectionString: process.env.DATABASE_URL });
96
- await pg.connect();
97
-
98
- // That's it! Full REST API with:
99
- // - Input validation (Zod)
100
- // - Error handling
101
- // - Relationship loading
102
- // - Auth middleware (if configured)
103
- // - Type safety throughout
104
-
105
- const api = createRouter({ pg });
106
- app.route("/", api);
107
-
108
- // GET /v1/authors
109
- // POST /v1/authors
110
- // GET /v1/authors/:id
111
- // PATCH /v1/authors/:id
112
- // DELETE /v1/authors/:id
113
- // POST /v1/authors/list (with filtering & includes)
114
- ```
115
-
116
- ### 🔒 Type Safety Everywhere
117
-
118
- ```typescript
119
- // TypeScript catches errors at compile time
120
- const book = await sdk.books.create({
121
- title: "Pride and Prejudice",
122
- author_id: "not-a-uuid", // ❌ Type error!
123
- published_at: "invalid-date" // ❌ Type error!
124
- });
125
-
126
- // Generated Zod schemas for runtime validation
127
- import { InsertBooksSchema } from "./api/server/zod/books";
128
-
129
- const validated = InsertBooksSchema.parse(requestBody);
130
- ```
131
-
132
- All from your existing database schema. No manual coding required.
5
+ Generate a typed server/client SDK from your PostgreSQL database schema.
133
6
 
134
7
  ## Features
135
8
 
@@ -137,11 +10,9 @@ All from your existing database schema. No manual coding required.
137
10
  - 🔒 **Type Safety** - Full TypeScript types derived from your database schema
138
11
  - ✅ **Runtime Validation** - Zod schemas for request/response validation
139
12
  - 🔗 **Smart Relationships** - Automatic handling of 1:N and M:N relationships with eager loading
140
- - 🔐 **Built-in Auth** - API key and JWT authentication with zero configuration
13
+ - 🔐 **Built-in Auth** - API key and JWT authentication
141
14
  - 🎯 **Zero Config** - Works out of the box with sensible defaults
142
- - 🏗️ **Framework Ready** - Server routes for Hono (Express & Fastify coming soon), client SDK works anywhere
143
- - 📦 **Lightweight** - Minimal dependencies, optimized bundle size with shared BaseClient
144
- - 🔄 **SDK Distribution** - Built-in SDK bundling and pull mechanism for easy client distribution
15
+ - 📦 **Lightweight** - Minimal dependencies, optimized bundle size
145
16
 
146
17
  ## Installation
147
18
 
@@ -182,13 +53,14 @@ postgresdk generate
182
53
  // Server (Hono)
183
54
  import { Hono } from "hono";
184
55
  import { Client } from "pg";
185
- import { registerUsersRoutes } from "./api/server/routes/users";
56
+ import { createRouter } from "./api/server/router";
186
57
 
187
58
  const app = new Hono();
188
59
  const pg = new Client({ connectionString: "..." });
189
60
  await pg.connect();
190
61
 
191
- registerUsersRoutes(app, { pg });
62
+ const api = createRouter({ pg });
63
+ app.route("/", api);
192
64
 
193
65
  // Client
194
66
  import { SDK } from "./api/client";
@@ -218,56 +90,26 @@ export default {
218
90
  softDeleteColumn: null, // Column name for soft deletes (e.g., "deleted_at")
219
91
  includeDepthLimit: 3, // Max depth for nested includes
220
92
  dateType: "date", // "date" | "string" - How to handle timestamps
221
- serverFramework: "hono", // "hono" | "express" | "fastify" (currently only hono)
93
+ serverFramework: "hono", // Currently only hono is supported
222
94
  useJsExtensions: false, // Add .js to imports (for Vercel Edge, Deno)
223
95
 
224
- // Authentication (optional) - simplified syntax
96
+ // Authentication (optional)
225
97
  auth: {
226
98
  apiKey: process.env.API_KEY, // Simple API key auth
227
99
  // OR
228
100
  jwt: process.env.JWT_SECRET, // Simple JWT auth
229
- // OR full syntax for advanced options:
230
- strategy: "none" | "api-key" | "jwt-hs256", // Default: "none"
231
- apiKeyHeader: "x-api-key", // Custom header name
232
- apiKeys: ["key1", "key2"], // Multiple valid keys
233
- jwt: {
234
- sharedSecret: "your-secret", // Shared secret for HS256
235
- issuer: "your-app", // Optional: validate issuer claim
236
- audience: "your-audience" // Optional: validate audience claim
237
- }
238
- }
239
- };
240
- ```
241
-
242
- Environment variables work directly in the config file - no function wrapper needed. postgresdk automatically loads `.env` files using dotenv.
243
-
244
- ### Environment Variables
245
-
246
- postgresdk automatically loads environment variables from `.env` files in your project root. You can use them directly in your config:
247
-
248
- ```bash
249
- # .env
250
- DATABASE_URL=postgres://user:pass@localhost:5432/mydb
251
- JWT_SECRET=my-super-secret-key
252
- API_KEYS=key1,key2,key3
253
- ```
254
-
255
- ```typescript
256
- // postgresdk.config.ts
257
- export default {
258
- connectionString: process.env.DATABASE_URL,
259
- auth: {
260
- strategy: "jwt-hs256",
261
- jwt: {
262
- sharedSecret: process.env.JWT_SECRET,
263
- }
101
+ },
102
+
103
+ // Test generation (optional)
104
+ tests: {
105
+ generate: true, // Generate test files
106
+ output: "./api/tests", // Test output directory
107
+ framework: "vitest" // vitest, jest, or bun
264
108
  }
265
109
  };
266
110
  ```
267
111
 
268
- No additional setup required - dotenv is automatically configured before loading your config file.
269
-
270
- ## Generated SDK Features
112
+ ## Generated SDK Usage
271
113
 
272
114
  ### CRUD Operations
273
115
 
@@ -327,59 +169,18 @@ const users = await sdk.users.list({
327
169
  });
328
170
  ```
329
171
 
330
- ### Type Safety
331
-
332
- All operations are fully typed based on your database schema:
333
-
334
- ```typescript
335
- // TypeScript will enforce correct types
336
- const user = await sdk.users.create({
337
- name: "Alice", // ✅ string required
338
- email: "alice@...", // ✅ string required
339
- age: "30" // ❌ Type error: should be number
340
- });
341
- ```
342
-
343
172
  ## Authentication
344
173
 
345
- postgresdk supports three authentication strategies out of the box:
346
-
347
- ### No Authentication (Default)
348
-
349
- ```typescript
350
- // postgresdk.config.ts
351
- export default {
352
- connectionString: "...",
353
- // No auth config needed - routes are unprotected
354
- };
355
- ```
174
+ postgresdk supports API key and JWT authentication:
356
175
 
357
176
  ### API Key Authentication
358
177
 
359
178
  ```typescript
360
- // postgresdk.config.ts - Simple syntax (recommended)
361
- export default {
362
- connectionString: "...",
363
- auth: {
364
- apiKey: process.env.API_KEY // Single key shorthand
365
- }
366
- };
367
-
368
- // Or multiple keys
369
- export default {
370
- connectionString: "...",
371
- auth: {
372
- apiKeys: [process.env.API_KEY_1, process.env.API_KEY_2]
373
- }
374
- };
375
-
376
- // Full syntax with custom header (optional)
179
+ // postgresdk.config.ts
377
180
  export default {
378
181
  connectionString: "...",
379
182
  auth: {
380
- strategy: "api-key",
381
- apiKeyHeader: "x-custom-key", // Default: "x-api-key"
382
- apiKeys: ["key1", "key2"]
183
+ apiKey: process.env.API_KEY
383
184
  }
384
185
  };
385
186
 
@@ -393,235 +194,50 @@ const sdk = new SDK({
393
194
  ### JWT Authentication (HS256)
394
195
 
395
196
  ```typescript
396
- // postgresdk.config.ts - Simple syntax (recommended)
397
- export default {
398
- connectionString: "...",
399
- auth: {
400
- jwt: process.env.JWT_SECRET // Shared secret shorthand
401
- }
402
- };
403
-
404
- // Full syntax with issuer/audience validation (optional)
197
+ // postgresdk.config.ts
405
198
  export default {
406
199
  connectionString: "...",
407
200
  auth: {
408
- strategy: "jwt-hs256",
409
- jwt: {
410
- sharedSecret: process.env.JWT_SECRET,
411
- issuer: "my-app", // Optional: validates 'iss' claim
412
- audience: "my-users" // Optional: validates 'aud' claim
413
- }
201
+ jwt: process.env.JWT_SECRET
414
202
  }
415
203
  };
416
204
 
417
- // Client SDK usage with static token
205
+ // Client SDK usage
418
206
  const sdk = new SDK({
419
207
  baseUrl: "http://localhost:3000",
420
208
  auth: { jwt: "eyJhbGciOiJIUzI1NiIs..." }
421
209
  });
422
-
423
- // Or with dynamic token provider
424
- const sdk = new SDK({
425
- baseUrl: "http://localhost:3000",
426
- auth: {
427
- jwt: async () => {
428
- // Refresh token if needed
429
- return await getAccessToken();
430
- }
431
- }
432
- });
433
-
434
- // Or with custom auth headers
435
- const sdk = new SDK({
436
- baseUrl: "http://localhost:3000",
437
- auth: async () => ({
438
- "Authorization": `Bearer ${await getToken()}`,
439
- "X-Tenant-ID": "tenant-123"
440
- })
441
- });
442
- ```
443
-
444
- ### Environment Variables in Auth Config
445
-
446
- The auth configuration supports environment variables with the `env:` prefix:
447
-
448
- ```typescript
449
- export default {
450
- auth: {
451
- strategy: "api-key",
452
- apiKeys: ["env:API_KEYS"], // Reads from process.env.API_KEYS
453
-
454
- // Or for JWT
455
- strategy: "jwt-hs256",
456
- jwt: {
457
- sharedSecret: "env:JWT_SECRET" // Reads from process.env.JWT_SECRET
458
- }
459
- }
460
- };
461
- ```
462
-
463
- ### How Auth Works
464
-
465
- When authentication is configured:
466
-
467
- 1. **Server Side**: All generated routes are automatically protected with the configured auth middleware
468
- 2. **Client Side**: The SDK handles auth headers transparently
469
- 3. **Type Safety**: Auth configuration is fully typed
470
- 4. **Zero Overhead**: When `strategy: "none"`, no auth code is included
471
-
472
- ### JWT Token Generation Example
473
-
474
- ```typescript
475
- // Install jose for JWT generation: npm install jose
476
- import { SignJWT } from 'jose';
477
-
478
- const secret = new TextEncoder().encode('your-secret-key');
479
-
480
- const token = await new SignJWT({
481
- sub: 'user123',
482
- email: 'user@example.com',
483
- roles: ['admin']
484
- })
485
- .setProtectedHeader({ alg: 'HS256' })
486
- .setIssuer('my-app')
487
- .setAudience('my-users')
488
- .setExpirationTime('2h')
489
- .sign(secret);
490
-
491
- // Use with SDK
492
- const sdk = new SDK({
493
- baseUrl: "http://localhost:3000",
494
- auth: { jwt: token }
495
- });
496
210
  ```
497
211
 
498
212
  ## Database Drivers
499
213
 
500
- The generated code works with any PostgreSQL client that implements a simple `query` interface. You can use the standard `pg` driver, Neon's serverless driver, or any other compatible client.
214
+ The generated code works with any PostgreSQL client that implements a simple `query` interface:
501
215
 
502
216
  ### Node.js `pg` Driver
503
217
 
504
- The standard PostgreSQL driver for Node.js environments. Works everywhere Node.js runs.
505
-
506
- Server setup:
507
218
  ```typescript
508
- import { Hono } from "hono";
509
219
  import { Client } from "pg";
510
220
  import { createRouter } from "./api/server/router";
511
221
 
512
- const app = new Hono();
513
-
514
- // Standard pg client
515
222
  const pg = new Client({ connectionString: process.env.DATABASE_URL });
516
223
  await pg.connect();
517
224
 
518
- // Wire up the generated routes
519
225
  const apiRouter = createRouter({ pg });
520
- app.route("/", apiRouter);
521
226
  ```
522
227
 
523
228
  ### Neon Serverless Driver (Edge-Compatible)
524
229
 
525
- For edge environments like Vercel Edge Functions or Cloudflare Workers. Uses HTTP/WebSocket instead of TCP connections.
526
-
527
- Configuration for Vercel Edge:
528
230
  ```typescript
529
- // postgresdk.config.ts
530
- export default {
531
- connectionString: process.env.DATABASE_URL,
532
- serverFramework: "hono", // Hono is edge-compatible
533
- useJsExtensions: true, // Required for Vercel Edge
534
- dateType: "string", // Better for JSON serialization
535
- auth: { apiKey: process.env.API_KEY }
536
- };
537
- ```
538
-
539
- Server setup:
540
- ```typescript
541
- import { Hono } from "hono";
542
231
  import { Pool } from "@neondatabase/serverless";
543
232
  import { createRouter } from "./api/server/router";
544
233
 
545
- const app = new Hono();
546
-
547
- // Neon's Pool is compatible with node-postgres
548
- const pool = new Pool({ connectionString: process.env.DATABASE_URL! });
549
-
550
- // Wire up the generated routes (Pool has the same query interface)
551
- const apiRouter = createRouter({ pg: pool });
552
- app.route("/", apiRouter);
553
-
554
- // Deploy to Vercel Edge
555
- export const config = { runtime: 'edge' };
556
- export default app;
557
- ```
558
-
559
- ### Which Driver Should I Use?
560
-
561
- - **Use `pg` (default) when:**
562
- - Running on traditional Node.js servers
563
- - Using Docker, VPS, or dedicated hosting
564
- - Need connection pooling or advanced PostgreSQL features
565
- - Running on AWS Lambda, Google Cloud Functions (with Node.js runtime)
566
-
567
- - **Use `neon` when:**
568
- - Deploying to Vercel Edge Functions
569
- - Deploying to Cloudflare Workers
570
- - Need globally distributed edge computing
571
- - Want to avoid TCP connection overhead
572
- - Using Neon as your PostgreSQL provider
573
-
574
- ### Connection Pooling with `pg`
575
-
576
- For production Node.js deployments, use connection pooling:
577
-
578
- ```typescript
579
- import { Pool } from "pg";
580
- import { createRouter } from "./api/server/router";
581
-
582
- const pool = new Pool({
583
- connectionString: process.env.DATABASE_URL,
584
- max: 20,
585
- idleTimeoutMillis: 30000,
586
- connectionTimeoutMillis: 2000,
587
- });
588
-
589
- // The generated routes work with both Client and Pool
234
+ const pool = new Pool({ connectionString: process.env.DATABASE_URL });
590
235
  const apiRouter = createRouter({ pg: pool });
591
236
  ```
592
237
 
593
- ### Custom Database Adapters
594
-
595
- You can use any database client as long as it matches the expected interface:
596
-
597
- ```typescript
598
- // Any client that implements this interface works
599
- interface DatabaseAdapter {
600
- query(text: string, params?: any[]): Promise<{ rows: any[] }>;
601
- }
602
-
603
- // Both pg and @neondatabase/serverless Pool/Client implement this interface natively
604
- // For other ORMs, you may need to create an adapter:
605
-
606
- // Example with a hypothetical ORM that doesn't match the interface
607
- const customClient = new SomeORM();
608
- const pg = {
609
- async query(text: string, params?: any[]) {
610
- const result = await customClient.raw(text, params);
611
- return { rows: result };
612
- }
613
- };
614
-
615
- const apiRouter = createRouter({ pg });
616
- ```
617
-
618
- ## Server Integration with Hono
238
+ ## Server Integration
619
239
 
620
- The generated code integrates seamlessly with [Hono](https://hono.dev/), a lightweight web framework for the Edge.
621
-
622
- ### Basic Setup
623
-
624
- postgresdk generates a `createRouter` function that returns a Hono router with all your routes:
240
+ postgresdk generates Hono-compatible routes:
625
241
 
626
242
  ```typescript
627
243
  import { Hono } from "hono";
@@ -635,303 +251,27 @@ const app = new Hono();
635
251
  const pg = new Client({ connectionString: process.env.DATABASE_URL });
636
252
  await pg.connect();
637
253
 
638
- // Mount all generated routes at once
254
+ // Mount all generated routes
639
255
  const apiRouter = createRouter({ pg });
640
256
  app.route("/", apiRouter);
641
257
 
642
258
  // Start server
643
259
  serve({ fetch: app.fetch, port: 3000 });
644
- console.log("Server running on http://localhost:3000");
645
- ```
646
-
647
- ### Mounting Routes at Different Paths
648
-
649
- The `createRouter` function returns a Hono router that can be mounted anywhere:
650
-
651
- ```typescript
652
- import { Hono } from "hono";
653
- import { createRouter } from "./api/server/router";
654
-
655
- const app = new Hono();
656
-
657
- // Your existing routes
658
- app.get("/", (c) => c.json({ message: "Welcome" }));
659
- app.get("/health", (c) => c.json({ status: "ok" }));
660
-
661
- // Mount generated routes under /api
662
- const apiRouter = createRouter({ pg });
663
- app.route("/api", apiRouter); // Routes will be at /api/v1/users, /api/v1/posts, etc.
664
-
665
- // Or mount under different version
666
- app.route("/v2", apiRouter); // Routes will be at /v2/v1/users, /v2/v1/posts, etc.
667
- ```
668
-
669
- ### Alternative: Register Routes Directly
670
-
671
- If you prefer to register routes directly on your app without a sub-router:
672
-
673
- ```typescript
674
- import { registerAllRoutes } from "./api/server/router";
675
-
676
- const app = new Hono();
677
- const pg = new Client({ connectionString: process.env.DATABASE_URL });
678
- await pg.connect();
679
-
680
- // Register all routes directly on app
681
- registerAllRoutes(app, { pg });
682
- ```
683
-
684
- ### Selective Route Registration
685
-
686
- You can also import and register individual routes:
687
-
688
- ```typescript
689
- import { registerUsersRoutes, registerPostsRoutes } from "./api/server/router";
690
-
691
- const app = new Hono();
692
-
693
- // Only register specific routes
694
- registerUsersRoutes(app, { pg });
695
- registerPostsRoutes(app, { pg });
696
-
697
- ### Adding to an Existing Hono App
698
-
699
- ```typescript
700
- import { Hono } from "hono";
701
- import { cors } from "hono/cors";
702
- import { logger } from "hono/logger";
703
-
704
- // Your existing Hono app
705
- const app = new Hono();
706
-
707
- // Your existing middleware
708
- app.use("*", cors());
709
- app.use("*", logger());
710
-
711
- // Your existing routes
712
- app.get("/", (c) => c.json({ message: "Hello World" }));
713
- app.get("/health", (c) => c.json({ status: "ok" }));
714
-
715
- // Add postgresdk generated routes
716
- const pg = new Client({ connectionString: process.env.DATABASE_URL });
717
- await pg.connect();
718
-
719
- // All generated routes are prefixed with /v1 by default
720
- import { registerUsersRoutes } from "./api/server/routes/users";
721
- import { registerPostsRoutes } from "./api/server/routes/posts";
722
-
723
- registerUsersRoutes(app, { pg }); // Adds /v1/users/*
724
- registerPostsRoutes(app, { pg }); // Adds /v1/posts/*
725
-
726
- // Your routes continue to work alongside generated ones
727
- app.get("/custom", (c) => c.json({ custom: true }));
728
- ```
729
-
730
- ### With Error Handling & Logging
731
-
732
- ```typescript
733
- import { Hono } from "hono";
734
- import { HTTPException } from "hono/http-exception";
735
-
736
- const app = new Hono();
737
-
738
- // Global error handling
739
- app.onError((err, c) => {
740
- if (err instanceof HTTPException) {
741
- return err.getResponse();
742
- }
743
- console.error("Unhandled error:", err);
744
- return c.json({ error: "Internal Server Error" }, 500);
745
- });
746
-
747
- // Request logging middleware
748
- app.use("*", async (c, next) => {
749
- const start = Date.now();
750
- await next();
751
- const ms = Date.now() - start;
752
- console.log(`${c.req.method} ${c.req.path} - ${c.res.status} ${ms}ms`);
753
- });
754
-
755
- // Register generated routes with database
756
- const pg = new Client({ connectionString: process.env.DATABASE_URL });
757
- await pg.connect();
758
-
759
- import { registerUsersRoutes } from "./api/server/routes/users";
760
- registerUsersRoutes(app, { pg });
761
- ```
762
-
763
- ### With Database Connection Pooling
764
-
765
- For production, use connection pooling:
766
-
767
- ```typescript
768
- import { Pool } from "pg";
769
- import { Hono } from "hono";
770
-
771
- // Use a connection pool instead of a single client
772
- const pool = new Pool({
773
- connectionString: process.env.DATABASE_URL,
774
- max: 20, // Maximum number of clients in the pool
775
- idleTimeoutMillis: 30000,
776
- connectionTimeoutMillis: 2000,
777
- });
778
-
779
- const app = new Hono();
780
-
781
- // The generated routes work with both Client and Pool
782
- import { registerUsersRoutes } from "./api/server/routes/users";
783
- import { registerPostsRoutes } from "./api/server/routes/posts";
784
-
785
- registerUsersRoutes(app, { pg: pool });
786
- registerPostsRoutes(app, { pg: pool });
787
-
788
- // Graceful shutdown
789
- process.on("SIGTERM", async () => {
790
- await pool.end();
791
- process.exit(0);
792
- });
793
- ```
794
-
795
- ### With Different Deployment Targets
796
-
797
- ```typescript
798
- // For Node.js
799
- import { serve } from "@hono/node-server";
800
- serve({ fetch: app.fetch, port: 3000 });
801
-
802
- // For Cloudflare Workers
803
- export default app;
804
-
805
- // For Vercel
806
- import { handle } from "@hono/vercel";
807
- export default handle(app);
808
-
809
- // For AWS Lambda
810
- import { handle } from "@hono/aws-lambda";
811
- export const handler = handle(app);
812
-
813
- // For Deno
814
- Deno.serve(app.fetch);
815
-
816
- // For Bun
817
- export default {
818
- port: 3000,
819
- fetch: app.fetch,
820
- };
821
- ```
822
-
823
- ### Complete Production Example
824
-
825
- ```typescript
826
- import { Hono } from "hono";
827
- import { cors } from "hono/cors";
828
- import { compress } from "hono/compress";
829
- import { secureHeaders } from "hono/secure-headers";
830
- import { serve } from "@hono/node-server";
831
- import { Pool } from "pg";
832
-
833
- // Import all generated route registrations
834
- import { registerUsersRoutes } from "./api/server/routes/users";
835
- import { registerPostsRoutes } from "./api/server/routes/posts";
836
- import { registerCommentsRoutes } from "./api/server/routes/comments";
837
-
838
- // Create app with type safety
839
- const app = new Hono();
840
-
841
- // Production middleware stack
842
- app.use("*", cors({
843
- origin: process.env.ALLOWED_ORIGINS?.split(",") || "*",
844
- credentials: true,
845
- }));
846
- app.use("*", compress());
847
- app.use("*", secureHeaders());
848
-
849
- // Health check
850
- app.get("/health", (c) => c.json({
851
- status: "ok",
852
- timestamp: new Date().toISOString()
853
- }));
854
-
855
- // Database connection pool
856
- const pool = new Pool({
857
- connectionString: process.env.DATABASE_URL,
858
- ssl: process.env.NODE_ENV === "production" ? { rejectUnauthorized: false } : false,
859
- max: 20,
860
- });
861
-
862
- // Register all generated routes
863
- registerUsersRoutes(app, { pg: pool });
864
- registerPostsRoutes(app, { pg: pool });
865
- registerCommentsRoutes(app, { pg: pool });
866
-
867
- // 404 handler
868
- app.notFound((c) => c.json({ error: "Not Found" }, 404));
869
-
870
- // Global error handler
871
- app.onError((err, c) => {
872
- console.error(`Error ${c.req.method} ${c.req.path}:`, err);
873
- return c.json({
874
- error: process.env.NODE_ENV === "production"
875
- ? "Internal Server Error"
876
- : err.message
877
- }, 500);
878
- });
879
-
880
- // Start server
881
- const port = parseInt(process.env.PORT || "3000");
882
- serve({
883
- fetch: app.fetch,
884
- port,
885
- hostname: "0.0.0.0"
886
- });
887
-
888
- console.log(`Server running on http://localhost:${port}`);
889
- console.log(`Environment: ${process.env.NODE_ENV || "development"}`);
890
-
891
- // Graceful shutdown
892
- process.on("SIGTERM", async () => {
893
- console.log("SIGTERM received, closing connections...");
894
- await pool.end();
895
- process.exit(0);
896
- });
897
260
  ```
898
261
 
899
262
  ## SDK Distribution
900
263
 
901
- postgresdk makes it easy to distribute your generated SDK to client applications. When you generate your SDK, it's automatically bundled and served through your API, allowing client apps to pull the latest SDK directly.
902
-
903
- ### Publishing Your SDK
904
-
905
- When you run `postgresdk generate`, the SDK is automatically:
906
- 1. Generated as TypeScript files for both server and client
907
- 2. Bundled and made available through API endpoints
908
- 3. Ready to be pulled by client applications
909
-
910
- Your API automatically serves the SDK at these endpoints:
911
- - `GET /sdk/manifest` - SDK metadata and file list
912
- - `GET /sdk/download` - Download all SDK files as JSON
913
- - `GET /sdk/files/:path` - Download individual SDK files
914
-
915
- ### Pulling the SDK in Client Apps
916
-
917
- Client applications can pull your SDK using the `postgresdk pull` command:
264
+ Your generated SDK can be pulled by client applications:
918
265
 
919
266
  ```bash
920
- # Install postgresdk in your client app
921
- npm install -D postgresdk
922
-
923
- # Pull the SDK from your API
267
+ # In your client app
924
268
  postgresdk pull --from=https://api.myapp.com --output=./src/sdk
925
-
926
- # Or with authentication
927
- postgresdk pull --from=https://api.myapp.com --output=./src/sdk --token=your-token
928
269
  ```
929
270
 
930
- ### Configuration-based Pull
931
-
932
- Create a `postgresdk.config.ts` in your client app:
271
+ Or with configuration:
933
272
 
934
273
  ```typescript
274
+ // postgresdk.config.ts in client app
935
275
  export default {
936
276
  pull: {
937
277
  from: "https://api.myapp.com",
@@ -941,127 +281,26 @@ export default {
941
281
  };
942
282
  ```
943
283
 
944
- Then simply run:
945
- ```bash
946
- postgresdk pull
947
- ```
948
-
949
- ### Automated SDK Updates
950
-
951
- You can automate SDK updates in your client app's build process:
952
-
953
- ```json
954
- // package.json
955
- {
956
- "scripts": {
957
- "prebuild": "postgresdk pull",
958
- "build": "tsc"
959
- }
960
- }
961
- ```
962
-
963
- ### SDK Versioning
964
-
965
- The pulled SDK includes metadata about when it was generated and from where:
966
-
967
- ```typescript
968
- // .postgresdk.json (auto-generated)
969
- {
970
- "version": "1.0.0",
971
- "generated": "2024-01-15T10:30:00Z",
972
- "pulledFrom": "https://api.myapp.com",
973
- "pulledAt": "2024-01-15T11:00:00Z"
974
- }
975
- ```
976
-
977
284
  ## Generated Tests
978
285
 
979
- postgresdk can generate basic SDK tests to help you get started quickly. These tests demonstrate CRUD operations for each table and include Docker setup for easy testing.
980
-
981
- ### Enabling Test Generation
982
-
983
- Add test configuration to your `postgresdk.config.ts`:
286
+ Enable test generation in your config:
984
287
 
985
288
  ```typescript
986
289
  export default {
987
290
  connectionString: process.env.DATABASE_URL,
988
-
989
291
  tests: {
990
- generate: true, // Enable test generation
991
- output: "./api/tests", // Output directory
992
- framework: "vitest" // Test framework (vitest, jest, or bun)
292
+ generate: true,
293
+ output: "./api/tests",
294
+ framework: "vitest"
993
295
  }
994
296
  };
995
297
  ```
996
298
 
997
- ### What Gets Generated
998
-
999
- When tests are enabled, postgresdk generates:
1000
-
1001
- 1. **Test files for each table** - Basic CRUD operation tests
1002
- 2. **setup.ts** - Common test utilities and helpers
1003
- 3. **docker-compose.yml** - PostgreSQL test database configuration
1004
- 4. **run-tests.sh** - Script to run tests with Docker
1005
-
1006
- ### Running Tests with Docker
1007
-
1008
- The generated test setup includes a Docker Compose file and a test runner script:
299
+ Run tests with the included Docker setup:
1009
300
 
1010
301
  ```bash
1011
- # 1. Make the test script executable (first time only)
1012
302
  chmod +x api/tests/run-tests.sh
1013
-
1014
- # 2. Edit api/tests/run-tests.sh to configure:
1015
- # - Your API server startup command
1016
- # - Migration commands (if needed)
1017
- # - Any other setup specific to your project
1018
-
1019
- # 3. Run the tests
1020
303
  ./api/tests/run-tests.sh
1021
-
1022
- # The script will:
1023
- # - Start a PostgreSQL 17 test database in Docker
1024
- # - Wait for it to be ready
1025
- # - Run your API server (once configured)
1026
- # - Execute the test suite
1027
- # - Provide cleanup instructions
1028
- ```
1029
-
1030
- The test script includes detailed comments and examples for common setups. You'll need to uncomment and customize the API server startup section for your specific project.
1031
-
1032
- ### Customizing Tests
1033
-
1034
- The generated tests are basic and meant as a starting point. Create your own test files for:
1035
-
1036
- - Business logic validation
1037
- - Complex query scenarios
1038
- - Edge cases and error handling
1039
- - Performance testing
1040
- - Integration workflows
1041
-
1042
- Example custom test:
1043
-
1044
- ```typescript
1045
- // tests/custom/user-workflow.test.ts
1046
- import { describe, it, expect } from 'vitest';
1047
- import { createTestSDK, randomEmail } from '../api/tests/setup';
1048
-
1049
- describe('User Registration Workflow', () => {
1050
- const sdk = createTestSDK();
1051
-
1052
- it('should handle complete registration flow', async () => {
1053
- // Your custom business logic tests
1054
- const user = await sdk.users.create({
1055
- email: randomEmail(),
1056
- name: 'Test User'
1057
- });
1058
-
1059
- // Verify welcome email was sent
1060
- // Check audit logs
1061
- // Validate permissions
1062
- // etc.
1063
- });
1064
- });
1065
304
  ```
1066
305
 
1067
306
  ## CLI Commands
@@ -1070,93 +309,28 @@ describe('User Registration Workflow', () => {
1070
309
  postgresdk <command> [options]
1071
310
 
1072
311
  Commands:
1073
- init Create a postgresdk.config.ts file with all options
312
+ init Create a postgresdk.config.ts file
1074
313
  generate Generate SDK from database
1075
314
  pull Pull SDK from API endpoint
1076
315
  version Show version
1077
316
  help Show help
1078
317
 
1079
- Init Options:
1080
- (no options) Creates postgresdk.config.ts in current directory
1081
-
1082
- Generate Options:
318
+ Options:
1083
319
  -c, --config <path> Path to config file (default: postgresdk.config.ts)
1084
320
 
1085
- Pull Options:
1086
- --from <url> API URL to pull SDK from
1087
- --output <path> Output directory (default: ./src/sdk)
1088
- --token <token> Authentication token
1089
- -c, --config <path> Path to config file with pull settings
1090
-
1091
321
  Examples:
1092
- postgresdk init # Create config file
1093
- postgresdk generate # Generate using default config
322
+ postgresdk init
323
+ postgresdk generate
1094
324
  postgresdk generate -c custom.config.ts
1095
325
  postgresdk pull --from=https://api.com --output=./src/sdk
1096
- postgresdk pull -c client.config.ts # Pull using config file
1097
326
  ```
1098
327
 
1099
- ## How It Works
1100
-
1101
- 1. **Introspection** - Connects to your PostgreSQL database and reads the schema
1102
- 2. **Relationship Detection** - Analyzes foreign keys to understand table relationships
1103
- 3. **Code Generation** - Generates TypeScript code for:
1104
- - Type definitions from table schemas
1105
- - Zod validation schemas
1106
- - REST API route handlers
1107
- - Client SDK with full typing
1108
- - Include/eager-loading system
1109
- 4. **Output** - Writes generated files to specified directories
1110
-
1111
328
  ## Requirements
1112
329
 
1113
- - Node.js 20+
330
+ - Node.js 18+
1114
331
  - PostgreSQL 12+
1115
332
  - TypeScript project (for using generated code)
1116
- - Optional: `jose` package for JWT authentication (auto-installed when using JWT auth)
1117
-
1118
- ## Development
1119
-
1120
- ```bash
1121
- # Clone the repository
1122
- git clone https://github.com/adpharm/postgresdk.git
1123
- cd postgresdk
1124
-
1125
- # Install dependencies
1126
- bun install
1127
-
1128
- # Run tests (starts PostgreSQL in Docker)
1129
- bun test
1130
-
1131
- # Build
1132
- bun run build
1133
-
1134
- # Publish new version
1135
- ./publish.sh
1136
- ```
1137
-
1138
- ## Testing
1139
-
1140
- The test suite automatically manages a PostgreSQL Docker container:
1141
-
1142
- ```bash
1143
- bun test
1144
- ```
1145
-
1146
- Tests cover:
1147
- - CRUD operations for all entities
1148
- - 1:N and M:N relationships
1149
- - Nested includes
1150
- - Validation and error handling
1151
333
 
1152
334
  ## License
1153
335
 
1154
- MIT
1155
-
1156
- ## Contributing
1157
-
1158
- Contributions are welcome! Please feel free to submit a Pull Request.
1159
-
1160
- ## Support
1161
-
1162
- For issues and feature requests, please [create an issue](https://github.com/adpharm/postgresdk/issues).
336
+ MIT