create-sprint 0.0.76 → 0.0.80

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -5,7 +5,7 @@ import { join } from "path";
5
5
  import color from "picocolors";
6
6
  import * as p from "@clack/prompts";
7
7
  import { validateProjectName } from "./validators.js";
8
- import { getTypeScriptPackageJson, getJavaScriptPackageJson, getTsConfig, getViteConfig, getMainFile, getHomeRoute, getAdminRoute, getHomeController, getAdminController, getEnvExample, getInternalAuthMiddleware, getUserAuthMiddleware, getHomeSchema, getAdminSchema, getDockerfile, getDockerCompose, getGitignore, getDockerIgnore, getSprintConfigFile, getEnvDevelopment, getEnvProduction, getExampleCronJob } from "./generators.js";
8
+ import { getTypeScriptPackageJson, getJavaScriptPackageJson, getTsConfig, getViteConfig, getMainFile, getHomeRoute, getAdminRoute, getHomeController, getAdminController, getEnvExample, getInternalAuthMiddleware, getUserAuthMiddleware, getHomeSchema, getAdminSchema, getDockerfile, getDockerCompose, getGitignore, getDockerIgnore, getSprintConfigFile, getEnvDevelopment, getEnvProduction, getExampleCronJob, getGraphQLFiles } from "./generators.js";
9
9
  export async function writeFile(path, content, options) {
10
10
  if (typeof content === "string")
11
11
  content = content.trimEnd();
@@ -23,6 +23,7 @@ export async function runCLI(args) {
23
23
  language: options.language || "typescript",
24
24
  telemetry: options.telemetry || "none",
25
25
  swagger: options.swagger ?? true,
26
+ graphql: options.graphql ?? false,
26
27
  docker: options.docker || false,
27
28
  };
28
29
  }
@@ -44,12 +45,14 @@ export async function runCLI(args) {
44
45
  message: "Error tracking:",
45
46
  options: [
46
47
  { value: "none", label: "None" },
48
+ { value: "open-telemetry", label: "OpenTelemetry", hint: "flexible, open standard", disabled: true },
47
49
  { value: "sentry", label: "Sentry", hint: "free tier available" },
48
50
  { value: "glitchtip", label: "GlitchTip", hint: "self-hostable" },
49
- { value: "discord", label: "Discord Webhook", hint: "sends to a channel" },
50
- ],
51
+ { value: "discord", label: "Discord Webhook", hint: "sends to a channel" }
52
+ ]
51
53
  }),
52
54
  swagger: () => p.confirm({ message: "Add Swagger UI & OpenAPI?", initialValue: true }),
55
+ graphql: () => p.confirm({ message: "Add GraphQL support?", initialValue: false }),
53
56
  docker: () => p.confirm({ message: "Add Docker support?", initialValue: false }),
