@lewebsimple/nuxt-graphql 0.4.0 → 0.5.1

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 (75) hide show
  1. package/README.md +130 -188
  2. package/dist/module.d.mts +71 -22
  3. package/dist/module.json +2 -2
  4. package/dist/module.mjs +406 -369
  5. package/dist/runtime/app/composables/useAsyncGraphQLQuery.d.ts +19 -0
  6. package/dist/runtime/app/composables/useAsyncGraphQLQuery.js +82 -0
  7. package/dist/runtime/app/composables/useGraphQLCache.client.d.ts +10 -7
  8. package/dist/runtime/app/composables/useGraphQLCache.client.js +16 -31
  9. package/dist/runtime/app/composables/useGraphQLMutation.d.ts +10 -18
  10. package/dist/runtime/app/composables/useGraphQLMutation.js +7 -11
  11. package/dist/runtime/app/composables/useGraphQLQuery.d.ts +11 -9
  12. package/dist/runtime/app/composables/useGraphQLQuery.js +20 -78
  13. package/dist/runtime/app/composables/useGraphQLSubscription.client.d.ts +19 -0
  14. package/dist/runtime/app/composables/{useGraphQLSubscription.js → useGraphQLSubscription.client.js} +9 -14
  15. package/dist/runtime/app/lib/cache.d.ts +18 -0
  16. package/dist/runtime/app/lib/cache.js +9 -0
  17. package/dist/runtime/app/lib/execute-http.d.ts +14 -0
  18. package/dist/runtime/app/lib/execute-http.js +8 -0
  19. package/dist/runtime/app/lib/in-flight.d.ts +14 -0
  20. package/dist/runtime/app/lib/{graphql-cache.js → in-flight.js} +2 -7
  21. package/dist/runtime/app/lib/persisted.d.ts +26 -0
  22. package/dist/runtime/app/plugins/graphql-request.d.ts +7 -2
  23. package/dist/runtime/app/plugins/graphql-request.js +13 -14
  24. package/dist/runtime/app/plugins/graphql-sse.client.d.ts +7 -2
  25. package/dist/runtime/server/api/graphql.d.ts +8 -0
  26. package/dist/runtime/server/api/graphql.js +16 -0
  27. package/dist/runtime/server/lib/default-context.d.ts +5 -0
  28. package/dist/runtime/server/lib/default-context.js +2 -0
  29. package/dist/runtime/server/lib/default-schema.d.ts +7 -0
  30. package/dist/runtime/server/lib/default-schema.js +18 -0
  31. package/dist/runtime/server/lib/execute-schema.d.ts +11 -0
  32. package/dist/runtime/server/lib/execute-schema.js +23 -0
  33. package/dist/runtime/server/lib/remote-executor.d.ts +17 -33
  34. package/dist/runtime/server/lib/remote-executor.js +24 -59
  35. package/dist/runtime/server/lib/yoga.d.ts +6 -0
  36. package/dist/runtime/server/lib/yoga.js +20 -0
  37. package/dist/runtime/server/utils/defineGraphQLContext.d.ts +10 -0
  38. package/dist/runtime/server/utils/defineGraphQLContext.js +3 -0
  39. package/dist/runtime/server/utils/defineGraphQLSchema.d.ts +14 -0
  40. package/dist/runtime/server/utils/defineGraphQLSchema.js +3 -0
  41. package/dist/runtime/server/utils/defineRemoteExecutorHooks.d.ts +13 -0
  42. package/dist/runtime/server/utils/defineRemoteExecutorHooks.js +3 -0
  43. package/dist/runtime/server/utils/useServerGraphQLMutation.d.ts +16 -8
  44. package/dist/runtime/server/utils/useServerGraphQLMutation.js +12 -11
  45. package/dist/runtime/server/utils/useServerGraphQLQuery.d.ts +16 -3
  46. package/dist/runtime/server/utils/useServerGraphQLQuery.js +16 -4
  47. package/dist/runtime/shared/lib/cache-config.d.ts +42 -0
  48. package/dist/runtime/{app → shared}/lib/cache-config.js +3 -3
  49. package/dist/runtime/shared/lib/error.d.ts +56 -0
  50. package/dist/runtime/shared/lib/error.js +61 -0
  51. package/dist/runtime/shared/lib/headers.d.ts +13 -3
  52. package/dist/runtime/shared/lib/headers.js +10 -35
  53. package/dist/runtime/shared/lib/registry.d.ts +12 -0
  54. package/dist/runtime/shared/lib/registry.js +8 -0
  55. package/dist/runtime/shared/lib/utils.d.ts +1 -0
  56. package/dist/runtime/shared/lib/utils.js +0 -0
  57. package/dist/runtime/{app → shared}/types/nuxt-graphql.d.ts +1 -5
  58. package/package.json +19 -33
  59. package/dist/helpers.d.mts +0 -3
  60. package/dist/helpers.mjs +0 -3
  61. package/dist/runtime/app/composables/useGraphQLSubscription.d.ts +0 -17
  62. package/dist/runtime/app/lib/cache-config.d.ts +0 -8
  63. package/dist/runtime/app/lib/graphql-cache.d.ts +0 -7
  64. package/dist/runtime/server/api/yoga-handler.d.ts +0 -2
  65. package/dist/runtime/server/api/yoga-handler.js +0 -42
  66. package/dist/runtime/server/lib/define-graphql-context.d.ts +0 -5
  67. package/dist/runtime/server/lib/define-graphql-context.js +0 -4
  68. package/dist/runtime/server/lib/define-remote-exec-middleware.d.ts +0 -30
  69. package/dist/runtime/server/lib/define-remote-exec-middleware.js +0 -3
  70. package/dist/runtime/server/lib/define-yoga-middleware.d.ts +0 -21
  71. package/dist/runtime/server/lib/define-yoga-middleware.js +0 -3
  72. package/dist/runtime/server/lib/execute-server-graphql.d.ts +0 -7
  73. package/dist/runtime/server/lib/execute-server-graphql.js +0 -34
  74. package/dist/runtime/shared/lib/graphql-error.d.ts +0 -17
  75. package/dist/runtime/shared/lib/graphql-error.js +0 -28
