@objectifthunes/create-sandstone 0.1.0 → 1.0.0
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/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +31 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/add-adapter.d.ts +2 -0
- package/dist/commands/add-adapter.d.ts.map +1 -0
- package/dist/commands/add-adapter.js +683 -0
- package/dist/commands/add-adapter.js.map +1 -0
- package/dist/commands/generate-adapter.d.ts +2 -0
- package/dist/commands/generate-adapter.d.ts.map +1 -0
- package/dist/commands/generate-adapter.js +467 -0
- package/dist/commands/generate-adapter.js.map +1 -0
- package/dist/commands/generate-entity.d.ts +2 -0
- package/dist/commands/generate-entity.d.ts.map +1 -0
- package/dist/commands/generate-entity.js +210 -0
- package/dist/commands/generate-entity.js.map +1 -0
- package/dist/generator.d.ts +3 -0
- package/dist/generator.d.ts.map +1 -0
- package/dist/generator.js +85 -0
- package/dist/generator.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +107 -61
- package/dist/index.js.map +1 -0
- package/dist/presets.d.ts +45 -0
- package/dist/presets.d.ts.map +1 -0
- package/dist/presets.js +105 -0
- package/dist/presets.js.map +1 -0
- package/dist/prompts.d.ts +3 -13
- package/dist/prompts.d.ts.map +1 -0
- package/dist/prompts.js +222 -49
- package/dist/prompts.js.map +1 -0
- package/dist/templates/claude-md.d.ts +3 -0
- package/dist/templates/claude-md.d.ts.map +1 -0
- package/dist/templates/claude-md.js +853 -0
- package/dist/templates/claude-md.js.map +1 -0
- package/dist/templates/docker-compose.d.ts +3 -0
- package/dist/templates/docker-compose.d.ts.map +1 -0
- package/dist/templates/docker-compose.js +75 -0
- package/dist/templates/docker-compose.js.map +1 -0
- package/dist/templates/env-example.d.ts +3 -0
- package/dist/templates/env-example.d.ts.map +1 -0
- package/dist/templates/env-example.js +137 -0
- package/dist/templates/env-example.js.map +1 -0
- package/dist/templates/gitignore.d.ts +2 -0
- package/dist/templates/gitignore.d.ts.map +1 -0
- package/dist/templates/gitignore.js +11 -0
- package/dist/templates/gitignore.js.map +1 -0
- package/dist/templates/infrastructure.d.ts +3 -0
- package/dist/templates/infrastructure.d.ts.map +1 -0
- package/dist/templates/infrastructure.js +647 -0
- package/dist/templates/infrastructure.js.map +1 -0
- package/dist/templates/main-express.d.ts +3 -0
- package/dist/templates/main-express.d.ts.map +1 -0
- package/dist/templates/main-express.js +80 -0
- package/dist/templates/main-express.js.map +1 -0
- package/dist/templates/main-fastify.d.ts +3 -0
- package/dist/templates/main-fastify.d.ts.map +1 -0
- package/dist/templates/main-fastify.js +73 -0
- package/dist/templates/main-fastify.js.map +1 -0
- package/dist/templates/main-hono.d.ts +3 -0
- package/dist/templates/main-hono.d.ts.map +1 -0
- package/dist/templates/main-hono.js +83 -0
- package/dist/templates/main-hono.js.map +1 -0
- package/dist/templates/migrate-script.d.ts +2 -0
- package/dist/templates/migrate-script.d.ts.map +1 -0
- package/dist/templates/migrate-script.js +18 -0
- package/dist/templates/migrate-script.js.map +1 -0
- package/dist/templates/migration.d.ts +2 -0
- package/dist/templates/migration.d.ts.map +1 -0
- package/dist/templates/migration.js +17 -0
- package/dist/templates/migration.js.map +1 -0
- package/dist/templates/package-json.d.ts +3 -0
- package/dist/templates/package-json.d.ts.map +1 -0
- package/dist/templates/package-json.js +149 -0
- package/dist/templates/package-json.js.map +1 -0
- package/dist/templates/schema.d.ts +3 -0
- package/dist/templates/schema.d.ts.map +1 -0
- package/dist/templates/schema.js +108 -0
- package/dist/templates/schema.js.map +1 -0
- package/dist/templates/test-setup.d.ts +3 -0
- package/dist/templates/test-setup.d.ts.map +1 -0
- package/dist/templates/test-setup.js +12 -0
- package/dist/templates/test-setup.js.map +1 -0
- package/dist/templates/tsconfig.d.ts +2 -0
- package/dist/templates/tsconfig.d.ts.map +1 -0
- package/dist/templates/tsconfig.js +21 -0
- package/dist/templates/tsconfig.js.map +1 -0
- package/package.json +16 -9
- package/dist/generators.d.ts +0 -7
- package/dist/generators.js +0 -328
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
export function schemaTemplate(config) {
|
|
2
|
+
const importNames = [
|
|
3
|
+
'buildSchema',
|
|
4
|
+
'GraphQLObjectType',
|
|
5
|
+
'GraphQLString',
|
|
6
|
+
'GraphQLNonNull',
|
|
7
|
+
'GraphQLID',
|
|
8
|
+
'GraphQLList',
|
|
9
|
+
];
|
|
10
|
+
if (config.auth) {
|
|
11
|
+
importNames.push('GraphQLBoolean');
|
|
12
|
+
}
|
|
13
|
+
const imports = [
|
|
14
|
+
`import {\n${importNames.map((n) => ` ${n},`).join('\n')}\n} from '@objectifthunes/sandstone-sdk'`,
|
|
15
|
+
];
|
|
16
|
+
if (config.auth) {
|
|
17
|
+
imports.push(`import type { GraphQLContext } from '@objectifthunes/sandstone-sdk'`);
|
|
18
|
+
}
|
|
19
|
+
const lines = [];
|
|
20
|
+
lines.push(imports.join('\n'));
|
|
21
|
+
lines.push('');
|
|
22
|
+
// Note type (sample entity)
|
|
23
|
+
lines.push(`// Sample entity — replace with your own`);
|
|
24
|
+
lines.push(`const NoteType = new GraphQLObjectType({`);
|
|
25
|
+
lines.push(` name: 'Note',`);
|
|
26
|
+
lines.push(` fields: () => ({`);
|
|
27
|
+
lines.push(` id: { type: new GraphQLNonNull(GraphQLID) },`);
|
|
28
|
+
lines.push(` title: { type: new GraphQLNonNull(GraphQLString) },`);
|
|
29
|
+
lines.push(` content: { type: GraphQLString },`);
|
|
30
|
+
lines.push(` createdAt: { type: GraphQLString },`);
|
|
31
|
+
lines.push(` }),`);
|
|
32
|
+
lines.push(`})`);
|
|
33
|
+
lines.push('');
|
|
34
|
+
// Auth types
|
|
35
|
+
if (config.auth) {
|
|
36
|
+
lines.push(`const AuthResultType = new GraphQLObjectType({`);
|
|
37
|
+
lines.push(` name: 'AuthResult',`);
|
|
38
|
+
lines.push(` fields: () => ({`);
|
|
39
|
+
lines.push(` accessToken: { type: new GraphQLNonNull(GraphQLString) },`);
|
|
40
|
+
lines.push(` refreshToken: { type: new GraphQLNonNull(GraphQLString) },`);
|
|
41
|
+
lines.push(` isNewUser: { type: new GraphQLNonNull(GraphQLBoolean) },`);
|
|
42
|
+
lines.push(` }),`);
|
|
43
|
+
lines.push(`})`);
|
|
44
|
+
lines.push('');
|
|
45
|
+
}
|
|
46
|
+
// Query type
|
|
47
|
+
lines.push(`const QueryType = new GraphQLObjectType({`);
|
|
48
|
+
lines.push(` name: 'Query',`);
|
|
49
|
+
lines.push(` fields: () => ({`);
|
|
50
|
+
lines.push(` hello: {`);
|
|
51
|
+
lines.push(` type: GraphQLString,`);
|
|
52
|
+
lines.push(` resolve: () => 'Hello from Sandstone!',`);
|
|
53
|
+
lines.push(` },`);
|
|
54
|
+
lines.push(` notes: {`);
|
|
55
|
+
lines.push(` type: new GraphQLList(NoteType),`);
|
|
56
|
+
lines.push(` description: 'Sample query — replace with your own',`);
|
|
57
|
+
lines.push(` resolve: () => [],`);
|
|
58
|
+
lines.push(` },`);
|
|
59
|
+
lines.push(` }),`);
|
|
60
|
+
lines.push(`})`);
|
|
61
|
+
lines.push('');
|
|
62
|
+
// Mutation type
|
|
63
|
+
if (config.auth) {
|
|
64
|
+
lines.push(`const MutationType = new GraphQLObjectType({`);
|
|
65
|
+
lines.push(` name: 'Mutation',`);
|
|
66
|
+
lines.push(` fields: () => ({`);
|
|
67
|
+
lines.push(` sendCode: {`);
|
|
68
|
+
lines.push(` type: GraphQLBoolean,`);
|
|
69
|
+
lines.push(` args: {`);
|
|
70
|
+
lines.push(` email: { type: new GraphQLNonNull(GraphQLString) },`);
|
|
71
|
+
lines.push(` },`);
|
|
72
|
+
lines.push(` resolve: async (_root, args, ctx: GraphQLContext) => {`);
|
|
73
|
+
lines.push(` if (!ctx.app.auth) throw new Error('Auth not configured')`);
|
|
74
|
+
lines.push(` await ctx.app.auth.sendCode(args.email)`);
|
|
75
|
+
lines.push(` return true`);
|
|
76
|
+
lines.push(` },`);
|
|
77
|
+
lines.push(` },`);
|
|
78
|
+
lines.push(` verifyCode: {`);
|
|
79
|
+
lines.push(` type: AuthResultType,`);
|
|
80
|
+
lines.push(` args: {`);
|
|
81
|
+
lines.push(` email: { type: new GraphQLNonNull(GraphQLString) },`);
|
|
82
|
+
lines.push(` code: { type: new GraphQLNonNull(GraphQLString) },`);
|
|
83
|
+
lines.push(` },`);
|
|
84
|
+
lines.push(` resolve: async (_root, args, ctx: GraphQLContext) => {`);
|
|
85
|
+
lines.push(` if (!ctx.app.auth) throw new Error('Auth not configured')`);
|
|
86
|
+
lines.push(` const result = await ctx.app.auth.verifyCode(args.email, args.code)`);
|
|
87
|
+
lines.push(` return {`);
|
|
88
|
+
lines.push(` accessToken: result.tokens.accessToken,`);
|
|
89
|
+
lines.push(` refreshToken: result.tokens.refreshToken,`);
|
|
90
|
+
lines.push(` isNewUser: result.isNewUser,`);
|
|
91
|
+
lines.push(` }`);
|
|
92
|
+
lines.push(` },`);
|
|
93
|
+
lines.push(` },`);
|
|
94
|
+
lines.push(` }),`);
|
|
95
|
+
lines.push(`})`);
|
|
96
|
+
lines.push('');
|
|
97
|
+
}
|
|
98
|
+
// Build schema
|
|
99
|
+
lines.push(`export const schema = buildSchema({`);
|
|
100
|
+
lines.push(` query: QueryType,`);
|
|
101
|
+
if (config.auth) {
|
|
102
|
+
lines.push(` mutation: MutationType,`);
|
|
103
|
+
}
|
|
104
|
+
lines.push(`})`);
|
|
105
|
+
lines.push('');
|
|
106
|
+
return lines.join('\n');
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/templates/schema.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-setup.d.ts","sourceRoot":"","sources":["../../src/templates/test-setup.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAEnD,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,aAAa,GAAG,MAAM,CAUhE"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export function testSetupTemplate(_config) {
|
|
2
|
+
return `import { createTestApp } from '@objectifthunes/sandstone-sdk/testing'
|
|
3
|
+
import type { TestApp } from '@objectifthunes/sandstone-sdk/testing'
|
|
4
|
+
|
|
5
|
+
export type { TestApp }
|
|
6
|
+
|
|
7
|
+
export async function setupTest(): Promise<TestApp> {
|
|
8
|
+
return await createTestApp()
|
|
9
|
+
}
|
|
10
|
+
`;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=test-setup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-setup.js","sourceRoot":"","sources":["../../src/templates/test-setup.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,iBAAiB,CAAC,OAAsB;IACtD,OAAO;;;;;;;;CAQR,CAAC;AACF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tsconfig.d.ts","sourceRoot":"","sources":["../../src/templates/tsconfig.ts"],"names":[],"mappings":"AAAA,wBAAgB,gBAAgB,IAAI,MAAM,CAoBzC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export function tsconfigTemplate() {
|
|
2
|
+
const config = {
|
|
3
|
+
compilerOptions: {
|
|
4
|
+
target: 'ES2022',
|
|
5
|
+
module: 'Node16',
|
|
6
|
+
moduleResolution: 'Node16',
|
|
7
|
+
outDir: './dist',
|
|
8
|
+
rootDir: './src',
|
|
9
|
+
strict: true,
|
|
10
|
+
esModuleInterop: true,
|
|
11
|
+
skipLibCheck: true,
|
|
12
|
+
forceConsistentCasingInFileNames: true,
|
|
13
|
+
declaration: true,
|
|
14
|
+
sourceMap: true,
|
|
15
|
+
},
|
|
16
|
+
include: ['src'],
|
|
17
|
+
exclude: ['node_modules', 'dist'],
|
|
18
|
+
};
|
|
19
|
+
return JSON.stringify(config, null, 2) + '\n';
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=tsconfig.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tsconfig.js","sourceRoot":"","sources":["../../src/templates/tsconfig.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,gBAAgB;IAC9B,MAAM,MAAM,GAAG;QACb,eAAe,EAAE;YACf,MAAM,EAAE,QAAQ;YAChB,MAAM,EAAE,QAAQ;YAChB,gBAAgB,EAAE,QAAQ;YAC1B,MAAM,EAAE,QAAQ;YAChB,OAAO,EAAE,OAAO;YAChB,MAAM,EAAE,IAAI;YACZ,eAAe,EAAE,IAAI;YACrB,YAAY,EAAE,IAAI;YAClB,gCAAgC,EAAE,IAAI;YACtC,WAAW,EAAE,IAAI;YACjB,SAAS,EAAE,IAAI;SAChB;QACD,OAAO,EAAE,CAAC,KAAK,CAAC;QAChB,OAAO,EAAE,CAAC,cAAc,EAAE,MAAM,CAAC;KAClC,CAAC;IAEF,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC;AAChD,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,23 +1,30 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@objectifthunes/create-sandstone",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "Scaffold a backend project using @objectifthunes/sandstone-sdk",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Scaffold a complete backend project using @objectifthunes/sandstone-sdk",
|
|
5
5
|
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": "ObjectifThunes",
|
|
6
8
|
"bin": {
|
|
7
|
-
"create-sandstone": "./dist/index.js"
|
|
9
|
+
"create-sandstone": "./dist/index.js",
|
|
10
|
+
"sandstone": "./dist/cli.js"
|
|
8
11
|
},
|
|
9
12
|
"files": [
|
|
10
13
|
"dist"
|
|
11
14
|
],
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "tsc",
|
|
17
|
+
"dev": "tsc --watch"
|
|
18
|
+
},
|
|
12
19
|
"dependencies": {
|
|
13
|
-
"prompts": "^2.4.
|
|
20
|
+
"prompts": "^2.4.2"
|
|
14
21
|
},
|
|
15
22
|
"devDependencies": {
|
|
16
|
-
"
|
|
23
|
+
"@types/prompts": "^2.4.9",
|
|
17
24
|
"@types/node": "^22.0.0",
|
|
18
|
-
"
|
|
25
|
+
"typescript": "^5.7.0"
|
|
19
26
|
},
|
|
20
|
-
"
|
|
21
|
-
"
|
|
27
|
+
"engines": {
|
|
28
|
+
"node": ">=20"
|
|
22
29
|
}
|
|
23
|
-
}
|
|
30
|
+
}
|
package/dist/generators.d.ts
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import type { ProjectConfig } from './prompts.js';
|
|
2
|
-
export declare function generatePackageJson(config: ProjectConfig): string;
|
|
3
|
-
export declare function generateTsConfig(config: ProjectConfig): string;
|
|
4
|
-
export declare function generateEnvExample(config: ProjectConfig): string;
|
|
5
|
-
export declare function generateGitignore(): string;
|
|
6
|
-
export declare function generateDockerCompose(): string;
|
|
7
|
-
export declare function generateMainTs(config: ProjectConfig): string;
|
package/dist/generators.js
DELETED
|
@@ -1,328 +0,0 @@
|
|
|
1
|
-
export function generatePackageJson(config) {
|
|
2
|
-
const deps = {
|
|
3
|
-
'@objectifthunes/sandstone-sdk': '^0.5.0',
|
|
4
|
-
graphql: '^16.9.0',
|
|
5
|
-
};
|
|
6
|
-
const devDeps = {
|
|
7
|
-
typescript: '^5.7.0',
|
|
8
|
-
'@types/node': '^22.0.0',
|
|
9
|
-
vitest: '^3.0.0',
|
|
10
|
-
};
|
|
11
|
-
// Database
|
|
12
|
-
deps.pg = '^8.13.0';
|
|
13
|
-
// JWT
|
|
14
|
-
deps.jose = '^5.9.0';
|
|
15
|
-
// Logger
|
|
16
|
-
deps.pino = '^9.6.0';
|
|
17
|
-
// Framework
|
|
18
|
-
switch (config.framework) {
|
|
19
|
-
case 'express':
|
|
20
|
-
deps.express = '^5.0.0';
|
|
21
|
-
devDeps['@types/express'] = '^5.0.0';
|
|
22
|
-
break;
|
|
23
|
-
case 'fastify':
|
|
24
|
-
deps.fastify = '^5.2.0';
|
|
25
|
-
break;
|
|
26
|
-
case 'hono':
|
|
27
|
-
deps.hono = '^4.6.0';
|
|
28
|
-
break;
|
|
29
|
-
case 'nestjs':
|
|
30
|
-
deps['@nestjs/common'] = '^11.0.0';
|
|
31
|
-
deps['@nestjs/core'] = '^11.0.0';
|
|
32
|
-
deps['@nestjs/platform-express'] = '^11.0.0';
|
|
33
|
-
deps['@nestjs/graphql'] = '^13.0.0';
|
|
34
|
-
deps['@nestjs/apollo'] = '^13.0.0';
|
|
35
|
-
deps['@apollo/server'] = '^5.0.0';
|
|
36
|
-
deps['reflect-metadata'] = '^0.2.0';
|
|
37
|
-
deps.rxjs = '^7.8.0';
|
|
38
|
-
devDeps['@nestjs/cli'] = '^11.0.0';
|
|
39
|
-
devDeps['@types/express'] = '^5.0.0';
|
|
40
|
-
break;
|
|
41
|
-
}
|
|
42
|
-
// Email
|
|
43
|
-
if (config.email === 'resend')
|
|
44
|
-
deps.resend = '^4.1.0';
|
|
45
|
-
if (config.email === 'nodemailer') {
|
|
46
|
-
deps.nodemailer = '^6.9.0';
|
|
47
|
-
devDeps['@types/nodemailer'] = '^6.0.0';
|
|
48
|
-
}
|
|
49
|
-
// Password
|
|
50
|
-
if (config.authStrategies.includes('password'))
|
|
51
|
-
deps.argon2 = '^0.41.0';
|
|
52
|
-
// Payments
|
|
53
|
-
if (config.payments === 'stripe')
|
|
54
|
-
deps.stripe = '^17.5.0';
|
|
55
|
-
// Storage
|
|
56
|
-
if (config.storage === 'r2' || config.storage === 's3') {
|
|
57
|
-
deps['@aws-sdk/client-s3'] = '^3.700.0';
|
|
58
|
-
deps['@aws-sdk/s3-request-presigner'] = '^3.700.0';
|
|
59
|
-
}
|
|
60
|
-
// Cache
|
|
61
|
-
if (config.cache === 'upstash')
|
|
62
|
-
deps['@upstash/redis'] = '^1.34.0';
|
|
63
|
-
const scripts = {
|
|
64
|
-
build: 'tsc',
|
|
65
|
-
start: 'node dist/main.js',
|
|
66
|
-
test: 'vitest run',
|
|
67
|
-
'test:watch': 'vitest',
|
|
68
|
-
};
|
|
69
|
-
if (config.framework === 'nestjs') {
|
|
70
|
-
scripts.build = 'nest build';
|
|
71
|
-
scripts['start:dev'] = 'nest start --watch';
|
|
72
|
-
}
|
|
73
|
-
return JSON.stringify({
|
|
74
|
-
name: config.name,
|
|
75
|
-
version: '0.0.1',
|
|
76
|
-
private: true,
|
|
77
|
-
type: 'module',
|
|
78
|
-
scripts,
|
|
79
|
-
dependencies: deps,
|
|
80
|
-
devDependencies: devDeps,
|
|
81
|
-
}, null, 2);
|
|
82
|
-
}
|
|
83
|
-
export function generateTsConfig(config) {
|
|
84
|
-
const isNest = config.framework === 'nestjs';
|
|
85
|
-
return JSON.stringify({
|
|
86
|
-
compilerOptions: {
|
|
87
|
-
target: 'ES2022',
|
|
88
|
-
module: isNest ? 'NodeNext' : 'NodeNext',
|
|
89
|
-
moduleResolution: 'NodeNext',
|
|
90
|
-
lib: ['ES2022'],
|
|
91
|
-
outDir: 'dist',
|
|
92
|
-
rootDir: 'src',
|
|
93
|
-
declaration: true,
|
|
94
|
-
strict: true,
|
|
95
|
-
esModuleInterop: true,
|
|
96
|
-
skipLibCheck: true,
|
|
97
|
-
forceConsistentCasingInFileNames: true,
|
|
98
|
-
...(isNest
|
|
99
|
-
? { emitDecoratorMetadata: true, experimentalDecorators: true }
|
|
100
|
-
: {}),
|
|
101
|
-
},
|
|
102
|
-
include: ['src'],
|
|
103
|
-
exclude: ['node_modules', 'dist'],
|
|
104
|
-
}, null, 2);
|
|
105
|
-
}
|
|
106
|
-
export function generateEnvExample(config) {
|
|
107
|
-
const lines = ['# Database'];
|
|
108
|
-
lines.push('DATABASE_URL=postgresql://user:password@localhost:5432/mydb');
|
|
109
|
-
lines.push('');
|
|
110
|
-
lines.push('# JWT');
|
|
111
|
-
lines.push('JWT_SECRET=your-secret-at-least-32-characters-long');
|
|
112
|
-
lines.push('');
|
|
113
|
-
if (config.email === 'resend') {
|
|
114
|
-
lines.push('# Resend');
|
|
115
|
-
lines.push('RESEND_API_KEY=re_xxxxxxxxxxxx');
|
|
116
|
-
lines.push('EMAIL_FROM=noreply@yourdomain.com');
|
|
117
|
-
lines.push('');
|
|
118
|
-
}
|
|
119
|
-
else if (config.email === 'nodemailer') {
|
|
120
|
-
lines.push('# SMTP');
|
|
121
|
-
lines.push('SMTP_HOST=smtp.example.com');
|
|
122
|
-
lines.push('SMTP_PORT=587');
|
|
123
|
-
lines.push('SMTP_USER=user');
|
|
124
|
-
lines.push('SMTP_PASS=pass');
|
|
125
|
-
lines.push('EMAIL_FROM=noreply@yourdomain.com');
|
|
126
|
-
lines.push('');
|
|
127
|
-
}
|
|
128
|
-
if (config.authStrategies.includes('oauth')) {
|
|
129
|
-
for (const p of config.oauthProviders) {
|
|
130
|
-
lines.push(`# OAuth: ${p}`);
|
|
131
|
-
lines.push(`${p.toUpperCase()}_CLIENT_ID=`);
|
|
132
|
-
lines.push(`${p.toUpperCase()}_CLIENT_SECRET=`);
|
|
133
|
-
lines.push('');
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
if (config.payments === 'stripe') {
|
|
137
|
-
lines.push('# Stripe');
|
|
138
|
-
lines.push('STRIPE_SECRET_KEY=sk_test_xxx');
|
|
139
|
-
lines.push('STRIPE_WEBHOOK_SECRET=whsec_xxx');
|
|
140
|
-
lines.push('');
|
|
141
|
-
}
|
|
142
|
-
else if (config.payments === 'revenuecat') {
|
|
143
|
-
lines.push('# RevenueCat');
|
|
144
|
-
lines.push('REVENUECAT_API_KEY=');
|
|
145
|
-
lines.push('REVENUECAT_WEBHOOK_SECRET=');
|
|
146
|
-
lines.push('');
|
|
147
|
-
}
|
|
148
|
-
if (config.storage === 'r2') {
|
|
149
|
-
lines.push('# Cloudflare R2');
|
|
150
|
-
lines.push('R2_ACCOUNT_ID=');
|
|
151
|
-
lines.push('R2_ACCESS_KEY_ID=');
|
|
152
|
-
lines.push('R2_SECRET_ACCESS_KEY=');
|
|
153
|
-
lines.push('R2_BUCKET=');
|
|
154
|
-
lines.push('R2_PUBLIC_URL=');
|
|
155
|
-
lines.push('');
|
|
156
|
-
}
|
|
157
|
-
else if (config.storage === 's3') {
|
|
158
|
-
lines.push('# AWS S3');
|
|
159
|
-
lines.push('S3_BUCKET=');
|
|
160
|
-
lines.push('S3_REGION=');
|
|
161
|
-
lines.push('S3_ACCESS_KEY_ID=');
|
|
162
|
-
lines.push('S3_SECRET_ACCESS_KEY=');
|
|
163
|
-
lines.push('');
|
|
164
|
-
}
|
|
165
|
-
if (config.cache === 'upstash') {
|
|
166
|
-
lines.push('# Upstash Redis');
|
|
167
|
-
lines.push('UPSTASH_REDIS_URL=');
|
|
168
|
-
lines.push('UPSTASH_REDIS_TOKEN=');
|
|
169
|
-
lines.push('');
|
|
170
|
-
}
|
|
171
|
-
lines.push('# Server');
|
|
172
|
-
lines.push('PORT=3000');
|
|
173
|
-
return lines.join('\n');
|
|
174
|
-
}
|
|
175
|
-
export function generateGitignore() {
|
|
176
|
-
return `node_modules/
|
|
177
|
-
dist/
|
|
178
|
-
*.tsbuildinfo
|
|
179
|
-
.env
|
|
180
|
-
.env.local
|
|
181
|
-
coverage/
|
|
182
|
-
.DS_Store
|
|
183
|
-
`;
|
|
184
|
-
}
|
|
185
|
-
export function generateDockerCompose() {
|
|
186
|
-
return `services:
|
|
187
|
-
postgres:
|
|
188
|
-
image: postgres:17-alpine
|
|
189
|
-
ports:
|
|
190
|
-
- "5488:5432"
|
|
191
|
-
environment:
|
|
192
|
-
POSTGRES_USER: dev
|
|
193
|
-
POSTGRES_PASSWORD: dev
|
|
194
|
-
POSTGRES_DB: dev
|
|
195
|
-
tmpfs:
|
|
196
|
-
- /var/lib/postgresql/data
|
|
197
|
-
healthcheck:
|
|
198
|
-
test: ["CMD-SHELL", "pg_isready -U dev"]
|
|
199
|
-
interval: 2s
|
|
200
|
-
timeout: 5s
|
|
201
|
-
retries: 10
|
|
202
|
-
|
|
203
|
-
mailhog:
|
|
204
|
-
image: mailhog/mailhog:latest
|
|
205
|
-
ports:
|
|
206
|
-
- "1025:1025"
|
|
207
|
-
- "8025:8025"
|
|
208
|
-
`;
|
|
209
|
-
}
|
|
210
|
-
export function generateMainTs(config) {
|
|
211
|
-
const pkg = '@objectifthunes/sandstone-sdk';
|
|
212
|
-
const dbImport = config.database === 'supabase'
|
|
213
|
-
? `import { createSupabaseClient } from '${pkg}/supabase';`
|
|
214
|
-
: `import { createPgClient } from '${pkg}/pg';`;
|
|
215
|
-
const dbCreate = config.database === 'supabase'
|
|
216
|
-
? `createSupabaseClient({ connectionString: process.env.DATABASE_URL! })`
|
|
217
|
-
: `createPgClient({ connectionString: process.env.DATABASE_URL! })`;
|
|
218
|
-
let emailImport = '';
|
|
219
|
-
let emailCreate = '';
|
|
220
|
-
if (config.email === 'resend') {
|
|
221
|
-
emailImport = `import { createResendTransport } from '${pkg}/resend';`;
|
|
222
|
-
emailCreate = `createResendTransport({ apiKey: process.env.RESEND_API_KEY! })`;
|
|
223
|
-
}
|
|
224
|
-
else if (config.email === 'nodemailer') {
|
|
225
|
-
emailImport = `import { createNodemailerTransport } from '${pkg}/nodemailer';`;
|
|
226
|
-
emailCreate = `createNodemailerTransport({ host: process.env.SMTP_HOST!, port: Number(process.env.SMTP_PORT ?? 587), auth: { user: process.env.SMTP_USER!, pass: process.env.SMTP_PASS! } })`;
|
|
227
|
-
}
|
|
228
|
-
let passwordImport = '';
|
|
229
|
-
let passwordConfig = '';
|
|
230
|
-
if (config.authStrategies.includes('password')) {
|
|
231
|
-
passwordImport = `import { createArgon2Hasher } from '${pkg}/argon2';`;
|
|
232
|
-
passwordConfig = ` password: { hasher: createArgon2Hasher() },`;
|
|
233
|
-
}
|
|
234
|
-
let oauthImports = '';
|
|
235
|
-
let oauthConfig = '';
|
|
236
|
-
if (config.authStrategies.includes('oauth') && config.oauthProviders.length > 0) {
|
|
237
|
-
const oauthLines = [];
|
|
238
|
-
const configLines = [];
|
|
239
|
-
for (const p of config.oauthProviders) {
|
|
240
|
-
const upper = p.charAt(0).toUpperCase() + p.slice(1);
|
|
241
|
-
oauthLines.push(`import { create${upper}OAuth } from '${pkg}/oauth-${p}';`);
|
|
242
|
-
configLines.push(` ${p}: create${upper}OAuth({ clientId: process.env.${p.toUpperCase()}_CLIENT_ID!, clientSecret: process.env.${p.toUpperCase()}_CLIENT_SECRET! }),`);
|
|
243
|
-
}
|
|
244
|
-
oauthImports = oauthLines.join('\n');
|
|
245
|
-
oauthConfig = ` oauth: {\n${configLines.join('\n')}\n },`;
|
|
246
|
-
}
|
|
247
|
-
let paymentImport = '';
|
|
248
|
-
let paymentConfig = '';
|
|
249
|
-
if (config.payments === 'stripe') {
|
|
250
|
-
paymentImport = `import { createStripeProvider } from '${pkg}/stripe';`;
|
|
251
|
-
paymentConfig = ` payments: { provider: createStripeProvider({ secretKey: process.env.STRIPE_SECRET_KEY!, webhookSecret: process.env.STRIPE_WEBHOOK_SECRET! }) },`;
|
|
252
|
-
}
|
|
253
|
-
else if (config.payments === 'revenuecat') {
|
|
254
|
-
paymentImport = `import { createRevenueCatProvider } from '${pkg}/revenuecat';`;
|
|
255
|
-
paymentConfig = ` payments: { provider: createRevenueCatProvider({ apiKey: process.env.REVENUECAT_API_KEY!, webhookSecret: process.env.REVENUECAT_WEBHOOK_SECRET! }) },`;
|
|
256
|
-
}
|
|
257
|
-
let storageImport = '';
|
|
258
|
-
let storageConfig = '';
|
|
259
|
-
if (config.storage === 'r2') {
|
|
260
|
-
storageImport = `import { createR2Storage } from '${pkg}/r2';`;
|
|
261
|
-
storageConfig = ` storage: createR2Storage({ accountId: process.env.R2_ACCOUNT_ID!, accessKeyId: process.env.R2_ACCESS_KEY_ID!, secretAccessKey: process.env.R2_SECRET_ACCESS_KEY!, bucket: process.env.R2_BUCKET! }),`;
|
|
262
|
-
}
|
|
263
|
-
else if (config.storage === 's3') {
|
|
264
|
-
storageImport = `import { createS3Storage } from '${pkg}/s3';`;
|
|
265
|
-
storageConfig = ` storage: createS3Storage({ bucket: process.env.S3_BUCKET!, region: process.env.S3_REGION!, accessKeyId: process.env.S3_ACCESS_KEY_ID!, secretAccessKey: process.env.S3_SECRET_ACCESS_KEY! }),`;
|
|
266
|
-
}
|
|
267
|
-
else if (config.storage === 'local') {
|
|
268
|
-
storageImport = `import { createLocalStorage } from '${pkg}/local-storage';`;
|
|
269
|
-
storageConfig = ` storage: createLocalStorage({ directory: './uploads' }),`;
|
|
270
|
-
}
|
|
271
|
-
let cacheImport = '';
|
|
272
|
-
let cacheConfig = '';
|
|
273
|
-
if (config.cache === 'upstash') {
|
|
274
|
-
cacheImport = `import { createUpstashCache } from '${pkg}/upstash';`;
|
|
275
|
-
cacheConfig = ` cache: createUpstashCache({ url: process.env.UPSTASH_REDIS_URL!, token: process.env.UPSTASH_REDIS_TOKEN! }),`;
|
|
276
|
-
}
|
|
277
|
-
const imports = [
|
|
278
|
-
`import { createAuth, createGraphQLHandler, createContextFactory, runMigrations } from '${pkg}';`,
|
|
279
|
-
`import { createJoseSigner } from '${pkg}/jose';`,
|
|
280
|
-
`import { createPinoLogger } from '${pkg}/pino';`,
|
|
281
|
-
dbImport,
|
|
282
|
-
emailImport,
|
|
283
|
-
passwordImport,
|
|
284
|
-
oauthImports,
|
|
285
|
-
paymentImport,
|
|
286
|
-
storageImport,
|
|
287
|
-
cacheImport,
|
|
288
|
-
]
|
|
289
|
-
.filter(Boolean)
|
|
290
|
-
.join('\n');
|
|
291
|
-
const authConfig = [
|
|
292
|
-
` otp: { length: 6, expiresIn: '10m', maxAttempts: 3, cooldown: '60s' },`,
|
|
293
|
-
passwordConfig,
|
|
294
|
-
oauthConfig,
|
|
295
|
-
` session: { enabled: true },`,
|
|
296
|
-
]
|
|
297
|
-
.filter(Boolean)
|
|
298
|
-
.join('\n');
|
|
299
|
-
return `${imports}
|
|
300
|
-
|
|
301
|
-
async function main() {
|
|
302
|
-
const db = ${dbCreate};
|
|
303
|
-
const logger = createPinoLogger({ level: 'info', pretty: true });
|
|
304
|
-
const tokens = createJoseSigner({ secret: process.env.JWT_SECRET! });
|
|
305
|
-
${config.email !== 'none' ? ` const emailTransport = ${emailCreate};` : ''}
|
|
306
|
-
|
|
307
|
-
await runMigrations(db, { includeBuiltIn: true });
|
|
308
|
-
|
|
309
|
-
const auth = createAuth({
|
|
310
|
-
db,
|
|
311
|
-
${config.email !== 'none' ? ' email: emailTransport,' : ''}
|
|
312
|
-
tokens,
|
|
313
|
-
logger,
|
|
314
|
-
${authConfig}
|
|
315
|
-
});
|
|
316
|
-
|
|
317
|
-
const createContext = createContextFactory({ db, tokens, logger });
|
|
318
|
-
// TODO: add your GraphQL schema here
|
|
319
|
-
// const graphqlHandler = createGraphQLHandler({ schema, createContext });
|
|
320
|
-
|
|
321
|
-
const port = process.env.PORT ?? 3000;
|
|
322
|
-
logger.info(\`Server ready to start on port \${port}\`);
|
|
323
|
-
logger.info('Add your HTTP framework and GraphQL schema to complete setup.');
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
main().catch(console.error);
|
|
327
|
-
`;
|
|
328
|
-
}
|