create-sprint 0.0.74 → 0.0.78

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
@@ -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,15 +64,13 @@ 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
- if (options.skipInstall) {
70
+ if (options.skipInstall)
68
71
  installDeps = false;
69
- }
70
- else if (!options.skipPrompts) {
72
+ else if (!options.skipPrompts)
71
73
  installDeps = await p.confirm({ message: "Install dependencies now?", initialValue: true });
72
- }
73
74
  if (installDeps) {
74
75
  const s2 = p.spinner();
75
76
  s2.start("Installing dependencies");
@@ -101,10 +102,8 @@ export async function runCLI(args) {
101
102
  const cdCmd = config.projectName === "." ? "" : `cd ${config.projectName} && `;
102
103
  p.note([
103
104
  !installDeps ? `${cdCmd}npm install` : "",
104
- `${cdCmd}npm run dev`,
105
- ]
106
- .filter(Boolean)
107
- .join("\n"), "Next steps");
105
+ `${cdCmd}npm run dev`
106
+ ].filter(Boolean).join("\n"), "Next steps");
108
107
  p.outro("Ready. Happy shipping.");
109
108
  }
110
109
  ;
@@ -134,6 +133,10 @@ function parseArgs(args) {
134
133
  options.swagger = true;
135
134
  else if (args.includes("--no-swagger"))
136
135
  options.swagger = false;
136
+ if (args.includes("--graphql"))
137
+ options.graphql = true;
138
+ else if (args.includes("--no-graphql"))
139
+ options.graphql = false;
137
140
  if (args.includes("--no-install"))
138
141
  options.skipInstall = true;
139
142
  if (telemetryArg && ["sentry", "glitchtip", "discord", "none"].includes(telemetryArg))
@@ -141,7 +144,7 @@ function parseArgs(args) {
141
144
  return options;
142
145
  }
143
146
  ;
144
- async function createProject(projectName, language, telemetry, swagger, useDocker) {
147
+ async function createProject(projectName, language, telemetry, swagger, graphql, useDocker) {
145
148
  const isCurrentDir = projectName === ".";
146
149
  const targetDir = isCurrentDir ? process.cwd() : join(process.cwd(), projectName);
147
150
  if (!isCurrentDir && existsSync(targetDir)) {
@@ -152,17 +155,17 @@ async function createProject(projectName, language, telemetry, swagger, useDocke
152
155
  await mkdir(targetDir, { recursive: true });
153
156
  let pkgJson;
154
157
  if (language === "typescript")
155
- pkgJson = getTypeScriptPackageJson(projectName, telemetry, swagger);
158
+ pkgJson = getTypeScriptPackageJson(projectName, telemetry, swagger, graphql);
156
159
  else
157
- pkgJson = getJavaScriptPackageJson(projectName, telemetry, swagger);
160
+ pkgJson = getJavaScriptPackageJson(projectName, telemetry, swagger, graphql);
158
161
  await writeFile(join(targetDir, "package.json"), JSON.stringify(pkgJson, null, 2));
159
162
  if (language === "typescript") {
160
163
  await writeFile(join(targetDir, "tsconfig.json"), getTsConfig());
161
164
  await writeFile(join(targetDir, "vite.config.ts"), getViteConfig());
162
- await writeFile(join(targetDir, "sprint.config.ts"), getSprintConfigFile(language, telemetry, swagger));
165
+ await writeFile(join(targetDir, "sprint.config.ts"), getSprintConfigFile(language, telemetry, swagger, graphql));
163
166
  }
164
167
  else
165
- await writeFile(join(targetDir, "sprint.config.js"), getSprintConfigFile(language, telemetry, swagger));
168
+ await writeFile(join(targetDir, "sprint.config.js"), getSprintConfigFile(language, telemetry, swagger, graphql));
166
169
  const srcDir = join(targetDir, "src");
167
170
  await mkdir(srcDir, { recursive: true });
168
171
  await mkdir(join(srcDir, "middlewares"), { recursive: true });
@@ -181,7 +184,7 @@ async function createProject(projectName, language, telemetry, swagger, useDocke
181
184
  await writeFile(join(srcDir, "config", "clients.js"), "");
182
185
  }
183
186
  await writeFile(join(srcDir, "services", ".gitkeep"), "");
184
- await writeFile(join(srcDir, "app." + (language === "typescript" ? "ts" : "js")), getMainFile(language));
187
+ await writeFile(join(srcDir, "app." + (language === "typescript" ? "ts" : "js")), getMainFile(language, graphql));
185
188
  await writeFile(join(srcDir, "routes", "home." + (language === "typescript" ? "ts" : "js")), getHomeRoute(language));
186
189
  await writeFile(join(srcDir, "routes", "admin." + (language === "typescript" ? "ts" : "js")), getAdminRoute(language));
187
190
  await writeFile(join(srcDir, "controllers", "home." + (language === "typescript" ? "ts" : "js")), getHomeController(language));
@@ -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 += `
@@ -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.73"
13
+ "sprint-es": "^0.0.82"
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",
@@ -34,6 +39,7 @@ export function getTypeScriptPackageJson(name, telemetry, swagger) {
34
39
  build: "sprint-es build",
35
40
  start: "sprint-es start",
36
41
  dev: "sprint-es dev",
42
+ doctor: "sprint-es doctor",
37
43
  "generate:keys": "sprint-es generate-keys"
38
44
  },
39
45
  dependencies: deps,
@@ -41,9 +47,9 @@ export function getTypeScriptPackageJson(name, telemetry, swagger) {
41
47
  };
42
48
  }
43
49
  ;
44
- export function getJavaScriptPackageJson(name, telemetry, swagger) {
50
+ export function getJavaScriptPackageJson(name, telemetry, swagger, graphql) {
45
51
  const deps = {
46
- "sprint-es": "^0.0.73"
52
+ "sprint-es": "^0.0.82"
47
53
  };
48
54
  if (telemetry === "sentry" || telemetry === "glitchtip")
49
55
  deps["@sentry/node"] = "^8.0.0";
@@ -51,6 +57,11 @@ export function getJavaScriptPackageJson(name, telemetry, swagger) {
51
57
  deps["axios"] = "^1.6.0";
52
58
  if (swagger)
53
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
+ }
54
65
  return {
55
66
  name: name === "." ? "sprint-app" : name,
56
67
  version: "0.0.1",
@@ -61,6 +72,7 @@ export function getJavaScriptPackageJson(name, telemetry, swagger) {
61
72
  build: "sprint-es build",
62
73
  start: "sprint-es start",
63
74
  dev: "sprint-es dev",
75
+ doctor: "sprint-es doctor",
64
76
  "generate:keys": "sprint-es generate-keys"
65
77
  },
66
78
  dependencies: deps
@@ -1,8 +1,136 @@
1
- export function getMainFile(language) {
1
+ export function getMainFile(language, graphql = false) {
2
2
  if (language === "typescript") {
3
+ if (graphql) {
4
+ return `import Sprint from "sprint-es";
5
+ import { config } from "./sprint.config.js";
6
+ import { GraphQLSchema, GraphQLObjectType, GraphQLString, GraphQLList, GraphQLNonNull } from "graphql";
7
+
8
+ const users = [
9
+ { id: "1", name: "John Doe", email: "john@example.com" },
10
+ { id: "2", name: "Jane Smith", email: "jane@example.com" }
11
+ ];
12
+
13
+ const UserType = new GraphQLObjectType({
14
+ name: "User",
15
+ fields: {
16
+ id: { type: new GraphQLNonNull(GraphQLString) },
17
+ name: { type: GraphQLString },
18
+ email: { type: GraphQLString }
19
+ }
20
+ });
21
+
22
+ const Query = new GraphQLObjectType({
23
+ name: "Query",
24
+ fields: {
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
+
43
+ const Mutation = new GraphQLObjectType({
44
+ name: "Mutation",
45
+ fields: {
46
+ createUser: {
47
+ type: UserType,
48
+ args: {
49
+ name: { type: new GraphQLNonNull(GraphQLString) },
50
+ email: { type: new GraphQLNonNull(GraphQLString) }
51
+ },
52
+ resolve: (_, args) => {
53
+ const newUser = { id: String(users.length + 1), name: args.name, email: args.email };
54
+ users.push(newUser);
55
+ return newUser;
56
+ }
57
+ }
58
+ }
59
+ });
60
+
61
+ const graphqlSchema = new GraphQLSchema({ query: Query, mutation: Mutation });
62
+
63
+ const app = new Sprint(config);
64
+ app.setGraphQLSchema(graphqlSchema);
65
+ `;
66
+ }
3
67
  return `import Sprint from "sprint-es";
4
68
 
5
69
  const app = new Sprint();
70
+ `;
71
+ }
72
+ if (graphql) {
73
+ return `import Sprint from "sprint-es";
74
+ import { config } from "./sprint.config.js";
75
+ import { GraphQLSchema, GraphQLObjectType, GraphQLString, GraphQLList, GraphQLNonNull } from "graphql";
76
+
77
+ const users = [
78
+ { id: "1", name: "John Doe", email: "john@example.com" },
79
+ { id: "2", name: "Jane Smith", email: "jane@example.com" }
80
+ ];
81
+
82
+ const UserType = new GraphQLObjectType({
83
+ name: "User",
84
+ fields: {
85
+ id: { type: new GraphQLNonNull(GraphQLString) },
86
+ name: { type: GraphQLString },
87
+ email: { type: GraphQLString }
88
+ }
89
+ });
90
+
91
+ const Query = new GraphQLObjectType({
92
+ name: "Query",
93
+ fields: {
94
+ hello: {
95
+ type: GraphQLString,
96
+ resolve: () => "Hello, GraphQL!"
97
+ },
98
+ users: {
99
+ type: new GraphQLList(UserType),
100
+ resolve: () => users
101
+ },
102
+ user: {
103
+ type: UserType,
104
+ args: {
105
+ id: { type: new GraphQLNonNull(GraphQLString) }
106
+ },
107
+ resolve: (_, args) => users.find(u => u.id === args.id)
108
+ }
109
+ }
110
+ });
111
+
112
+ const Mutation = new GraphQLObjectType({
113
+ name: "Mutation",
114
+ fields: {
115
+ createUser: {
116
+ type: UserType,
117
+ args: {
118
+ name: { type: new GraphQLNonNull(GraphQLString) },
119
+ email: { type: new GraphQLNonNull(GraphQLString) }
120
+ },
121
+ resolve: (_, args) => {
122
+ const newUser = { id: String(users.length + 1), name: args.name, email: args.email };
123
+ users.push(newUser);
124
+ return newUser;
125
+ }
126
+ }
127
+ }
128
+ });
129
+
130
+ const graphqlSchema = new GraphQLSchema({ query: Query, mutation: Mutation });
131
+
132
+ const app = new Sprint(config);
133
+ app.setGraphQLSchema(graphqlSchema);
6
134
  `;
7
135
  }
8
136
  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.74",
3
+ "version": "0.0.78",
4
4
  "description": "Create a new Sprint API project",
5
5
  "type": "module",
6
6
  "bin": {
package/src/index.ts CHANGED
@@ -12,6 +12,7 @@ export interface CLIOptions {
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,16 +103,14 @@ export async function runCLI(args: string[]) {
99
103
  config.language,
100
104
  config.telemetry,
101
105
  config.swagger,
102
- config.docker,
106
+ config.graphql,
107
+ config.docker
103
108
  );
104
109
  s.stop("Project created");
105
110
 
106
111
  let installDeps = true;
107
- if (options.skipInstall) {
108
- installDeps = false;
109
- } else if (!options.skipPrompts) {
110
- installDeps = await p.confirm({ message: "Install dependencies now?", initialValue: true }) as boolean;
111
- }
112
+ if (options.skipInstall) installDeps = false;
113
+ else if (!options.skipPrompts) installDeps = await p.confirm({ message: "Install dependencies now?", initialValue: true }) as boolean;
112
114
 
113
115
  if (installDeps) {
114
116
  const s2 = p.spinner();
@@ -140,10 +142,8 @@ export async function runCLI(args: string[]) {
140
142
  p.note(
141
143
  [
142
144
  !installDeps ? `${cdCmd}npm install` : "",
143
- `${cdCmd}npm run dev`,
144
- ]
145
- .filter(Boolean)
146
- .join("\n"),
145
+ `${cdCmd}npm run dev`
146
+ ].filter(Boolean).join("\n"),
147
147
  "Next steps"
148
148
  );
149
149
 
@@ -174,6 +174,9 @@ function parseArgs(args: string[]): CLIOptions {
174
174
  if (args.includes("--swagger")) options.swagger = true;
175
175
  else if (args.includes("--no-swagger")) options.swagger = false;
176
176
 
177
+ if (args.includes("--graphql")) options.graphql = true;
178
+ else if (args.includes("--no-graphql")) options.graphql = false;
179
+
177
180
  if (args.includes("--no-install")) options.skipInstall = true;
178
181
 
179
182
  if (telemetryArg && ["sentry", "glitchtip", "discord", "none"].includes(telemetryArg)) options.telemetry = telemetryArg as CLIOptions["telemetry"];
@@ -186,6 +189,7 @@ async function createProject(
186
189
  language: "typescript" | "javascript",
187
190
  telemetry: string,
188
191
  swagger: boolean,
192
+ graphql: boolean,
189
193
  useDocker: boolean
190
194
  ) {
191
195
  const isCurrentDir = projectName === ".";
@@ -199,16 +203,16 @@ async function createProject(
199
203
  if (!isCurrentDir) await mkdir(targetDir, { recursive: true });
200
204
 
201
205
  let pkgJson;
202
- if (language === "typescript") pkgJson = getTypeScriptPackageJson(projectName, telemetry, swagger);
203
- else pkgJson = getJavaScriptPackageJson(projectName, telemetry, swagger);
206
+ if (language === "typescript") pkgJson = getTypeScriptPackageJson(projectName, telemetry, swagger, graphql);
207
+ else pkgJson = getJavaScriptPackageJson(projectName, telemetry, swagger, graphql);
204
208
 
205
209
  await writeFile(join(targetDir, "package.json"), JSON.stringify(pkgJson, null, 2));
206
210
 
207
211
  if (language === "typescript") {
208
212
  await writeFile(join(targetDir, "tsconfig.json"), getTsConfig());
209
213
  await writeFile(join(targetDir, "vite.config.ts"), getViteConfig());
210
- await writeFile(join(targetDir, "sprint.config.ts"), getSprintConfigFile(language, telemetry, swagger));
211
- } 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));
212
216
 
213
217
  const srcDir = join(targetDir, "src");
214
218
  await mkdir(srcDir, { recursive: true });
@@ -231,7 +235,7 @@ async function createProject(
231
235
 
232
236
  await writeFile(join(srcDir, "services", ".gitkeep"), "");
233
237
 
234
- await writeFile(join(srcDir, "app." + (language === "typescript" ? "ts" : "js")), getMainFile(language));
238
+ await writeFile(join(srcDir, "app." + (language === "typescript" ? "ts" : "js")), getMainFile(language, graphql));
235
239
 
236
240
  await writeFile(join(srcDir, "routes", "home." + (language === "typescript" ? "ts" : "js")), getHomeRoute(language));
237
241
  await writeFile(join(srcDir, "routes", "admin." + (language === "typescript" ? "ts" : "js")), getAdminRoute(language));
@@ -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") {
@@ -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.73"
19
+ "sprint-es": "^0.0.82"
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",
@@ -40,6 +46,7 @@ export function getTypeScriptPackageJson(name: string, telemetry: string, swagge
40
46
  build: "sprint-es build",
41
47
  start: "sprint-es start",
42
48
  dev: "sprint-es dev",
49
+ doctor: "sprint-es doctor",
43
50
  "generate:keys": "sprint-es generate-keys"
44
51
  },
45
52
  dependencies: deps,
@@ -47,9 +54,9 @@ export function getTypeScriptPackageJson(name: string, telemetry: string, swagge
47
54
  };
48
55
  };
49
56
 
50
- export function getJavaScriptPackageJson(name: string, telemetry: string, swagger: boolean) {
57
+ export function getJavaScriptPackageJson(name: string, telemetry: string, swagger: boolean, graphql: boolean) {
51
58
  const deps: Record<string, string> = {
52
- "sprint-es": "^0.0.73"
59
+ "sprint-es": "^0.0.82"
53
60
  };
54
61
 
55
62
  if (telemetry === "sentry" || telemetry === "glitchtip") deps["@sentry/node"] = "^8.0.0";
@@ -57,6 +64,12 @@ export function getJavaScriptPackageJson(name: string, telemetry: string, swagge
57
64
 
58
65
  if (swagger) deps["swagger-ui-express"] = "^5.0.0";
59
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
+
60
73
  return {
61
74
  name: name === "." ? "sprint-app" : name,
62
75
  version: "0.0.1",
@@ -67,6 +80,7 @@ export function getJavaScriptPackageJson(name: string, telemetry: string, swagge
67
80
  build: "sprint-es build",
68
81
  start: "sprint-es start",
69
82
  dev: "sprint-es dev",
83
+ doctor: "sprint-es doctor",
70
84
  "generate:keys": "sprint-es generate-keys"
71
85
  },
72
86
  dependencies: deps
@@ -1,11 +1,140 @@
1
- export function getMainFile(language: string) {
1
+ export function getMainFile(language: string, graphql: boolean = false) {
2
2
  if (language === "typescript") {
3
+ if (graphql) {
4
+ return `import Sprint from "sprint-es";
5
+ import { config } from "./sprint.config.js";
6
+ import { GraphQLSchema, GraphQLObjectType, GraphQLString, GraphQLList, GraphQLNonNull } from "graphql";
7
+
8
+ const users = [
9
+ { id: "1", name: "John Doe", email: "john@example.com" },
10
+ { id: "2", name: "Jane Smith", email: "jane@example.com" }
11
+ ];
12
+
13
+ const UserType = new GraphQLObjectType({
14
+ name: "User",
15
+ fields: {
16
+ id: { type: new GraphQLNonNull(GraphQLString) },
17
+ name: { type: GraphQLString },
18
+ email: { type: GraphQLString }
19
+ }
20
+ });
21
+
22
+ const Query = new GraphQLObjectType({
23
+ name: "Query",
24
+ fields: {
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
+
43
+ const Mutation = new GraphQLObjectType({
44
+ name: "Mutation",
45
+ fields: {
46
+ createUser: {
47
+ type: UserType,
48
+ args: {
49
+ name: { type: new GraphQLNonNull(GraphQLString) },
50
+ email: { type: new GraphQLNonNull(GraphQLString) }
51
+ },
52
+ resolve: (_, args) => {
53
+ const newUser = { id: String(users.length + 1), name: args.name, email: args.email };
54
+ users.push(newUser);
55
+ return newUser;
56
+ }
57
+ }
58
+ }
59
+ });
60
+
61
+ const graphqlSchema = new GraphQLSchema({ query: Query, mutation: Mutation });
62
+
63
+ const app = new Sprint(config);
64
+ app.setGraphQLSchema(graphqlSchema);
65
+ `;
66
+ }
3
67
  return `import Sprint from "sprint-es";
4
68
 
5
69
  const app = new Sprint();
6
70
  `;
7
71
  }
8
72
 
73
+ if (graphql) {
74
+ return `import Sprint from "sprint-es";
75
+ import { config } from "./sprint.config.js";
76
+ import { GraphQLSchema, GraphQLObjectType, GraphQLString, GraphQLList, GraphQLNonNull } from "graphql";
77
+
78
+ const users = [
79
+ { id: "1", name: "John Doe", email: "john@example.com" },
80
+ { id: "2", name: "Jane Smith", email: "jane@example.com" }
81
+ ];
82
+
83
+ const UserType = new GraphQLObjectType({
84
+ name: "User",
85
+ fields: {
86
+ id: { type: new GraphQLNonNull(GraphQLString) },
87
+ name: { type: GraphQLString },
88
+ email: { type: GraphQLString }
89
+ }
90
+ });
91
+
92
+ const Query = new GraphQLObjectType({
93
+ name: "Query",
94
+ fields: {
95
+ hello: {
96
+ type: GraphQLString,
97
+ resolve: () => "Hello, GraphQL!"
98
+ },
99
+ users: {
100
+ type: new GraphQLList(UserType),
101
+ resolve: () => users
102
+ },
103
+ user: {
104
+ type: UserType,
105
+ args: {
106
+ id: { type: new GraphQLNonNull(GraphQLString) }
107
+ },
108
+ resolve: (_, args) => users.find(u => u.id === args.id)
109
+ }
110
+ }
111
+ });
112
+
113
+ const Mutation = new GraphQLObjectType({
114
+ name: "Mutation",
115
+ fields: {
116
+ createUser: {
117
+ type: UserType,
118
+ args: {
119
+ name: { type: new GraphQLNonNull(GraphQLString) },
120
+ email: { type: new GraphQLNonNull(GraphQLString) }
121
+ },
122
+ resolve: (_, args) => {
123
+ const newUser = { id: String(users.length + 1), name: args.name, email: args.email };
124
+ users.push(newUser);
125
+ return newUser;
126
+ }
127
+ }
128
+ }
129
+ });
130
+
131
+ const graphqlSchema = new GraphQLSchema({ query: Query, mutation: Mutation });
132
+
133
+ const app = new Sprint(config);
134
+ app.setGraphQLSchema(graphqlSchema);
135
+ `;
136
+ }
137
+
9
138
  return `import Sprint from "sprint-es";
10
139
 
11
140
  const app = new Sprint();
package/src/validators.ts CHANGED
@@ -13,7 +13,6 @@ export function validateProjectName(name: string): string | null {
13
13
 
14
14
  if (n !== encodeURIComponent(n)) return "Project name must be URL-safe";
15
15
 
16
-
17
16
  const reserved = ["node_modules", "favicon.ico"];
18
17
  if (reserved.includes(n.toLowerCase())) return `Cannot use "${n}" as project name`;
19
18