@lewebsimple/nuxt-graphql 0.1.8 → 0.1.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/module.d.mts CHANGED
@@ -3,7 +3,6 @@ import * as _nuxt_schema from '@nuxt/schema';
3
3
  interface ModuleOptions {
4
4
  endpoint?: string;
5
5
  codegen?: {
6
- enabled?: boolean;
7
6
  pattern?: string;
8
7
  schemaOutput?: string;
9
8
  };
package/dist/module.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@lewebsimple/nuxt-graphql",
3
3
  "configKey": "graphql",
4
- "version": "0.1.8",
4
+ "version": "0.1.10",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.2",
7
7
  "unbuild": "3.6.1"
package/dist/module.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { useLogger, defineNuxtModule, createResolver, getLayerDirectories, addServerTemplate, addServerHandler, addImportsDir, addPlugin, addTypeTemplate } from '@nuxt/kit';
1
+ import { useLogger, defineNuxtModule, createResolver, getLayerDirectories, addServerTemplate, addServerHandler, addImportsDir, addServerImportsDir, addPlugin, addTypeTemplate } from '@nuxt/kit';
2
2
  import { existsSync, readFileSync, mkdirSync, writeFileSync } from 'node:fs';
3
3
  import { join, dirname, relative } from 'node:path';
4
4
  import { glob } from 'tinyglobby';
@@ -44,6 +44,16 @@ function writeFileIfChanged(path, content) {
44
44
  return true;
45
45
  }
46
46
 
47
+ async function loadGraphQLSchema(schemaPath) {
48
+ const { createJiti } = await import('jiti');
49
+ const jiti = createJiti(import.meta.url, { interopDefault: true });
50
+ const module = await jiti.import(schemaPath);
51
+ if (!module.schema) {
52
+ throw new Error(`${schemaPath} must export a 'schema' variable`);
53
+ }
54
+ const { printSchema, lexicographicSortSchema } = await import('graphql');
55
+ return printSchema(lexicographicSortSchema(module.schema));
56
+ }
47
57
  function analyzeGraphQLDocuments(docs) {
48
58
  const byFile = /* @__PURE__ */ new Map();
49
59
  const operationsByType = {
@@ -92,9 +102,9 @@ function analyzeGraphQLDocuments(docs) {
92
102
  return { byFile, operationsByType };
93
103
  }
94
104
  function generateRegistryByTypeSource(analysis) {
95
- const q = analysis.query.map((o) => o.name);
96
- const m = analysis.mutation.map((o) => o.name);
97
- const s = analysis.subscription.map((o) => o.name);
105
+ const queries = analysis.query.map((o) => o.name);
106
+ const mutations = analysis.mutation.map((o) => o.name);
107
+ const subscriptions = analysis.subscription.map((o) => o.name);
98
108
  const lines = [
99
109
  `import type { TypedDocumentNode } from "@graphql-typed-document-node/core";`,
100
110
  `import * as ops from "#graphql/operations";`,
@@ -102,11 +112,11 @@ function generateRegistryByTypeSource(analysis) {
102
112
  `type ResultOf<T> = T extends { __apiType?: (variables: infer _) => infer R } ? R : never;`,
103
113
  `type VariablesOf<T> = T extends { __apiType?: (variables: infer V) => infer _ } ? V : never;`
104
114
  ];
105
- if (q.length > 0) {
115
+ if (queries.length > 0) {
106
116
  lines.push(
107
117
  ``,
108
118
  `export const queries = {`,
109
- ...q.map((name) => ` ${name}: ops.${name}Document,`),
119
+ ...queries.map((name) => ` ${name}: ops.${name}Document,`),
110
120
  `} as const;`
111
121
  );
112
122
  } else {
@@ -117,11 +127,11 @@ function generateRegistryByTypeSource(analysis) {
117
127
  `export type QueryResult<N extends QueryName> = ResultOf<(typeof queries)[N]>;`,
118
128
  `export type QueryVariables<N extends QueryName> = VariablesOf<(typeof queries)[N]>;`
119
129
  );
120
- if (m.length > 0) {
130
+ if (mutations.length > 0) {
121
131
  lines.push(
122
132
  ``,
123
133
  `export const mutations = {`,
124
- ...m.map((name) => ` ${name}: ops.${name}Document,`),
134
+ ...mutations.map((name) => ` ${name}: ops.${name}Document,`),
125
135
  `} as const;`
126
136
  );
127
137
  } else {
@@ -132,11 +142,11 @@ function generateRegistryByTypeSource(analysis) {
132
142
  `export type MutationResult<N extends MutationName> = ResultOf<(typeof mutations)[N]>;`,
133
143
  `export type MutationVariables<N extends MutationName> = VariablesOf<(typeof mutations)[N]>;`
134
144
  );
135
- if (s.length > 0) {
145
+ if (subscriptions.length > 0) {
136
146
  lines.push(
137
147
  ``,
138
148
  `export const subscriptions = {`,
139
- ...s.map((name) => ` ${name}: ops.${name}Document,`),
149
+ ...subscriptions.map((name) => ` ${name}: ops.${name}Document,`),
140
150
  `} as const;`
141
151
  );
142
152
  } else {
@@ -164,16 +174,6 @@ function formatDefinitions(defs) {
164
174
  };
165
175
  return defs.map((def) => `${colorOf(def)}${def.name}${reset}`).join(`${dim} / ${reset}`);
166
176
  }
167
- async function loadGraphQLSchema(schemaPath) {
168
- const { createJiti } = await import('jiti');
169
- const jiti = createJiti(import.meta.url, { interopDefault: true });
170
- const module = await jiti.import(schemaPath);
171
- if (!module.schema) {
172
- throw new Error(`${schemaPath} must export a 'schema' variable`);
173
- }
174
- const { printSchema, lexicographicSortSchema } = await import('graphql');
175
- return printSchema(lexicographicSortSchema(module.schema));
176
- }
177
177
  async function runCodegen(options) {
178
178
  const { sdl, documents, operationsFile } = options;
179
179
  if (documents.length === 0) {
@@ -219,13 +219,17 @@ const module$1 = defineNuxtModule({
219
219
  defaults: {
220
220
  endpoint: "/api/graphql",
221
221
  codegen: {
222
- enabled: true,
223
222
  pattern: "**/*.gql",
224
223
  schemaOutput: "server/graphql/schema.graphql"
225
224
  }
226
225
  },
227
226
  async setup(options, nuxt) {
228
227
  const { resolve } = createResolver(import.meta.url);
228
+ if (options.endpoint) {
229
+ if (!options.endpoint.startsWith("/")) {
230
+ logger.warn("GraphQL endpoint should start with '/' (e.g., '/api/graphql')");
231
+ }
232
+ }
229
233
  const { rootDir, serverDir } = nuxt.options;
230
234
  const layerDirs = [
231
235
  ...getLayerDirectories(nuxt),
@@ -234,7 +238,7 @@ const module$1 = defineNuxtModule({
234
238
  const layerServerDirs = layerDirs.map(({ server }) => server);
235
239
  const layerRootDirs = layerDirs.map(({ root }) => root);
236
240
  const schemaPath = await findSingleFile(layerServerDirs, "graphql/schema.{ts,mjs}", true);
237
- const contextPath = await findSingleFile(layerServerDirs, "graphql/context.{ts,mjs}") || resolve("./runtime/server/default-context.ts");
241
+ const contextPath = await findSingleFile(layerServerDirs, "graphql/context.{ts,mjs}") || resolve("./runtime/server/graphql/default-context.ts");
238
242
  nuxt.hook("nitro:config", (config) => {
239
243
  config.alias ||= {};
240
244
  config.alias["#graphql/schema"] = schemaPath;
@@ -250,53 +254,57 @@ const module$1 = defineNuxtModule({
250
254
  logger.success(`GraphQL Yoga ready at ${cyan}${url.replace(/\/$/, "")}${endpoint}${reset}`);
251
255
  });
252
256
  nuxt.options.runtimeConfig.public.graphql = { endpoint };
253
- if (options.codegen?.enabled !== false) {
254
- const codegenPattern = options.codegen?.pattern ?? "**/*.gql";
255
- const graphqlrcFile = join(rootDir, ".graphqlrc");
256
- const operationsFile = join(nuxt.options.buildDir, "graphql/operations.ts");
257
- const registryFile = join(nuxt.options.buildDir, "graphql/registry.ts");
258
- const schemaOutput = options.codegen?.schemaOutput ?? "server/graphql/schema.graphql";
259
- const schemaFile = join(rootDir, schemaOutput);
260
- const generate = async () => {
261
- const [sdl, documents] = await Promise.all([
262
- loadGraphQLSchema(schemaPath),
263
- findMultipleFiles(layerRootDirs, codegenPattern)
264
- ]);
265
- const docs = documents.map((document) => ({ path: document, content: readFileSync(document, "utf-8") }));
266
- const analysis = analyzeGraphQLDocuments(docs);
267
- for (const doc of docs) {
268
- const relativePath = doc.path.startsWith(rootDir) ? doc.path.slice(rootDir.length + 1) : doc.path;
269
- const defs = analysis.byFile.get(doc.path) ?? [];
270
- logger.info(`${cyan}${relativePath}${reset} [${formatDefinitions(defs)}]`);
271
- }
272
- await runCodegen({ sdl, documents, operationsFile });
273
- if (writeFileIfChanged(schemaFile, sdl)) {
274
- logger.info(`GraphQL schema saved to ${cyan}${schemaOutput}${reset}`);
275
- }
276
- const config = JSON.stringify({ schema: relative(rootDir, schemaFile), documents: codegenPattern }, null, 2);
277
- if (writeFileIfChanged(graphqlrcFile, config)) {
278
- logger.info(`GraphQL config saved to ${cyan}.graphqlrc${reset}`);
279
- }
280
- if (writeFileIfChanged(registryFile, generateRegistryByTypeSource(analysis.operationsByType))) {
281
- logger.info(`GraphQL registry saved to ${cyan}${relative(rootDir, registryFile)}${reset}`);
257
+ const codegenPattern = options.codegen?.pattern ?? "**/*.gql";
258
+ const graphqlrcFile = join(rootDir, ".graphqlrc");
259
+ const operationsFile = join(nuxt.options.buildDir, "graphql/operations.ts");
260
+ const registryFile = join(nuxt.options.buildDir, "graphql/registry.ts");
261
+ nuxt.options.alias["#graphql/operations"] = operationsFile;
262
+ nuxt.options.alias["#graphql/registry"] = registryFile;
263
+ const schemaOutput = options.codegen?.schemaOutput ?? "server/graphql/schema.graphql";
264
+ if (schemaOutput) {
265
+ if (!schemaOutput.endsWith(".graphql")) {
266
+ logger.warn(`Schema output '${schemaOutput}' should have .graphql extension.`);
267
+ }
268
+ }
269
+ const schemaFile = join(rootDir, schemaOutput);
270
+ const generate = async () => {
271
+ const [sdl, documents] = await Promise.all([
272
+ loadGraphQLSchema(schemaPath),
273
+ findMultipleFiles(layerRootDirs, codegenPattern)
274
+ ]);
275
+ const docs = documents.map((document) => ({ path: document, content: readFileSync(document, "utf-8") }));
276
+ const analysis = analyzeGraphQLDocuments(docs);
277
+ for (const doc of docs) {
278
+ const relativePath = doc.path.startsWith(rootDir) ? doc.path.slice(rootDir.length + 1) : doc.path;
279
+ const defs = analysis.byFile.get(doc.path) ?? [];
280
+ logger.info(`${cyan}${relativePath}${reset} [${formatDefinitions(defs)}]`);
281
+ }
282
+ await runCodegen({ sdl, documents, operationsFile });
283
+ if (writeFileIfChanged(schemaFile, sdl)) {
284
+ logger.info(`GraphQL schema saved to ${cyan}${schemaOutput}${reset}`);
285
+ }
286
+ const config = JSON.stringify({ schema: relative(rootDir, schemaFile), documents: codegenPattern }, null, 2);
287
+ if (writeFileIfChanged(graphqlrcFile, config)) {
288
+ logger.info(`GraphQL config saved to ${cyan}.graphqlrc${reset}`);
289
+ }
290
+ if (writeFileIfChanged(registryFile, generateRegistryByTypeSource(analysis.operationsByType))) {
291
+ logger.info(`GraphQL registry saved to ${cyan}${relative(rootDir, registryFile)}${reset}`);
292
+ }
293
+ };
294
+ nuxt.hook("prepare:types", async ({ references }) => {
295
+ await generate();
296
+ if (existsSync(operationsFile)) references.push({ path: operationsFile });
297
+ if (existsSync(registryFile)) references.push({ path: registryFile });
298
+ });
299
+ if (nuxt.options.dev) {
300
+ nuxt.hook("builder:watch", async (event, path) => {
301
+ if (path.endsWith(".gql")) {
302
+ await generate();
282
303
  }
283
- };
284
- nuxt.hook("prepare:types", async ({ references }) => {
285
- await generate();
286
- if (existsSync(operationsFile)) references.push({ path: operationsFile });
287
- if (existsSync(registryFile)) references.push({ path: registryFile });
288
304
  });
289
- if (nuxt.options.dev) {
290
- nuxt.hook("builder:watch", async (event, path) => {
291
- if (path.endsWith(".gql")) {
292
- await generate();
293
- }
294
- });
295
- }
296
- nuxt.options.alias["#graphql/operations"] = operationsFile;
297
- nuxt.options.alias["#graphql/registry"] = registryFile;
298
305
  }
299
306
  addImportsDir(resolve("./runtime/composables"));
307
+ addServerImportsDir(resolve("./runtime/server/utils"));
300
308
  addPlugin(resolve("./runtime/plugins/graphql"));
301
309
  addTypeTemplate({
302
310
  filename: "types/graphql-client.d.ts",
@@ -1,10 +1,9 @@
1
- import { type Ref } from "vue";
2
1
  import { type MutationName, type MutationResult, type MutationVariables } from "#graphql/registry";
3
- type IsEmptyObject<T> = T extends Record<string, never> ? true : keyof T extends never ? true : false;
2
+ import type { IsEmptyObject } from "../utils/helpers.js";
4
3
  export declare function useGraphQLMutation<N extends MutationName>(operationName: N): {
5
- mutate: (...args: IsEmptyObject<MutationVariables<N>> extends true ? [variables?: MutationVariables<N>] : [variables: MutationVariables<N>]) => Promise<MutationResult<N>>;
6
- data: Ref<MutationResult<N> | null, MutationResult<N> | null>;
7
- error: Ref<Error | null, Error | null>;
8
- pending: Ref<boolean, boolean>;
4
+ mutate: (...args: IsEmptyObject<MutationVariables<N>> extends true ? [variables?: MutationVariables<N>, headers?: HeadersInit] : [variables: MutationVariables<N>, headers?: HeadersInit]) => Promise<{
5
+ data: MutationResult<N> | null;
6
+ error: Error | null;
7
+ }>;
8
+ pending: import("vue").Ref<boolean, boolean>;
9
9
  };
10
- export {};
@@ -1,25 +1,22 @@
1
1
  import { ref } from "vue";
2
- import { useGraphQL } from "./useGraphQL.js";
2
+ import { useNuxtApp } from "#imports";
3
3
  import { mutations } from "#graphql/registry";
4
4
  export function useGraphQLMutation(operationName) {
5
5
  const document = mutations[operationName];
6
- const { request } = useGraphQL();
7
- const data = ref(null);
8
- const error = ref(null);
6
+ const { $graphql } = useNuxtApp();
9
7
  const pending = ref(false);
10
8
  async function mutate(...args) {
11
9
  pending.value = true;
12
- error.value = null;
13
10
  try {
14
- const result = await request(document, args[0]);
15
- data.value = result;
16
- return result;
11
+ const [variables, headers] = args;
12
+ const result = await $graphql().request(document, variables, headers);
13
+ return { data: result, error: null };
17
14
  } catch (e) {
18
- error.value = e instanceof Error ? e : new Error(String(e));
19
- throw e;
15
+ const error = e instanceof Error ? e : new Error(String(e));
16
+ return { data: null, error };
20
17
  } finally {
21
18
  pending.value = false;
22
19
  }
23
20
  }
24
- return { mutate, data, error, pending };
21
+ return { mutate, pending };
25
22
  }
@@ -1,5 +1,4 @@
1
1
  import type { AsyncData, AsyncDataOptions } from "#app";
2
2
  import { type QueryName, type QueryResult, type QueryVariables } from "#graphql/registry";
3
- type IsEmptyObject<T> = T extends Record<string, never> ? true : keyof T extends never ? true : false;
4
- export declare function useGraphQLQuery<N extends QueryName>(operationName: N, ...args: IsEmptyObject<QueryVariables<N>> extends true ? [variables?: QueryVariables<N>, opts?: AsyncDataOptions<QueryResult<N>>] : [variables: QueryVariables<N>, opts?: AsyncDataOptions<QueryResult<N>>]): AsyncData<QueryResult<N>, Error | null>;
5
- export {};
3
+ import type { IsEmptyObject } from "../utils/helpers.js";
4
+ export declare function useGraphQLQuery<N extends QueryName>(operationName: N, ...args: IsEmptyObject<QueryVariables<N>> extends true ? [variables?: QueryVariables<N>, options?: AsyncDataOptions<QueryResult<N>>, headers?: HeadersInit] : [variables: QueryVariables<N>, options?: AsyncDataOptions<QueryResult<N>>, headers?: HeadersInit]): AsyncData<QueryResult<N>, Error | null>;
@@ -1,11 +1,10 @@
1
- import { useAsyncData } from "#imports";
1
+ import { useAsyncData, useNuxtApp } from "#imports";
2
2
  import { hash } from "ohash";
3
- import { useGraphQL } from "./useGraphQL.js";
4
3
  import { queries } from "#graphql/registry";
5
4
  export function useGraphQLQuery(operationName, ...args) {
5
+ const { $graphql } = useNuxtApp();
6
6
  const document = queries[operationName];
7
- const [variables, opts] = args;
8
- const { request } = useGraphQL();
9
- const key = `gql:q:${operationName}:${hash(variables ?? {})}`;
10
- return useAsyncData(key, () => request(document, variables), opts);
7
+ const [variables, options, headers] = args;
8
+ const key = `graphql:query:${operationName}:${hash(variables ?? {})}`;
9
+ return useAsyncData(key, () => $graphql().request(document, variables, headers), options);
11
10
  }
@@ -0,0 +1,10 @@
1
+ import { type MaybeRefOrGetter, type Ref } from "vue";
2
+ import { type SubscriptionName, type SubscriptionResult, type SubscriptionVariables } from "#graphql/registry";
3
+ import type { IsEmptyObject } from "../utils/helpers.js";
4
+ export type UseGraphQLSubscriptionReturn<N extends SubscriptionName> = {
5
+ data: Ref<SubscriptionResult<N> | null>;
6
+ error: Ref<Error | null>;
7
+ start: () => void;
8
+ stop: () => void;
9
+ };
10
+ export declare function useGraphQLSubscription<N extends SubscriptionName>(operationName: N, ...args: IsEmptyObject<SubscriptionVariables<N>> extends true ? [variables?: MaybeRefOrGetter<SubscriptionVariables<N>>] : [variables: MaybeRefOrGetter<SubscriptionVariables<N>>]): UseGraphQLSubscriptionReturn<N>;
@@ -0,0 +1,45 @@
1
+ import { ref, onScopeDispose, toValue } from "vue";
2
+ import { print } from "graphql";
3
+ import { useNuxtApp } from "#imports";
4
+ import { subscriptions } from "#graphql/registry";
5
+ export function useGraphQLSubscription(operationName, ...args) {
6
+ const { $graphqlSSE } = useNuxtApp();
7
+ const [variables] = args;
8
+ const data = ref(null);
9
+ const error = ref(null);
10
+ let unsubscribe = null;
11
+ function start() {
12
+ stop();
13
+ error.value = null;
14
+ unsubscribe = $graphqlSSE().subscribe(
15
+ {
16
+ query: print(subscriptions[operationName]),
17
+ variables: toValue(variables)
18
+ },
19
+ {
20
+ next: (result) => {
21
+ if (result.errors?.length) {
22
+ error.value = new Error(result.errors.map((e) => e.message).join(", "));
23
+ } else if (result.data) {
24
+ data.value = result.data;
25
+ }
26
+ },
27
+ error: (e) => {
28
+ error.value = e instanceof Error ? e : new Error(String(e));
29
+ },
30
+ complete: () => {
31
+ unsubscribe = null;
32
+ }
33
+ }
34
+ );
35
+ }
36
+ function stop() {
37
+ unsubscribe?.();
38
+ unsubscribe = null;
39
+ }
40
+ if (import.meta.client) {
41
+ start();
42
+ }
43
+ onScopeDispose(stop);
44
+ return { data, error, start, stop };
45
+ }
@@ -1,7 +1,10 @@
1
1
  import { GraphQLClient } from "graphql-request";
2
+ import { type Client as SSEClient } from "graphql-sse";
2
3
  declare const _default: import("nuxt/app").Plugin<{
3
- graphql: GraphQLClient;
4
+ graphql: () => GraphQLClient;
5
+ graphqlSSE: () => SSEClient;
4
6
  }> & import("nuxt/app").ObjectPlugin<{
5
- graphql: GraphQLClient;
7
+ graphql: () => GraphQLClient;
8
+ graphqlSSE: () => SSEClient;
6
9
  }>;
7
10
  export default _default;
@@ -1,12 +1,35 @@
1
1
  import { GraphQLClient } from "graphql-request";
2
- import { defineNuxtPlugin, useRequestURL, useRuntimeConfig } from "#imports";
2
+ import { createClient } from "graphql-sse";
3
+ import { defineNuxtPlugin, useRequestHeaders, useRequestURL, useRuntimeConfig } from "#imports";
3
4
  export default defineNuxtPlugin(() => {
4
- const config = useRuntimeConfig();
5
+ const { public: { graphql: { endpoint } } } = useRuntimeConfig();
5
6
  const { origin } = useRequestURL();
6
- const client = new GraphQLClient(`${origin}${config.public.graphql.endpoint}`);
7
+ const url = `${origin}${endpoint}`;
8
+ let client = null;
9
+ const getClient = () => {
10
+ if (!client) {
11
+ client = new GraphQLClient(url);
12
+ }
13
+ if (import.meta.server) {
14
+ const headers = useRequestHeaders(["cookie", "authorization"]);
15
+ client.setHeaders(headers);
16
+ }
17
+ return client;
18
+ };
19
+ let sseClient = null;
20
+ const getSSEClient = () => {
21
+ if (import.meta.server) {
22
+ throw new Error("SSE subscriptions are not available on the server");
23
+ }
24
+ if (!sseClient) {
25
+ sseClient = createClient({ url });
26
+ }
27
+ return sseClient;
28
+ };
7
29
  return {
8
30
  provide: {
9
- graphql: client
31
+ graphql: getClient,
32
+ graphqlSSE: getSSEClient
10
33
  }
11
34
  };
12
35
  });
@@ -0,0 +1,15 @@
1
+ import type { H3Event } from "h3";
2
+ import { GraphQLClient } from "graphql-request";
3
+ /**
4
+ * Create server-side GraphQL client instance for the given H3 event.
5
+ *
6
+ * @param event H3 event
7
+ *
8
+ * @returns GraphQL client instance
9
+ */
10
+ export declare function getGraphQLClient(event: H3Event): GraphQLClient;
11
+ declare module "h3" {
12
+ interface H3EventContext {
13
+ __nuxtGraphQLClient?: GraphQLClient;
14
+ }
15
+ }
@@ -0,0 +1,14 @@
1
+ import { getRequestHeaders, getRequestURL } from "h3";
2
+ import { GraphQLClient } from "graphql-request";
3
+ import { useRuntimeConfig } from "#imports";
4
+ export function getGraphQLClient(event) {
5
+ if (event.context.__nuxtGraphQLClient) {
6
+ return event.context.__nuxtGraphQLClient;
7
+ }
8
+ const { public: { graphql: { endpoint } } } = useRuntimeConfig();
9
+ const { origin } = getRequestURL(event);
10
+ const url = `${origin}${endpoint}`;
11
+ const headers = getRequestHeaders(event);
12
+ event.context.__nuxtGraphQLClient = new GraphQLClient(url, { headers });
13
+ return event.context.__nuxtGraphQLClient;
14
+ }
@@ -0,0 +1,9 @@
1
+ import type { H3Event } from "h3";
2
+ import { type MutationName, type MutationResult, type MutationVariables } from "#graphql/registry";
3
+ import type { IsEmptyObject } from "../../utils/helpers.js";
4
+ export declare function useGraphQLMutation<N extends MutationName>(event: H3Event, operationName: N): Promise<{
5
+ mutate: (...args: IsEmptyObject<MutationVariables<N>> extends true ? [variables?: MutationVariables<N>, headers?: HeadersInit] : [variables: MutationVariables<N>, headers?: HeadersInit]) => Promise<{
6
+ data: MutationResult<N> | null;
7
+ error: Error | null;
8
+ }>;
9
+ }>;
@@ -0,0 +1,16 @@
1
+ import { getGraphQLClient } from "./graphql-client.js";
2
+ import { mutations } from "#graphql/registry";
3
+ export async function useGraphQLMutation(event, operationName) {
4
+ const client = getGraphQLClient(event);
5
+ async function mutate(...args) {
6
+ try {
7
+ const [variables, headers] = args;
8
+ const result = await client.request(mutations[operationName], variables, headers);
9
+ return { data: result, error: null };
10
+ } catch (e) {
11
+ const error = e instanceof Error ? e : new Error(String(e));
12
+ return { data: null, error };
13
+ }
14
+ }
15
+ return { mutate };
16
+ }
@@ -0,0 +1,4 @@
1
+ import type { H3Event } from "h3";
2
+ import { type QueryName, type QueryResult, type QueryVariables } from "#graphql/registry";
3
+ import type { IsEmptyObject } from "../../utils/helpers.js";
4
+ export declare function useGraphQLQuery<N extends QueryName>(event: H3Event, operationName: N, ...args: IsEmptyObject<QueryVariables<N>> extends true ? [variables?: QueryVariables<N>, headers?: HeadersInit] : [variables: QueryVariables<N>, headers?: HeadersInit]): Promise<QueryResult<N>>;
@@ -0,0 +1,7 @@
1
+ import { getGraphQLClient } from "./graphql-client.js";
2
+ import { queries } from "#graphql/registry";
3
+ export async function useGraphQLQuery(event, operationName, ...args) {
4
+ const client = getGraphQLClient(event);
5
+ const [variables, headers] = args;
6
+ return client.request(queries[operationName], variables, headers);
7
+ }
@@ -1,8 +1,10 @@
1
1
  import type { GraphQLClient } from "graphql-request";
2
+ import type { Client as SSEClient } from "graphql-sse";
2
3
 
3
4
  declare module "#app" {
4
5
  interface NuxtApp {
5
- $graphql: GraphQLClient;
6
+ $graphql: () => GraphQLClient;
7
+ $graphqlSSE: () => SSEClient;
6
8
  }
7
9
  }
8
10
 
@@ -0,0 +1 @@
1
+ export type IsEmptyObject<T> = T extends Record<string, never> ? true : keyof T extends never ? true : false;
File without changes
@@ -1,7 +1,8 @@
1
1
  import { createYoga } from "graphql-yoga";
2
- import { defineEventHandler, toWebRequest, sendWebResponse } from "h3";
2
+ import { defineEventHandler, toWebRequest, sendWebResponse, createError } from "h3";
3
3
  import { schema } from "#graphql/schema";
4
4
  import { createContext } from "#graphql/context";
5
+ import { useLogger } from "@nuxt/kit";
5
6
 
6
7
  let yoga = null;
7
8
 
@@ -11,14 +12,24 @@ function getYoga() {
11
12
  schema,
12
13
  graphqlEndpoint: "{{endpoint}}",
13
14
  fetchAPI: globalThis,
15
+ graphiql: process.env.NODE_ENV !== "production",
16
+ subscriptions: { protocol: "SSE" },
14
17
  });
15
18
  }
16
19
  return yoga;
17
20
  }
18
21
 
19
22
  export default defineEventHandler(async (event) => {
20
- const request = toWebRequest(event);
21
- const context = await createContext(event);
22
- const response = await getYoga().handleRequest(request, context);
23
- return sendWebResponse(event, response);
23
+ const logger = useLogger();
24
+ try {
25
+ const request = toWebRequest(event);
26
+ const context = await createContext(event);
27
+ const response = await getYoga().handleRequest(request, context);
28
+ return sendWebResponse(event, response);
29
+ }
30
+ catch (error) {
31
+ const message = error instanceof Error ? error.message : String(error);
32
+ logger.error("GraphQL Server Error:", message);
33
+ throw createError({ statusCode: 500, message: "GraphQL server error" });
34
+ }
24
35
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lewebsimple/nuxt-graphql",
3
- "version": "0.1.8",
3
+ "version": "0.1.10",
4
4
  "description": "Opinionated Nuxt module for using GraphQL",
5
5
  "repository": "lewebsimple/nuxt-graphql",
6
6
  "license": "MIT",
@@ -42,7 +42,8 @@
42
42
  "@nuxt/kit": "^4.2.2",
43
43
  "graphql": "^16.12.0",
44
44
  "graphql-request": "^7.4.0",
45
- "graphql-yoga": "^5.17.1",
45
+ "graphql-sse": "^2.6.0",
46
+ "graphql-yoga": "^5.18.0",
46
47
  "jiti": "^2.6.1",
47
48
  "ohash": "^2.0.11",
48
49
  "tinyglobby": "^0.2.15"
@@ -59,8 +60,8 @@
59
60
  "eslint": "^9.39.2",
60
61
  "nuxt": "^4.2.2",
61
62
  "typescript": "~5.9.3",
62
- "vitest": "^4.0.15",
63
- "vue-tsc": "^3.1.8"
63
+ "vitest": "^4.0.16",
64
+ "vue-tsc": "^3.2.1"
64
65
  },
65
66
  "publishConfig": {
66
67
  "access": "public"
@@ -1,4 +0,0 @@
1
- import type { TypedDocumentNode } from "@graphql-typed-document-node/core";
2
- export declare function useGraphQL(): {
3
- request: <TResult, TVariables extends Record<string, unknown> | undefined>(document: TypedDocumentNode<TResult, TVariables>, variables?: TVariables) => Promise<TResult>;
4
- };
@@ -1,8 +0,0 @@
1
- import { useNuxtApp } from "#imports";
2
- export function useGraphQL() {
3
- const { $graphql } = useNuxtApp();
4
- async function request(document, variables) {
5
- return $graphql.request({ document, variables });
6
- }
7
- return { request };
8
- }