nitro-graphql 0.0.23 → 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/README.md CHANGED
@@ -1,60 +1,107 @@
1
- # Nitro GraphQL Yoga Module
1
+ # Nitro GraphQL
2
+
3
+ <div align="center">
4
+
5
+ [![npm version][npm-version-src]][npm-version-href]
6
+ [![npm downloads][npm-downloads-src]][npm-downloads-href]
7
+ [![bundle][bundle-src]][bundle-href]
8
+ [![License][license-src]][license-href]
9
+
10
+ **A standalone Nitro module that integrates GraphQL servers into any Nitro application with automatic type generation, file watching, and seamless framework integration.**
11
+
12
+ [🚀 Quick Start](#-quick-start) • [📖 Documentation](#-documentation) • [🎮 Playground](#-playground) • [💬 Community](#-community--contributing)
13
+
14
+ </div>
15
+
16
+ ---
2
17
 
3
18
  > [!NOTE]
4
19
  > This project is actively under development. We're always open to new ideas, different perspectives, and feature suggestions! If you have a suggestion, please first [open an issue](https://github.com/productdevbook/nitro-graphql/issues) to discuss it, then you can contribute with a PR.
5
20
 
6
- A standalone Nitro module that integrates GraphQL Yoga server into any Nitro application with automatic type generation and file watching.
21
+ ## Features
22
+
23
+ - 🚀 **Multi-Framework Support**: Works with GraphQL Yoga and Apollo Server
24
+ - 🔧 **Auto-Discovery**: Automatically scans and loads GraphQL schema and resolver files
25
+ - 📝 **Type Generation**: Automatic TypeScript type generation from GraphQL schemas (server & client)
26
+ - 🎮 **Apollo Sandbox**: Built-in GraphQL playground for development
27
+ - 🏥 **Health Check**: Built-in health check endpoint
28
+ - 🔌 **Universal Compatibility**: Works with any Nitro-based application (Nuxt, standalone Nitro, etc.)
29
+ - 🎯 **Zero Configuration**: Sensible defaults with optional customization
30
+ - 📂 **File-Based Organization**: Domain-driven resolver and schema organization
31
+ - 🔄 **Hot Reload**: Development mode with automatic schema and resolver updates
32
+ - 📦 **Optimized Bundling**: Smart chunking and dynamic imports for production
33
+ - 🌐 **Nuxt Integration**: First-class Nuxt.js support with dedicated module
7
34
 
8
- ## Features
35
+ ## 🚀 Quick Start
9
36
 
10
- - 🚀 Easy GraphQL server setup with GraphQL Yoga
11
- - 🔧 Auto-discovery of GraphQL schema and resolver files
12
- - 📝 Automatic TypeScript type generation from GraphQL schemas
13
- - 🎮 Apollo Sandbox integration (instead of GraphiQL)
14
- - 🏥 Built-in health check endpoint
15
- - 💾 Configurable cache headers for better performance
16
- - 🔌 Works with any Nitro-based application
17
- - 🎯 Zero-config with sensible defaults
18
- - 📂 File-based resolver organization
19
- - 🔄 Hot reload in development mode
20
- - 📦 Optimized bundle size with dynamic imports
21
- - 🏷️ Minimal logging with consistent tagging
37
+ ### Step 1: Installation
22
38
 
23
- ## Installation
39
+ Choose your preferred package manager:
24
40
 
25
41
  ```bash
42
+ # npm
26
43
  npm install nitro-graphql
27
- # or
44
+
45
+ # pnpm (recommended)
28
46
  pnpm add nitro-graphql
29
- # or
47
+
48
+ # yarn
30
49
  yarn add nitro-graphql
31
50
  ```
32
51
 
33
- ## Usage
52
+ ### Step 2: Setup Your Project
34
53
 
35
- ### 1. Add the module to your Nitro config
54
+ <details>
55
+ <summary>🔧 <strong>For Standalone Nitro Projects</strong></summary>
36
56
 
57
+ 1. **Update your `nitro.config.ts`:**
37
58
  ```ts
38
- // nitro.config.ts
39
59
  import { defineNitroConfig } from 'nitropack/config'
40
60
 
41
61
  export default defineNitroConfig({
42
62
  modules: ['nitro-graphql'],
63
+ graphql: {
64
+ framework: 'graphql-yoga', // or 'apollo-server'
65
+ },
66
+ })
67
+ ```
43
68
 
44
- // Optional configuration
45
- graphqlYoga: {
46
- endpoint: '/api/graphql', // default
47
- playground: true, // default (Apollo Sandbox)
48
- cors: false, // default
49
- }
69
+ 2. **Create the GraphQL directory structure:**
70
+ ```bash
71
+ mkdir -p server/graphql
72
+ ```
73
+
74
+ </details>
75
+
76
+ <details>
77
+ <summary>🟢 <strong>For Nuxt.js Projects</strong></summary>
78
+
79
+ 1. **Update your `nuxt.config.ts`:**
80
+ ```ts
81
+ export default defineNuxtConfig({
82
+ modules: [
83
+ 'nitro-graphql/nuxt',
84
+ ],
85
+ nitro: {
86
+ modules: ['nitro-graphql'],
87
+ graphql: {
88
+ framework: 'graphql-yoga',
89
+ },
90
+ },
50
91
  })
51
92
  ```
52
93
 
53
- ### 2. Create your GraphQL schema files
94
+ 2. **Create the GraphQL directory structure:**
95
+ ```bash
96
+ mkdir -p server/graphql
97
+ ```
98
+
99
+ </details>
100
+
101
+ ### Step 3: Create Your First Schema
54
102
 
55
- The module automatically scans for GraphQL files in your `graphql/` directory using a domain-driven structure:
103
+ Create your main schema file:
56
104
 
57
- #### Main Schema File
58
105
  ```graphql
59
106
  # server/graphql/schema.graphql
60
107
  scalar DateTime
@@ -68,7 +115,79 @@ type Query {
68
115
  type Mutation
69
116
  ```
70
117
 
71
- #### Domain-specific Schema Files
118
+ ### Step 4: Create Your First Resolver
119
+
120
+ Create a resolver for your queries:
121
+
122
+ ```ts
123
+ // server/graphql/hello.resolver.ts
124
+ import { defineResolver } from 'nitro-graphql/utils/define'
125
+
126
+ export const helloResolver = defineResolver({
127
+ Query: {
128
+ hello: () => 'Hello from GraphQL!',
129
+ greeting: (_, { name }) => `Hello, ${name}!`,
130
+ },
131
+ })
132
+
133
+ // You can also export multiple resolvers from the same file
134
+ export const additionalResolver = defineResolver({
135
+ Query: {
136
+ // Additional query resolvers
137
+ },
138
+ })
139
+ ```
140
+
141
+ ### Step 5: Start Your Server
142
+
143
+ ```bash
144
+ # For Nitro
145
+ pnpm dev
146
+
147
+ # For Nuxt
148
+ pnpm dev
149
+ ```
150
+
151
+ ### Step 6: Test Your GraphQL API
152
+
153
+ 🎉 **That's it!** Your GraphQL server is now running at:
154
+
155
+ - **GraphQL Endpoint**: `http://localhost:3000/api/graphql`
156
+ - **Apollo Sandbox**: `http://localhost:3000/api/graphql` (in browser)
157
+ - **Health Check**: `http://localhost:3000/api/graphql/health`
158
+
159
+ ## 📖 Documentation
160
+
161
+ ### Project Structure
162
+
163
+ The module uses a domain-driven file structure under `server/graphql/`:
164
+
165
+ ```
166
+ server/
167
+ ├── graphql/
168
+ │ ├── schema.graphql # Main schema with scalars and base types
169
+ │ ├── hello.resolver.ts # Global resolvers (use named exports)
170
+ │ ├── users/
171
+ │ │ ├── user.graphql # User schema definitions
172
+ │ │ ├── user-queries.resolver.ts # User query resolvers (use named exports)
173
+ │ │ └── create-user.resolver.ts # User mutation resolvers (use named exports)
174
+ │ ├── posts/
175
+ │ │ ├── post.graphql # Post schema definitions
176
+ │ │ ├── post-queries.resolver.ts # Post query resolvers (use named exports)
177
+ │ │ └── create-post.resolver.ts # Post mutation resolvers (use named exports)
178
+ │ └── config.ts # Optional GraphQL configuration
179
+ ```
180
+
181
+ > [!TIP]
182
+ > **New Named Export Pattern**: The module now supports named exports for GraphQL resolvers, allowing you to export multiple resolvers from a single file. This provides better organization and flexibility in structuring your resolver code.
183
+
184
+ ### Building Your First Feature
185
+
186
+ Let's create a complete user management feature:
187
+
188
+ <details>
189
+ <summary>👤 <strong>Step 1: Define User Schema</strong></summary>
190
+
72
191
  ```graphql
73
192
  # server/graphql/users/user.graphql
74
193
  type User {
@@ -93,267 +212,483 @@ extend type Mutation {
93
212
  }
94
213
  ```
95
214
 
96
- #### Domain-based Resolver Files
215
+ </details>
216
+
217
+ <details>
218
+ <summary>🔍 <strong>Step 2: Create Query Resolvers</strong></summary>
219
+
97
220
  ```ts
98
- // server/graphql/users/user-queries.ts
99
- import { defineResolver } from 'nitro-graphql'
221
+ // server/graphql/users/user-queries.resolver.ts
222
+ import { defineQuery } from 'nitro-graphql/utils/define'
100
223
 
101
- export default defineResolver({
102
- Query: {
103
- users: async (_, __, { storage }) => {
104
- return await storage.getItem('users') || []
105
- },
106
- user: async (_, { id }, { storage }) => {
107
- const users = await storage.getItem('users') || []
108
- return users.find(user => user.id === id)
109
- }
224
+ export const userQueries = defineQuery({
225
+ users: async (_, __, { storage }) => {
226
+ return await storage.getItem('users') || []
227
+ },
228
+ user: async (_, { id }, { storage }) => {
229
+ const users = await storage.getItem('users') || []
230
+ return users.find(user => user.id === id)
110
231
  }
111
232
  })
233
+
234
+ // You can also split queries into separate named exports
235
+ export const additionalUserQueries = defineQuery({
236
+ userCount: async (_, __, { storage }) => {
237
+ const users = await storage.getItem('users') || []
238
+ return users.length
239
+ },
240
+ })
112
241
  ```
113
242
 
114
- ```ts
115
- // server/graphql/users/create-user.ts
116
- import { defineResolver } from 'nitro-graphql'
243
+ </details>
117
244
 
118
- export default defineResolver({
119
- Mutation: {
120
- createUser: async (_, { input }, { storage }) => {
121
- const users = await storage.getItem('users') || []
122
- const user = {
123
- id: Date.now().toString(),
124
- ...input,
125
- createdAt: new Date()
126
- }
127
- users.push(user)
128
- await storage.setItem('users', users)
129
- return user
245
+ <details>
246
+ <summary>✏️ <strong>Step 3: Create Mutation Resolvers</strong></summary>
247
+
248
+ ```ts
249
+ // server/graphql/users/create-user.resolver.ts
250
+ import { defineMutation } from 'nitro-graphql/utils/define'
251
+
252
+ export const createUserMutation = defineMutation({
253
+ createUser: async (_, { input }, { storage }) => {
254
+ const users = await storage.getItem('users') || []
255
+ const user = {
256
+ id: Date.now().toString(),
257
+ ...input,
258
+ createdAt: new Date()
130
259
  }
260
+ users.push(user)
261
+ await storage.setItem('users', users)
262
+ return user
263
+ }
264
+ })
265
+
266
+ // You can also export multiple mutations from the same file
267
+ export const updateUserMutation = defineMutation({
268
+ updateUser: async (_, { id, input }, { storage }) => {
269
+ const users = await storage.getItem('users') || []
270
+ const userIndex = users.findIndex(user => user.id === id)
271
+ if (userIndex === -1)
272
+ throw new Error('User not found')
273
+
274
+ users[userIndex] = { ...users[userIndex], ...input }
275
+ await storage.setItem('users', users)
276
+ return users[userIndex]
131
277
  }
132
278
  })
133
279
  ```
134
280
 
135
- ### 3. Using the utilities
281
+ </details>
136
282
 
137
- The module provides utilities for better developer experience:
283
+ <details>
284
+ <summary>🧪 <strong>Step 4: Test Your Feature</strong></summary>
138
285
 
139
- ```ts
140
- // server/graphql/hello.ts
141
- import { defineResolver } from 'nitro-graphql'
286
+ Open Apollo Sandbox at `http://localhost:3000/api/graphql` and try:
142
287
 
143
- export default defineResolver({
144
- Query: {
145
- hello: () => 'Hello World!',
146
- greeting: (_, { name }) => `Hello ${name}!`
288
+ ```graphql
289
+ # Create a user
290
+ mutation {
291
+ createUser(input: {
292
+ name: "John Doe"
293
+ email: "john@example.com"
294
+ }) {
295
+ id
296
+ name
297
+ email
298
+ createdAt
147
299
  }
148
- })
300
+ }
301
+
302
+ # Query users
303
+ query {
304
+ users {
305
+ id
306
+ name
307
+ email
308
+ }
309
+ }
149
310
  ```
150
311
 
151
- ### 4. Type Generation
312
+ </details>
152
313
 
153
- The module automatically generates TypeScript types from your GraphQL schema:
314
+ ### Type Generation
154
315
 
155
- - **Server types**: `.nitro/types/graphql-types.generated.ts`
156
- - **Type declarations**: `.nitro/types/graphql.d.ts`
316
+ The module automatically generates TypeScript types for you:
157
317
 
158
- These types are automatically available in your resolvers:
318
+ - **Server types**: `.nitro/types/nitro-graphql-server.d.ts`
319
+ - **Client types**: `.nitro/types/nitro-graphql-client.d.ts`
320
+ - **Auto-imports**: Available for `defineResolver` and other utilities
159
321
 
160
- ```ts
161
- import type { QueryResolvers } from '#graphql/server'
162
- // server/graphql/users/user-queries.ts
163
- import { defineResolver } from 'nitro-graphql'
322
+ Your IDE will automatically provide type safety and autocomplete!
164
323
 
165
- export default defineResolver({
166
- Query: {
167
- users: async (_, __, { storage }): Promise<User[]> => {
168
- return await storage.getItem('users') || []
324
+ > [!TIP]
325
+ > **Nitro Auto-Imports**: Thanks to Nitro's auto-import feature, you don't need to manually import `defineResolver`, `defineQuery`, `defineMutation`, and other utilities in your resolver files. They're available globally! However, if you prefer explicit imports, you can use:
326
+ > ```ts
327
+ > import { defineResolver } from 'nitro-graphql/utils/define'
328
+ > ```
329
+
330
+ ### Configuration
331
+
332
+ <details>
333
+ <summary>⚙️ <strong>Runtime Configuration</strong></summary>
334
+
335
+ ```ts
336
+ // nitro.config.ts
337
+ export default defineNitroConfig({
338
+ modules: ['nitro-graphql'],
339
+ graphql: {
340
+ framework: 'graphql-yoga', // or 'apollo-server'
341
+ },
342
+ runtimeConfig: {
343
+ graphql: {
344
+ endpoint: {
345
+ graphql: '/api/graphql', // GraphQL endpoint
346
+ healthCheck: '/api/graphql/health' // Health check endpoint
347
+ },
348
+ playground: true, // Enable Apollo Sandbox
169
349
  }
170
- } satisfies QueryResolvers
350
+ }
171
351
  })
172
352
  ```
173
353
 
174
- ## File Structure
354
+ </details>
175
355
 
176
- The module follows a domain-driven file structure:
356
+ <details>
357
+ <summary>🔧 <strong>Advanced Configuration</strong></summary>
177
358
 
178
- ```
179
- server/
180
- ├── graphql/
181
- │ ├── schema.graphql # Main schema file with scalars and base types
182
- │ ├── hello.ts # Global resolvers
183
- │ ├── users/
184
- │ │ ├── user.graphql # User schema definitions
185
- │ │ ├── user-queries.ts # User query resolvers
186
- │ │ └── create-user.ts # User mutation resolvers
187
- │ ├── todos/
188
- │ │ ├── todo.graphql # Todo schema definitions
189
- │ │ ├── todo-queries.ts # Todo query resolvers
190
- │ │ └── todo-mutations.ts # Todo mutation resolvers
191
- │ ├── posts/
192
- │ │ ├── post.graphql # Post schema definitions
193
- │ │ ├── post-queries.ts # Post query resolvers
194
- │ │ └── create-post.ts # Post mutation resolvers
195
- │ └── comments/
196
- │ ├── comment.graphql # Comment schema definitions
197
- │ ├── comment-queries.ts # Comment query resolvers
198
- │ └── add-comment.ts # Comment mutation resolvers
359
+ ```ts
360
+ // server/graphql/config.ts
361
+ import { defineGraphQLConfig } from 'nitro-graphql/utils/define'
362
+
363
+ export default defineGraphQLConfig({
364
+ // Custom GraphQL Yoga or Apollo Server configuration
365
+ plugins: [
366
+ // Add custom plugins
367
+ ],
368
+ context: async ({ request }) => {
369
+ // Enhanced context with custom properties
370
+ return {
371
+ user: await authenticateUser(request),
372
+ db: await connectDatabase(),
373
+ }
374
+ },
375
+ })
199
376
  ```
200
377
 
201
- ## Context
378
+ </details>
202
379
 
203
- The GraphQL context includes:
204
- - `event`: The H3 event object
205
- - `request`: The original request object
206
- - `storage`: Nitro storage instance
380
+ ## 🎮 Playground
381
+
382
+ Try out the examples:
383
+
384
+ - **Standalone Nitro**: [`playground/`](playground/)
385
+ - **Nuxt.js Integration**: [`playground-nuxt/`](playground-nuxt/)
386
+
387
+ Both examples include working GraphQL schemas, resolvers, and demonstrate the module's capabilities.
388
+
389
+ ## 🔧 API Reference
390
+
391
+ ### Core Utilities
392
+
393
+ > [!NOTE]
394
+ > **Auto-Import Available**: All utilities are automatically imported in your resolver files thanks to Nitro's auto-import feature. You can use them directly without import statements, or use explicit imports if you prefer:
395
+ > ```ts
396
+ > import { defineMutation, defineQuery, defineResolver } from 'nitro-graphql/utils/define'
397
+ > ```
398
+
399
+ > [!IMPORTANT]
400
+ > **Named Exports Required**: All GraphQL resolvers must now use named exports instead of default exports. This allows you to export multiple resolvers from a single file, providing better organization and flexibility. For example:
401
+ > ```ts
402
+ > // ✅ Correct - Named exports
403
+ > export const userQueries = defineQuery({ ... })
404
+ > export const userMutations = defineMutation({ ... })
405
+ >
406
+ > // ❌ Incorrect - Default exports (deprecated)
407
+ > export default defineQuery({ ... })
408
+ > ```
409
+
410
+ <details>
411
+ <summary><strong>defineResolver</strong> - Define complete resolvers</summary>
207
412
 
208
413
  ```ts
209
- // Example resolver with full context usage
210
- import { defineResolver } from 'nitro-graphql'
414
+ import { defineResolver } from 'nitro-graphql/utils/define'
211
415
 
212
- export default defineResolver({
416
+ export const mainResolver = defineResolver({
213
417
  Query: {
214
- currentUser: async (_, __, { event, request, storage }) => {
215
- const token = getCookie(event, 'auth-token')
216
- const userAgent = getHeader(event, 'user-agent')
418
+ // Query resolvers
419
+ },
420
+ Mutation: {
421
+ // Mutation resolvers
422
+ },
423
+ // Custom type resolvers
424
+ })
217
425
 
218
- if (!token) {
219
- throw new Error('Unauthorized')
220
- }
426
+ // You can also export multiple resolvers from the same file
427
+ export const additionalResolver = defineResolver({
428
+ Query: {
429
+ // Additional query resolvers
430
+ },
431
+ })
432
+ ```
221
433
 
222
- const userId = await verifyToken(token)
223
- return await storage.getItem(`user:${userId}`)
224
- }
434
+ </details>
435
+
436
+ <details>
437
+ <summary><strong>defineQuery</strong> - Define only Query resolvers</summary>
438
+
439
+ ```ts
440
+ import { defineQuery } from 'nitro-graphql/utils/define'
441
+
442
+ export const userQueries = defineQuery({
443
+ users: async (_, __, { storage }) => {
444
+ return await storage.getItem('users') || []
445
+ },
446
+ user: async (_, { id }, { storage }) => {
447
+ const users = await storage.getItem('users') || []
448
+ return users.find(user => user.id === id)
225
449
  }
226
450
  })
451
+
452
+ // You can also split queries into separate named exports
453
+ export const userStatsQueries = defineQuery({
454
+ userCount: async (_, __, { storage }) => {
455
+ const users = await storage.getItem('users') || []
456
+ return users.length
457
+ },
458
+ })
227
459
  ```
228
460
 
229
- ## Configuration Options
461
+ </details>
462
+
463
+ <details>
464
+ <summary><strong>defineMutation</strong> - Define only Mutation resolvers</summary>
230
465
 
231
466
  ```ts
232
- interface NitroGraphQLYogaOptions {
233
- // GraphQL endpoint path
234
- endpoint?: string // default: '/api/graphql'
235
-
236
- // Enable/disable Apollo Sandbox
237
- playground?: boolean // default: true
238
-
239
- // CORS configuration
240
- cors?: boolean | {
241
- origin?: string | string[] | boolean
242
- credentials?: boolean
243
- methods?: string[]
467
+ import { defineMutation } from 'nitro-graphql/utils/define'
468
+
469
+ export const userMutations = defineMutation({
470
+ createUser: async (_, { input }, { storage }) => {
471
+ const users = await storage.getItem('users') || []
472
+ const user = {
473
+ id: Date.now().toString(),
474
+ ...input,
475
+ createdAt: new Date()
476
+ }
477
+ users.push(user)
478
+ await storage.setItem('users', users)
479
+ return user
244
480
  }
481
+ })
245
482
 
246
- // Client type generation
247
- client?: {
248
- enabled?: boolean // default: false
249
- outputPath?: string // default: buildDir/types/graphql-client.generated.ts
250
- watchPatterns?: string[] // default: src/**/*.{graphql,gql} excluding server/graphql
251
- config?: {
252
- documentMode?: 'string' | 'graphQLTag'
253
- emitLegacyCommonJSImports?: boolean
254
- useTypeImports?: boolean
255
- enumsAsTypes?: boolean
256
- }
483
+ // You can also export multiple mutations from the same file
484
+ export const userUpdateMutations = defineMutation({
485
+ updateUser: async (_, { id, input }, { storage }) => {
486
+ const users = await storage.getItem('users') || []
487
+ const userIndex = users.findIndex(user => user.id === id)
488
+ if (userIndex === -1)
489
+ throw new Error('User not found')
490
+
491
+ users[userIndex] = { ...users[userIndex], ...input }
492
+ await storage.setItem('users', users)
493
+ return users[userIndex]
257
494
  }
258
- }
495
+ })
259
496
  ```
260
497
 
261
- ## Development Features
498
+ </details>
262
499
 
263
- ### Hot Reload
264
- The module watches for changes in your GraphQL files and automatically:
265
- - Regenerates TypeScript types
266
- - Reloads the GraphQL schema
267
- - Updates resolvers
500
+ <details>
501
+ <summary><strong>defineSubscription</strong> - Define Subscription resolvers</summary>
268
502
 
269
- ### Bundle Optimization
270
- - Uses dynamic imports to prevent bundling large codegen dependencies
271
- - Optimized chunk organization for better caching
272
- - Minimal logging output with consistent `[graphql]` tagging
273
-
274
- ### Health Check
275
- Access the health check endpoint at `/api/graphql/health` to verify your GraphQL server status.
503
+ ```ts
504
+ import { defineSubscription } from 'nitro-graphql/utils/define'
276
505
 
277
- ## Advanced Usage
506
+ export const userSubscriptions = defineSubscription({
507
+ userAdded: {
508
+ subscribe: () => pubsub.asyncIterator('USER_ADDED'),
509
+ },
510
+ postUpdated: {
511
+ subscribe: withFilter(
512
+ () => pubsub.asyncIterator('POST_UPDATED'),
513
+ (payload, variables) => payload.postUpdated.id === variables.postId
514
+ ),
515
+ }
516
+ })
278
517
 
279
- ### Custom GraphQL Yoga Configuration
518
+ // You can also export multiple subscriptions from the same file
519
+ export const notificationSubscriptions = defineSubscription({
520
+ notificationAdded: {
521
+ subscribe: () => pubsub.asyncIterator('NOTIFICATION_ADDED'),
522
+ },
523
+ })
524
+ ```
280
525
 
281
- You can create a custom GraphQL Yoga configuration file that will be automatically merged with the default configuration. The module will look for this file **only in the `server/graphql/` directory**:
526
+ </details>
282
527
 
283
- - `server/graphql/yoga.config.ts`
528
+ <details>
529
+ <summary><strong>defineType</strong> - Define custom type resolvers</summary>
284
530
 
285
531
  ```ts
286
- import { useCORS } from '@graphql-yoga/plugin-cors'
287
- import { useResponseCache } from '@graphql-yoga/plugin-response-cache'
288
- // server/graphql/yoga.config.ts
289
- import { defineYogaConfig } from 'nitro-graphql'
290
-
291
- export default defineYogaConfig({
292
- // Add custom plugins
293
- plugins: [
294
- useCORS({
295
- origin: process.env.NODE_ENV === 'production' ? 'https://yourdomain.com' : '*',
296
- credentials: true,
297
- }),
298
- useResponseCache({
299
- session: () => null,
300
- ttl: 60_000, // 1 minute
301
- }),
302
- ],
303
-
304
- // Enhanced context with custom properties
305
- context: async ({ request }) => {
306
- const event = request.$$event
532
+ import { defineType } from 'nitro-graphql/utils/define'
307
533
 
308
- return {
309
- event,
310
- request,
311
- storage: useStorage(),
312
- // Add custom context properties
313
- user: await authenticateUser(event),
314
- db: await connectDatabase(),
315
- startTime: Date.now(),
316
- }
534
+ export const userTypes = defineType({
535
+ User: {
536
+ posts: async (parent, _, { storage }) => {
537
+ const posts = await storage.getItem('posts') || []
538
+ return posts.filter(post => post.authorId === parent.id)
539
+ },
540
+ fullName: parent => `${parent.firstName} ${parent.lastName}`,
317
541
  },
542
+ })
318
543
 
319
- // Custom error handling
320
- maskedErrors: {
321
- maskError: (error, message, isDev) => {
322
- if (error.message.startsWith('USER_')) {
323
- return error // Don't mask user-facing errors
324
- }
325
- return isDev ? error : new Error('Internal server error')
544
+ // You can also export multiple type resolvers from the same file
545
+ export const postTypes = defineType({
546
+ Post: {
547
+ author: async (parent, _, { storage }) => {
548
+ const users = await storage.getItem('users') || []
549
+ return users.find(user => user.id === parent.authorId)
326
550
  },
327
551
  },
552
+ })
553
+ ```
554
+
555
+ </details>
328
556
 
329
- // Additional yoga options
330
- // See: https://the-guild.dev/graphql/yoga-server/docs
557
+ <details>
558
+ <summary><strong>defineSchema</strong> - Define custom schema with validation</summary>
559
+
560
+ You can override schema types if needed. StandardSchema supported — Zod, Valibot, anything works:
561
+
562
+ ```ts
563
+ import { defineSchema } from 'nitro-graphql/utils/define'
564
+ import { z } from 'zod'
565
+
566
+ export default defineSchema({
567
+ Todo: z.object({
568
+ id: z.string(),
569
+ title: z.string(),
570
+ completed: z.boolean(),
571
+ createdAt: z.date(),
572
+ }),
573
+ User: z.object({
574
+ id: z.string(),
575
+ name: z.string(),
576
+ email: z.string().email(),
577
+ age: z.number().min(0),
578
+ }),
331
579
  })
332
580
  ```
333
581
 
334
- **Configuration Merging**: Your custom config is merged with the default config, allowing you to override specific options while keeping defaults for others. The `schema` and `graphqlEndpoint` are always preserved from the module's configuration.
582
+ **With Drizzle Schema:**
583
+ ```ts
584
+ import { defineSchema } from 'nitro-graphql/utils/define'
585
+ import { z } from 'zod'
586
+ import { userSchema } from './drizzle/user'
587
+
588
+ export default defineSchema({
589
+ Todo: z.object({
590
+ id: z.string(),
591
+ title: z.string(),
592
+ }),
593
+ User: userSchema, // Import from Drizzle schema
594
+ })
595
+ ```
596
+
597
+ </details>
598
+
599
+ ## 🚨 Troubleshooting
600
+
601
+ <details>
602
+ <summary><strong>Common Issues</strong></summary>
603
+
604
+ ### GraphQL endpoint returns 404
605
+
606
+ **Solution**: Make sure you have:
607
+ 1. Added `nitro-graphql` to your modules
608
+ 2. Set the `graphql.framework` option
609
+ 3. Created at least one schema file
610
+
611
+ ### Types not generating
612
+
613
+ **Solution**:
614
+ 1. Restart your dev server
615
+ 2. Check that your schema files end with `.graphql`
616
+ 3. Verify your resolver files end with `.resolver.ts`
617
+
618
+ ### Hot reload not working
619
+
620
+ **Solution**:
621
+ 1. Make sure you're in development mode
622
+ 2. Check file naming conventions
623
+ 3. Restart the dev server
624
+
625
+ ### Import errors with utilities
626
+
627
+ **Solution**:
628
+ ```ts
629
+ // ❌ Incorrect import path
630
+ import { defineResolver } from 'nitro-graphql'
631
+
632
+ // ✅ Correct import path
633
+ import { defineResolver } from 'nitro-graphql/utils/define'
634
+ ```
635
+
636
+ ### Export pattern errors
637
+
638
+ **Solution**:
639
+ ```ts
640
+ // ❌ Incorrect - Default exports (deprecated)
641
+ export default defineResolver({ ... })
642
+
643
+ // ✅ Correct - Named exports
644
+ export const myResolver = defineResolver({ ... })
645
+ export const anotherResolver = defineResolver({ ... })
646
+ ```
647
+
648
+ </details>
335
649
 
336
- ### Client Type Generation
650
+ ## 🌟 Framework Support
337
651
 
338
- Enable client type generation for your frontend queries:
652
+ <details>
653
+ <summary><strong>GraphQL Yoga</strong></summary>
339
654
 
340
655
  ```ts
341
656
  // nitro.config.ts
342
657
  export default defineNitroConfig({
343
- graphqlYoga: {
344
- }
658
+ graphql: {
659
+ framework: 'graphql-yoga',
660
+ },
345
661
  })
346
662
  ```
347
663
 
348
- ### Custom Scalars
664
+ </details>
665
+
666
+ <details>
667
+ <summary><strong>Apollo Server</strong></summary>
349
668
 
350
669
  ```ts
670
+ // nitro.config.ts
671
+ export default defineNitroConfig({
672
+ graphql: {
673
+ framework: 'apollo-server',
674
+ },
675
+ })
676
+ ```
677
+
678
+ </details>
679
+
680
+ ## 🔥 Advanced Features
681
+
682
+ <details>
683
+ <summary><strong>Custom Scalars</strong></summary>
684
+
685
+ ```ts
686
+ // server/graphql/scalars/DateTime.resolver.ts
351
687
  import { GraphQLScalarType } from 'graphql'
352
688
  import { Kind } from 'graphql/language'
353
- // server/graphql/scalars/DateTime.ts
354
- import { defineResolver } from 'nitro-graphql'
689
+ import { defineResolver } from 'nitro-graphql/utils/define'
355
690
 
356
- export default defineResolver({
691
+ export const dateTimeScalar = defineResolver({
357
692
  DateTime: new GraphQLScalarType({
358
693
  name: 'DateTime',
359
694
  serialize: (value: Date) => value.toISOString(),
@@ -366,47 +701,282 @@ export default defineResolver({
366
701
  }
367
702
  })
368
703
  })
704
+
705
+ // You can also export multiple scalars from the same file
706
+ export const jsonScalar = defineResolver({
707
+ JSON: new GraphQLScalarType({
708
+ name: 'JSON',
709
+ serialize: value => value,
710
+ parseValue: value => value,
711
+ parseLiteral: (ast) => {
712
+ if (ast.kind === Kind.STRING) {
713
+ return JSON.parse(ast.value)
714
+ }
715
+ return null
716
+ }
717
+ })
718
+ })
369
719
  ```
370
720
 
371
- ### Error Handling
721
+ </details>
372
722
 
373
- ```ts
374
- // server/graphql/users/user-queries.ts
375
- import { defineResolver } from 'nitro-graphql'
723
+ <details>
724
+ <summary><strong>Error Handling</strong></summary>
376
725
 
377
- export default defineResolver({
378
- Query: {
379
- user: async (_, { id }, { storage }) => {
380
- try {
381
- const user = await storage.getItem(`user:${id}`)
382
- if (!user) {
383
- throw new Error(`User with id ${id} not found`)
384
- }
385
- return user
386
- }
387
- catch (error) {
388
- console.error('[graphql] Error fetching user:', error)
389
- throw error
726
+ ```ts
727
+ // server/graphql/users/user-queries.resolver.ts
728
+ import { defineQuery } from 'nitro-graphql/utils/define'
729
+
730
+ export const userQueries = defineQuery({
731
+ user: async (_, { id }, { storage }) => {
732
+ try {
733
+ const user = await storage.getItem(`user:${id}`)
734
+ if (!user) {
735
+ throw new Error(`User with id ${id} not found`)
390
736
  }
737
+ return user
738
+ }
739
+ catch (error) {
740
+ console.error('Error fetching user:', error)
741
+ throw error
391
742
  }
392
743
  }
393
744
  })
745
+
746
+ // You can also export additional error handling queries
747
+ export const safeUserQueries = defineQuery({
748
+ userSafe: async (_, { id }, { storage }) => {
749
+ try {
750
+ const user = await storage.getItem(`user:${id}`)
751
+ return user || null // Return null instead of throwing
752
+ }
753
+ catch (error) {
754
+ console.error('Error fetching user:', error)
755
+ return null
756
+ }
757
+ }
758
+ })
759
+ ```
760
+
761
+ </details>
762
+
763
+ <details>
764
+ <summary><strong>Nuxt Integration</strong></summary>
765
+
766
+ For Nuxt.js applications, the module provides enhanced integration:
767
+
768
+ ```ts
769
+ // nuxt.config.ts
770
+ export default defineNuxtConfig({
771
+ modules: [
772
+ 'nitro-graphql/nuxt',
773
+ ],
774
+ nitro: {
775
+ modules: ['nitro-graphql'],
776
+ graphql: {
777
+ framework: 'graphql-yoga',
778
+ },
779
+ },
780
+ })
781
+ ```
782
+
783
+ Client-side GraphQL files are automatically detected in the `app/graphql/` directory.
784
+
785
+ ### Client-Side Usage
786
+
787
+ The module automatically generates a GraphQL SDK and provides type-safe client access for frontend usage.
788
+
789
+ <details>
790
+ <summary>📁 <strong>GraphQL File Structure</strong></summary>
791
+
792
+ Create your GraphQL queries and mutations in the `app/graphql/` directory:
793
+
794
+ ```
795
+ app/
796
+ ├── graphql/
797
+ │ ├── queries.graphql # GraphQL queries
798
+ │ ├── mutations.graphql # GraphQL mutations
799
+ │ └── subscriptions.graphql # GraphQL subscriptions (optional)
800
+ ```
801
+
802
+ </details>
803
+
804
+ <details>
805
+ <summary>🔥 <strong>Creating GraphQL Files</strong></summary>
806
+
807
+ **Query File Example:**
808
+ ```graphql
809
+ # app/graphql/queries.graphql
810
+ query GetUsers {
811
+ users {
812
+ id
813
+ name
814
+ email
815
+ createdAt
816
+ }
817
+ }
818
+
819
+ query GetUser($id: ID!) {
820
+ user(id: $id) {
821
+ id
822
+ name
823
+ email
824
+ createdAt
825
+ }
826
+ }
827
+ ```
828
+
829
+ **Mutation File Example:**
830
+ ```graphql
831
+ # app/graphql/mutations.graphql
832
+ mutation CreateUser($input: CreateUserInput!) {
833
+ createUser(input: $input) {
834
+ id
835
+ name
836
+ email
837
+ createdAt
838
+ }
839
+ }
840
+
841
+ mutation UpdateUser($id: ID!, $input: UpdateUserInput!) {
842
+ updateUser(id: $id, input: $input) {
843
+ id
844
+ name
845
+ email
846
+ createdAt
847
+ }
848
+ }
849
+ ```
850
+
851
+ </details>
852
+
853
+ <details>
854
+ <summary>⚡ <strong>Using the Generated SDK</strong></summary>
855
+
856
+ The module automatically generates a type-safe SDK based on your GraphQL files:
857
+
858
+ ```ts
859
+ // The SDK is automatically generated and available as an import
860
+ import { createGraphQLClient } from '#graphql/client'
861
+
862
+ // Create a client instance
863
+ const client = createGraphQLClient({
864
+ endpoint: '/api/graphql',
865
+ headers: {
866
+ 'Authorization': 'Bearer your-token-here'
867
+ }
868
+ })
869
+
870
+ // Use the generated methods with full type safety
871
+ const getUsersData = await client.GetUsers()
872
+ console.log(getUsersData.users) // Fully typed response
873
+
874
+ const newUser = await client.CreateUser({
875
+ input: {
876
+ name: 'John Doe',
877
+ email: 'john@example.com'
878
+ }
879
+ })
880
+ console.log(newUser.createUser) // Fully typed response
394
881
  ```
395
882
 
396
- ## Performance
883
+ </details>
884
+
885
+ <details>
886
+ <summary>🎯 <strong>Basic Usage Examples</strong></summary>
397
887
 
398
- ### Bundle Size
399
- The module is optimized for minimal bundle size:
400
- - Development dependencies are excluded from production builds
401
- - Uses Function constructor for dynamic imports to prevent bundling
402
- - Efficient chunk organization
888
+ **Fetching Data:**
889
+ ```ts
890
+ // Import the generated client
891
+ import { createGraphQLClient } from '#graphql/client'
403
892
 
404
- ### Caching
405
- - Built-in cache headers for Apollo Sandbox (1 week)
406
- - Configurable cache settings
407
- - Lazy schema initialization
893
+ const client = createGraphQLClient()
408
894
 
409
- ## Community & Contributing
895
+ // Query users
896
+ const { users } = await client.GetUsers()
897
+ console.log(users) // Array of User objects with full typing
898
+
899
+ // Query specific user
900
+ const { user } = await client.GetUser({ id: '123' })
901
+ console.log(user) // User object or null
902
+ ```
903
+
904
+ **Creating Data:**
905
+ ```ts
906
+ // Create a new user
907
+ const { createUser } = await client.CreateUser({
908
+ input: {
909
+ name: 'Jane Doe',
910
+ email: 'jane@example.com'
911
+ }
912
+ })
913
+ console.log(createUser) // Newly created user with full typing
914
+ ```
915
+
916
+ **Error Handling:**
917
+ ```ts
918
+ try {
919
+ const { users } = await client.GetUsers()
920
+ console.log(users)
921
+ } catch (error) {
922
+ console.error('GraphQL Error:', error)
923
+ // Handle GraphQL errors appropriately
924
+ }
925
+ ```
926
+
927
+ </details>
928
+
929
+ <details>
930
+ <summary>🔧 <strong>Client Configuration</strong></summary>
931
+
932
+ ```ts
933
+ import { createGraphQLClient } from '#graphql/client'
934
+
935
+ // Basic configuration
936
+ const client = createGraphQLClient({
937
+ endpoint: '/api/graphql',
938
+ headers: {
939
+ 'Authorization': 'Bearer your-token',
940
+ 'X-Client-Version': '1.0.0'
941
+ },
942
+ timeout: 10000
943
+ })
944
+
945
+ // Advanced configuration with dynamic headers
946
+ const client = createGraphQLClient({
947
+ endpoint: '/api/graphql',
948
+ headers: async () => {
949
+ const token = await getAuthToken()
950
+ return {
951
+ 'Authorization': token ? `Bearer ${token}` : '',
952
+ 'X-Request-ID': crypto.randomUUID()
953
+ }
954
+ },
955
+ retry: 3,
956
+ timeout: 30000
957
+ })
958
+ ```
959
+
960
+ </details>
961
+
962
+ </details>
963
+
964
+ ## 🛠️ Development
965
+
966
+ ### Scripts
967
+
968
+ - `pnpm build` - Build the module
969
+ - `pnpm dev` - Watch mode with automatic rebuilding
970
+ - `pnpm lint` - ESLint with auto-fix
971
+ - `pnpm playground` - Run the Nitro playground example
972
+ - `pnpm release` - Build, version bump, and publish
973
+
974
+ ### Requirements
975
+
976
+ - Node.js 20.x or later
977
+ - pnpm (required package manager)
978
+
979
+ ## 💬 Community & Contributing
410
980
 
411
981
  > [!TIP]
412
982
  > **Want to contribute?** We believe you can play a role in the growth of this project!
@@ -442,6 +1012,26 @@ The module is optimized for minimal bundle size:
442
1012
 
443
1013
  Thank you for using and developing this project. Every contribution makes the GraphQL ecosystem stronger!
444
1014
 
1015
+ ## Sponsors
1016
+
1017
+ <p align="center">
1018
+ <a href="https://cdn.jsdelivr.net/gh/productdevbook/static/sponsors.svg">
1019
+ <img src='https://cdn.jsdelivr.net/gh/productdevbook/static/sponsors.svg?t=1721043966'/>
1020
+ </a>
1021
+ </p>
1022
+
445
1023
  ## License
446
1024
 
447
- MIT
1025
+ [MIT](./LICENSE) License © 2023 [productdevbook](https://github.com/productdevbook)
1026
+
1027
+ <!-- Badges -->
1028
+
1029
+ [npm-version-src]: https://img.shields.io/npm/v/nitro-graphql?style=flat&colorA=080f12&colorB=1fa669
1030
+ [npm-version-href]: https://npmjs.com/package/nitro-graphql
1031
+ [npm-downloads-src]: https://img.shields.io/npm/dm/nitro-graphql?style=flat&colorA=080f12&colorB=1fa669
1032
+ [npm-downloads-href]: https://npmjs.com/package/nitro-graphql
1033
+ [bundle-src]: https://deno.bundlejs.com/badge?q=nitro-graphql@0.0.4
1034
+ [bundle-href]: https://deno.bundlejs.com/badge?q=nitro-graphql@0.0.4
1035
+ [license-src]: https://img.shields.io/github/license/productdevbook/nitro-graphql.svg?style=flat&colorA=080f12&colorB=1fa669
1036
+ [license-href]: https://github.com/productdevbook/nitro-graphql/blob/main/LICENSE
1037
+ [jsdocs-href]: https://www.jsdocs.io/package/nitro-graphql
@@ -1,7 +1,7 @@
1
- import * as _nuxt_schema3 from "@nuxt/schema";
1
+ import * as _nuxt_schema0 from "@nuxt/schema";
2
2
 
3
3
  //#region src/ecosystem/nuxt.d.ts
4
4
  interface ModuleOptions {}
5
- declare const _default: _nuxt_schema3.NuxtModule<ModuleOptions, ModuleOptions, false>;
5
+ declare const _default: _nuxt_schema0.NuxtModule<ModuleOptions, ModuleOptions, false>;
6
6
  //#endregion
7
7
  export { ModuleOptions, _default as default };
package/dist/index.d.ts CHANGED
@@ -1,9 +1,9 @@
1
1
  import { StandardSchemaV1 } from "./types/standard-schema.js";
2
2
  import { CodegenClientConfig, CodegenServerConfig, GenImport, NitroGraphQLOptions } from "./types/index.js";
3
- import * as nitropack0 from "nitropack";
3
+ import * as nitropack3 from "nitropack";
4
4
 
5
5
  //#region src/index.d.ts
6
6
  type GraphQLFramework = 'graphql-yoga';
7
- declare const _default: nitropack0.NitroModule;
7
+ declare const _default: nitropack3.NitroModule;
8
8
  //#endregion
9
9
  export { CodegenClientConfig, CodegenServerConfig, GenImport, GraphQLFramework, NitroGraphQLOptions, StandardSchemaV1, _default as default };
@@ -1,6 +1,6 @@
1
- import * as h31 from "h3";
1
+ import * as h36 from "h3";
2
2
 
3
3
  //#region src/routes/apollo-server.d.ts
4
- declare const _default: h31.EventHandler<h31.EventHandlerRequest, any>;
4
+ declare const _default: h36.EventHandler<h36.EventHandlerRequest, any>;
5
5
  //#endregion
6
6
  export { _default as default };
@@ -1,6 +1,6 @@
1
- import * as h34 from "h3";
1
+ import * as h31 from "h3";
2
2
 
3
3
  //#region src/routes/graphql-yoga.d.ts
4
- declare const _default: h34.EventHandler<h34.EventHandlerRequest, Promise<Response>>;
4
+ declare const _default: h31.EventHandler<h31.EventHandlerRequest, Promise<Response>>;
5
5
  //#endregion
6
6
  export { _default as default };
@@ -1,7 +1,7 @@
1
- import * as h36 from "h3";
1
+ import * as h34 from "h3";
2
2
 
3
3
  //#region src/routes/health.d.ts
4
- declare const _default: h36.EventHandler<h36.EventHandlerRequest, Promise<{
4
+ declare const _default: h34.EventHandler<h34.EventHandlerRequest, Promise<{
5
5
  status: string;
6
6
  message: string;
7
7
  timestamp: string;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "nitro-graphql",
3
3
  "type": "module",
4
- "version": "0.0.23",
4
+ "version": "0.1.0",
5
5
  "description": "GraphQL integration for Nitro",
6
6
  "license": "MIT",
7
7
  "sideEffects": false,