@@ -0,0 +1,16 @@
1
+ import { createError, defineEventHandler, sendWebResponse, toWebRequest } from "h3";
2
+ import { createContext } from "#graphql/context";
3
+ import { getYogaInstance } from "../lib/yoga.js";
4
+ export default defineEventHandler(async (event) => {
5
+ try {
6
+ const request = toWebRequest(event);
7
+ const context = await createContext(event);
8
+ const yoga = getYogaInstance();
9
+ const response = await yoga.handleRequest(request, context);
10
+ return sendWebResponse(event, response);
11
+ } catch (error) {
12
+ const message = error instanceof Error ? error.message : String(error);
13
+ console.error("GraphQL server error:", message);
14
+ throw createError({ statusCode: 500, message: "GraphQL server error (see server logs for details)." });
15
+ }
16
+ });
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Default empty GraphQL context factory.
3
+ */
4
+ declare const _default: (event: import("h3").H3Event) => {} | Promise<{}>;
5
+ export default _default;
@@ -0,0 +1,2 @@
1
+ import { defineGraphQLContext } from "../utils/defineGraphQLContext.js";
2
+ export default defineGraphQLContext(() => ({}));
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Export the default schema definition wrapper.
3
+ */
4
+ declare const _default: {
5
+ schema: import("graphql").GraphQLSchema | import("@graphql-tools/delegate").SubschemaConfig<any, any, any, Record<string, any>>;
6
+ };
7
+ export default _default;
@@ -0,0 +1,18 @@
1
+ import { createSchema } from "graphql-yoga";
2
+ import { defineGraphQLSchema } from "../utils/defineGraphQLSchema.js";
3
+ const schema = createSchema({
4
+ typeDefs: (
5
+ /* GraphQL */
6
+ `
7
+ type Query {
8
+ hello(name: String): String!
9
+ }
10
+ `
11
+ ),
12
+ resolvers: {
13
+ Query: {
14
+ hello: (_parent, { name }) => `Hello ${name || "world"}!`
15
+ }
16
+ }
17
+ });
18
+ export default defineGraphQLSchema({ schema });
@@ -0,0 +1,11 @@
1
+ import type { H3Event } from "h3";
2
+ import type { VariablesOf, ResultOf, QueryName, MutationName } from "#graphql/registry";
3
+ /**
4
+ * Execute a GraphQL operation directly against the stitched schema.
5
+ *
6
+ * @param event H3 event for context creation.
7
+ * @param operationName Operation name from the registry.
8
+ * @param variables Operation variables.
9
+ * @returns Operation result data.
10
+ */
11
+ export declare function executeGraphQLSchema<TName extends QueryName | MutationName>(event: H3Event, operationName: TName, variables: VariablesOf<TName>): Promise<ResultOf<TName>>;
@@ -0,0 +1,23 @@
1
+ import { execute } from "graphql";
2
+ import { createContext } from "#graphql/context";
3
+ import { schema } from "#graphql/schema";
4
+ import { normalizeError } from "../../shared/lib/error.js";
5
+ import { getOperationDocument } from "../../shared/lib/registry.js";
6
+ export async function executeGraphQLSchema(event, operationName, variables) {
7
+ const document = getOperationDocument(operationName);
8
+ const result = await execute({
9
+ schema,
10
+ document,
11
+ variableValues: variables,
12
+ contextValue: await createContext(event)
13
+ });
14
+ if (result.errors?.length) {
15
+ throw normalizeError(result.errors);
16
+ }
17
+ if (!result.data) {
18
+ throw normalizeError(
19
+ new Error("GraphQL execution returned no data")
20
+ );
21
+ }
22
+ return result.data;
23
+ }
@@ -1,35 +1,19 @@
1
1
  import type { Executor } from "@graphql-tools/utils";
