@objectifthunes/create-sandstone 0.1.0 → 0.2.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.
Files changed (71) hide show
  1. package/dist/generator.d.ts +3 -0
  2. package/dist/generator.d.ts.map +1 -0
  3. package/dist/generator.js +78 -0
  4. package/dist/generator.js.map +1 -0
  5. package/dist/index.d.ts +1 -0
  6. package/dist/index.d.ts.map +1 -0
  7. package/dist/index.js +106 -61
  8. package/dist/index.js.map +1 -0
  9. package/dist/presets.d.ts +25 -0
  10. package/dist/presets.d.ts.map +1 -0
  11. package/dist/presets.js +58 -0
  12. package/dist/presets.js.map +1 -0
  13. package/dist/prompts.d.ts +3 -13
  14. package/dist/prompts.d.ts.map +1 -0
  15. package/dist/prompts.js +61 -62
  16. package/dist/prompts.js.map +1 -0
  17. package/dist/templates/claude-md.d.ts +3 -0
  18. package/dist/templates/claude-md.d.ts.map +1 -0
  19. package/dist/templates/claude-md.js +385 -0
  20. package/dist/templates/claude-md.js.map +1 -0
  21. package/dist/templates/docker-compose.d.ts +3 -0
  22. package/dist/templates/docker-compose.d.ts.map +1 -0
  23. package/dist/templates/docker-compose.js +33 -0
  24. package/dist/templates/docker-compose.js.map +1 -0
  25. package/dist/templates/env-example.d.ts +3 -0
  26. package/dist/templates/env-example.d.ts.map +1 -0
  27. package/dist/templates/env-example.js +58 -0
  28. package/dist/templates/env-example.js.map +1 -0
  29. package/dist/templates/gitignore.d.ts +2 -0
  30. package/dist/templates/gitignore.d.ts.map +1 -0
  31. package/dist/templates/gitignore.js +11 -0
  32. package/dist/templates/gitignore.js.map +1 -0
  33. package/dist/templates/infrastructure.d.ts +3 -0
  34. package/dist/templates/infrastructure.d.ts.map +1 -0
  35. package/dist/templates/infrastructure.js +243 -0
  36. package/dist/templates/infrastructure.js.map +1 -0
  37. package/dist/templates/main-express.d.ts +3 -0
  38. package/dist/templates/main-express.d.ts.map +1 -0
  39. package/dist/templates/main-express.js +45 -0
  40. package/dist/templates/main-express.js.map +1 -0
  41. package/dist/templates/main-hono.d.ts +3 -0
  42. package/dist/templates/main-hono.d.ts.map +1 -0
  43. package/dist/templates/main-hono.js +47 -0
  44. package/dist/templates/main-hono.js.map +1 -0
  45. package/dist/templates/migrate-script.d.ts +2 -0
  46. package/dist/templates/migrate-script.d.ts.map +1 -0
  47. package/dist/templates/migrate-script.js +18 -0
  48. package/dist/templates/migrate-script.js.map +1 -0
  49. package/dist/templates/migration.d.ts +2 -0
  50. package/dist/templates/migration.d.ts.map +1 -0
  51. package/dist/templates/migration.js +17 -0
  52. package/dist/templates/migration.js.map +1 -0
  53. package/dist/templates/package-json.d.ts +3 -0
  54. package/dist/templates/package-json.d.ts.map +1 -0
  55. package/dist/templates/package-json.js +85 -0
  56. package/dist/templates/package-json.js.map +1 -0
  57. package/dist/templates/schema.d.ts +3 -0
  58. package/dist/templates/schema.d.ts.map +1 -0
  59. package/dist/templates/schema.js +108 -0
  60. package/dist/templates/schema.js.map +1 -0
  61. package/dist/templates/test-setup.d.ts +3 -0
  62. package/dist/templates/test-setup.d.ts.map +1 -0
  63. package/dist/templates/test-setup.js +41 -0
  64. package/dist/templates/test-setup.js.map +1 -0
  65. package/dist/templates/tsconfig.d.ts +2 -0
  66. package/dist/templates/tsconfig.d.ts.map +1 -0
  67. package/dist/templates/tsconfig.js +21 -0
  68. package/dist/templates/tsconfig.js.map +1 -0
  69. package/package.json +12 -6
  70. package/dist/generators.d.ts +0 -7
  71. 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,3 @@
