nitro-graphql 2.0.0-beta.3 → 2.0.0-beta.30
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 +476 -19
- package/dist/define.d.mts +296 -0
- package/dist/define.mjs +323 -0
- package/dist/ecosystem/nuxt.mjs +109 -0
- package/dist/index.d.mts +43 -0
- package/dist/index.mjs +63 -0
- package/dist/rollup.d.mts +12 -0
- package/dist/rollup.mjs +282 -0
- package/dist/routes/apollo-server.d.mts +6 -0
- package/dist/routes/{apollo-server.js → apollo-server.mjs} +7 -7
- package/dist/routes/debug.d.mts +61 -0
- package/dist/routes/debug.mjs +445 -0
- package/dist/routes/graphql-yoga.d.mts +6 -0
- package/dist/routes/{graphql-yoga.js → graphql-yoga.mjs} +11 -7
- package/dist/routes/health.d.mts +10 -0
- package/dist/routes/{health.js → health.mjs} +3 -2
- package/dist/setup.d.mts +11 -0
- package/dist/setup.mjs +392 -0
- package/dist/{utils/define.d.ts → types/define.d.mts} +4 -27
- package/dist/types/define.mjs +1 -0
- package/dist/types/index.d.mts +246 -0
- package/dist/types/index.mjs +1 -0
- package/dist/types/standard-schema.mjs +1 -0
- package/dist/utils/{apollo.d.ts → apollo.d.mts} +2 -2
- package/dist/utils/apollo.mjs +59 -0
- package/dist/utils/{client-codegen.d.ts → client-codegen.d.mts} +6 -3
- package/dist/utils/{client-codegen.js → client-codegen.mjs} +6 -6
- package/dist/utils/errors.d.mts +73 -0
- package/dist/utils/errors.mjs +89 -0
- package/dist/utils/file-generator.d.mts +37 -0
- package/dist/utils/file-generator.mjs +72 -0
- package/dist/utils/{index.d.ts → index.d.mts} +4 -3
- package/dist/utils/{index.js → index.mjs} +76 -37
- package/dist/utils/path-resolver.d.mts +70 -0
- package/dist/utils/path-resolver.mjs +127 -0
- package/dist/utils/{server-codegen.d.ts → server-codegen.d.mts} +1 -1
- package/dist/utils/{server-codegen.js → server-codegen.mjs} +3 -3
- package/dist/utils/type-generation.d.mts +12 -0
- package/dist/utils/type-generation.mjs +420 -0
- package/dist/virtual/debug-info.d.mts +9 -0
- package/dist/virtual/debug-info.mjs +26 -0
- package/dist/virtual/graphql-config.d.mts +9 -0
- package/dist/virtual/graphql-config.mjs +10 -0
- package/dist/virtual/module-config.d.mts +9 -0
- package/dist/virtual/module-config.mjs +10 -0
- package/dist/virtual/server-directives.d.mts +11 -0
- package/dist/virtual/server-directives.mjs +10 -0
- package/dist/virtual/server-resolvers.d.mts +11 -0
- package/dist/virtual/server-resolvers.mjs +10 -0
- package/dist/virtual/server-schemas.d.mts +11 -0
- package/dist/virtual/server-schemas.mjs +10 -0
- package/package.json +79 -70
- package/dist/ecosystem/nuxt.js +0 -67
- package/dist/index.d.ts +0 -8
- package/dist/index.js +0 -264
- package/dist/rollup.js +0 -114
- package/dist/routes/apollo-server.d.ts +0 -6
- package/dist/routes/graphql-yoga.d.ts +0 -6
- package/dist/routes/health.d.ts +0 -6
- package/dist/types/index.d.ts +0 -128
- package/dist/utils/apollo.js +0 -61
- package/dist/utils/define.js +0 -57
- package/dist/utils/type-generation.d.ts +0 -7
- package/dist/utils/type-generation.js +0 -287
- /package/dist/ecosystem/{nuxt.d.ts → nuxt.d.mts} +0 -0
- /package/dist/graphql/{index.d.ts → index.d.mts} +0 -0
- /package/dist/graphql/{index.js → index.mjs} +0 -0
- /package/dist/graphql/{server.d.ts → server.d.mts} +0 -0
- /package/dist/graphql/{server.js → server.mjs} +0 -0
- /package/dist/types/{standard-schema.d.ts → standard-schema.d.mts} +0 -0
- /package/dist/utils/{directive-parser.d.ts → directive-parser.d.mts} +0 -0
- /package/dist/utils/{directive-parser.js → directive-parser.mjs} +0 -0
package/dist/rollup.js
DELETED
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
import { getImportId, scanGraphql } from "./utils/index.js";
|
|
2
|
-
import { clientTypeGeneration, serverTypeGeneration } from "./utils/type-generation.js";
|
|
3
|
-
import { resolve } from "pathe";
|
|
4
|
-
import { readFile } from "node:fs/promises";
|
|
5
|
-
import { parse } from "graphql";
|
|
6
|
-
import { genImport } from "knitwork";
|
|
7
|
-
|
|
8
|
-
//#region src/rollup.ts
|
|
9
|
-
async function rollupConfig(app) {
|
|
10
|
-
virtualSchemas(app);
|
|
11
|
-
virtualResolvers(app);
|
|
12
|
-
virtualDirectives(app);
|
|
13
|
-
getGraphQLConfig(app);
|
|
14
|
-
virtualModuleConfig(app);
|
|
15
|
-
app.hooks.hook("rollup:before", (nitro, rollupConfig$1) => {
|
|
16
|
-
rollupConfig$1.plugins = rollupConfig$1.plugins || [];
|
|
17
|
-
const { include = /\.(graphql|gql)$/i, exclude, validate = false } = app.options.graphql?.loader || {};
|
|
18
|
-
if (Array.isArray(rollupConfig$1.plugins)) {
|
|
19
|
-
rollupConfig$1.plugins.push({
|
|
20
|
-
name: "nitro-graphql",
|
|
21
|
-
async load(id) {
|
|
22
|
-
if (exclude?.test?.(id)) return null;
|
|
23
|
-
if (!include.test(id)) return null;
|
|
24
|
-
try {
|
|
25
|
-
const content = await readFile(id, "utf-8");
|
|
26
|
-
if (validate) parse(content);
|
|
27
|
-
return `export default ${JSON.stringify(content)}`;
|
|
28
|
-
} catch (error) {
|
|
29
|
-
if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") return null;
|
|
30
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
31
|
-
this.error(`Failed to read GraphQL file ${id}: ${message}`);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
});
|
|
35
|
-
rollupConfig$1.plugins.push({
|
|
36
|
-
name: "nitro-graphql-watcher",
|
|
37
|
-
async buildStart() {
|
|
38
|
-
const graphqlFiles = await scanGraphql(nitro);
|
|
39
|
-
for (const file of graphqlFiles) this.addWatchFile(file);
|
|
40
|
-
}
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
});
|
|
44
|
-
app.hooks.hook("dev:reload", async () => {
|
|
45
|
-
await serverTypeGeneration(app);
|
|
46
|
-
await clientTypeGeneration(app);
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
|
-
function virtualSchemas(app) {
|
|
50
|
-
const getSchemas = () => [...app.scanSchemas, ...app.options.graphql?.typedefs ?? []];
|
|
51
|
-
app.options.virtual ??= {};
|
|
52
|
-
app.options.virtual["#nitro-internal-virtual/server-schemas"] = () => {
|
|
53
|
-
const imports = getSchemas();
|
|
54
|
-
return `
|
|
55
|
-
${imports.map((handler) => `import ${getImportId(handler)} from '${handler}';`).join("\n")}
|
|
56
|
-
|
|
57
|
-
export const schemas = [
|
|
58
|
-
${imports.map((h) => `{ def: ${getImportId(h)} }`).join(",\n")}
|
|
59
|
-
];
|
|
60
|
-
`;
|
|
61
|
-
};
|
|
62
|
-
}
|
|
63
|
-
function virtualResolvers(app) {
|
|
64
|
-
const getResolvers = () => [...app.scanResolvers];
|
|
65
|
-
app.options.virtual ??= {};
|
|
66
|
-
app.options.virtual["#nitro-internal-virtual/server-resolvers"] = () => {
|
|
67
|
-
const imports = getResolvers();
|
|
68
|
-
const importsContent = imports.map(({ specifier, imports: imports$1, options }) => genImport(specifier, imports$1, options));
|
|
69
|
-
const data = imports.map(({ imports: imports$1 }) => imports$1.map((i) => `{ resolver: ${i.as} }`).join(",\n")).filter(Boolean).join(",\n");
|
|
70
|
-
return [
|
|
71
|
-
...importsContent,
|
|
72
|
-
"export const resolvers = [",
|
|
73
|
-
data,
|
|
74
|
-
"]",
|
|
75
|
-
""
|
|
76
|
-
].join("\n");
|
|
77
|
-
};
|
|
78
|
-
}
|
|
79
|
-
function virtualDirectives(app) {
|
|
80
|
-
const getDirectives = () => app.scanDirectives || [];
|
|
81
|
-
app.options.virtual ??= {};
|
|
82
|
-
app.options.virtual["#nitro-internal-virtual/server-directives"] = () => {
|
|
83
|
-
const imports = getDirectives();
|
|
84
|
-
const importsContent = imports.map(({ specifier, imports: imports$1, options }) => genImport(specifier, imports$1, options));
|
|
85
|
-
const data = imports.map(({ imports: imports$1 }) => imports$1.map((i) => `{ directive: ${i.as} }`).join(",\n")).filter(Boolean).join(",\n");
|
|
86
|
-
return [
|
|
87
|
-
...importsContent,
|
|
88
|
-
"export const directives = [",
|
|
89
|
-
data,
|
|
90
|
-
"]",
|
|
91
|
-
""
|
|
92
|
-
].join("\n");
|
|
93
|
-
};
|
|
94
|
-
}
|
|
95
|
-
function getGraphQLConfig(app) {
|
|
96
|
-
const configPath = resolve(app.graphql.serverDir, "config.ts");
|
|
97
|
-
app.options.virtual ??= {};
|
|
98
|
-
app.options.virtual["#nitro-internal-virtual/graphql-config"] = () => {
|
|
99
|
-
return `import config from '${configPath}'
|
|
100
|
-
const importedConfig = config
|
|
101
|
-
export { importedConfig }
|
|
102
|
-
`;
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
|
-
function virtualModuleConfig(app) {
|
|
106
|
-
app.options.virtual ??= {};
|
|
107
|
-
app.options.virtual["#nitro-internal-virtual/module-config"] = () => {
|
|
108
|
-
const moduleConfig = app.options.graphql || {};
|
|
109
|
-
return `export const moduleConfig = ${JSON.stringify(moduleConfig, null, 2)};`;
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
//#endregion
|
|
114
|
-
export { rollupConfig };
|
package/dist/routes/health.d.ts
DELETED
package/dist/types/index.d.ts
DELETED
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
import { StandardSchemaV1 } from "./standard-schema.js";
|
|
2
|
-
import { ESMCodeGenOptions } from "knitwork";
|
|
3
|
-
import { IResolvers } from "@graphql-tools/utils";
|
|
4
|
-
import { TypeScriptPluginConfig } from "@graphql-codegen/typescript";
|
|
5
|
-
import { plugin as plugin$1 } from "@graphql-codegen/typescript-generic-sdk";
|
|
6
|
-
import { TypeScriptDocumentsPluginConfig } from "@graphql-codegen/typescript-operations";
|
|
7
|
-
import { TypeScriptResolversPluginConfig } from "@graphql-codegen/typescript-resolvers";
|
|
8
|
-
|
|
9
|
-
//#region src/types/index.d.ts
|
|
10
|
-
type CodegenServerConfig = TypeScriptPluginConfig & TypeScriptResolversPluginConfig;
|
|
11
|
-
type DocumentModeConfig = Pick<Parameters<typeof plugin$1>[2], 'documentMode'>;
|
|
12
|
-
type DocumentModeEnum = NonNullable<DocumentModeConfig['documentMode']>;
|
|
13
|
-
type DocumentModeType = `${DocumentModeEnum}`;
|
|
14
|
-
type GenericSdkConfig = Omit<Parameters<typeof plugin$1>[2], 'documentMode'> & {
|
|
15
|
-
documentMode?: DocumentModeType;
|
|
16
|
-
};
|
|
17
|
-
type CodegenClientConfig = TypeScriptPluginConfig & TypeScriptDocumentsPluginConfig & {
|
|
18
|
-
endpoint?: string;
|
|
19
|
-
};
|
|
20
|
-
interface IESMImport {
|
|
21
|
-
name: string;
|
|
22
|
-
as?: string;
|
|
23
|
-
type: 'resolver' | 'query' | 'mutation' | 'type' | 'subscription' | 'directive';
|
|
24
|
-
}
|
|
25
|
-
interface GenImport {
|
|
26
|
-
specifier: string;
|
|
27
|
-
imports: IESMImport[];
|
|
28
|
-
options?: ESMCodeGenOptions;
|
|
29
|
-
}
|
|
30
|
-
declare module 'nitro/types' {
|
|
31
|
-
interface Nitro {
|
|
32
|
-
scanSchemas: string[];
|
|
33
|
-
scanDocuments: string[];
|
|
34
|
-
scanResolvers: GenImport[];
|
|
35
|
-
scanDirectives: GenImport[];
|
|
36
|
-
graphql: {
|
|
37
|
-
buildDir: string;
|
|
38
|
-
watchDirs: string[];
|
|
39
|
-
clientDir: string;
|
|
40
|
-
serverDir: string;
|
|
41
|
-
dir: {
|
|
42
|
-
build: string;
|
|
43
|
-
client: string;
|
|
44
|
-
server: string;
|
|
45
|
-
};
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
declare module 'nitro/types' {
|
|
50
|
-
interface NitroOptions {
|
|
51
|
-
graphql?: NitroGraphQLOptions;
|
|
52
|
-
}
|
|
53
|
-
interface NitroRuntimeConfig {
|
|
54
|
-
graphql?: NitroGraphQLOptions;
|
|
55
|
-
}
|
|
56
|
-
interface NitroConfig {
|
|
57
|
-
graphql?: NitroGraphQLOptions;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
interface ExternalGraphQLService {
|
|
61
|
-
/** Unique name for this service (used for file naming and type generation) */
|
|
62
|
-
name: string;
|
|
63
|
-
/** Schema source - can be URL(s) for remote schemas or file path(s) for local schemas */
|
|
64
|
-
schema: string | string[];
|
|
65
|
-
/** GraphQL endpoint for this service */
|
|
66
|
-
endpoint: string;
|
|
67
|
-
/** Optional headers for schema introspection and client requests */
|
|
68
|
-
headers?: Record<string, string> | (() => Record<string, string>);
|
|
69
|
-
/** Optional: specific document patterns for this service */
|
|
70
|
-
documents?: string[];
|
|
71
|
-
/**
|
|
72
|
-
* Optional: Download and cache schema locally for offline usage
|
|
73
|
-
* - true or 'once': Download if file doesn't exist, then use cached version (offline-friendly)
|
|
74
|
-
* - 'always': Check for updates on every build (current behavior)
|
|
75
|
-
* - 'manual': Never download automatically, user manages schema files manually
|
|
76
|
-
* - false: Disable schema downloading
|
|
77
|
-
*/
|
|
78
|
-
downloadSchema?: boolean | 'once' | 'always' | 'manual';
|
|
79
|
-
/** Optional: Custom path to save downloaded schema (default: .nitro/graphql/schemas/[serviceName].graphql) */
|
|
80
|
-
downloadPath?: string;
|
|
81
|
-
/** Optional: service-specific codegen configuration */
|
|
82
|
-
codegen?: {
|
|
83
|
-
client?: CodegenClientConfig;
|
|
84
|
-
clientSDK?: GenericSdkConfig;
|
|
85
|
-
};
|
|
86
|
-
}
|
|
87
|
-
interface FederationConfig {
|
|
88
|
-
/** Enable Apollo Federation subgraph support */
|
|
89
|
-
enabled: boolean;
|
|
90
|
-
/** Service name for federation (used in subgraph config) */
|
|
91
|
-
serviceName?: string;
|
|
92
|
-
/** Service version for federation */
|
|
93
|
-
serviceVersion?: string;
|
|
94
|
-
/** Service URL for federation gateway */
|
|
95
|
-
serviceUrl?: string;
|
|
96
|
-
}
|
|
97
|
-
interface NitroGraphQLOptions {
|
|
98
|
-
framework: 'graphql-yoga' | 'apollo-server';
|
|
99
|
-
endpoint?: {
|
|
100
|
-
graphql?: string;
|
|
101
|
-
healthCheck?: string;
|
|
102
|
-
};
|
|
103
|
-
playground?: boolean;
|
|
104
|
-
typedefs?: string[];
|
|
105
|
-
resolvers?: Array<IResolvers<any, any>>;
|
|
106
|
-
loader?: {
|
|
107
|
-
include?: RegExp;
|
|
108
|
-
exclude?: RegExp;
|
|
109
|
-
validate?: boolean;
|
|
110
|
-
};
|
|
111
|
-
codegen?: {
|
|
112
|
-
server?: CodegenServerConfig;
|
|
113
|
-
client?: CodegenClientConfig;
|
|
114
|
-
clientSDK?: GenericSdkConfig;
|
|
115
|
-
};
|
|
116
|
-
/** External GraphQL services to generate types and SDKs for */
|
|
117
|
-
externalServices?: ExternalGraphQLService[];
|
|
118
|
-
/** Apollo Federation configuration */
|
|
119
|
-
federation?: FederationConfig;
|
|
120
|
-
/** Server GraphQL directory path */
|
|
121
|
-
serverDir?: string;
|
|
122
|
-
/** Layer directories (populated by Nuxt module) */
|
|
123
|
-
layerDirectories?: string[];
|
|
124
|
-
layerServerDirs?: string[];
|
|
125
|
-
layerAppDirs?: string[];
|
|
126
|
-
}
|
|
127
|
-
//#endregion
|
|
128
|
-
export { CodegenClientConfig, CodegenServerConfig, ExternalGraphQLService, FederationConfig, GenImport, GenericSdkConfig, NitroGraphQLOptions };
|
package/dist/utils/apollo.js
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import { HeaderMap } from "@apollo/server";
|
|
2
|
-
import { eventHandler, getHeaders, isMethod, readBody, setHeaders } from "h3";
|
|
3
|
-
|
|
4
|
-
//#region src/utils/apollo.ts
|
|
5
|
-
function startServerAndCreateH3Handler(server, options) {
|
|
6
|
-
const defaultContext = () => Promise.resolve({});
|
|
7
|
-
const contextFunction = options?.context ?? defaultContext;
|
|
8
|
-
return eventHandler({
|
|
9
|
-
handler: async (event) => {
|
|
10
|
-
const apolloServer = typeof server === "function" ? server() : server;
|
|
11
|
-
if (!options?.serverAlreadyStarted) apolloServer.startInBackgroundHandlingStartupErrorsByLoggingAndFailingAllRequests();
|
|
12
|
-
if (isMethod(event, "OPTIONS")) return null;
|
|
13
|
-
try {
|
|
14
|
-
const graphqlRequest = await toGraphqlRequest(event);
|
|
15
|
-
const { body, headers, status } = await apolloServer.executeHTTPGraphQLRequest({
|
|
16
|
-
httpGraphQLRequest: graphqlRequest,
|
|
17
|
-
context: () => contextFunction({ event })
|
|
18
|
-
});
|
|
19
|
-
if (body.kind === "chunked") throw new Error("Incremental delivery not implemented");
|
|
20
|
-
setHeaders(event, Object.fromEntries(headers));
|
|
21
|
-
event.res.statusCode = status || 200;
|
|
22
|
-
return body.string;
|
|
23
|
-
} catch (error) {
|
|
24
|
-
if (error instanceof SyntaxError) {
|
|
25
|
-
event.res.statusCode = 400;
|
|
26
|
-
return error.message;
|
|
27
|
-
} else throw error;
|
|
28
|
-
}
|
|
29
|
-
},
|
|
30
|
-
websocket: options?.websocket
|
|
31
|
-
});
|
|
32
|
-
}
|
|
33
|
-
async function toGraphqlRequest(event) {
|
|
34
|
-
return {
|
|
35
|
-
method: event.req.method || "POST",
|
|
36
|
-
headers: normalizeHeaders(getHeaders(event)),
|
|
37
|
-
search: normalizeQueryString(event.req.url),
|
|
38
|
-
body: await normalizeBody(event)
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
function normalizeHeaders(headers) {
|
|
42
|
-
const headerMap = new HeaderMap();
|
|
43
|
-
for (const [key, value] of Object.entries(headers)) if (Array.isArray(value)) headerMap.set(key, value.join(","));
|
|
44
|
-
else if (value) headerMap.set(key, value);
|
|
45
|
-
return headerMap;
|
|
46
|
-
}
|
|
47
|
-
function normalizeQueryString(url) {
|
|
48
|
-
if (!url) return "";
|
|
49
|
-
return url.split("?")[1] || "";
|
|
50
|
-
}
|
|
51
|
-
async function normalizeBody(event) {
|
|
52
|
-
if (isMethod(event, [
|
|
53
|
-
"PATCH",
|
|
54
|
-
"POST",
|
|
55
|
-
"PUT",
|
|
56
|
-
"DELETE"
|
|
57
|
-
])) return await readBody(event);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
//#endregion
|
|
61
|
-
export { startServerAndCreateH3Handler };
|
package/dist/utils/define.js
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
//#region src/utils/define.ts
|
|
2
|
-
function defineSchema(config) {
|
|
3
|
-
return config;
|
|
4
|
-
}
|
|
5
|
-
function defineResolver(resolvers) {
|
|
6
|
-
return resolvers;
|
|
7
|
-
}
|
|
8
|
-
function defineQuery(resolvers = {}) {
|
|
9
|
-
return { Query: { ...resolvers } };
|
|
10
|
-
}
|
|
11
|
-
function defineMutation(resolvers = {}) {
|
|
12
|
-
return { Mutation: { ...resolvers } };
|
|
13
|
-
}
|
|
14
|
-
function defineSubscription(resolvers = {}) {
|
|
15
|
-
return { Subscription: { ...resolvers } };
|
|
16
|
-
}
|
|
17
|
-
function defineType(resolvers) {
|
|
18
|
-
return resolvers;
|
|
19
|
-
}
|
|
20
|
-
function defineGraphQLConfig(config) {
|
|
21
|
-
return config;
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* Helper function to create directive arguments with proper type inference
|
|
25
|
-
* @example
|
|
26
|
-
* args: {
|
|
27
|
-
* myArg: arg('String!', { defaultValue: 'hello' })
|
|
28
|
-
* }
|
|
29
|
-
*/
|
|
30
|
-
function arg(type, options) {
|
|
31
|
-
return {
|
|
32
|
-
type,
|
|
33
|
-
...options
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
function defineDirective(config) {
|
|
37
|
-
const args = config.args ? Object.entries(config.args).map(([name, arg$1]) => {
|
|
38
|
-
const defaultValue = arg$1.defaultValue !== void 0 ? ` = ${JSON.stringify(arg$1.defaultValue)}` : "";
|
|
39
|
-
return `${name}: ${arg$1.type}${defaultValue}`;
|
|
40
|
-
}).join(", ") : "";
|
|
41
|
-
const argsString = args ? `(${args})` : "";
|
|
42
|
-
const locations = config.locations.join(" | ");
|
|
43
|
-
const schemaDefinition = `directive @${config.name}${argsString} on ${locations}`;
|
|
44
|
-
Object.defineProperty(config, "__schema", {
|
|
45
|
-
value: schemaDefinition,
|
|
46
|
-
enumerable: false,
|
|
47
|
-
configurable: false,
|
|
48
|
-
writable: false
|
|
49
|
-
});
|
|
50
|
-
return {
|
|
51
|
-
...config,
|
|
52
|
-
locations: [...config.locations]
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
//#endregion
|
|
57
|
-
export { arg, defineDirective, defineGraphQLConfig, defineMutation, defineQuery, defineResolver, defineSchema, defineSubscription, defineType };
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import { Nitro } from "nitro/types";
|
|
2
|
-
|
|
3
|
-
//#region src/utils/type-generation.d.ts
|
|
4
|
-
declare function serverTypeGeneration(app: Nitro): Promise<void>;
|
|
5
|
-
declare function clientTypeGeneration(nitro: Nitro): Promise<void>;
|
|
6
|
-
//#endregion
|
|
7
|
-
export { clientTypeGeneration, serverTypeGeneration };
|
|
@@ -1,287 +0,0 @@
|
|
|
1
|
-
import { downloadAndSaveSchema, generateClientTypes, generateExternalClientTypes, loadExternalSchema, loadGraphQLDocuments } from "./client-codegen.js";
|
|
2
|
-
import { generateTypes } from "./server-codegen.js";
|
|
3
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
4
|
-
import consola from "consola";
|
|
5
|
-
import { basename, dirname, join, resolve } from "pathe";
|
|
6
|
-
import { buildSchema, parse } from "graphql";
|
|
7
|
-
import { buildSubgraphSchema } from "@apollo/subgraph";
|
|
8
|
-
import { loadFilesSync } from "@graphql-tools/load-files";
|
|
9
|
-
import { mergeTypeDefs } from "@graphql-tools/merge";
|
|
10
|
-
import { printSchemaWithDirectives } from "@graphql-tools/utils";
|
|
11
|
-
|
|
12
|
-
//#region src/utils/type-generation.ts
|
|
13
|
-
function generateGraphQLIndexFile(clientDir, externalServices = []) {
|
|
14
|
-
const indexPath = resolve(clientDir, "index.ts");
|
|
15
|
-
if (!existsSync(indexPath)) {
|
|
16
|
-
let indexContent = `// This file is auto-generated once by nitro-graphql for quick start
|
|
17
|
-
// You can modify this file according to your needs
|
|
18
|
-
//
|
|
19
|
-
// Export your main GraphQL service (auto-generated)
|
|
20
|
-
export * from './default/ofetch'
|
|
21
|
-
|
|
22
|
-
// Export external GraphQL services (auto-generated for existing services)
|
|
23
|
-
// When you add new external services, don't forget to add their exports here:
|
|
24
|
-
// export * from './yourServiceName/ofetch'
|
|
25
|
-
`;
|
|
26
|
-
for (const service of externalServices) indexContent += `export * from './${service.name}/ofetch'\n`;
|
|
27
|
-
writeFileSync(indexPath, indexContent, "utf-8");
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
function generateOfetchClient(clientDir, serviceName, endpoint, isDefault = false) {
|
|
31
|
-
const serviceDir = resolve(clientDir, serviceName);
|
|
32
|
-
const ofetchPath = resolve(serviceDir, "ofetch.ts");
|
|
33
|
-
if (!existsSync(serviceDir)) mkdirSync(serviceDir, { recursive: true });
|
|
34
|
-
if (existsSync(ofetchPath)) return;
|
|
35
|
-
const capitalizedServiceName = serviceName.charAt(0).toUpperCase() + serviceName.slice(1);
|
|
36
|
-
const functionName = isDefault ? "createGraphQLClient" : `create${capitalizedServiceName}GraphQLClient`;
|
|
37
|
-
const exportName = isDefault ? "$sdk" : `$${serviceName}Sdk`;
|
|
38
|
-
writeFileSync(ofetchPath, `// This file is auto-generated once by nitro-graphql for quick start
|
|
39
|
-
// You can modify this file according to your needs
|
|
40
|
-
import type { ${isDefault ? "Requester" : "Sdk, Requester"} } from './sdk'
|
|
41
|
-
import { getSdk } from './sdk'
|
|
42
|
-
|
|
43
|
-
export function ${functionName}(endpoint: string${isDefault ? "" : ` = '${endpoint}'`}): Requester {
|
|
44
|
-
return async <R>(doc: string, vars?: any): Promise<R> => {
|
|
45
|
-
const headers = import.meta.server ? useRequestHeaders() : undefined
|
|
46
|
-
|
|
47
|
-
const result = await $fetch(endpoint, {
|
|
48
|
-
method: 'POST',
|
|
49
|
-
body: { query: doc, variables: vars },
|
|
50
|
-
headers: {
|
|
51
|
-
'Content-Type': 'application/json',
|
|
52
|
-
...headers,
|
|
53
|
-
},
|
|
54
|
-
})
|
|
55
|
-
|
|
56
|
-
return result as R
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
export const ${exportName}${isDefault ? "" : ": Sdk"} = getSdk(${functionName}(${isDefault ? "'/api/graphql'" : ""}))`, "utf-8");
|
|
61
|
-
}
|
|
62
|
-
/**
|
|
63
|
-
* Check for duplicate type definitions using a simpler approach
|
|
64
|
-
* Try to build each schema individually - if that succeeds but merging fails, we have duplicates
|
|
65
|
-
* @returns true if validation passes, false if duplicates found
|
|
66
|
-
*/
|
|
67
|
-
function validateNoDuplicateTypes(schemas, schemaStrings) {
|
|
68
|
-
const individualSchemasByFile = /* @__PURE__ */ new Map();
|
|
69
|
-
schemaStrings.forEach((schemaContent, index) => {
|
|
70
|
-
const schemaPath = schemas[index];
|
|
71
|
-
const fileName = basename(schemaPath);
|
|
72
|
-
try {
|
|
73
|
-
parse(schemaContent);
|
|
74
|
-
individualSchemasByFile.set(fileName, schemaContent);
|
|
75
|
-
} catch (error) {
|
|
76
|
-
consola.warn(`Invalid GraphQL syntax in ${fileName}:`, error);
|
|
77
|
-
throw error;
|
|
78
|
-
}
|
|
79
|
-
});
|
|
80
|
-
try {
|
|
81
|
-
mergeTypeDefs([schemaStrings.join("\n\n")], {
|
|
82
|
-
throwOnConflict: false,
|
|
83
|
-
commentDescriptions: true,
|
|
84
|
-
sort: true
|
|
85
|
-
});
|
|
86
|
-
mergeTypeDefs([schemaStrings.join("\n\n")], {
|
|
87
|
-
throwOnConflict: true,
|
|
88
|
-
commentDescriptions: true,
|
|
89
|
-
sort: true
|
|
90
|
-
});
|
|
91
|
-
} catch (conflictError) {
|
|
92
|
-
if (conflictError?.message?.includes("already defined with a different type")) throw conflictError;
|
|
93
|
-
}
|
|
94
|
-
const typeNames = /* @__PURE__ */ new Set();
|
|
95
|
-
const duplicateTypes = [];
|
|
96
|
-
schemaStrings.forEach((schemaContent, index) => {
|
|
97
|
-
const fileName = basename(schemas[index]);
|
|
98
|
-
try {
|
|
99
|
-
parse(schemaContent).definitions.forEach((def) => {
|
|
100
|
-
if (def.kind === "ObjectTypeDefinition" || def.kind === "InterfaceTypeDefinition" || def.kind === "UnionTypeDefinition" || def.kind === "EnumTypeDefinition" || def.kind === "InputObjectTypeDefinition" || def.kind === "ScalarTypeDefinition") {
|
|
101
|
-
const typeName = def.name.value;
|
|
102
|
-
if ([
|
|
103
|
-
"String",
|
|
104
|
-
"Int",
|
|
105
|
-
"Float",
|
|
106
|
-
"Boolean",
|
|
107
|
-
"ID",
|
|
108
|
-
"DateTime",
|
|
109
|
-
"JSON"
|
|
110
|
-
].includes(typeName)) return;
|
|
111
|
-
if (typeNames.has(typeName)) {
|
|
112
|
-
const existing = duplicateTypes.find((d) => d.type === typeName);
|
|
113
|
-
if (existing) existing.files.push(fileName);
|
|
114
|
-
else {
|
|
115
|
-
const firstFile = schemas.find((_, i) => {
|
|
116
|
-
const content = schemaStrings[i];
|
|
117
|
-
if (!content) return false;
|
|
118
|
-
try {
|
|
119
|
-
return parse(content).definitions.some((d) => (d.kind === "ObjectTypeDefinition" || d.kind === "InterfaceTypeDefinition" || d.kind === "UnionTypeDefinition" || d.kind === "EnumTypeDefinition" || d.kind === "InputObjectTypeDefinition" || d.kind === "ScalarTypeDefinition") && d.name.value === typeName);
|
|
120
|
-
} catch {
|
|
121
|
-
return false;
|
|
122
|
-
}
|
|
123
|
-
});
|
|
124
|
-
duplicateTypes.push({
|
|
125
|
-
type: typeName,
|
|
126
|
-
files: [basename(firstFile || ""), fileName]
|
|
127
|
-
});
|
|
128
|
-
}
|
|
129
|
-
} else typeNames.add(typeName);
|
|
130
|
-
}
|
|
131
|
-
});
|
|
132
|
-
} catch {}
|
|
133
|
-
});
|
|
134
|
-
if (duplicateTypes.length > 0) {
|
|
135
|
-
let errorMessage = "⚠️ DUPLICATE TYPE DEFINITIONS DETECTED!\n\n";
|
|
136
|
-
duplicateTypes.forEach(({ type, files }) => {
|
|
137
|
-
errorMessage += `❌ Type "${type}" is defined in multiple files:\n`;
|
|
138
|
-
files.forEach((fileName) => {
|
|
139
|
-
const fullPath = schemas.find((path) => basename(path) === fileName) || fileName;
|
|
140
|
-
errorMessage += ` • ${fullPath}\n`;
|
|
141
|
-
});
|
|
142
|
-
errorMessage += "\n";
|
|
143
|
-
});
|
|
144
|
-
errorMessage += "💡 Each GraphQL type should only be defined once.\n";
|
|
145
|
-
errorMessage += " Consider using \"extend type\" syntax instead of duplicate definitions.\n";
|
|
146
|
-
errorMessage += `\n🔍 Found ${duplicateTypes.length} duplicate type(s): ${duplicateTypes.map((d) => d.type).join(", ")}`;
|
|
147
|
-
consola.error(errorMessage);
|
|
148
|
-
return false;
|
|
149
|
-
}
|
|
150
|
-
return true;
|
|
151
|
-
}
|
|
152
|
-
async function serverTypeGeneration(app) {
|
|
153
|
-
try {
|
|
154
|
-
const schemas = app.scanSchemas || [];
|
|
155
|
-
if (!schemas.length) {
|
|
156
|
-
consola.info("No GraphQL definitions found for server type generation.");
|
|
157
|
-
return;
|
|
158
|
-
}
|
|
159
|
-
const schemaStrings = loadFilesSync(schemas).map((schema$1) => typeof schema$1 === "string" ? schema$1 : schema$1.loc?.source?.body || "").filter(Boolean);
|
|
160
|
-
if (!validateNoDuplicateTypes(schemas, schemaStrings)) return;
|
|
161
|
-
const federationEnabled = app.options.graphql?.federation?.enabled === true;
|
|
162
|
-
const mergedSchemas = mergeTypeDefs([schemaStrings.join("\n\n")], {
|
|
163
|
-
throwOnConflict: true,
|
|
164
|
-
commentDescriptions: true,
|
|
165
|
-
sort: true
|
|
166
|
-
});
|
|
167
|
-
const schema = federationEnabled ? buildSubgraphSchema([{ typeDefs: parse(mergedSchemas) }]) : buildSchema(mergedSchemas);
|
|
168
|
-
const data = await generateTypes(app.options.graphql?.framework || "graphql-yoga", schema, app.options.graphql ?? {});
|
|
169
|
-
const printSchema = printSchemaWithDirectives(schema);
|
|
170
|
-
const schemaPath = resolve(app.graphql.buildDir, "schema.graphql");
|
|
171
|
-
mkdirSync(dirname(schemaPath), { recursive: true });
|
|
172
|
-
writeFileSync(schemaPath, printSchema, "utf-8");
|
|
173
|
-
const serverTypesPath = resolve(app.options.buildDir, "types", "nitro-graphql-server.d.ts");
|
|
174
|
-
mkdirSync(dirname(serverTypesPath), { recursive: true });
|
|
175
|
-
writeFileSync(serverTypesPath, data, "utf-8");
|
|
176
|
-
} catch (error) {
|
|
177
|
-
consola.error("Server schema generation error:", error);
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
async function clientTypeGeneration(nitro) {
|
|
181
|
-
try {
|
|
182
|
-
if (nitro.scanSchemas && nitro.scanSchemas.length > 0) await generateMainClientTypes(nitro);
|
|
183
|
-
if (nitro.options.graphql?.externalServices?.length) await generateExternalServicesTypes(nitro);
|
|
184
|
-
} catch (error) {
|
|
185
|
-
consola.error("Client schema generation error:", error);
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
/**
|
|
189
|
-
* Check for old structure files and warn user about manual migration
|
|
190
|
-
*/
|
|
191
|
-
function checkOldStructure(clientDir) {
|
|
192
|
-
const oldOfetchPath = resolve(clientDir, "ofetch.ts");
|
|
193
|
-
const oldSdkPath = resolve(clientDir, "sdk.ts");
|
|
194
|
-
if (existsSync(oldOfetchPath) || existsSync(oldSdkPath)) {
|
|
195
|
-
const foundFiles = [];
|
|
196
|
-
if (existsSync(oldOfetchPath)) foundFiles.push("app/graphql/ofetch.ts");
|
|
197
|
-
if (existsSync(oldSdkPath)) foundFiles.push("app/graphql/sdk.ts");
|
|
198
|
-
consola.error(`⚠️ OLD GRAPHQL STRUCTURE DETECTED!
|
|
199
|
-
|
|
200
|
-
📁 Found old files in app/graphql/ directory that need to be moved:
|
|
201
|
-
• ${foundFiles.join("\n • ")}
|
|
202
|
-
|
|
203
|
-
🔄 Please manually move these files to the new structure:
|
|
204
|
-
• app/graphql/ofetch.ts → app/graphql/default/ofetch.ts
|
|
205
|
-
• app/graphql/sdk.ts → app/graphql/default/sdk.ts
|
|
206
|
-
|
|
207
|
-
📝 Also update your app/graphql/index.ts to include:
|
|
208
|
-
export * from './default/ofetch'
|
|
209
|
-
|
|
210
|
-
💡 After moving, update your imports to use:
|
|
211
|
-
import { $sdk } from "#graphql/client"
|
|
212
|
-
|
|
213
|
-
🚫 The old files will cause import conflicts until moved!`);
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
async function generateMainClientTypes(nitro) {
|
|
217
|
-
checkOldStructure(nitro.graphql.clientDir);
|
|
218
|
-
const docs = nitro.scanDocuments;
|
|
219
|
-
const loadDocs = await loadGraphQLDocuments(docs);
|
|
220
|
-
const schemaFilePath = join(nitro.graphql.buildDir, "schema.graphql");
|
|
221
|
-
if (!existsSync(schemaFilePath)) {
|
|
222
|
-
consola.info("Schema file not ready yet for client type generation. Server types need to be generated first.");
|
|
223
|
-
return;
|
|
224
|
-
}
|
|
225
|
-
const graphqlString = readFileSync(schemaFilePath, "utf-8");
|
|
226
|
-
const types = await generateClientTypes(nitro.options.graphql?.federation?.enabled === true ? buildSubgraphSchema([{ typeDefs: parse(graphqlString) }]) : buildSchema(graphqlString), loadDocs, nitro.options.graphql?.codegen?.client ?? {}, nitro.options.graphql?.codegen?.clientSDK ?? {});
|
|
227
|
-
if (types === false) return;
|
|
228
|
-
const clientTypesPath = resolve(nitro.options.buildDir, "types", "nitro-graphql-client.d.ts");
|
|
229
|
-
const defaultServiceDir = resolve(nitro.graphql.clientDir, "default");
|
|
230
|
-
const sdkTypesPath = resolve(defaultServiceDir, "sdk.ts");
|
|
231
|
-
mkdirSync(dirname(clientTypesPath), { recursive: true });
|
|
232
|
-
writeFileSync(clientTypesPath, types.types, "utf-8");
|
|
233
|
-
mkdirSync(defaultServiceDir, { recursive: true });
|
|
234
|
-
let shouldWriteSdk = true;
|
|
235
|
-
if (existsSync(sdkTypesPath)) shouldWriteSdk = readFileSync(sdkTypesPath, "utf-8") !== types.sdk;
|
|
236
|
-
if (shouldWriteSdk) writeFileSync(sdkTypesPath, types.sdk, "utf-8");
|
|
237
|
-
if (nitro.options.framework?.name === "nuxt") {
|
|
238
|
-
generateOfetchClient(nitro.graphql.clientDir, "default", "/api/graphql", true);
|
|
239
|
-
const externalServices = nitro.options.graphql?.externalServices || [];
|
|
240
|
-
generateGraphQLIndexFile(nitro.graphql.clientDir, externalServices);
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
async function generateExternalServicesTypes(nitro) {
|
|
244
|
-
const externalServices = nitro.options.graphql?.externalServices || [];
|
|
245
|
-
for (const service of externalServices) try {
|
|
246
|
-
consola.info(`[graphql:${service.name}] Processing external service`);
|
|
247
|
-
await downloadAndSaveSchema(service, nitro.options.buildDir);
|
|
248
|
-
const schema = await loadExternalSchema(service, nitro.options.buildDir);
|
|
249
|
-
if (!schema) {
|
|
250
|
-
consola.warn(`[graphql:${service.name}] Failed to load schema, skipping`);
|
|
251
|
-
continue;
|
|
252
|
-
}
|
|
253
|
-
const documentPatterns = service.documents || [];
|
|
254
|
-
let loadDocs = [];
|
|
255
|
-
if (documentPatterns.length > 0) try {
|
|
256
|
-
loadDocs = await loadGraphQLDocuments(documentPatterns);
|
|
257
|
-
if (!loadDocs || loadDocs.length === 0) {
|
|
258
|
-
consola.warn(`[graphql:${service.name}] No GraphQL documents found, skipping service generation`);
|
|
259
|
-
continue;
|
|
260
|
-
}
|
|
261
|
-
} catch (error) {
|
|
262
|
-
consola.warn(`[graphql:${service.name}] No documents found, skipping service generation:`, error);
|
|
263
|
-
continue;
|
|
264
|
-
}
|
|
265
|
-
const types = await generateExternalClientTypes(service, schema, loadDocs);
|
|
266
|
-
if (types === false) {
|
|
267
|
-
consola.warn(`[graphql:${service.name}] Type generation failed`);
|
|
268
|
-
continue;
|
|
269
|
-
}
|
|
270
|
-
const serviceTypesPath = resolve(nitro.options.buildDir, "types", `nitro-graphql-client-${service.name}.d.ts`);
|
|
271
|
-
const serviceDir = resolve(nitro.graphql.clientDir, service.name);
|
|
272
|
-
const serviceSdkPath = resolve(serviceDir, "sdk.ts");
|
|
273
|
-
mkdirSync(dirname(serviceTypesPath), { recursive: true });
|
|
274
|
-
writeFileSync(serviceTypesPath, types.types, "utf-8");
|
|
275
|
-
mkdirSync(serviceDir, { recursive: true });
|
|
276
|
-
let shouldWriteServiceSdk = true;
|
|
277
|
-
if (existsSync(serviceSdkPath)) shouldWriteServiceSdk = readFileSync(serviceSdkPath, "utf-8") !== types.sdk;
|
|
278
|
-
if (shouldWriteServiceSdk) writeFileSync(serviceSdkPath, types.sdk, "utf-8");
|
|
279
|
-
if (nitro.options.framework?.name === "nuxt") generateOfetchClient(nitro.graphql.clientDir, service.name, service.endpoint, false);
|
|
280
|
-
consola.success(`[graphql:${service.name}] External service types generated successfully`);
|
|
281
|
-
} catch (error) {
|
|
282
|
-
consola.error(`[graphql:${service.name}] External service generation failed:`, error);
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
//#endregion
|
|
287
|
-
export { clientTypeGeneration, serverTypeGeneration };
|
|
File without changes
|
|
File without changes
|
|
File without changes
|