2
- import type { GraphQLContext } from "#graphql/context";
3
- export type RemoteExecMiddlewareOnRequestArgs = {
4
- remoteName: string;
5
- operationName: string;
6
- context: GraphQLContext;
7
- fetchOptions: {
8
- headers: Headers;
9
- };
10
- };
11
- export type RemoteExecMiddlewareOnResponseArgs = {
12
- remoteName: string;
13
- operationName: string;
14
- context: GraphQLContext;
15
- response: Response;
16
- };
17
- export type RemoteExecMiddlewareOnErrorArgs = {
18
- remoteName: string;
19
- operationName: string;
20
- context: GraphQLContext;
21
- error: unknown;
22
- response?: Response;
23
- };
24
- export type RemoteExecMiddlewareHandler = {
25
- onRequest?: (args: RemoteExecMiddlewareOnRequestArgs) => Promise<void> | void;
26
- onResponse?: (args: RemoteExecMiddlewareOnResponseArgs) => Promise<void> | void;
27
- onError?: (args: RemoteExecMiddlewareOnErrorArgs) => Promise<void> | void;
28
- };
29
- export interface CreateRemoteExecutorOptions {
2
+ import { type HeadersInput } from "../../shared/lib/headers.js";
3
+ import type { GraphQLRemoteExecHooks } from "../utils/defineRemoteExecutorHooks.js";
4
+ type CreateRemoteExecutorInput = {
30
5
  url: string;
31
- remoteName: string;
32
- headers?: HeadersInit;
33
- middleware?: RemoteExecMiddlewareHandler;
34
- }
35
- export declare function createRemoteExecutor(options: CreateRemoteExecutorOptions): Executor;
6
+ headers?: HeadersInput;
7
+ hooks: GraphQLRemoteExecHooks[];
8
+ };
9
+ /**
10
+ * Create an HTTP executor for a remote GraphQL schema.
11
+ *
12
+ * @param {CreateRemoteExecutorInput} options Remote executor configuration.
13
+ * @param options.url Remote GraphQL endpoint.
14
+ * @param options.headers Static headers for all requests.
15
+ * @param options.hooks Per-operation hooks.
16
+ * @returns Executor function for GraphQL Tools.
17
+ */
18
+ export declare function createRemoteExecutor({ url, headers, hooks }: CreateRemoteExecutorInput): Executor;
19
+ export {};
@@ -1,68 +1,33 @@
1
- import { parse, print, getOperationAST } from "graphql";
2
- import { normalizeGraphQLError } from "../../shared/lib/graphql-error.js";
3
- export function createRemoteExecutor(options) {
4
- const { url, remoteName, headers = {}, middleware } = options;
5
- const { onRequest, onResponse, onError } = middleware ?? {};
6
- let executionDepth = 0;
7
- return async ({ document, variables, context, operationName }) => {
8
- executionDepth++;
9
- const parsedDocument = typeof document === "string" ? parse(document) : document;
10
- const op = getOperationAST(parsedDocument, operationName);
11
- const resolvedOperationName = op?.name?.value ?? operationName ?? "anonymous";
12
- const query = typeof document === "string" ? document : print(document);
13
- const graphQLContext = context;
14
- const requestHeaders = new Headers({ "Content-Type": "application/json", ...headers });
15
- const fetchOptions = {
16
- method: "POST",
17
- headers: requestHeaders,
18
- body: JSON.stringify({ query, variables, operationName: resolvedOperationName })
19
- };
20
- if (onRequest && executionDepth === 1) {
21
- await onRequest({
22
- remoteName,
23
- operationName: resolvedOperationName,
24
- context: graphQLContext,
25
- fetchOptions: { headers: requestHeaders }
26
- });
27
- }
1
+ import { buildHTTPExecutor } from "@graphql-tools/executor-http";
2
+ import { mergeHeaders } from "../../shared/lib/headers.js";
3
+ export function createRemoteExecutor({ url, headers, hooks }) {
4
+ function getHeaders(request) {
5
+ const extHeaders = request?.extensions?.headers || {};
6
+ const mergedHeaders = mergeHeaders(headers, extHeaders);
7
+ return Object.fromEntries(mergedHeaders.entries());
8
+ }
9
+ const executor = buildHTTPExecutor({
10
+ endpoint: url,
11
+ headers: (request) => getHeaders(request),
12
+ fetch: globalThis.fetch
13
+ });
14
+ return async (request) => {
28
15
  try {
29
- const response = await fetch(url, fetchOptions);
30
- const safeResponse = response.clone();
31
- if (!response.ok) {
32
- const statusError = normalizeGraphQLError(new Error(`Remote ${remoteName} responded with status ${response.status}`));
33
- if (onError) {
34
- await onError({ remoteName, operationName: resolvedOperationName, context: graphQLContext, error: statusError, response: safeResponse });
35
- }
36
- throw statusError;
16
+ for (const hook of hooks) {
17
+ await hook.onRequest?.(request);
37
18
  }
38
- if (onResponse && executionDepth === 1) {
39
- await onResponse({ remoteName, operationName: resolvedOperationName, context: graphQLContext, response: safeResponse });
40
- }
41
- try {
42
- const json = await response.json();
43
- if (json && typeof json === "object" && Array.isArray(json.errors)) {
44
- const normalized = normalizeGraphQLError({ errors: json.errors });
45
- if (onError) {
46
- await onError({ remoteName, operationName: resolvedOperationName, context: graphQLContext, error: normalized, response: safeResponse });
47
- }
48
- throw normalized;
49
- }
50
- return json;
51
- } catch (error) {
52
- const normalized = normalizeGraphQLError(error);
53
- if (onError) {
54
- await onError({ remoteName, operationName: resolvedOperationName, context: graphQLContext, error: normalized, response: safeResponse });
19
+ const result = await executor(request);
20
+ if (!(Symbol.asyncIterator in result)) {
21
+ for (const hook of hooks) {
22
+ await hook.onResult?.(result);
55
23
  }
56
- throw normalized;
57
24
  }
25
+ return result;
58
26
  } catch (error) {
59
- const normalized = normalizeGraphQLError(error);
60
- if (onError) {
61
- await onError({ remoteName, operationName: resolvedOperationName, context: graphQLContext, error: normalized });
27
+ for (const hook of hooks) {
28
+ await hook.onError?.(error);
62
29
  }
63
- throw normalized;
64
- } finally {
65
- executionDepth--;
30
+ throw error;
66
31
  }
67
32
  };
68
33
  }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Get or create the singleton GraphQL Yoga instance.
3
+ *
4
+ * @returns GraphQL Yoga server instance.
5
+ */
6
+ export declare function getYogaInstance(): import("graphql-yoga").YogaServerInstance<{}, {}>;
@@ -0,0 +1,20 @@
1
+ import { createYoga } from "graphql-yoga";
2
+ import { schema } from "#graphql/schema";
3
+ let yoga = null;
4
+ export function getYogaInstance() {
5
+ if (!yoga) {
6
+ yoga = createYoga({
7
+ schema,
8
+ graphqlEndpoint: "/api/graphql",
9
+ fetchAPI: globalThis,
10
+ graphiql: process.env.NODE_ENV !== "production",
11
+ // @ts-expect-error subscriptions type available at runtime
12
+ subscriptions: { protocol: "SSE" }
13
+ });
14
+ if (!yoga) {
15
+ throw new Error("Failed to create Yoga instance");
16
+ }
17
+ }
18
+ return yoga;
19
+ }
20
+ ;
@@ -0,0 +1,10 @@
1
+ import type { H3Event } from "h3";
2
+ type GraphQLContextFactory<TContext extends Record<string, unknown>> = (event: H3Event) => TContext | Promise<TContext>;
3
+ /**
4
+ * Define a GraphQL context factory with proper typing.
5
+ *
6
+ * @param factory Context factory function.
7
+ * @returns The same factory, typed for inference.
8
+ */
9
+ export declare function defineGraphQLContext<TContext extends Record<string, unknown>>(factory: GraphQLContextFactory<TContext>): GraphQLContextFactory<TContext>;
10
+ export {};
@@ -0,0 +1,3 @@
1
+ export function defineGraphQLContext(factory) {
2
+ return factory;
3
+ }
@@ -0,0 +1,14 @@
1
+ import type { GraphQLSchema } from "graphql";
2
+ import type { SubschemaConfig } from "@graphql-tools/delegate";
3
+ /**
4
+ * Wrap a GraphQL schema or subschema config for module consumption.
5
+ *
6
+ * @param {{ schema: GraphQLSchema | SubschemaConfig }} options Schema wrapper input.
7
+ * @param options.schema Local schema or subschema config.
8
+ * @returns Wrapper object containing the schema.
9
+ */
10
+ export declare function defineGraphQLSchema({ schema }: {
11
+ schema: GraphQLSchema | SubschemaConfig;
12
+ }): {
13
+ schema: GraphQLSchema | SubschemaConfig<any, any, any, Record<string, any>>;
14
+ };
@@ -0,0 +1,3 @@
1
+ export function defineGraphQLSchema({ schema }) {
2
+ return { schema };
3
+ }
@@ -0,0 +1,13 @@
1
+ import type { ExecutionRequest, ExecutionResult } from "@graphql-tools/utils";
2
+ export interface GraphQLRemoteExecHooks {
3
+ onRequest?: (request: ExecutionRequest) => void | Promise<void>;
4
+ onResult?: (result: ExecutionResult) => void | Promise<void>;
5
+ onError?: (error: unknown) => void | Promise<void>;
6
+ }
7
+ /**
8
+ * Define remote executor hooks with proper typing.
9
+ *
10
+ * @param hooks Hooks implementation.
11
+ * @returns The same hooks object.
12
+ */
13
+ export declare function defineRemoteExecutorHooks(hooks: GraphQLRemoteExecHooks): GraphQLRemoteExecHooks;
@@ -0,0 +1,3 @@
1
+ export function defineRemoteExecutorHooks(hooks) {
2
+ return hooks;
3
+ }
@@ -1,9 +1,17 @@
1
1
  import type { H3Event } from "h3";
2
- import { type MutationName, type MutationResult, type MutationVariables } from "#graphql/registry";
3
- import { type ExecuteServerGraphQLOptions } from "../lib/execute-server-graphql.js";
4
- export interface ServerMutateOptions {
5
- headers?: HeadersInit;
6
- }
7
- export declare function useServerGraphQLMutation<N extends MutationName>(event: H3Event, operationName: N, options?: ExecuteServerGraphQLOptions): {
8
- mutate: (...args: IsEmptyObject<MutationVariables<N>> extends true ? [variables?: MutationVariables<N>, mutateOptions?: ServerMutateOptions] : [variables: MutationVariables<N>, mutateOptions?: ServerMutateOptions]) => Promise<MutationResult<N>>;
9
- };
2
+ import type { MutationName, VariablesOf, ResultOf } from "#graphql/registry";
3
+ import { type SafeResult } from "../../shared/lib/error.js";
4
+ import type { IsEmptyObject } from "../../shared/lib/utils.js";
5
+ /**
6
+ * Execute a GraphQL mutation against the local stitched schema (server-side).
7
+ *
8
+ * - Schema execution only (no HTTP)
9
+ * - Context comes from the H3 event
10
+ * - Errors are normalized
11
+ *
12
+ * @param event H3 event used to create context.
13
+ * @param operationName Operation name from the registry.
14
+ * @param variables Operation variables.
15
+ * @returns SafeResult containing data or a normalized error.
16
+ */
17
+ export declare function useServerGraphQLMutation<TName extends MutationName>(event: H3Event, operationName: TName, ...args: IsEmptyObject<VariablesOf<TName>> extends true ? [variables?: VariablesOf<TName>] : [variables: VariablesOf<TName>]): Promise<SafeResult<ResultOf<TName>>>;
@@ -1,13 +1,14 @@
1
- import { mutations } from "#graphql/registry";
2
- import { executeServerGraphQL } from "../lib/execute-server-graphql.js";
3
- import { mergeHeaders } from "../../shared/lib/headers.js";
4
- export function useServerGraphQLMutation(event, operationName, options) {
5
- async function mutate(...args) {
6
- const [variables, mutateOptions] = args;
7
- return executeServerGraphQL(event, mutations[operationName], variables, {
8
- ...options,
9
- headers: mergeHeaders(options?.headers, mutateOptions?.headers)
10
- });
1
+ import { executeGraphQLSchema } from "../lib/execute-schema.js";
2
+ import { normalizeError } from "../../shared/lib/error.js";
3
+ export async function useServerGraphQLMutation(event, operationName, ...args) {
4
+ try {
5
+ const [variables] = args;
6
+ const data = await executeGraphQLSchema(event, operationName, variables);
7
+ return { data, error: null };
8
+ } catch (err) {
9
+ return {
10
+ data: null,
11
+ error: normalizeError(err)
12
+ };
11
13
  }
12
- return { mutate };
13
14
  }
@@ -1,4 +1,17 @@
1
1
  import type { H3Event } from "h3";
2
- import { type QueryName, type QueryResult, type QueryVariables } from "#graphql/registry";
3
- import { type ExecuteServerGraphQLOptions } from "../lib/execute-server-graphql.js";
4
- export declare function useServerGraphQLQuery<N extends QueryName>(event: H3Event, operationName: N, ...args: IsEmptyObject<QueryVariables<N>> extends true ? [variables?: QueryVariables<N>, options?: ExecuteServerGraphQLOptions] : [variables: QueryVariables<N>, options?: ExecuteServerGraphQLOptions]): Promise<QueryResult<N>>;
2
+ import type { QueryName, VariablesOf, ResultOf } from "#graphql/registry";
3
+ import { type SafeResult } from "../../shared/lib/error.js";
4
+ import type { IsEmptyObject } from "../../shared/lib/utils.js";
5
+ /**
6
+ * Execute a GraphQL query against the local stitched schema (server-side).
7
+ *
8
+ * - Schema execution only (no HTTP)
9
+ * - Context comes from the H3 event
10
+ * - Errors are normalized
11
+ *
12
+ * @param event H3 event used to create context.
13
+ * @param operationName Operation name from the registry.
14
+ * @param variables Operation variables.
15
+ * @returns SafeResult containing data or a normalized error.
16
+ */
17
+ export declare function useServerGraphQLQuery<TName extends QueryName>(event: H3Event, operationName: TName, ...args: IsEmptyObject<VariablesOf<TName>> extends true ? [variables?: VariablesOf<TName>] : [variables: VariablesOf<TName>]): Promise<SafeResult<ResultOf<TName>>>;
@@ -1,6 +1,18 @@
1
- import { queries } from "#graphql/registry";
2
- import { executeServerGraphQL } from "../lib/execute-server-graphql.js";
1
+ import { executeGraphQLSchema } from "../lib/execute-schema.js";
2
+ import { normalizeError } from "../../shared/lib/error.js";
3
3
  export async function useServerGraphQLQuery(event, operationName, ...args) {
4
- const [variables, options] = args;
5
- return executeServerGraphQL(event, queries[operationName], variables, options);
4
+ const [variables] = args;
5
+ try {
6
+ const data = await executeGraphQLSchema(
7
+ event,
8
+ operationName,
9
+ variables
10
+ );
11
+ return { data, error: null };
12
+ } catch (err) {
13
+ return {
14
+ data: null,
15
+ error: normalizeError(err)
16
+ };
17
+ }
6
18
  }
@@ -0,0 +1,42 @@
1
+ type GraphQLCachePolicy = "no-cache" | "cache-first" | "network-first" | "swr";
2
+ export interface CacheConfig {
3
+ /**
4
+ * Prefix used for all persisted cache keys.
5
+ *
6
+ * Used for namespacing and bulk invalidation.
7
+ * Default: 'graphql'
8
+ */
9
+ keyPrefix: string;
10
+ /**
11
+ * Version included in cache keys.
12
+ *
13
+ * Changing this value invalidates all existing cache entries.
14
+ * Default: '1'
15
+ */
16
+ keyVersion: string | number;
17
+ /**
18
+ * Cache strategy used by useAsyncGraphQLQuery.
19
+ *
20
+ * - 'no-cache' → always fetch, never read/write cache
21
+ * - 'cache-first' → return cache if valid, otherwise fetch
22
+ * - 'network-first' → fetch first, fallback to cache on failure
23
+ * - 'swr' → return cache immediately, revalidate in background
24
+ */
25
+ policy: GraphQLCachePolicy;
26
+ /**
27
+ * Time-to-live in seconds.
28
+ *
29
+ * - undefined → inherit from higher-level config
30
+ * - 0 → never expires
31
+ * - > 0 → expires after TTL
32
+ */
33
+ ttl?: number;
34
+ }
35
+ /**
36
+ * Merge the default cache config with user overrides.
37
+ *
38
+ * @param overrides Partial cache config overrides.
39
+ * @returns Resolved cache configuration.
40
+ */
41
+ export declare function resolveCacheConfig(...overrides: Array<Partial<CacheConfig> | undefined>): CacheConfig;
42
+ export {};
@@ -1,8 +1,8 @@
1
1
  const defaultCacheConfig = {
2
- cachePolicy: "cache-first",
3
- cacheVersion: "1",
4
2
  keyPrefix: "gql",
5
- ttl: 60
3
+ keyVersion: "1",
4
+ policy: "no-cache",
5
+ ttl: void 0
6
6
  };
7
7
  export function resolveCacheConfig(...overrides) {
8
8
  return Object.assign({}, defaultCacheConfig, ...overrides);
@@ -0,0 +1,56 @@
1
+ import type { GraphQLError } from "graphql";
2
+ /**
3
+ * Safe result type.
4
+ *
5
+ * - On success, `data` contains the result and `error` is `null`.
6
+ * - On failure, `data` is `null` and `error` contains a NormalizedError.
7
+ */
8
+ export type SafeResult<T> = {
9
+ data: T;
10
+ error: null;
11
+ } | {
12
+ data: null;
13
+ error: NormalizedError;
14
+ };
15
+ /**
16
+ * Base GraphQL error codes.
17
+ * Users may extend this interface via declaration merging.
18
+ */
19
+ export interface GraphQLErrorCodeMap {
20
+ INTERNAL_ERROR: true;
21
+ NETWORK_ERROR: true;
22
+ BAD_REQUEST: true;
23
+ UNAUTHORIZED: true;
24
+ FORBIDDEN: true;
25
+ }
26
+ /**
27
+ * Typed GraphQL error code.
28
+ * Extensible via interface augmentation.
29
+ */
30
+ type GraphQLErrorCode = keyof GraphQLErrorCodeMap;
31
+ /**
32
+ * Unified, transport-agnostic GraphQL error.
33
+ *
34
+ * - `message` : human-readable summary
35
+ * - `code` : typed, extensible error code
36
+ * - `errors[]` : underlying GraphQL execution errors (lossless)
37
+ */
38
+ export declare class NormalizedError extends Error {
39
+ readonly errors: readonly GraphQLError[];
40
+ readonly code?: GraphQLErrorCode;
41
+ constructor(input: {
42
+ message: string;
43
+ errors?: readonly GraphQLError[];
44
+ code?: GraphQLErrorCode;
45
+ });
46
+ }
47
+ /**
48
+ * Normalize an unknown error into a NormalizedError.
49
+ *
50
+ * This function is the **only** place where untrusted errors are interpreted.
51
+ *
52
+ * @param error Unknown error value.
53
+ * @returns NormalizedError instance.
54
+ */
55
+ export declare function normalizeError(error: unknown): NormalizedError;
56
+ export {};
@@ -0,0 +1,61 @@
1
+ export class NormalizedError extends Error {
2
+ errors;
3
+ code;
4
+ constructor(input) {
5
+ super(input.message);
6
+ this.name = "NormalizedError";
7
+ this.errors = input.errors ?? [];
8
+ this.code = input.code;
9
+ }
10
+ }
11
+ function isGraphQLError(error) {
12
+ return typeof error === "object" && error !== null && "message" in error && "extensions" in error;
13
+ }
14
+ function isGraphQLErrorArray(error) {
15
+ return Array.isArray(error) && error.every(isGraphQLError);
16
+ }
17
+ function isGraphQLClientError(error) {
18
+ return typeof error === "object" && error !== null && "response" in error;
19
+ }
20
+ function extractCode(error) {
21
+ const code = error?.extensions?.code;
22
+ return typeof code === "string" ? code : void 0;
23
+ }
24
+ export function normalizeError(error) {
25
+ if (error instanceof NormalizedError) {
26
+ return error;
27
+ }
28
+ if (isGraphQLError(error)) {
29
+ return new NormalizedError({
30
+ message: error.message,
31
+ errors: [error],
32
+ code: extractCode(error)
33
+ });
34
+ }
35
+ if (isGraphQLClientError(error)) {
36
+ const errors = error.response?.errors;
37
+ if (errors && isGraphQLErrorArray(errors)) {
38
+ return new NormalizedError({
39
+ message: errors.map(({ message }) => message).join("\n"),
40
+ errors,
41
+ code: extractCode(errors[0])
42
+ });
43
+ }
44
+ return new NormalizedError({
45
+ message: error.message ?? "GraphQL network error",
46
+ code: "NETWORK_ERROR"
47
+ });
48
+ }
49
+ if (typeof error === "object" && error !== null && "errors" in error && isGraphQLErrorArray(error.errors)) {
50
+ const errors = error.errors;
51
+ return new NormalizedError({
52
+ message: errors.map(({ message }) => message).join("\n"),
53
+ errors,
54
+ code: extractCode(errors[0])
55
+ });
56
+ }
57
+ return new NormalizedError({
58
+ message: error instanceof Error ? error.message : String(error),
59
+ code: "INTERNAL_ERROR"
60
+ });
61
+ }
@@ -1,3 +1,13 @@
1
- import type { H3Event } from "h3";
2
- export declare function getClientForwardHeaders(event: H3Event): HeadersInit | undefined;
3
- export declare function mergeHeaders(...headers: Array<HeadersInit | undefined>): HeadersInit | undefined;
1
+ /**
2
+ * Header map where:
3
+ * - string → set / override header
4
+ * - null → delete header
5
+ */
6
+ export type HeadersInput = Record<string, string | null>;
7
+ /**
8
+ * Merge multiple header inputs into a single Headers instance.
9
+ *
10
+ * @param inputs Header input objects (later inputs override earlier).
11
+ * @returns Merged Headers instance.
12
+ */
13
+ export declare function mergeHeaders(...inputs: Array<HeadersInput | undefined>): Headers;