1
+ import type { ProjectConfig } from '../presets.js';
2
+ export declare function testSetupTemplate(config: ProjectConfig): string;
3
+ //# sourceMappingURL=test-setup.d.ts.map
@@ -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,MAAM,EAAE,aAAa,GAAG,MAAM,CA6C/D"}
@@ -0,0 +1,41 @@
1
+ export function testSetupTemplate(config) {
2
+ const imports = [
3
+ `import {`,
4
+ ` createInMemoryDatabase,`,
5
+ ` createInMemoryEmail,`,
6
+ ` createInMemoryTokenSigner,`,
7
+ ` createInMemoryLogger,`,
8
+ `} from '@objectifthunes/sandstone-sdk/testing'`,
9
+ `import { createApp } from '@objectifthunes/sandstone-sdk'`,
10
+ ];
11
+ if (config.graphql) {
12
+ imports.push(`import { schema } from '../src/schema.js'`);
13
+ }
14
+ const lines = [];
15
+ lines.push(imports.join('\n'));
16
+ lines.push('');
17
+ lines.push(`export async function createTestApp() {`);
18
+ lines.push(` const db = createInMemoryDatabase()`);
19
+ lines.push(` const email = createInMemoryEmail()`);
20
+ lines.push(` const tokens = createInMemoryTokenSigner()`);
21
+ lines.push(` const logger = createInMemoryLogger()`);
22
+ lines.push('');
23
+ lines.push(` const app = await createApp({`);
24
+ lines.push(` db,`);
25
+ lines.push(` logger,`);
26
+ lines.push(` tokens,`);
27
+ if (config.auth) {
28
+ lines.push(` email: { transport: email, from: 'test@test.com' },`);
29
+ lines.push(` auth: { otp: { length: 6, expiresIn: '10m' } },`);
30
+ }
31
+ if (config.graphql) {
32
+ lines.push(` graphql: { schema },`);
33
+ }
34
+ lines.push(` })`);
35
+ lines.push('');
36
+ lines.push(` return { app, db, email, tokens, logger }`);
37
+ lines.push(`}`);
38
+ lines.push('');
39
+ return lines.join('\n');
40
+ }
41
+ //# 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,MAAqB;IACrD,MAAM,OAAO,GAAG;QACd,UAAU;QACV,2BAA2B;QAC3B,wBAAwB;QACxB,8BAA8B;QAC9B,yBAAyB;QACzB,gDAAgD;QAChD,2DAA2D;KAC5D,CAAC;IAEF,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QACnB,OAAO,CAAC,IAAI,CAAC,2CAA2C,CAAC,CAAC;IAC5D,CAAC;IAED,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAC/B,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,yCAAyC,CAAC,CAAC;IACtD,KAAK,CAAC,IAAI,CAAC,uCAAuC,CAAC,CAAC;IACpD,KAAK,CAAC,IAAI,CAAC,uCAAuC,CAAC,CAAC;IACpD,KAAK,CAAC,IAAI,CAAC,8CAA8C,CAAC,CAAC;IAC3D,KAAK,CAAC,IAAI,CAAC,yCAAyC,CAAC,CAAC;IACtD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,iCAAiC,CAAC,CAAC;IAC9C,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACtB,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;IAC1B,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;IAE1B,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;QAChB,KAAK,CAAC,IAAI,CAAC,yDAAyD,CAAC,CAAC;QACtE,KAAK,CAAC,IAAI,CAAC,qDAAqD,CAAC,CAAC;IACpE,CAAC;IAED,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QACnB,KAAK,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC;IACzC,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACnB,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,6CAA6C,CAAC,CAAC;IAC1D,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAChB,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAEf,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function tsconfigTemplate(): string;
2
+ //# sourceMappingURL=tsconfig.d.ts.map
@@ -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,8 +1,10 @@
1
1
  {
2
2
  "name": "@objectifthunes/create-sandstone",
3
- "version": "0.1.0",
4
- "description": "Scaffold a backend project using @objectifthunes/sandstone-sdk",
3
+ "version": "0.2.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
9
  "create-sandstone": "./dist/index.js"
8
10
  },
@@ -10,14 +12,18 @@
10
12
  "dist"
11
13
  ],
12
14
  "dependencies": {
13
- "prompts": "^2.4.0"
15
+ "prompts": "^2.4.2"
14
16
  },
15
17
  "devDependencies": {
16
- "typescript": "^5.7.0",
18
+ "@types/prompts": "^2.4.9",
17
19
  "@types/node": "^22.0.0",
18
- "@types/prompts": "^2.4.0"
20
+ "typescript": "^5.7.0"
21
+ },
22
+ "engines": {
23
+ "node": ">=20"
19
24
  },
20
25
  "scripts": {
21
- "build": "tsc"
26
+ "build": "tsc",
27
+ "dev": "tsc --watch"
22
28
  }
23
29
  }
@@ -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;
@@ -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
- }