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 +27 -10
- package/dist/templates/configFiles.js +20 -5
- package/dist/templates/graphql.js +73 -0
- package/dist/templates/index.js +2 -0
- package/dist/templates/packageJson.js +14 -4
- package/dist/templates/routes.js +18 -1
- package/package.json +1 -1
- package/src/index.ts +34 -12
- package/src/templates/configFiles.ts +20 -5
- package/src/templates/graphql.ts +74 -0
- package/src/templates/index.ts +3 -0
- package/src/templates/packageJson.ts +16 -4
- package/src/templates/routes.ts +20 -1
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
|
-
//
|
|
70
|
-
//
|
|
71
|
-
|
|
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
|
+
}
|
package/dist/templates/index.js
CHANGED
|
@@ -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.
|
|
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.
|
|
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",
|
package/dist/templates/routes.js
CHANGED
|
@@ -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
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
|
-
|
|
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
|
-
//
|
|
70
|
-
//
|
|
71
|
-
|
|
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
|
+
}
|
package/src/templates/index.ts
CHANGED
|
@@ -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.
|
|
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.
|
|
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",
|
package/src/templates/routes.ts
CHANGED
|
@@ -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
|
|