nitro-graphql 2.0.0-beta.37 → 2.0.0-beta.39
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 +2 -2
- package/dist/cli/commands/generate.d.mts +26 -0
- package/dist/cli/commands/generate.mjs +196 -0
- package/dist/cli/commands/index.d.mts +4 -0
- package/dist/cli/commands/index.mjs +5 -0
- package/dist/cli/commands/init.d.mts +43 -0
- package/dist/cli/commands/init.mjs +191 -0
- package/dist/cli/commands/validate.d.mts +10 -0
- package/dist/cli/commands/validate.mjs +69 -0
- package/dist/cli/completions.d.mts +7 -0
- package/dist/cli/completions.mjs +34 -0
- package/dist/cli/config.d.mts +75 -0
- package/dist/cli/config.mjs +20 -0
- package/dist/cli/index.d.mts +24 -0
- package/dist/cli/index.mjs +253 -0
- package/dist/core/codegen/client.d.mts +23 -0
- package/dist/core/codegen/client.mjs +150 -0
- package/dist/core/codegen/document-loader.d.mts +10 -0
- package/dist/core/codegen/document-loader.mjs +18 -0
- package/dist/core/codegen/index.d.mts +8 -0
- package/dist/core/codegen/index.mjs +9 -0
- package/dist/{utils/codegen-plugin.d.mts → core/codegen/plugin.d.mts} +2 -2
- package/dist/{utils/codegen-plugin.mjs → core/codegen/plugin.mjs} +1 -1
- package/dist/core/codegen/runtime.d.mts +20 -0
- package/dist/core/codegen/runtime.mjs +60 -0
- package/dist/core/codegen/schema-loader.d.mts +28 -0
- package/dist/core/codegen/schema-loader.mjs +128 -0
- package/dist/core/codegen/server.d.mts +28 -0
- package/dist/core/codegen/server.mjs +143 -0
- package/dist/{codegen → core/codegen}/validation.d.mts +1 -1
- package/dist/{codegen → core/codegen}/validation.mjs +1 -1
- package/dist/core/config.d.mts +50 -0
- package/dist/core/config.mjs +82 -0
- package/dist/core/constants.d.mts +188 -0
- package/dist/core/constants.mjs +210 -0
- package/dist/core/index.d.mts +32 -0
- package/dist/core/index.mjs +26 -0
- package/dist/core/scanning/ast-scanner.d.mts +23 -0
- package/dist/core/scanning/ast-scanner.mjs +103 -0
- package/dist/core/scanning/common.d.mts +37 -0
- package/dist/core/scanning/common.mjs +60 -0
- package/dist/core/scanning/directives.d.mts +10 -0
- package/dist/core/scanning/directives.mjs +29 -0
- package/dist/core/scanning/documents.d.mts +21 -0
- package/dist/core/scanning/documents.mjs +43 -0
- package/dist/core/scanning/index.d.mts +7 -0
- package/dist/core/scanning/index.mjs +8 -0
- package/dist/core/scanning/resolvers.d.mts +10 -0
- package/dist/core/scanning/resolvers.mjs +58 -0
- package/dist/core/scanning/schemas.d.mts +14 -0
- package/dist/core/scanning/schemas.mjs +64 -0
- package/dist/{utils/schema-builder.d.mts → core/schema/builder.d.mts} +7 -2
- package/dist/{utils/schema-builder.mjs → core/schema/builder.mjs} +22 -3
- package/dist/{utils → core/schema}/federation.d.mts +10 -5
- package/dist/{utils → core/schema}/federation.mjs +1 -1
- package/dist/core/schema/index.d.mts +3 -0
- package/dist/core/schema/index.mjs +4 -0
- package/dist/core/types/adapter.d.mts +58 -0
- package/dist/core/types/codegen.d.mts +133 -0
- package/dist/core/types/config.d.mts +212 -0
- package/dist/{types → core/types}/define.d.mts +3 -7
- package/dist/core/types/index.d.mts +5 -0
- package/dist/core/types/scanning.d.mts +69 -0
- package/dist/core/types/scanning.mjs +1 -0
- package/dist/{utils → core/utils}/directive-parser.d.mts +21 -5
- package/dist/{utils → core/utils}/directive-parser.mjs +25 -36
- package/dist/{utils → core/utils}/errors.d.mts +8 -4
- package/dist/{utils → core/utils}/errors.mjs +8 -4
- package/dist/core/utils/file-io.d.mts +24 -0
- package/dist/core/utils/file-io.mjs +47 -0
- package/dist/{utils → core/utils}/imports.d.mts +1 -1
- package/dist/{utils → core/utils}/imports.mjs +1 -1
- package/dist/core/utils/index.d.mts +7 -0
- package/dist/core/utils/index.mjs +8 -0
- package/dist/core/utils/logger.d.mts +19 -0
- package/dist/core/utils/logger.mjs +38 -0
- package/dist/{utils → core/utils}/ofetch-templates.d.mts +1 -1
- package/dist/{utils → core/utils}/ofetch-templates.mjs +1 -1
- package/dist/core/validation/external-services.d.mts +11 -0
- package/dist/{utils/validation.mjs → core/validation/external-services.mjs} +3 -3
- package/dist/core/validation/index.d.mts +2 -0
- package/dist/core/validation/index.mjs +3 -0
- package/dist/define.d.mts +2 -4
- package/dist/define.mjs +1 -1
- package/dist/index.d.mts +6 -44
- package/dist/index.mjs +5 -62
- package/dist/nitro/adapter.d.mts +30 -0
- package/dist/nitro/adapter.mjs +97 -0
- package/dist/{utils → nitro}/apollo.d.mts +1 -1
- package/dist/{utils → nitro}/apollo.mjs +1 -1
- package/dist/nitro/codegen.d.mts +19 -0
- package/dist/nitro/codegen.mjs +141 -0
- package/dist/nitro/config.d.mts +52 -0
- package/dist/nitro/config.mjs +58 -0
- package/dist/nitro/index.d.mts +46 -0
- package/dist/nitro/index.mjs +65 -0
- package/dist/{utils/path-resolver.d.mts → nitro/paths.d.mts} +3 -19
- package/dist/{utils/path-resolver.mjs → nitro/paths.mjs} +2 -36
- package/dist/{rollup.d.mts → nitro/rollup.d.mts} +1 -1
- package/dist/{rollup.mjs → nitro/rollup.mjs} +11 -23
- package/dist/{routes → nitro/routes}/apollo-server.d.mts +1 -1
- package/dist/{routes → nitro/routes}/apollo-server.mjs +5 -5
- package/dist/{routes → nitro/routes}/debug-template.d.mts +1 -1
- package/dist/{routes → nitro/routes}/debug-template.mjs +1 -1
- package/dist/{routes → nitro/routes}/debug.d.mts +10 -16
- package/dist/{routes → nitro/routes}/debug.mjs +2 -2
- package/dist/{routes → nitro/routes}/graphql-yoga.d.mts +1 -1
- package/dist/{routes → nitro/routes}/graphql-yoga.mjs +3 -3
- package/dist/{routes → nitro/routes}/health.d.mts +1 -1
- package/dist/{routes → nitro/routes}/health.mjs +1 -1
- package/dist/nitro/setup/file-watcher.d.mts +16 -0
- package/dist/{setup → nitro/setup}/file-watcher.mjs +14 -18
- package/dist/{setup.d.mts → nitro/setup/logging.d.mts} +5 -6
- package/dist/nitro/setup/logging.mjs +66 -0
- package/dist/nitro/setup/rollup-integration.d.mts +16 -0
- package/dist/{setup → nitro/setup}/rollup-integration.mjs +2 -2
- package/dist/nitro/setup/routes.d.mts +10 -0
- package/dist/nitro/setup/routes.mjs +35 -0
- package/dist/nitro/setup/ts-config.d.mts +11 -0
- package/dist/{setup → nitro/setup}/ts-config.mjs +3 -3
- package/dist/nitro/setup.d.mts +12 -0
- package/dist/{setup.mjs → nitro/setup.mjs} +33 -100
- package/dist/{types/index.d.mts → nitro/types.d.mts} +125 -43
- package/dist/nitro/types.mjs +1 -0
- package/dist/nitro/virtual/generators.d.mts +31 -0
- package/dist/nitro/virtual/generators.mjs +193 -0
- package/dist/nitro/virtual/stubs.d.mts +20 -0
- package/dist/nitro/virtual/stubs.mjs +31 -0
- package/dist/{ecosystem/nuxt.d.mts → nuxt.d.mts} +1 -1
- package/dist/{ecosystem/nuxt.mjs → nuxt.mjs} +2 -2
- package/dist/{graphql/server.d.mts → stubs/index.d.mts} +5 -1
- package/dist/stubs/index.mjs +1 -0
- package/package.json +45 -42
- package/dist/codegen/client-types.d.mts +0 -13
- package/dist/codegen/client-types.mjs +0 -131
- package/dist/codegen/external-types.d.mts +0 -12
- package/dist/codegen/external-types.mjs +0 -88
- package/dist/codegen/index.d.mts +0 -18
- package/dist/codegen/index.mjs +0 -24
- package/dist/codegen/server-types.d.mts +0 -13
- package/dist/codegen/server-types.mjs +0 -64
- package/dist/config/defaults.mjs +0 -36
- package/dist/constants/scalars.mjs +0 -27
- package/dist/constants.mjs +0 -106
- package/dist/graphql/index.d.mts +0 -5
- package/dist/setup/graphql-scanner.mjs +0 -25
- package/dist/setup/scaffold-generator.mjs +0 -109
- package/dist/types/standard-schema.d.mts +0 -59
- package/dist/utils/client-codegen.d.mts +0 -41
- package/dist/utils/client-codegen.mjs +0 -277
- package/dist/utils/file-generator.d.mts +0 -37
- package/dist/utils/file-generator.mjs +0 -72
- package/dist/utils/file-writer.d.mts +0 -35
- package/dist/utils/file-writer.mjs +0 -32
- package/dist/utils/index.d.mts +0 -13
- package/dist/utils/index.mjs +0 -13
- package/dist/utils/layers.d.mts +0 -22
- package/dist/utils/layers.mjs +0 -28
- package/dist/utils/scanning/common.d.mts +0 -23
- package/dist/utils/scanning/common.mjs +0 -39
- package/dist/utils/scanning/directives.d.mts +0 -11
- package/dist/utils/scanning/directives.mjs +0 -43
- package/dist/utils/scanning/documents.d.mts +0 -15
- package/dist/utils/scanning/documents.mjs +0 -46
- package/dist/utils/scanning/index.d.mts +0 -6
- package/dist/utils/scanning/index.mjs +0 -7
- package/dist/utils/scanning/resolvers.d.mts +0 -11
- package/dist/utils/scanning/resolvers.mjs +0 -100
- package/dist/utils/scanning/schemas.d.mts +0 -15
- package/dist/utils/scanning/schemas.mjs +0 -29
- package/dist/utils/server-codegen.d.mts +0 -7
- package/dist/utils/server-codegen.mjs +0 -113
- package/dist/utils/type-generation.d.mts +0 -6
- package/dist/utils/type-generation.mjs +0 -7
- package/dist/utils/validation.d.mts +0 -11
- package/dist/virtual/debug-info.d.mts +0 -9
- package/dist/virtual/debug-info.mjs +0 -26
- package/dist/virtual/generators/config.d.mts +0 -22
- package/dist/virtual/generators/config.mjs +0 -36
- package/dist/virtual/generators/debug.d.mts +0 -14
- package/dist/virtual/generators/debug.mjs +0 -53
- package/dist/virtual/generators/directives.d.mts +0 -14
- package/dist/virtual/generators/directives.mjs +0 -52
- package/dist/virtual/generators/index.d.mts +0 -6
- package/dist/virtual/generators/index.mjs +0 -7
- package/dist/virtual/generators/resolvers.d.mts +0 -14
- package/dist/virtual/generators/resolvers.mjs +0 -55
- package/dist/virtual/generators/schemas.d.mts +0 -14
- package/dist/virtual/generators/schemas.mjs +0 -43
- package/dist/virtual/graphql-config.d.mts +0 -9
- package/dist/virtual/graphql-config.mjs +0 -10
- package/dist/virtual/module-config.d.mts +0 -9
- package/dist/virtual/module-config.mjs +0 -10
- package/dist/virtual/server-directives.d.mts +0 -11
- package/dist/virtual/server-directives.mjs +0 -10
- package/dist/virtual/server-resolvers.d.mts +0 -11
- package/dist/virtual/server-resolvers.mjs +0 -10
- package/dist/virtual/server-schemas.d.mts +0 -11
- package/dist/virtual/server-schemas.mjs +0 -10
- /package/dist/{graphql/index.mjs → core/types/adapter.mjs} +0 -0
- /package/dist/{graphql/server.mjs → core/types/codegen.mjs} +0 -0
- /package/dist/{types/define.mjs → core/types/config.mjs} +0 -0
- /package/dist/{types/index.mjs → core/types/define.mjs} +0 -0
- /package/dist/{types/standard-schema.mjs → core/types/index.mjs} +0 -0
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<div align="center">
|
|
2
2
|
|
|
3
|
-
<img src="./.
|
|
3
|
+
<img src="./.github/assets/logo.svg" alt="Nitro GraphQL Logo" width="120" height="120">
|
|
4
4
|
|
|
5
5
|
# Nitro GraphQL
|
|
6
6
|
|
|
@@ -633,7 +633,7 @@ import { defineResolver, defineQuery, defineMutation, defineField, defineDirecti
|
|
|
633
633
|
| `defineGraphQLConfig` | GraphQL server config | `defineGraphQLConfig({ maskedErrors: {...} })` |
|
|
634
634
|
| `defineSchema` | Schema with Zod integration | `defineSchema({ Book: selectBookSchema })` |
|
|
635
635
|
|
|
636
|
-
**Additional Utilities** from `nitro-graphql/
|
|
636
|
+
**Additional Utilities** from `nitro-graphql/core`:
|
|
637
637
|
- `createDefaultMaskError()` - Error handler for ZodError and HTTPError (use in `defineGraphQLConfig`)
|
|
638
638
|
|
|
639
639
|
### Type Generation
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { CLIContext } from "../index.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/cli/commands/generate.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Generate all types (server + client + optional runtime)
|
|
7
|
+
*/
|
|
8
|
+
declare function generateAll(ctx: CLIContext, options?: {
|
|
9
|
+
silent?: boolean;
|
|
10
|
+
watch?: boolean;
|
|
11
|
+
runtime?: boolean;
|
|
12
|
+
}): Promise<void>;
|
|
13
|
+
/**
|
|
14
|
+
* Generate server types
|
|
15
|
+
*/
|
|
16
|
+
declare function generateServer(ctx: CLIContext, options?: {
|
|
17
|
+
silent?: boolean;
|
|
18
|
+
}): Promise<void>;
|
|
19
|
+
/**
|
|
20
|
+
* Generate client types
|
|
21
|
+
*/
|
|
22
|
+
declare function generateClient(ctx: CLIContext, options?: {
|
|
23
|
+
silent?: boolean;
|
|
24
|
+
}): Promise<void>;
|
|
25
|
+
//#endregion
|
|
26
|
+
export { generateAll, generateClient, generateServer };
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import { LOG_TAG } from "../../core/constants.mjs";
|
|
2
|
+
import { loadGraphQLDocuments } from "../../core/codegen/document-loader.mjs";
|
|
3
|
+
import { generateClientTypesCore } from "../../core/codegen/client.mjs";
|
|
4
|
+
import { generateResolverModule, generateRuntimeIndex, generateSchemaModule } from "../../core/codegen/runtime.mjs";
|
|
5
|
+
import { generateServerTypesCore } from "../../core/codegen/server.mjs";
|
|
6
|
+
import { scanDocumentsCore } from "../../core/scanning/documents.mjs";
|
|
7
|
+
import { scanResolversCore } from "../../core/scanning/resolvers.mjs";
|
|
8
|
+
import { scanSchemasCore } from "../../core/scanning/schemas.mjs";
|
|
9
|
+
import { buildGraphQLSchema } from "../../core/schema/builder.mjs";
|
|
10
|
+
import consola from "consola";
|
|
11
|
+
import { dirname, join, relative } from "pathe";
|
|
12
|
+
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
13
|
+
|
|
14
|
+
//#region src/cli/commands/generate.ts
|
|
15
|
+
const logger = consola.withTag(LOG_TAG);
|
|
16
|
+
/**
|
|
17
|
+
* Create ScanContext from CLI context
|
|
18
|
+
*/
|
|
19
|
+
function createScanContext(ctx) {
|
|
20
|
+
return {
|
|
21
|
+
rootDir: ctx.config.rootDir,
|
|
22
|
+
serverDir: ctx.config.serverDir,
|
|
23
|
+
clientDir: ctx.config.clientDir,
|
|
24
|
+
ignorePatterns: ctx.config.ignore,
|
|
25
|
+
isDev: false,
|
|
26
|
+
logger: {
|
|
27
|
+
info: (msg, ...args) => logger.info(msg, ...args),
|
|
28
|
+
warn: (msg, ...args) => logger.warn(msg, ...args),
|
|
29
|
+
error: (msg, ...args) => logger.error(msg, ...args),
|
|
30
|
+
success: (msg, ...args) => logger.success(msg, ...args),
|
|
31
|
+
debug: (msg, ...args) => logger.debug(msg, ...args)
|
|
32
|
+
},
|
|
33
|
+
layerServerDirs: [],
|
|
34
|
+
layerAppDirs: []
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Generate all types (server + client + optional runtime)
|
|
39
|
+
*/
|
|
40
|
+
async function generateAll(ctx, options = {}) {
|
|
41
|
+
await generateServer(ctx, options);
|
|
42
|
+
await generateClient(ctx, options);
|
|
43
|
+
if (options.runtime) await generateRuntimeFiles(ctx, options);
|
|
44
|
+
if (options.watch) await watchAndRegenerate(ctx, options);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Generate server types
|
|
48
|
+
*/
|
|
49
|
+
async function generateServer(ctx, options = {}) {
|
|
50
|
+
const schemaResult = await scanSchemasCore(createScanContext(ctx));
|
|
51
|
+
if (schemaResult.errors.length > 0) for (const error of schemaResult.errors) logger.error(error);
|
|
52
|
+
if (schemaResult.items.length === 0) {
|
|
53
|
+
if (!options.silent) logger.info("No GraphQL schemas found in server directory");
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
const schema = await buildGraphQLSchema(schemaResult.items);
|
|
57
|
+
if (!schema) {
|
|
58
|
+
logger.error("Failed to build GraphQL schema");
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
const result = await generateServerTypesCore({
|
|
62
|
+
framework: ctx.config.framework,
|
|
63
|
+
schema,
|
|
64
|
+
config: ctx.config.codegen?.server,
|
|
65
|
+
federationEnabled: ctx.config.federation?.enabled
|
|
66
|
+
});
|
|
67
|
+
const schemaPath = join(ctx.config.buildDir, "schema.graphql");
|
|
68
|
+
mkdirSync(dirname(schemaPath), { recursive: true });
|
|
69
|
+
writeFileSync(schemaPath, result.schemaString, "utf-8");
|
|
70
|
+
const typesPath = join(ctx.config.typesDir, "nitro-graphql-server.d.ts");
|
|
71
|
+
mkdirSync(dirname(typesPath), { recursive: true });
|
|
72
|
+
writeFileSync(typesPath, result.types, "utf-8");
|
|
73
|
+
if (!options.silent) logger.success(`Generated server types: ${relative(ctx.config.rootDir, typesPath)}`);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Generate client types
|
|
77
|
+
*/
|
|
78
|
+
async function generateClient(ctx, options = {}) {
|
|
79
|
+
const scanCtx = createScanContext(ctx);
|
|
80
|
+
const schemaPath = join(ctx.config.buildDir, "schema.graphql");
|
|
81
|
+
if (!existsSync(schemaPath)) {
|
|
82
|
+
if (!options.silent) logger.info("Server schema not found. Generate server types first.");
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
const docsResult = await scanDocumentsCore(scanCtx, { externalServices: ctx.config.externalServices });
|
|
86
|
+
if (docsResult.errors.length > 0) for (const error of docsResult.errors) logger.error(error);
|
|
87
|
+
if (docsResult.items.length === 0) {
|
|
88
|
+
if (!options.silent) logger.info("No GraphQL documents found in client directory");
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
const documents = await loadGraphQLDocuments(docsResult.items);
|
|
92
|
+
const { buildSchema } = await import("graphql");
|
|
93
|
+
const { readFileSync: readFileSync$1 } = await import("node:fs");
|
|
94
|
+
const result = await generateClientTypesCore({
|
|
95
|
+
schema: buildSchema(readFileSync$1(schemaPath, "utf-8")),
|
|
96
|
+
documents,
|
|
97
|
+
config: ctx.config.codegen?.client,
|
|
98
|
+
sdkConfig: ctx.config.codegen?.clientSDK,
|
|
99
|
+
options: { silent: options.silent }
|
|
100
|
+
});
|
|
101
|
+
if (result === false) {
|
|
102
|
+
if (!options.silent) logger.warn("Client type generation skipped");
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
const typesPath = join(ctx.config.typesDir, "nitro-graphql-client.d.ts");
|
|
106
|
+
mkdirSync(dirname(typesPath), { recursive: true });
|
|
107
|
+
writeFileSync(typesPath, result.types, "utf-8");
|
|
108
|
+
const sdkPath = join(ctx.config.clientDir, "default", "sdk.ts");
|
|
109
|
+
mkdirSync(dirname(sdkPath), { recursive: true });
|
|
110
|
+
writeFileSync(sdkPath, result.sdk, "utf-8");
|
|
111
|
+
if (!options.silent) logger.success(`Generated client types: ${relative(ctx.config.rootDir, typesPath)}`);
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Generate runtime files (resolvers.ts, schema.ts, index.ts)
|
|
115
|
+
*/
|
|
116
|
+
async function generateRuntimeFiles(ctx, options = {}) {
|
|
117
|
+
const scanCtx = createScanContext(ctx);
|
|
118
|
+
const runtimeConfig = ctx.config.runtime;
|
|
119
|
+
const runtimeDir = typeof runtimeConfig === "object" && runtimeConfig.outDir ? join(ctx.config.rootDir, runtimeConfig.outDir) : join(ctx.config.buildDir, "runtime");
|
|
120
|
+
mkdirSync(runtimeDir, { recursive: true });
|
|
121
|
+
const include = typeof runtimeConfig === "object" && runtimeConfig.include ? runtimeConfig.include : {
|
|
122
|
+
resolvers: true,
|
|
123
|
+
schema: true,
|
|
124
|
+
index: true
|
|
125
|
+
};
|
|
126
|
+
if (include.resolvers !== false) {
|
|
127
|
+
const resolversResult = await scanResolversCore(scanCtx);
|
|
128
|
+
if (resolversResult.items.length > 0) {
|
|
129
|
+
const resolverCode = generateResolverModule(resolversResult.items, runtimeDir);
|
|
130
|
+
writeFileSync(join(runtimeDir, "resolvers.ts"), resolverCode, "utf-8");
|
|
131
|
+
if (!options.silent) logger.success(`Generated runtime: ${relative(ctx.config.rootDir, join(runtimeDir, "resolvers.ts"))}`);
|
|
132
|
+
} else if (!options.silent) logger.info("No resolvers found for runtime generation");
|
|
133
|
+
}
|
|
134
|
+
if (include.schema !== false) {
|
|
135
|
+
const schemaPath = join(ctx.config.buildDir, "schema.graphql");
|
|
136
|
+
if (existsSync(schemaPath)) {
|
|
137
|
+
const { readFileSync: readFileSync$1 } = await import("node:fs");
|
|
138
|
+
const schemaCode = generateSchemaModule(readFileSync$1(schemaPath, "utf-8"));
|
|
139
|
+
writeFileSync(join(runtimeDir, "schema.ts"), schemaCode, "utf-8");
|
|
140
|
+
if (!options.silent) logger.success(`Generated runtime: ${relative(ctx.config.rootDir, join(runtimeDir, "schema.ts"))}`);
|
|
141
|
+
} else if (!options.silent) logger.info("Schema not found for runtime generation. Run generate first.");
|
|
142
|
+
}
|
|
143
|
+
if (include.index !== false) {
|
|
144
|
+
const indexCode = generateRuntimeIndex();
|
|
145
|
+
writeFileSync(join(runtimeDir, "index.ts"), indexCode, "utf-8");
|
|
146
|
+
if (!options.silent) logger.success(`Generated runtime: ${relative(ctx.config.rootDir, join(runtimeDir, "index.ts"))}`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Watch mode - regenerate on file changes
|
|
151
|
+
*/
|
|
152
|
+
async function watchAndRegenerate(ctx, options = {}) {
|
|
153
|
+
const { watch } = await import("chokidar");
|
|
154
|
+
const watchDirs = [ctx.config.serverDir, ctx.config.clientDir];
|
|
155
|
+
const watcher = watch(watchDirs, {
|
|
156
|
+
ignoreInitial: true,
|
|
157
|
+
ignored: [
|
|
158
|
+
...ctx.config.ignore || [],
|
|
159
|
+
/node_modules/,
|
|
160
|
+
/\.git/
|
|
161
|
+
],
|
|
162
|
+
persistent: true
|
|
163
|
+
});
|
|
164
|
+
await new Promise((resolve$1) => {
|
|
165
|
+
watcher.on("ready", resolve$1);
|
|
166
|
+
watcher.on("error", (error) => logger.error("Watcher error:", error));
|
|
167
|
+
});
|
|
168
|
+
const relPath = (p) => relative(ctx.config.rootDir, p) || ".";
|
|
169
|
+
logger.info(`Watching: ${watchDirs.map(relPath).join(", ")}`);
|
|
170
|
+
let debounceTimer = null;
|
|
171
|
+
const debounceMs = ctx.config.watch?.debounce ?? 300;
|
|
172
|
+
watcher.on("all", (event, filePath) => {
|
|
173
|
+
if (!filePath.endsWith(".graphql") && !filePath.endsWith(".resolver.ts")) return;
|
|
174
|
+
if (debounceTimer) clearTimeout(debounceTimer);
|
|
175
|
+
debounceTimer = setTimeout(async () => {
|
|
176
|
+
try {
|
|
177
|
+
await generateAll(ctx, {
|
|
178
|
+
silent: options.silent ?? true,
|
|
179
|
+
watch: false
|
|
180
|
+
});
|
|
181
|
+
logger.success(`Types regenerated (${relPath(filePath)})`);
|
|
182
|
+
} catch (error) {
|
|
183
|
+
logger.error("Regeneration failed:", error);
|
|
184
|
+
}
|
|
185
|
+
}, debounceMs);
|
|
186
|
+
});
|
|
187
|
+
await new Promise((resolve$1) => {
|
|
188
|
+
process.on("SIGINT", () => {
|
|
189
|
+
watcher.close();
|
|
190
|
+
resolve$1();
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
//#endregion
|
|
196
|
+
export { generateAll, generateClient, generateServer };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { CLIContext } from "../index.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/cli/commands/init.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Available templates from the examples directory
|
|
7
|
+
*/
|
|
8
|
+
declare const AVAILABLE_TEMPLATES: readonly [{
|
|
9
|
+
readonly name: "drizzle-orm";
|
|
10
|
+
readonly description: "Nitro + GraphQL + Drizzle ORM with PostgreSQL";
|
|
11
|
+
}, {
|
|
12
|
+
readonly name: "vite";
|
|
13
|
+
readonly description: "Vite + Nitro GraphQL integration";
|
|
14
|
+
}, {
|
|
15
|
+
readonly name: "vite-react";
|
|
16
|
+
readonly description: "Vite + React + Nitro GraphQL";
|
|
17
|
+
}, {
|
|
18
|
+
readonly name: "vite-vue";
|
|
19
|
+
readonly description: "Vite + Vue + Nitro GraphQL";
|
|
20
|
+
}, {
|
|
21
|
+
readonly name: "better-auth";
|
|
22
|
+
readonly description: "Nitro + GraphQL + Better Auth integration";
|
|
23
|
+
}];
|
|
24
|
+
type TemplateName = typeof AVAILABLE_TEMPLATES[number]['name'];
|
|
25
|
+
/**
|
|
26
|
+
* List available templates
|
|
27
|
+
*/
|
|
28
|
+
declare function listTemplates(): void;
|
|
29
|
+
/**
|
|
30
|
+
* Initialize project from template
|
|
31
|
+
*/
|
|
32
|
+
declare function initFromTemplate(projectName: string, templateName: string, options?: {
|
|
33
|
+
force?: boolean;
|
|
34
|
+
cwd?: string;
|
|
35
|
+
}): Promise<void>;
|
|
36
|
+
/**
|
|
37
|
+
* Initialize project structure (basic scaffolding)
|
|
38
|
+
*/
|
|
39
|
+
declare function init(ctx: CLIContext, options?: {
|
|
40
|
+
force?: boolean;
|
|
41
|
+
}): Promise<void>;
|
|
42
|
+
//#endregion
|
|
43
|
+
export { AVAILABLE_TEMPLATES, TemplateName, init, initFromTemplate, listTemplates };
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { LOG_TAG } from "../../core/constants.mjs";
|
|
2
|
+
import consola from "consola";
|
|
3
|
+
import { basename, join, relative, resolve } from "pathe";
|
|
4
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
5
|
+
import { downloadTemplate } from "giget";
|
|
6
|
+
|
|
7
|
+
//#region src/cli/commands/init.ts
|
|
8
|
+
const logger = consola.withTag(LOG_TAG);
|
|
9
|
+
/**
|
|
10
|
+
* Available templates from the examples directory
|
|
11
|
+
*/
|
|
12
|
+
const AVAILABLE_TEMPLATES = [
|
|
13
|
+
{
|
|
14
|
+
name: "drizzle-orm",
|
|
15
|
+
description: "Nitro + GraphQL + Drizzle ORM with PostgreSQL"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
name: "vite",
|
|
19
|
+
description: "Vite + Nitro GraphQL integration"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
name: "vite-react",
|
|
23
|
+
description: "Vite + React + Nitro GraphQL"
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
name: "vite-vue",
|
|
27
|
+
description: "Vite + Vue + Nitro GraphQL"
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
name: "better-auth",
|
|
31
|
+
description: "Nitro + GraphQL + Better Auth integration"
|
|
32
|
+
}
|
|
33
|
+
];
|
|
34
|
+
/**
|
|
35
|
+
* Default GitHub template source
|
|
36
|
+
*/
|
|
37
|
+
const DEFAULT_TEMPLATE_REGISTRY = "github:productdevbook/nitro-graphql/examples";
|
|
38
|
+
/**
|
|
39
|
+
* List available templates
|
|
40
|
+
*/
|
|
41
|
+
function listTemplates() {
|
|
42
|
+
logger.info("Available templates:\n");
|
|
43
|
+
for (const template of AVAILABLE_TEMPLATES) console.log(` ${template.name.padEnd(15)} - ${template.description}`);
|
|
44
|
+
console.log("\nUsage:");
|
|
45
|
+
console.log(" nitro-graphql init <project-name> --template <template-name>");
|
|
46
|
+
console.log(" nitro-graphql init my-app -t drizzle-orm");
|
|
47
|
+
console.log("\nCustom templates:");
|
|
48
|
+
console.log(" nitro-graphql init my-app -t gh:user/repo");
|
|
49
|
+
console.log(" nitro-graphql init my-app -t github:user/repo/subdir");
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Initialize project from template
|
|
53
|
+
*/
|
|
54
|
+
async function initFromTemplate(projectName, templateName, options = {}) {
|
|
55
|
+
const { force, cwd = process.cwd() } = options;
|
|
56
|
+
const targetDir = resolve(cwd, projectName);
|
|
57
|
+
if (existsSync(targetDir) && !force) {
|
|
58
|
+
logger.error(`Directory "${projectName}" already exists. Use --force to overwrite.`);
|
|
59
|
+
process.exit(1);
|
|
60
|
+
}
|
|
61
|
+
let templateSource;
|
|
62
|
+
if (templateName.includes(":") || templateName.includes("/")) templateSource = templateName;
|
|
63
|
+
else {
|
|
64
|
+
if (!AVAILABLE_TEMPLATES.find((t) => t.name === templateName)) {
|
|
65
|
+
logger.error(`Unknown template: "${templateName}"`);
|
|
66
|
+
logger.info("Use --list to see available templates");
|
|
67
|
+
process.exit(1);
|
|
68
|
+
}
|
|
69
|
+
templateSource = `${DEFAULT_TEMPLATE_REGISTRY}/${templateName}`;
|
|
70
|
+
}
|
|
71
|
+
logger.info(`Downloading template: ${templateName}`);
|
|
72
|
+
logger.debug(`Source: ${templateSource}`);
|
|
73
|
+
try {
|
|
74
|
+
const result = await downloadTemplate(templateSource, {
|
|
75
|
+
dir: targetDir,
|
|
76
|
+
force
|
|
77
|
+
});
|
|
78
|
+
logger.success(`Template downloaded to: ${result.dir}`);
|
|
79
|
+
const packageJsonPath = join(targetDir, "package.json");
|
|
80
|
+
if (existsSync(packageJsonPath)) try {
|
|
81
|
+
const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
|
|
82
|
+
packageJson.name = basename(projectName).replace(/[^a-z0-9-]/gi, "-").replace(/^-+|-+$/g, "").toLowerCase() || "my-graphql-app";
|
|
83
|
+
writeFileSync(packageJsonPath, `${JSON.stringify(packageJson, null, 2)}\n`, "utf-8");
|
|
84
|
+
logger.debug(`Updated package.json name to: ${packageJson.name}`);
|
|
85
|
+
} catch {
|
|
86
|
+
logger.warn("Could not update package.json name");
|
|
87
|
+
}
|
|
88
|
+
console.log("");
|
|
89
|
+
logger.info("Next steps:");
|
|
90
|
+
console.log(` cd ${projectName}`);
|
|
91
|
+
console.log(" pnpm install");
|
|
92
|
+
console.log(" pnpm dev");
|
|
93
|
+
console.log("");
|
|
94
|
+
} catch (error) {
|
|
95
|
+
logger.error("Failed to download template:", error);
|
|
96
|
+
process.exit(1);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Initialize project structure (basic scaffolding)
|
|
101
|
+
*/
|
|
102
|
+
async function init(ctx, options = {}) {
|
|
103
|
+
const { force } = options;
|
|
104
|
+
const dirs = [ctx.config.serverDir, ctx.config.clientDir];
|
|
105
|
+
for (const dir of dirs) if (!existsSync(dir)) {
|
|
106
|
+
mkdirSync(dir, { recursive: true });
|
|
107
|
+
logger.info(`Created directory: ${dir}`);
|
|
108
|
+
}
|
|
109
|
+
const configPath = join(ctx.config.rootDir, "nitro-graphql.config.ts");
|
|
110
|
+
if (force || !existsSync(configPath)) {
|
|
111
|
+
const relativeServerDir = relative(ctx.config.rootDir, ctx.config.serverDir) || "server/graphql";
|
|
112
|
+
const relativeClientDir = relative(ctx.config.rootDir, ctx.config.clientDir) || "graphql";
|
|
113
|
+
writeFileSync(configPath, `import { defineConfig } from 'nitro-graphql/cli'
|
|
114
|
+
|
|
115
|
+
export default defineConfig({
|
|
116
|
+
framework: '${ctx.config.framework}',
|
|
117
|
+
serverDir: './${relativeServerDir}',
|
|
118
|
+
clientDir: './${relativeClientDir}',
|
|
119
|
+
})
|
|
120
|
+
`, "utf-8");
|
|
121
|
+
logger.success(`Created config file: ${configPath}`);
|
|
122
|
+
} else logger.info(`Config file already exists: ${configPath}`);
|
|
123
|
+
const tsconfigPath = join(ctx.config.rootDir, "tsconfig.json");
|
|
124
|
+
if (force || !existsSync(tsconfigPath)) {
|
|
125
|
+
const relativeBuildDir = relative(ctx.config.rootDir, ctx.config.buildDir) || ".graphql";
|
|
126
|
+
writeFileSync(tsconfigPath, `{
|
|
127
|
+
"compilerOptions": {
|
|
128
|
+
"target": "ESNext",
|
|
129
|
+
"module": "ESNext",
|
|
130
|
+
"moduleResolution": "Bundler",
|
|
131
|
+
"resolveJsonModule": true,
|
|
132
|
+
"allowSyntheticDefaultImports": true,
|
|
133
|
+
"strict": true,
|
|
134
|
+
"noEmit": true,
|
|
135
|
+
"skipLibCheck": true,
|
|
136
|
+
"forceConsistentCasingInFileNames": true,
|
|
137
|
+
"paths": {
|
|
138
|
+
"#graphql/server": ["./${relativeBuildDir}/types/nitro-graphql-server.d.ts"],
|
|
139
|
+
"#graphql/client": ["./${relativeBuildDir}/types/nitro-graphql-client.d.ts"],
|
|
140
|
+
"#graphql/schema": ["./${relative(ctx.config.rootDir, ctx.config.serverDir) || "server/graphql"}/schema.ts"]
|
|
141
|
+
}
|
|
142
|
+
},
|
|
143
|
+
"include": ["**/*.ts"],
|
|
144
|
+
"exclude": ["node_modules", "${relativeBuildDir}"]
|
|
145
|
+
}
|
|
146
|
+
`, "utf-8");
|
|
147
|
+
logger.success(`Created tsconfig.json: ${tsconfigPath}`);
|
|
148
|
+
} else logger.info(`tsconfig.json already exists: ${tsconfigPath}`);
|
|
149
|
+
const schemaPath = join(ctx.config.serverDir, "schema.graphql");
|
|
150
|
+
if (force || !existsSync(schemaPath)) {
|
|
151
|
+
writeFileSync(schemaPath, `# GraphQL Schema
|
|
152
|
+
# Add your type definitions here
|
|
153
|
+
|
|
154
|
+
type Query {
|
|
155
|
+
hello: String!
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
type Mutation {
|
|
159
|
+
# Add your mutations here
|
|
160
|
+
_empty: String
|
|
161
|
+
}
|
|
162
|
+
`, "utf-8");
|
|
163
|
+
logger.success(`Created example schema: ${schemaPath}`);
|
|
164
|
+
} else logger.info(`Schema file already exists: ${schemaPath}`);
|
|
165
|
+
const resolverPath = join(ctx.config.serverDir, "hello.resolver.ts");
|
|
166
|
+
if (force || !existsSync(resolverPath)) {
|
|
167
|
+
writeFileSync(resolverPath, `import { defineQuery } from 'nitro-graphql/define'
|
|
168
|
+
|
|
169
|
+
export const helloQueries = defineQuery({
|
|
170
|
+
hello: () => 'Hello, world!',
|
|
171
|
+
})
|
|
172
|
+
`, "utf-8");
|
|
173
|
+
logger.success(`Created example resolver: ${resolverPath}`);
|
|
174
|
+
} else logger.info(`Resolver file already exists: ${resolverPath}`);
|
|
175
|
+
const queryPath = join(ctx.config.clientDir, "hello.graphql");
|
|
176
|
+
if (force || !existsSync(queryPath)) {
|
|
177
|
+
writeFileSync(queryPath, `query Hello {
|
|
178
|
+
hello
|
|
179
|
+
}
|
|
180
|
+
`, "utf-8");
|
|
181
|
+
logger.success(`Created example query: ${queryPath}`);
|
|
182
|
+
} else logger.info(`Query file already exists: ${queryPath}`);
|
|
183
|
+
logger.info("");
|
|
184
|
+
logger.info("Next steps:");
|
|
185
|
+
logger.info(" 1. Run \"nitro-graphql generate\" to generate types");
|
|
186
|
+
logger.info(" 2. Add more schemas to your server directory");
|
|
187
|
+
logger.info(" 3. Add more queries/mutations to your client directory");
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
//#endregion
|
|
191
|
+
export { AVAILABLE_TEMPLATES, init, initFromTemplate, listTemplates };
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { LOG_TAG } from "../../core/constants.mjs";
|
|
2
|
+
import { validateNoDuplicateTypes } from "../../core/codegen/validation.mjs";
|
|
3
|
+
import { scanSchemasCore } from "../../core/scanning/schemas.mjs";
|
|
4
|
+
import consola from "consola";
|
|
5
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
6
|
+
|
|
7
|
+
//#region src/cli/commands/validate.ts
|
|
8
|
+
const logger = consola.withTag(LOG_TAG);
|
|
9
|
+
/**
|
|
10
|
+
* Validate GraphQL schemas
|
|
11
|
+
*/
|
|
12
|
+
async function validate(ctx) {
|
|
13
|
+
const schemaResult = await scanSchemasCore({
|
|
14
|
+
rootDir: ctx.config.rootDir,
|
|
15
|
+
serverDir: ctx.config.serverDir,
|
|
16
|
+
clientDir: ctx.config.clientDir,
|
|
17
|
+
ignorePatterns: ctx.config.ignore,
|
|
18
|
+
isDev: false,
|
|
19
|
+
logger: {
|
|
20
|
+
info: (msg, ...args) => logger.info(msg, ...args),
|
|
21
|
+
warn: (msg, ...args) => logger.warn(msg, ...args),
|
|
22
|
+
error: (msg, ...args) => logger.error(msg, ...args),
|
|
23
|
+
success: (msg, ...args) => logger.success(msg, ...args),
|
|
24
|
+
debug: (msg, ...args) => logger.debug(msg, ...args)
|
|
25
|
+
},
|
|
26
|
+
layerServerDirs: [],
|
|
27
|
+
layerAppDirs: []
|
|
28
|
+
});
|
|
29
|
+
if (schemaResult.errors.length > 0) {
|
|
30
|
+
for (const error of schemaResult.errors) logger.error(error);
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
if (schemaResult.items.length === 0) {
|
|
34
|
+
logger.warn("No GraphQL schemas found to validate");
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
const schemaContents = [];
|
|
38
|
+
for (const schemaPath of schemaResult.items) {
|
|
39
|
+
if (!existsSync(schemaPath)) {
|
|
40
|
+
logger.error(`Schema file not found: ${schemaPath}`);
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
try {
|
|
44
|
+
const content = readFileSync(schemaPath, "utf-8");
|
|
45
|
+
schemaContents.push(content);
|
|
46
|
+
} catch (error) {
|
|
47
|
+
logger.error(`Failed to read schema file ${schemaPath}:`, error);
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
if (!validateNoDuplicateTypes(schemaResult.items, schemaContents)) {
|
|
52
|
+
logger.error("Schema validation failed");
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
try {
|
|
56
|
+
const { buildSchema, print } = await import("graphql");
|
|
57
|
+
const { mergeTypeDefs } = await import("@graphql-tools/merge");
|
|
58
|
+
const mergedTypeDefs = mergeTypeDefs(schemaContents);
|
|
59
|
+
buildSchema(typeof mergedTypeDefs === "string" ? mergedTypeDefs : print(mergedTypeDefs));
|
|
60
|
+
logger.info(`Validated ${schemaResult.items.length} schema file(s)`);
|
|
61
|
+
return true;
|
|
62
|
+
} catch (error) {
|
|
63
|
+
logger.error("Schema syntax error:", error);
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
//#endregion
|
|
69
|
+
export { validate };
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { AVAILABLE_TEMPLATES } from "./commands/init.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/cli/completions.ts
|
|
4
|
+
async function initCompletions(command) {
|
|
5
|
+
const { default: tab } = await import("@bomb.sh/tab/citty");
|
|
6
|
+
await tab(command, { subCommands: {
|
|
7
|
+
"init": { options: {
|
|
8
|
+
template: (complete) => {
|
|
9
|
+
for (const template of AVAILABLE_TEMPLATES) complete(template.name, template.description);
|
|
10
|
+
complete("gh:", "GitHub shorthand (gh:user/repo)");
|
|
11
|
+
complete("github:", "GitHub template (github:user/repo/path)");
|
|
12
|
+
complete("gitlab:", "GitLab template (gitlab:user/repo)");
|
|
13
|
+
},
|
|
14
|
+
cwd: (complete) => {
|
|
15
|
+
complete(".", "Current directory");
|
|
16
|
+
}
|
|
17
|
+
} },
|
|
18
|
+
"generate": { options: { cwd: (complete) => {
|
|
19
|
+
complete(".", "Current directory");
|
|
20
|
+
} } },
|
|
21
|
+
"generate:server": { options: { cwd: (complete) => {
|
|
22
|
+
complete(".", "Current directory");
|
|
23
|
+
} } },
|
|
24
|
+
"generate:client": { options: { cwd: (complete) => {
|
|
25
|
+
complete(".", "Current directory");
|
|
26
|
+
} } },
|
|
27
|
+
"validate": { options: { cwd: (complete) => {
|
|
28
|
+
complete(".", "Current directory");
|
|
29
|
+
} } }
|
|
30
|
+
} });
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
//#endregion
|
|
34
|
+
export { initCompletions };
|