@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.
Files changed (91) hide show
  1. package/dist/cli.d.ts +3 -0
  2. package/dist/cli.d.ts.map +1 -0
  3. package/dist/cli.js +31 -0
  4. package/dist/cli.js.map +1 -0
  5. package/dist/commands/add-adapter.d.ts +2 -0
  6. package/dist/commands/add-adapter.d.ts.map +1 -0
  7. package/dist/commands/add-adapter.js +683 -0
  8. package/dist/commands/add-adapter.js.map +1 -0
  9. package/dist/commands/generate-adapter.d.ts +2 -0
  10. package/dist/commands/generate-adapter.d.ts.map +1 -0
  11. package/dist/commands/generate-adapter.js +467 -0
  12. package/dist/commands/generate-adapter.js.map +1 -0
  13. package/dist/commands/generate-entity.d.ts +2 -0
  14. package/dist/commands/generate-entity.d.ts.map +1 -0
  15. package/dist/commands/generate-entity.js +210 -0
  16. package/dist/commands/generate-entity.js.map +1 -0
  17. package/dist/generator.d.ts +3 -0
  18. package/dist/generator.d.ts.map +1 -0
  19. package/dist/generator.js +85 -0
  20. package/dist/generator.js.map +1 -0
  21. package/dist/index.d.ts +1 -0
  22. package/dist/index.d.ts.map +1 -0
  23. package/dist/index.js +107 -61
  24. package/dist/index.js.map +1 -0
  25. package/dist/presets.d.ts +45 -0
  26. package/dist/presets.d.ts.map +1 -0
  27. package/dist/presets.js +105 -0
  28. package/dist/presets.js.map +1 -0
  29. package/dist/prompts.d.ts +3 -13
  30. package/dist/prompts.d.ts.map +1 -0
  31. package/dist/prompts.js +222 -49
  32. package/dist/prompts.js.map +1 -0
  33. package/dist/templates/claude-md.d.ts +3 -0
  34. package/dist/templates/claude-md.d.ts.map +1 -0
  35. package/dist/templates/claude-md.js +853 -0
  36. package/dist/templates/claude-md.js.map +1 -0
  37. package/dist/templates/docker-compose.d.ts +3 -0
  38. package/dist/templates/docker-compose.d.ts.map +1 -0
  39. package/dist/templates/docker-compose.js +75 -0
  40. package/dist/templates/docker-compose.js.map +1 -0
  41. package/dist/templates/env-example.d.ts +3 -0
  42. package/dist/templates/env-example.d.ts.map +1 -0
  43. package/dist/templates/env-example.js +137 -0
  44. package/dist/templates/env-example.js.map +1 -0
  45. package/dist/templates/gitignore.d.ts +2 -0
  46. package/dist/templates/gitignore.d.ts.map +1 -0
  47. package/dist/templates/gitignore.js +11 -0
  48. package/dist/templates/gitignore.js.map +1 -0
  49. package/dist/templates/infrastructure.d.ts +3 -0
  50. package/dist/templates/infrastructure.d.ts.map +1 -0
  51. package/dist/templates/infrastructure.js +647 -0
  52. package/dist/templates/infrastructure.js.map +1 -0
  53. package/dist/templates/main-express.d.ts +3 -0
  54. package/dist/templates/main-express.d.ts.map +1 -0
  55. package/dist/templates/main-express.js +80 -0
  56. package/dist/templates/main-express.js.map +1 -0
  57. package/dist/templates/main-fastify.d.ts +3 -0
  58. package/dist/templates/main-fastify.d.ts.map +1 -0
  59. package/dist/templates/main-fastify.js +73 -0
  60. package/dist/templates/main-fastify.js.map +1 -0
  61. package/dist/templates/main-hono.d.ts +3 -0
  62. package/dist/templates/main-hono.d.ts.map +1 -0
  63. package/dist/templates/main-hono.js +83 -0
  64. package/dist/templates/main-hono.js.map +1 -0
  65. package/dist/templates/migrate-script.d.ts +2 -0
  66. package/dist/templates/migrate-script.d.ts.map +1 -0
  67. package/dist/templates/migrate-script.js +18 -0
  68. package/dist/templates/migrate-script.js.map +1 -0
  69. package/dist/templates/migration.d.ts +2 -0
  70. package/dist/templates/migration.d.ts.map +1 -0
  71. package/dist/templates/migration.js +17 -0
  72. package/dist/templates/migration.js.map +1 -0
  73. package/dist/templates/package-json.d.ts +3 -0
  74. package/dist/templates/package-json.d.ts.map +1 -0
  75. package/dist/templates/package-json.js +149 -0
  76. package/dist/templates/package-json.js.map +1 -0
  77. package/dist/templates/schema.d.ts +3 -0
  78. package/dist/templates/schema.d.ts.map +1 -0
  79. package/dist/templates/schema.js +108 -0
  80. package/dist/templates/schema.js.map +1 -0
  81. package/dist/templates/test-setup.d.ts +3 -0
  82. package/dist/templates/test-setup.d.ts.map +1 -0
  83. package/dist/templates/test-setup.js +12 -0
  84. package/dist/templates/test-setup.js.map +1 -0
  85. package/dist/templates/tsconfig.d.ts +2 -0
  86. package/dist/templates/tsconfig.d.ts.map +1 -0
  87. package/dist/templates/tsconfig.js +21 -0
  88. package/dist/templates/tsconfig.js.map +1 -0
  89. package/package.json +16 -9
  90. package/dist/generators.d.ts +0 -7
  91. 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,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,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,23 +1,30 @@
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": "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.0"
20
+ "prompts": "^2.4.2"
14
21
  },
15
22
  "devDependencies": {
16
- "typescript": "^5.7.0",
23
+ "@types/prompts": "^2.4.9",
17
24
  "@types/node": "^22.0.0",
18
- "@types/prompts": "^2.4.0"
25
+ "typescript": "^5.7.0"
19
26
  },
20
- "scripts": {
21
- "build": "tsc"
27
+ "engines": {
28
+ "node": ">=20"
22
29
  }
23
- }
30
+ }
@@ -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
- }