Skip to content

Commit f79d92e

Browse files
fix: generate _directives.graphql
1 parent 238cabe commit f79d92e

File tree

5 files changed

+110
-7
lines changed

5 files changed

+110
-7
lines changed

playgrounds/nuxt/server/graphql/_directives.graphql

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,6 @@
22
# Do not modify this file directly. It will be overwritten.
33
# To define custom directives, create .directive.ts files using defineDirective()
44

5-
directive @layerTest on FIELD_DEFINITION
5+
directive @auth on FIELD_DEFINITION
6+
7+
directive @hasRole(role: String!) on FIELD_DEFINITION
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import { getDirective, MapperKind, mapSchema } from '@graphql-tools/utils'
2+
import { defaultFieldResolver, GraphQLError } from 'graphql'
3+
4+
export const authDirective = defineDirective({
5+
name: 'auth',
6+
locations: ['FIELD_DEFINITION'],
7+
description: 'Directive to check authentication',
8+
transformer: (schema) => {
9+
return mapSchema(schema, {
10+
[MapperKind.OBJECT_FIELD]: (fieldConfig) => {
11+
const authDirectiveConfig = getDirective(schema, fieldConfig, 'auth')?.[0]
12+
13+
if (authDirectiveConfig) {
14+
const { resolve = defaultFieldResolver } = fieldConfig
15+
16+
fieldConfig.resolve = async function (source, args, context, info) {
17+
const { auth } = context
18+
const user = auth?.user
19+
20+
if (!user?.id) {
21+
throw new GraphQLError('You must be logged in to access this field', {
22+
extensions: {
23+
code: 'UNAUTHENTICATED',
24+
},
25+
})
26+
}
27+
28+
return resolve(source, args, context, info)
29+
}
30+
}
31+
32+
return fieldConfig
33+
},
34+
})
35+
},
36+
})
37+
38+
export const hasRoleDirective = defineDirective({
39+
name: 'hasRole',
40+
locations: ['FIELD_DEFINITION'],
41+
args: {
42+
role: {
43+
type: 'String!',
44+
description: 'Required role to access this field',
45+
},
46+
},
47+
description: 'Directive to check user role authorization',
48+
transformer: (schema) => {
49+
return mapSchema(schema, {
50+
[MapperKind.OBJECT_FIELD]: (fieldConfig) => {
51+
const hasRoleDirectiveConfig = getDirective(schema, fieldConfig, 'hasRole')?.[0]
52+
53+
if (hasRoleDirectiveConfig) {
54+
const { role: requiredRole } = hasRoleDirectiveConfig
55+
const { resolve = defaultFieldResolver } = fieldConfig
56+
57+
fieldConfig.resolve = async function (source, args, context, info) {
58+
const { auth } = context
59+
const user = auth?.user
60+
61+
if (!user?.id) {
62+
throw new GraphQLError('You must be logged in to access this field', {
63+
extensions: {
64+
code: 'UNAUTHENTICATED',
65+
},
66+
})
67+
}
68+
69+
const userRole = context.userRole
70+
71+
if (!userRole || userRole !== requiredRole) {
72+
throw new GraphQLError(`You must have ${requiredRole} role to access this field`, {
73+
extensions: {
74+
code: 'FORBIDDEN',
75+
},
76+
})
77+
}
78+
79+
return resolve(source, args, context, info)
80+
}
81+
}
82+
83+
return fieldConfig
84+
},
85+
})
86+
},
87+
})

src/ecosystem/nuxt.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ export default defineNuxtModule<ModuleOptions>({
9090
nitroConfig.graphql!.layerServerDirs = layerServerDirs
9191
nitroConfig.graphql!.layerAppDirs = layerAppDirs
9292

93-
// Check if app/graphql directory exists
93+
// Check if app/graphql directory exists - use default app directory
9494
const appGraphqlDir = resolve(nuxt.options.rootDir, 'app/graphql')
9595
const hasAppGraphqlDir = existsSync(appGraphqlDir)
9696

src/index.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,9 +98,17 @@ export default defineNitroModule({
9898

9999
switch (nitro.options.framework.name) {
100100
case 'nuxt': {
101-
watchDirs.push(join(nitro.options.rootDir, 'app', 'graphql'))
102-
nitro.graphql.clientDir = resolve(nitro.options.rootDir, 'app', 'graphql')
103-
nitro.graphql.dir.client = 'app/graphql'
101+
// For Nuxt, set clientDir to app/graphql if not already configured
102+
if (!nitro.graphql.clientDir) {
103+
nitro.graphql.clientDir = resolve(nitro.options.rootDir, 'app', 'graphql')
104+
nitro.graphql.dir.client = 'app/graphql'
105+
}
106+
107+
// For Nuxt, ensure serverDir points to server/graphql if using default srcDir
108+
if (!nitro.options.graphql?.serverDir) {
109+
nitro.graphql.serverDir = resolve(nitro.options.rootDir, 'server', 'graphql')
110+
}
111+
watchDirs.push(nitro.graphql.clientDir)
104112

105113
// Add layer directories to watch list
106114
const layerServerDirs = getLayerServerDirectories(nitro)

src/utils/directive-parser.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -273,9 +273,9 @@ export async function generateDirectiveSchemas(nitro: any, directives: any[]) {
273273
if (directives.length === 0)
274274
return
275275

276-
const { existsSync, readFileSync, writeFileSync } = await import('node:fs')
276+
const { existsSync, readFileSync, writeFileSync, mkdirSync } = await import('node:fs')
277277
const { readFile } = await import('node:fs/promises')
278-
const { resolve } = await import('pathe')
278+
const { resolve, dirname } = await import('pathe')
279279

280280
const directiveSchemas: string[] = []
281281
const seenDirectives = new Set<string>()
@@ -307,6 +307,12 @@ export async function generateDirectiveSchemas(nitro: any, directives: any[]) {
307307
308308
${directiveSchemas.join('\n\n')}`
309309

310+
// Ensure the target directory exists
311+
const targetDir = dirname(directivesPath)
312+
if (!existsSync(targetDir)) {
313+
mkdirSync(targetDir, { recursive: true })
314+
}
315+
310316
// Only write if content has changed
311317
let shouldWrite = true
312318
if (existsSync(directivesPath)) {

0 commit comments

Comments
 (0)