54
57
  }, {
55
58
  onCancel: () => {
@@ -61,7 +64,7 @@ export async function runCLI(args) {
61
64
  const targetDir = config.projectName === "." ? process.cwd() : join(process.cwd(), config.projectName);
62
65
  const s = p.spinner();
63
66
  s.start("Creating project");
64
- await createProject(config.projectName, config.language, config.telemetry, config.swagger, config.docker);
67
+ await createProject(config.projectName, config.language, config.telemetry, config.swagger, config.graphql, config.docker);
65
68
  s.stop("Project created");
66
69
  let installDeps = true;
67
70
  if (options.skipInstall)
@@ -130,6 +133,10 @@ function parseArgs(args) {
130
133
  options.swagger = true;
131
134
  else if (args.includes("--no-swagger"))
132
135
  options.swagger = false;
136
+ if (args.includes("--graphql"))
137
+ options.graphql = true;
138
+ else if (args.includes("--no-graphql"))
139
+ options.graphql = false;
133
140
  if (args.includes("--no-install"))
134
141
  options.skipInstall = true;
135
142
  if (telemetryArg && ["sentry", "glitchtip", "discord", "none"].includes(telemetryArg))
@@ -137,7 +144,7 @@ function parseArgs(args) {
137
144
  return options;
138
145
  }
139
146
  ;
140
- async function createProject(projectName, language, telemetry, swagger, useDocker) {
147
+ async function createProject(projectName, language, telemetry, swagger, graphql, useDocker) {
141
148
  const isCurrentDir = projectName === ".";
142
149
  const targetDir = isCurrentDir ? process.cwd() : join(process.cwd(), projectName);
143
150
  if (!isCurrentDir && existsSync(targetDir)) {
@@ -148,17 +155,17 @@ async function createProject(projectName, language, telemetry, swagger, useDocke
148
155
  await mkdir(targetDir, { recursive: true });
149
156
  let pkgJson;
150
157
  if (language === "typescript")
151
- pkgJson = getTypeScriptPackageJson(projectName, telemetry, swagger);
158
+ pkgJson = getTypeScriptPackageJson(projectName, telemetry, swagger, graphql);
152
159
  else
153
- pkgJson = getJavaScriptPackageJson(projectName, telemetry, swagger);
160
+ pkgJson = getJavaScriptPackageJson(projectName, telemetry, swagger, graphql);
154
161
  await writeFile(join(targetDir, "package.json"), JSON.stringify(pkgJson, null, 2));
155
162
  if (language === "typescript") {
156
163
  await writeFile(join(targetDir, "tsconfig.json"), getTsConfig());
157
164
  await writeFile(join(targetDir, "vite.config.ts"), getViteConfig());
158
- await writeFile(join(targetDir, "sprint.config.ts"), getSprintConfigFile(language, telemetry, swagger));
165
+ await writeFile(join(targetDir, "sprint.config.ts"), getSprintConfigFile(language, telemetry, swagger, graphql));
159
166
  }
160
167
  else
161
- await writeFile(join(targetDir, "sprint.config.js"), getSprintConfigFile(language, telemetry, swagger));
168
+ await writeFile(join(targetDir, "sprint.config.js"), getSprintConfigFile(language, telemetry, swagger, graphql));
162
169
  const srcDir = join(targetDir, "src");
163
170
  await mkdir(srcDir, { recursive: true });
164
171
  await mkdir(join(srcDir, "middlewares"), { recursive: true });
@@ -168,6 +175,9 @@ async function createProject(projectName, language, telemetry, swagger, useDocke
168
175
  await mkdir(join(srcDir, "cronjobs"), { recursive: true });
169
176
  await mkdir(join(srcDir, "config"), { recursive: true });
170
177
  await mkdir(join(srcDir, "services"), { recursive: true });
178
+ if (graphql) {
179
+ await mkdir(join(srcDir, "graphql"), { recursive: true });
180
+ }
171
181
  if (language === "typescript") {
172
182
  await writeFile(join(srcDir, "config", "index.ts"), "");
173
183
  await writeFile(join(srcDir, "config", "clients.ts"), "");
@@ -177,7 +187,7 @@ async function createProject(projectName, language, telemetry, swagger, useDocke
177
187
  await writeFile(join(srcDir, "config", "clients.js"), "");
178
188
  }
179
189
  await writeFile(join(srcDir, "services", ".gitkeep"), "");
180
- await writeFile(join(srcDir, "app." + (language === "typescript" ? "ts" : "js")), getMainFile(language));
190
+ await writeFile(join(srcDir, "app." + (language === "typescript" ? "ts" : "js")), getMainFile(language, graphql));
181
191
  await writeFile(join(srcDir, "routes", "home." + (language === "typescript" ? "ts" : "js")), getHomeRoute(language));
182
192
  await writeFile(join(srcDir, "routes", "admin." + (language === "typescript" ? "ts" : "js")), getAdminRoute(language));
183
193
  await writeFile(join(srcDir, "controllers", "home." + (language === "typescript" ? "ts" : "js")), getHomeController(language));
@@ -187,6 +197,13 @@ async function createProject(projectName, language, telemetry, swagger, useDocke
187
197
  await writeFile(join(srcDir, "schemas", "home." + (language === "typescript" ? "ts" : "js")), getHomeSchema(language));
188
198
  await writeFile(join(srcDir, "schemas", "admin." + (language === "typescript" ? "ts" : "js")), getAdminSchema(language));
189
199
  await writeFile(join(srcDir, "cronjobs", "example." + (language === "typescript" ? "ts" : "js")), getExampleCronJob(language));
200
+ if (graphql) {
201
+ const graphqlFiles = getGraphQLFiles(language);
202
+ const ext = language === "typescript" ? "ts" : "js";
203
+ await writeFile(join(srcDir, "graphql", `types.${ext}`), graphqlFiles["types.ts"]);
204
+ await writeFile(join(srcDir, "graphql", `resolvers.${ext}`), graphqlFiles["resolvers.ts"]);
205
+ await writeFile(join(srcDir, "graphql", `schema.${ext}`), graphqlFiles["schema.ts"]);
206
+ }
190
207
  await writeFile(join(targetDir, ".env.development.example"), getEnvExample(telemetry));
191
208
  await writeFile(join(targetDir, ".env.production.example"), getEnvExample(telemetry));
192
209
  await writeFile(join(targetDir, ".env.development"), getEnvDevelopment(telemetry));
@@ -52,7 +52,7 @@ export default defineConfig({
52
52
  `;
53
53
  }
54
54
  ;
55
- export function getSprintConfigFile(language, telemetry, swagger) {
55
+ export function getSprintConfigFile(language, telemetry, swagger, graphql) {
56
56
  if (language === "typescript") {
57
57
  let config = `import type { SprintOptions } from "sprint-es";
58
58
 
@@ -63,13 +63,18 @@ export const config: SprintOptions = {
63
63
  swaggerUi: {
64
64
  enabled: ${swagger}
65
65
  }
66
+ },
67
+ graphql: {
68
+ enabled: ${graphql},
69
+ graphiql: {
70
+ enabled: ${graphql}
71
+ }
66
72
  }
67
73
  };
68
74
 
69
- // Add Vite config here if needed
70
- // export const vite = {
71
- // build: { ... }
72
- // };
75
+ // To use GraphQL, create a schema at src/graphql/schema.ts and import it here
76
+ // import { GraphQLSchema } from "graphql";
77
+ // export const graphqlSchema = new GraphQLSchema({ ... });
73
78
  `;
74
79
  if (telemetry === "sentry" || telemetry === "glitchtip") {
75
80
  config += `import { initTelemetry } from "sprint-es/telemetry";
@@ -99,8 +104,18 @@ initTelemetry({
99
104
  swaggerUi: {
100
105
  enabled: ${swagger}
101
106
  }
107
+ },
108
+ graphql: {
109
+ enabled: ${graphql},
110
+ graphiql: {
111
+ enabled: ${graphql}
112
+ }
102
113
  }
103
114
  };
115
+
116
+ // To use GraphQL, create a schema at src/graphql/schema.js and import it here
117
+ // import { GraphQLSchema } from "graphql";
118
+ // export const graphqlSchema = new GraphQLSchema({ ... });
104
119
  `;
105
120
  if (telemetry === "sentry" || telemetry === "glitchtip") {
106
121
  config += `
@@ -0,0 +1,73 @@
1
+ export function getGraphQLFiles(language) {
2
+ const ext = language === "typescript" ? "ts" : "js";
3
+ return {
4
+ "types.ts": `import { GraphQLObjectType, GraphQLString, GraphQLList, GraphQLNonNull } from "graphql";
5
+
6
+ export const UserType = new GraphQLObjectType({
7
+ name: "User",
8
+ fields: {
9
+ id: { type: new GraphQLNonNull(GraphQLString) },
10
+ name: { type: GraphQLString },
11
+ email: { type: GraphQLString }
12
+ }
13
+ });
14
+ `,
15
+ "resolvers.ts": `import { GraphQLString, GraphQLList, GraphQLNonNull } from "graphql";
16
+ import { UserType } from "./types.js";
17
+
18
+ export const users = [
19
+ { id: "1", name: "John Doe", email: "john@example.com" },
20
+ { id: "2", name: "Jane Smith", email: "jane@example.com" }
21
+ ];
22
+
23
+ export const queries = {
24
+ hello: {
25
+ type: GraphQLString,
26
+ resolve: () => "Hello, GraphQL!"
27
+ },
28
+ users: {
29
+ type: new GraphQLList(UserType),
30
+ resolve: () => users
31
+ },
32
+ user: {
33
+ type: UserType,
34
+ args: {
35
+ id: { type: new GraphQLNonNull(GraphQLString) }
36
+ },
37
+ resolve: (_, args) => users.find(u => u.id === args.id)
38
+ }
39
+ };
40
+
41
+ export const mutations = {
42
+ createUser: {
43
+ type: UserType,
44
+ args: {
45
+ name: { type: new GraphQLNonNull(GraphQLString) },
46
+ email: { type: new GraphQLNonNull(GraphQLString) }
47
+ },
48
+ resolve: (_, args) => {
49
+ const newUser = { id: String(users.length + 1), name: args.name, email: args.email };
50
+ users.push(newUser);
51
+ return newUser;
52
+ }
53
+ }
54
+ };
55
+ `,
56
+ "schema.ts": `import { GraphQLSchema, GraphQLObjectType } from "graphql";
57
+ import { queries } from "./resolvers.js";
58
+ import { mutations } from "./resolvers.js";
59
+
60
+ const Query = new GraphQLObjectType({
61
+ name: "Query",
62
+ fields: queries
63
+ });
64
+
65
+ const Mutation = new GraphQLObjectType({
66
+ name: "Mutation",
67
+ fields: mutations
68
+ });
69
+
70
+ export const graphqlSchema = new GraphQLSchema({ query: Query, mutation: Mutation });
71
+ `
72
+ };
73
+ }
@@ -16,5 +16,7 @@ export { getHomeSchema, getAdminSchema } from "./schemas.js";
16
16
  export { getExampleCronJob } from "./cronjobs.js";
17
17
  // Docker
18
18
  export { getDockerfile, getDockerCompose } from "./docker.js";
19
+ // GraphQL
20
+ export { getGraphQLFiles } from "./graphql.js";
19
21
  // Misc
20
22
  export { getGitignore, getDockerIgnore } from "./misc.js";
@@ -8,9 +8,9 @@ export function generateJWTKeys() {
8
8
  return keys;
9
9
  }
10
10
  ;
11
- export function getTypeScriptPackageJson(name, telemetry, swagger) {
11
+ export function getTypeScriptPackageJson(name, telemetry, swagger, graphql) {
12
12
  const deps = {
13
- "sprint-es": "^0.0.81"
13
+ "sprint-es": "^0.0.83"
14
14
  };
15
15
  const devDeps = {
16
16
  "@types/node": "^22.0.0",
@@ -25,6 +25,11 @@ export function getTypeScriptPackageJson(name, telemetry, swagger) {
25
25
  deps["swagger-ui-express"] = "^5.0.0";
26
26
  if (swagger)
27
27
  devDeps["@types/swagger-ui-express"] = "^4.1.8";
28
+ if (graphql) {
29
+ deps["graphql"] = "^16.9.0";
30
+ deps["graphql-http"] = "^1.22.0";
31
+ deps["ruru"] = "^1.1.0";
32
+ }
28
33
  return {
29
34
  name: name === "." ? "sprint-app" : name,
30
35
  version: "0.0.1",
@@ -42,9 +47,9 @@ export function getTypeScriptPackageJson(name, telemetry, swagger) {
42
47
  };
43
48
  }
44
49
  ;
45
- export function getJavaScriptPackageJson(name, telemetry, swagger) {
50
+ export function getJavaScriptPackageJson(name, telemetry, swagger, graphql) {
46
51
  const deps = {
47
- "sprint-es": "^0.0.81"
52
+ "sprint-es": "^0.0.83"
48
53
  };
49
54
  if (telemetry === "sentry" || telemetry === "glitchtip")
50
55
  deps["@sentry/node"] = "^8.0.0";
@@ -52,6 +57,11 @@ export function getJavaScriptPackageJson(name, telemetry, swagger) {
52
57
  deps["axios"] = "^1.6.0";
53
58
  if (swagger)
54
59
  deps["swagger-ui-express"] = "^5.0.0";
60
+ if (graphql) {
61
+ deps["graphql"] = "^16.9.0";
62
+ deps["graphql-http"] = "^1.22.0";
63
+ deps["ruru"] = "^1.1.0";
64
+ }
55
65
  return {
56
66
  name: name === "." ? "sprint-app" : name,
57
67
  version: "0.0.1",
@@ -1,8 +1,25 @@
1
- export function getMainFile(language) {
1
+ export function getMainFile(language, graphql = false) {
2
+ const ext = language === "typescript" ? "ts" : "js";
2
3
  if (language === "typescript") {
4
+ if (graphql) {
5
+ return `import Sprint from "sprint-es";
6
+ import { graphqlSchema } from "./graphql/schema.js";
7
+
8
+ const app = new Sprint();
9
+ app.setGraphQLSchema(graphqlSchema);
10
+ `;
11
+ }
12
+ return `import Sprint from "sprint-es";
13
+
14
+ const app = new Sprint();
15
+ `;
16
+ }
17
+ if (graphql) {
3
18
  return `import Sprint from "sprint-es";
19
+ import { graphqlSchema } from "./graphql/schema.js";
4
20
 
5
21
  const app = new Sprint();
22
+ app.setGraphQLSchema(graphqlSchema);
6
23
  `;
7
24
  }
8
25
  return `import Sprint from "sprint-es";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-sprint",
3
- "version": "0.0.76",
3
+ "version": "0.0.80",
4
4
  "description": "Create a new Sprint API project",
5
5
  "type": "module",
6
6
  "bin": {
package/src/index.ts CHANGED
@@ -5,13 +5,14 @@ import { join } from "path";
5
5
  import color from "picocolors";
6
6
  import * as p from "@clack/prompts";
7
7
  import { validateProjectName } from "./validators.js";
8
- import { getTypeScriptPackageJson, getJavaScriptPackageJson, getTsConfig, getViteConfig, getMainFile, getHomeRoute, getAdminRoute, getHomeController, getAdminController, getEnvExample, getInternalAuthMiddleware, getUserAuthMiddleware, getHomeSchema, getAdminSchema, getDockerfile, getDockerCompose, getGitignore, getDockerIgnore, getSprintConfigFile, getEnvDevelopment, getEnvProduction, getExampleCronJob } from "./generators.js";
8
+ import { getTypeScriptPackageJson, getJavaScriptPackageJson, getTsConfig, getViteConfig, getMainFile, getHomeRoute, getAdminRoute, getHomeController, getAdminController, getEnvExample, getInternalAuthMiddleware, getUserAuthMiddleware, getHomeSchema, getAdminSchema, getDockerfile, getDockerCompose, getGitignore, getDockerIgnore, getSprintConfigFile, getEnvDevelopment, getEnvProduction, getExampleCronJob, getGraphQLFiles } from "./generators.js";
9
9
 
10
10
  export interface CLIOptions {
11
11
  projectName?: string;
12
12
  language?: "typescript" | "javascript";
13
13
  telemetry?: "none" | "sentry" | "glitchtip" | "discord";
14
14
  swagger?: boolean;
15
+ graphql?: boolean;
15
16
  docker?: boolean;
16
17
  skipInstall?: boolean;
17
18
  skipPrompts?: boolean;
@@ -34,6 +35,7 @@ export async function runCLI(args: string[]) {
34
35
  language: "typescript" | "javascript";
35
36
  telemetry: string;
36
37
  swagger: boolean;
38
+ graphql: boolean;
37
39
  docker: boolean;
38
40
  };
39
41
 
@@ -43,6 +45,7 @@ export async function runCLI(args: string[]) {
43
45
  language: options.language || "typescript",
44
46
  telemetry: options.telemetry || "none",
45
47
  swagger: options.swagger ?? true,
48
+ graphql: options.graphql ?? false,
46
49
  docker: options.docker || false,
47
50
  };
48
51
  } else {
@@ -69,17 +72,18 @@ export async function runCLI(args: string[]) {
69
72
  message: "Error tracking:",
70
73
  options: [
71
74
  { value: "none", label: "None" },
75
+ { value: "open-telemetry", label: "OpenTelemetry", hint: "flexible, open standard", disabled: true },
72
76
  { value: "sentry", label: "Sentry", hint: "free tier available" },
73
77
  { value: "glitchtip", label: "GlitchTip", hint: "self-hostable" },
74
- { value: "discord", label: "Discord Webhook", hint: "sends to a channel" },
75
- ],
78
+ { value: "discord", label: "Discord Webhook", hint: "sends to a channel" }
79
+ ]
76
80
  }),
77
81
 
78
- swagger: () =>
79
- p.confirm({ message: "Add Swagger UI & OpenAPI?", initialValue: true }),
82
+ swagger: () => p.confirm({ message: "Add Swagger UI & OpenAPI?", initialValue: true }),
83
+
84
+ graphql: () => p.confirm({ message: "Add GraphQL support?", initialValue: false }),
80
85
 
81
- docker: () =>
82
- p.confirm({ message: "Add Docker support?", initialValue: false }),
86
+ docker: () => p.confirm({ message: "Add Docker support?", initialValue: false }),
83
87
  },
84
88
  {
85
89
  onCancel: () => {
@@ -99,6 +103,7 @@ export async function runCLI(args: string[]) {
99
103
  config.language,
100
104
  config.telemetry,
101
105
  config.swagger,
106
+ config.graphql,
102
107
  config.docker
103
108
  );
104
109
  s.stop("Project created");
@@ -169,6 +174,9 @@ function parseArgs(args: string[]): CLIOptions {
169
174
  if (args.includes("--swagger")) options.swagger = true;
170
175
  else if (args.includes("--no-swagger")) options.swagger = false;
171
176
 
177
+ if (args.includes("--graphql")) options.graphql = true;
178
+ else if (args.includes("--no-graphql")) options.graphql = false;
179
+
172
180
  if (args.includes("--no-install")) options.skipInstall = true;
173
181
 
174
182
  if (telemetryArg && ["sentry", "glitchtip", "discord", "none"].includes(telemetryArg)) options.telemetry = telemetryArg as CLIOptions["telemetry"];
@@ -181,6 +189,7 @@ async function createProject(
181
189
  language: "typescript" | "javascript",
182
190
  telemetry: string,
183
191
  swagger: boolean,
192
+ graphql: boolean,
184
193
  useDocker: boolean
185
194
  ) {
186
195
  const isCurrentDir = projectName === ".";
@@ -194,16 +203,16 @@ async function createProject(
194
203
  if (!isCurrentDir) await mkdir(targetDir, { recursive: true });
195
204
 
196
205
  let pkgJson;
197
- if (language === "typescript") pkgJson = getTypeScriptPackageJson(projectName, telemetry, swagger);
198
- else pkgJson = getJavaScriptPackageJson(projectName, telemetry, swagger);
206
+ if (language === "typescript") pkgJson = getTypeScriptPackageJson(projectName, telemetry, swagger, graphql);
207
+ else pkgJson = getJavaScriptPackageJson(projectName, telemetry, swagger, graphql);
199
208
 
200
209
  await writeFile(join(targetDir, "package.json"), JSON.stringify(pkgJson, null, 2));
201
210
 
202
211
  if (language === "typescript") {
203
212
  await writeFile(join(targetDir, "tsconfig.json"), getTsConfig());
204
213
  await writeFile(join(targetDir, "vite.config.ts"), getViteConfig());
205
- await writeFile(join(targetDir, "sprint.config.ts"), getSprintConfigFile(language, telemetry, swagger));
206
- } else await writeFile(join(targetDir, "sprint.config.js"), getSprintConfigFile(language, telemetry, swagger));
214
+ await writeFile(join(targetDir, "sprint.config.ts"), getSprintConfigFile(language, telemetry, swagger, graphql));
215
+ } else await writeFile(join(targetDir, "sprint.config.js"), getSprintConfigFile(language, telemetry, swagger, graphql));
207
216
 
208
217
  const srcDir = join(targetDir, "src");
209
218
  await mkdir(srcDir, { recursive: true });
@@ -215,6 +224,10 @@ async function createProject(
215
224
  await mkdir(join(srcDir, "cronjobs"), { recursive: true });
216
225
  await mkdir(join(srcDir, "config"), { recursive: true });
217
226
  await mkdir(join(srcDir, "services"), { recursive: true });
227
+
228
+ if (graphql) {
229
+ await mkdir(join(srcDir, "graphql"), { recursive: true });
230
+ }
218
231
 
219
232
  if (language === "typescript") {
220
233
  await writeFile(join(srcDir, "config", "index.ts"), "");
@@ -226,7 +239,7 @@ async function createProject(
226
239
 
227
240
  await writeFile(join(srcDir, "services", ".gitkeep"), "");
228
241
 
229
- await writeFile(join(srcDir, "app." + (language === "typescript" ? "ts" : "js")), getMainFile(language));
242
+ await writeFile(join(srcDir, "app." + (language === "typescript" ? "ts" : "js")), getMainFile(language, graphql));
230
243
 
231
244
  await writeFile(join(srcDir, "routes", "home." + (language === "typescript" ? "ts" : "js")), getHomeRoute(language));
232
245
  await writeFile(join(srcDir, "routes", "admin." + (language === "typescript" ? "ts" : "js")), getAdminRoute(language));
@@ -242,6 +255,15 @@ async function createProject(
242
255
 
243
256
  await writeFile(join(srcDir, "cronjobs", "example." + (language === "typescript" ? "ts" : "js")), getExampleCronJob(language));
244
257
 
258
+ if (graphql) {
259
+ const graphqlFiles = getGraphQLFiles(language);
260
+ const ext = language === "typescript" ? "ts" : "js";
261
+
262
+ await writeFile(join(srcDir, "graphql", `types.${ext}`), graphqlFiles["types.ts"]);
263
+ await writeFile(join(srcDir, "graphql", `resolvers.${ext}`), graphqlFiles["resolvers.ts"]);
264
+ await writeFile(join(srcDir, "graphql", `schema.${ext}`), graphqlFiles["schema.ts"]);
265
+ }
266
+
245
267
  await writeFile(join(targetDir, ".env.development.example"), getEnvExample(telemetry));
246
268
  await writeFile(join(targetDir, ".env.production.example"), getEnvExample(telemetry));
247
269
 
@@ -52,7 +52,7 @@ export default defineConfig({
52
52
  `;
53
53
  };
54
54
 
55
- export function getSprintConfigFile(language: string, telemetry: string, swagger: boolean) {
55
+ export function getSprintConfigFile(language: string, telemetry: string, swagger: boolean, graphql: boolean) {
56
56
  if (language === "typescript") {
57
57
  let config = `import type { SprintOptions } from "sprint-es";
58
58
 
@@ -63,13 +63,18 @@ export const config: SprintOptions = {
63
63
  swaggerUi: {
64
64
  enabled: ${swagger}
65
65
  }
66
+ },
67
+ graphql: {
68
+ enabled: ${graphql},
69
+ graphiql: {
70
+ enabled: ${graphql}
71
+ }
66
72
  }
67
73
  };
68
74
 
69
- // Add Vite config here if needed
70
- // export const vite = {
71
- // build: { ... }
72
- // };
75
+ // To use GraphQL, create a schema at src/graphql/schema.ts and import it here
76
+ // import { GraphQLSchema } from "graphql";
77
+ // export const graphqlSchema = new GraphQLSchema({ ... });
73
78
  `;
74
79
 
75
80
  if (telemetry === "sentry" || telemetry === "glitchtip") {
@@ -101,8 +106,18 @@ initTelemetry({
101
106
  swaggerUi: {
102
107
  enabled: ${swagger}
103
108
  }
109
+ },
110
+ graphql: {
111
+ enabled: ${graphql},
112
+ graphiql: {
113
+ enabled: ${graphql}
114
+ }
104
115
  }
105
116
  };
117
+
118
+ // To use GraphQL, create a schema at src/graphql/schema.js and import it here
119
+ // import { GraphQLSchema } from "graphql";
120
+ // export const graphqlSchema = new GraphQLSchema({ ... });
106
121
  `;
107
122
 
108
123
  if (telemetry === "sentry" || telemetry === "glitchtip") {
@@ -0,0 +1,74 @@
1
+ export function getGraphQLFiles(language: string) {
2
+ const ext = language === "typescript" ? "ts" : "js";
3
+
4
+ return {
5
+ "types.ts": `import { GraphQLObjectType, GraphQLString, GraphQLList, GraphQLNonNull } from "graphql";
6
+
7
+ export const UserType = new GraphQLObjectType({
8
+ name: "User",
9
+ fields: {
10
+ id: { type: new GraphQLNonNull(GraphQLString) },
11
+ name: { type: GraphQLString },
12
+ email: { type: GraphQLString }
13
+ }
14
+ });
15
+ `,
16
+ "resolvers.ts": `import { GraphQLString, GraphQLList, GraphQLNonNull } from "graphql";
17
+ import { UserType } from "./types.js";
18
+
19
+ export const users = [
20
+ { id: "1", name: "John Doe", email: "john@example.com" },
21
+ { id: "2", name: "Jane Smith", email: "jane@example.com" }
22
+ ];
23
+
24
+ export const queries = {
25
+ hello: {
26
+ type: GraphQLString,
27
+ resolve: () => "Hello, GraphQL!"
28
+ },
29
+ users: {
30
+ type: new GraphQLList(UserType),
31
+ resolve: () => users
32
+ },
33
+ user: {
34
+ type: UserType,
35
+ args: {
36
+ id: { type: new GraphQLNonNull(GraphQLString) }
37
+ },
38
+ resolve: (_, args) => users.find(u => u.id === args.id)
39
+ }
40
+ };
41
+
42
+ export const mutations = {
43
+ createUser: {
44
+ type: UserType,
45
+ args: {
46
+ name: { type: new GraphQLNonNull(GraphQLString) },
47
+ email: { type: new GraphQLNonNull(GraphQLString) }
48
+ },
49
+ resolve: (_, args) => {
50
+ const newUser = { id: String(users.length + 1), name: args.name, email: args.email };
51
+ users.push(newUser);
52
+ return newUser;
53
+ }
54
+ }
55
+ };
56
+ `,
57
+ "schema.ts": `import { GraphQLSchema, GraphQLObjectType } from "graphql";
58
+ import { queries } from "./resolvers.js";
59
+ import { mutations } from "./resolvers.js";
60
+
61
+ const Query = new GraphQLObjectType({
62
+ name: "Query",
63
+ fields: queries
64
+ });
65
+
66
+ const Mutation = new GraphQLObjectType({
67
+ name: "Mutation",
68
+ fields: mutations
69
+ });
70
+
71
+ export const graphqlSchema = new GraphQLSchema({ query: Query, mutation: Mutation });
72
+ `
73
+ };
74
+ }
@@ -25,5 +25,8 @@ export { getExampleCronJob } from "./cronjobs.js";
25
25
  // Docker
26
26
  export { getDockerfile, getDockerCompose } from "./docker.js";
27
27
 
28
+ // GraphQL
29
+ export { getGraphQLFiles } from "./graphql.js";
30
+
28
31
  // Misc
29
32
  export { getGitignore, getDockerIgnore } from "./misc.js";
@@ -14,9 +14,9 @@ export function generateJWTKeys(): JWTKeys {
14
14
  return keys;
15
15
  };
16
16
 
17
- export function getTypeScriptPackageJson(name: string, telemetry: string, swagger: boolean) {
17
+ export function getTypeScriptPackageJson(name: string, telemetry: string, swagger: boolean, graphql: boolean) {
18
18
  const deps: Record<string, string> = {
19
- "sprint-es": "^0.0.81"
19
+ "sprint-es": "^0.0.83"
20
20
  };
21
21
 
22
22
  const devDeps: Record<string, string> = {
@@ -31,6 +31,12 @@ export function getTypeScriptPackageJson(name: string, telemetry: string, swagge
31
31
  if (swagger) deps["swagger-ui-express"] = "^5.0.0";
32
32
  if (swagger) devDeps["@types/swagger-ui-express"] = "^4.1.8";
33
33
 
34
+ if (graphql) {
35
+ deps["graphql"] = "^16.9.0";
36
+ deps["graphql-http"] = "^1.22.0";
37
+ deps["ruru"] = "^1.1.0";
38
+ }
39
+
34
40
  return {
35
41
  name: name === "." ? "sprint-app" : name,
36
42
  version: "0.0.1",
@@ -48,9 +54,9 @@ export function getTypeScriptPackageJson(name: string, telemetry: string, swagge
48
54
  };
49
55
  };
50
56
 
51
- export function getJavaScriptPackageJson(name: string, telemetry: string, swagger: boolean) {
57
+ export function getJavaScriptPackageJson(name: string, telemetry: string, swagger: boolean, graphql: boolean) {
52
58
  const deps: Record<string, string> = {
53
- "sprint-es": "^0.0.81"
59
+ "sprint-es": "^0.0.83"
54
60
  };
55
61
 
56
62
  if (telemetry === "sentry" || telemetry === "glitchtip") deps["@sentry/node"] = "^8.0.0";
@@ -58,6 +64,12 @@ export function getJavaScriptPackageJson(name: string, telemetry: string, swagge
58
64
 
59
65
  if (swagger) deps["swagger-ui-express"] = "^5.0.0";
60
66
 
67
+ if (graphql) {
68
+ deps["graphql"] = "^16.9.0";
69
+ deps["graphql-http"] = "^1.22.0";
70
+ deps["ruru"] = "^1.1.0";
71
+ }
72
+
61
73
  return {
62
74
  name: name === "." ? "sprint-app" : name,
63
75
  version: "0.0.1",
@@ -1,8 +1,27 @@
1
- export function getMainFile(language: string) {
1
+ export function getMainFile(language: string, graphql: boolean = false) {
2
+ const ext = language === "typescript" ? "ts" : "js";
3
+
2
4
  if (language === "typescript") {
5
+ if (graphql) {
6
+ return `import Sprint from "sprint-es";
7
+ import { graphqlSchema } from "./graphql/schema.js";
8
+
9
+ const app = new Sprint();
10
+ app.setGraphQLSchema(graphqlSchema);
11
+ `;
12
+ }
13
+ return `import Sprint from "sprint-es";
14
+
15
+ const app = new Sprint();
16
+ `;
17
+ }
18
+
19
+ if (graphql) {
3
20
  return `import Sprint from "sprint-es";
21
+ import { graphqlSchema } from "./graphql/schema.js";
4
22
 
5
23
  const app = new Sprint();
24
+ app.setGraphQLSchema(graphqlSchema);
6
25
  `;
7
26
  }
8
27