forgestack-os-cli 0.1.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 (82) hide show
  1. package/dist/commands/create.d.ts +1 -0
  2. package/dist/commands/create.d.ts.map +1 -0
  3. package/dist/commands/create.js +78 -0
  4. package/dist/commands/create.js.map +1 -0
  5. package/dist/generators/api.d.ts +3 -0
  6. package/dist/generators/api.d.ts.map +1 -0
  7. package/dist/generators/api.js +346 -0
  8. package/dist/generators/api.js.map +1 -0
  9. package/dist/generators/auth.d.ts +2 -0
  10. package/dist/generators/auth.d.ts.map +1 -0
  11. package/dist/generators/auth.js +371 -0
  12. package/dist/generators/auth.js.map +1 -0
  13. package/dist/generators/backend.d.ts +2 -0
  14. package/dist/generators/backend.d.ts.map +1 -0
  15. package/dist/generators/backend.js +875 -0
  16. package/dist/generators/backend.js.map +1 -0
  17. package/dist/generators/common.d.ts +2 -0
  18. package/dist/generators/common.d.ts.map +1 -0
  19. package/dist/generators/common.js +354 -0
  20. package/dist/generators/common.js.map +1 -0
  21. package/dist/generators/database.d.ts +2 -0
  22. package/dist/generators/database.d.ts.map +1 -0
  23. package/dist/generators/database.js +157 -0
  24. package/dist/generators/database.js.map +1 -0
  25. package/dist/generators/docker.d.ts +2 -0
  26. package/dist/generators/docker.d.ts.map +1 -0
  27. package/dist/generators/docker.js +181 -0
  28. package/dist/generators/docker.js.map +1 -0
  29. package/dist/generators/frontend-helpers.d.ts +3 -0
  30. package/dist/generators/frontend-helpers.d.ts.map +1 -0
  31. package/dist/generators/frontend-helpers.js +23 -0
  32. package/dist/generators/frontend-helpers.js.map +1 -0
  33. package/dist/generators/frontend.d.ts +2 -0
  34. package/dist/generators/frontend.d.ts.map +1 -0
  35. package/dist/generators/frontend.js +735 -0
  36. package/dist/generators/frontend.js.map +1 -0
  37. package/dist/generators/index.d.ts +2 -0
  38. package/dist/generators/index.d.ts.map +1 -0
  39. package/dist/generators/index.js +59 -0
  40. package/dist/generators/index.js.map +1 -0
  41. package/dist/generators/nextjs-helpers.d.ts +6 -0
  42. package/dist/generators/nextjs-helpers.d.ts.map +1 -0
  43. package/dist/generators/nextjs-helpers.js +216 -0
  44. package/dist/generators/nextjs-helpers.js.map +1 -0
  45. package/dist/index.d.ts +2 -0
  46. package/dist/index.d.ts.map +1 -0
  47. package/dist/index.js +24 -0
  48. package/dist/index.js.map +1 -0
  49. package/dist/types.d.ts +15 -0
  50. package/dist/types.d.ts.map +1 -0
  51. package/dist/types.js +3 -0
  52. package/dist/types.js.map +1 -0
  53. package/dist/utils/logger.d.ts +9 -0
  54. package/dist/utils/logger.d.ts.map +1 -0
  55. package/dist/utils/logger.js +32 -0
  56. package/dist/utils/logger.js.map +1 -0
  57. package/dist/utils/prompts.d.ts +2 -0
  58. package/dist/utils/prompts.d.ts.map +1 -0
  59. package/dist/utils/prompts.js +107 -0
  60. package/dist/utils/prompts.js.map +1 -0
  61. package/dist/utils/validators.d.ts +2 -0
  62. package/dist/utils/validators.d.ts.map +1 -0
  63. package/dist/utils/validators.js +48 -0
  64. package/dist/utils/validators.js.map +1 -0
  65. package/package.json +49 -0
  66. package/src/commands/create.ts +82 -0
  67. package/src/generators/api.ts +353 -0
  68. package/src/generators/auth.ts +406 -0
  69. package/src/generators/backend.ts +927 -0
  70. package/src/generators/common.ts +377 -0
  71. package/src/generators/database.ts +165 -0
  72. package/src/generators/docker.ts +185 -0
  73. package/src/generators/frontend.ts +783 -0
  74. package/src/generators/index.ts +64 -0
  75. package/src/index.ts +27 -0
  76. package/src/types.ts +16 -0
  77. package/src/utils/logger.ts +31 -0
  78. package/src/utils/prompts.ts +105 -0
  79. package/src/utils/validators.ts +50 -0
  80. package/tests/validators.test.ts +69 -0
  81. package/tsc_output.txt +0 -0
  82. package/tsconfig.json +21 -0
@@ -0,0 +1 @@
1
+ export declare function createCommand(projectName: string, options: any): Promise<void>;
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../src/commands/create.ts"],"names":[],"mappings":"AAQA,wBAAsB,aAAa,CAAC,WAAW,EAAE,MAAM,iBAyEtD"}
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.createCommand = createCommand;
7
+ const path_1 = __importDefault(require("path"));
8
+ const fs_extra_1 = __importDefault(require("fs-extra"));
9
+ const chalk_1 = __importDefault(require("chalk"));
10
+ const logger_1 = require("../utils/logger");
11
+ const prompts_1 = require("../utils/prompts");
12
+ const validators_1 = require("../utils/validators");
13
+ const generators_1 = require("../generators");
14
+ async function createCommand(projectName, options) {
15
+ try {
16
+ // Display welcome banner
17
+ console.log(chalk_1.default.bold.cyan('\n╔═══════════════════════════════════════╗'));
18
+ console.log(chalk_1.default.bold.cyan('║ ║'));
19
+ console.log(chalk_1.default.bold.cyan('║ 🚀 ForgeStack OS v0.1.0 ║'));
20
+ console.log(chalk_1.default.bold.cyan('║ ║'));
21
+ console.log(chalk_1.default.bold.cyan('║ One platform. Any stack. Production. ║'));
22
+ console.log(chalk_1.default.bold.cyan('║ ║'));
23
+ console.log(chalk_1.default.bold.cyan('╚═══════════════════════════════════════╝\n'));
24
+ // Check if directory already exists
25
+ const targetDir = path_1.default.resolve(process.cwd(), projectName);
26
+ if (await fs_extra_1.default.pathExists(targetDir)) {
27
+ logger_1.logger.error(`Directory "${projectName}" already exists!`);
28
+ process.exit(1);
29
+ }
30
+ // Prompt for stack configuration
31
+ logger_1.logger.title('📋 Configure Your Stack');
32
+ const config = await (0, prompts_1.promptForStack)(projectName, options);
33
+ // Validate configuration
34
+ const validation = (0, validators_1.validateStackConfig)(config);
35
+ if (validation.warnings.length > 0) {
36
+ console.log('');
37
+ validation.warnings.forEach(warning => logger_1.logger.warning(warning));
38
+ }
39
+ if (!validation.valid) {
40
+ console.log('');
41
+ validation.errors.forEach(error => logger_1.logger.error(error));
42
+ process.exit(1);
43
+ }
44
+ // Display selected stack
45
+ console.log('');
46
+ logger_1.logger.title('✨ Your Stack Configuration');
47
+ console.log(chalk_1.default.gray('─'.repeat(50)));
48
+ console.log(`${chalk_1.default.bold('Project:')} ${chalk_1.default.cyan(config.projectName)}`);
49
+ console.log(`${chalk_1.default.bold('Frontend:')} ${chalk_1.default.cyan(config.frontend)}`);
50
+ console.log(`${chalk_1.default.bold('Backend:')} ${chalk_1.default.cyan(config.backend)}`);
51
+ console.log(`${chalk_1.default.bold('Auth:')} ${chalk_1.default.cyan(config.auth)}`);
52
+ console.log(`${chalk_1.default.bold('Database:')} ${chalk_1.default.cyan(config.database)}`);
53
+ console.log(`${chalk_1.default.bold('API Style:')} ${chalk_1.default.cyan(config.apiStyle)}`);
54
+ console.log(`${chalk_1.default.bold('Docker:')} ${chalk_1.default.cyan(config.docker ? 'Yes' : 'No')}`);
55
+ console.log(`${chalk_1.default.bold('Multi-Tenant:')} ${chalk_1.default.cyan(config.multiTenant ? 'Yes' : 'No')}`);
56
+ console.log(chalk_1.default.gray('─'.repeat(50)));
57
+ console.log('');
58
+ // Generate project
59
+ await (0, generators_1.generateProject)(config, targetDir);
60
+ // Success message
61
+ console.log('');
62
+ logger_1.logger.success(chalk_1.default.bold('🎉 Project created successfully!\n'));
63
+ console.log(chalk_1.default.bold('Next steps:\n'));
64
+ console.log(chalk_1.default.cyan(` cd ${projectName}`));
65
+ console.log(chalk_1.default.cyan(' npm install'));
66
+ console.log(chalk_1.default.cyan(' npm run dev\n'));
67
+ console.log(chalk_1.default.gray('For more information, check out the README.md in your project.\n'));
68
+ console.log(chalk_1.default.bold('Built by Sumit Chauhan'));
69
+ console.log(chalk_1.default.gray('GitHub: https://github.com/halloffame12'));
70
+ console.log(chalk_1.default.gray('LinkedIn: https://www.linkedin.com/in/sumit-chauhan-a4ba98325/\n'));
71
+ }
72
+ catch (error) {
73
+ logger_1.logger.error('Failed to create project');
74
+ console.error(error);
75
+ process.exit(1);
76
+ }
77
+ }
78
+ //# sourceMappingURL=create.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create.js","sourceRoot":"","sources":["../../src/commands/create.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { StackConfig } from '../types';
2
+ export declare function generateGraphQL(config: StackConfig, backendDir: string): Promise<void>;
3
+ export declare function generateTRPC(config: StackConfig, backendDir: string, frontendDir: string): Promise<void>;
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/generators/api.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAEvC,wBAAsB,eAAe,CAAC,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,iBAM5E;AA2OD,wBAAsB,YAAY,CAAC,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,iBA2G9F"}
@@ -0,0 +1,346 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.generateGraphQL = generateGraphQL;
7
+ exports.generateTRPC = generateTRPC;
8
+ const path_1 = __importDefault(require("path"));
9
+ const fs_extra_1 = __importDefault(require("fs-extra"));
10
+ async function generateGraphQL(config, backendDir) {
11
+ if (config.backend === 'express') {
12
+ await generateExpressGraphQL(config, backendDir);
13
+ }
14
+ else if (config.backend === 'nestjs') {
15
+ await generateNestJSGraphQL(config, backendDir);
16
+ }
17
+ }
18
+ async function generateExpressGraphQL(config, backendDir) {
19
+ // Update package.json
20
+ const packageJson = await fs_extra_1.default.readJSON(path_1.default.join(backendDir, 'package.json'));
21
+ packageJson.dependencies['graphql'] = '^16.8.1';
22
+ packageJson.dependencies['@apollo/server'] = '^4.10.0';
23
+ packageJson.dependencies['@graphql-tools/schema'] = '^10.0.2';
24
+ await fs_extra_1.default.writeJSON(path_1.default.join(backendDir, 'package.json'), packageJson, { spaces: 2 });
25
+ // Create GraphQL directory
26
+ const graphqlDir = path_1.default.join(backendDir, 'src', 'graphql');
27
+ await fs_extra_1.default.ensureDir(graphqlDir);
28
+ await fs_extra_1.default.ensureDir(path_1.default.join(graphqlDir, 'resolvers'));
29
+ await fs_extra_1.default.ensureDir(path_1.default.join(graphqlDir, 'types'));
30
+ // Schema
31
+ const schema = `import { gql } from 'graphql-tag';
32
+
33
+ export const typeDefs = gql\`
34
+ type User {
35
+ id: ID!
36
+ email: String!
37
+ name: String
38
+ ${config.multiTenant ? 'tenantId: String' : ''}
39
+ }
40
+
41
+ type AuthPayload {
42
+ token: String!
43
+ user: User!
44
+ }
45
+
46
+ type Query {
47
+ me: User
48
+ users: [User!]!
49
+ }
50
+
51
+ type Mutation {
52
+ register(email: String!, password: String!, name: String): AuthPayload!
53
+ login(email: String!, password: String!): AuthPayload!
54
+ }
55
+ \`;
56
+ `;
57
+ await fs_extra_1.default.writeFile(path_1.default.join(graphqlDir, 'schema.ts'), schema);
58
+ // Resolvers
59
+ const resolvers = `import bcrypt from 'bcrypt';
60
+ import jwt from 'jsonwebtoken';
61
+ ${config.database === 'mongodb' ? "import User from '../models/User';" : "import prisma from '../lib/prisma';"}
62
+
63
+ export const resolvers = {
64
+ Query: {
65
+ me: async (_: any, __: any, context: any) => {
66
+ if (!context.user) throw new Error('Not authenticated');
67
+
68
+ ${config.database === 'mongodb' ? `
69
+ return await User.findById(context.user.userId);
70
+ ` : `
71
+ return await prisma.user.findUnique({
72
+ where: { id: context.user.userId },
73
+ });
74
+ `}
75
+ },
76
+ users: async (_: any, __: any, context: any) => {
77
+ if (!context.user) throw new Error('Not authenticated');
78
+
79
+ ${config.database === 'mongodb' ? `
80
+ return await User.find(${config.multiTenant ? '{ tenantId: context.user.tenantId }' : '{}'});
81
+ ` : `
82
+ return await prisma.user.findMany(${config.multiTenant ? '{ where: { tenantId: context.user.tenantId } }' : '{}'});
83
+ `}
84
+ },
85
+ },
86
+ Mutation: {
87
+ register: async (_: any, { email, password, name }: any) => {
88
+ const hashedPassword = await bcrypt.hash(password, 10);
89
+
90
+ ${config.database === 'mongodb' ? `
91
+ const user = await User.create({
92
+ email,
93
+ password: hashedPassword,
94
+ name,
95
+ });
96
+ ` : `
97
+ const user = await prisma.user.create({
98
+ data: {
99
+ email,
100
+ password: hashedPassword,
101
+ name,
102
+ },
103
+ });
104
+ `}
105
+
106
+ const token = jwt.sign(
107
+ { userId: user.id, email: user.email },
108
+ process.env.JWT_SECRET!,
109
+ { expiresIn: '7d' }
110
+ );
111
+
112
+ return { token, user };
113
+ },
114
+ login: async (_: any, { email, password }: any) => {
115
+ ${config.database === 'mongodb' ? `
116
+ const user = await User.findOne({ email });
117
+ ` : `
118
+ const user = await prisma.user.findUnique({
119
+ where: { email },
120
+ });
121
+ `}
122
+
123
+ if (!user) throw new Error('Invalid credentials');
124
+
125
+ const valid = await bcrypt.compare(password, user.password);
126
+ if (!valid) throw new Error('Invalid credentials');
127
+
128
+ const token = jwt.sign(
129
+ { userId: user.id, email: user.email },
130
+ process.env.JWT_SECRET!,
131
+ { expiresIn: '7d' }
132
+ );
133
+
134
+ return { token, user };
135
+ },
136
+ },
137
+ };
138
+ `;
139
+ await fs_extra_1.default.writeFile(path_1.default.join(graphqlDir, 'resolvers', 'index.ts'), resolvers);
140
+ // Apollo Server setup
141
+ const apolloSetup = `import { ApolloServer } from '@apollo/server';
142
+ import { expressMiddleware } from '@apollo/server/express4';
143
+ import { typeDefs } from './schema';
144
+ import { resolvers } from './resolvers';
145
+ import jwt from 'jsonwebtoken';
146
+
147
+ export async function createApolloServer() {
148
+ const server = new ApolloServer({
149
+ typeDefs,
150
+ resolvers,
151
+ });
152
+
153
+ await server.start();
154
+
155
+ return expressMiddleware(server, {
156
+ context: async ({ req }) => {
157
+ const token = req.headers.authorization?.replace('Bearer ', '');
158
+
159
+ if (token) {
160
+ try {
161
+ const user = jwt.verify(token, process.env.JWT_SECRET!);
162
+ return { user };
163
+ } catch (err) {
164
+ return {};
165
+ }
166
+ }
167
+
168
+ return {};
169
+ },
170
+ });
171
+ }
172
+ `;
173
+ await fs_extra_1.default.writeFile(path_1.default.join(graphqlDir, 'server.ts'), apolloSetup);
174
+ }
175
+ async function generateNestJSGraphQL(config, backendDir) {
176
+ // Update package.json
177
+ const packageJson = await fs_extra_1.default.readJSON(path_1.default.join(backendDir, 'package.json'));
178
+ packageJson.dependencies['@nestjs/graphql'] = '^12.0.11';
179
+ packageJson.dependencies['@nestjs/apollo'] = '^12.0.11';
180
+ packageJson.dependencies['@apollo/server'] = '^4.10.0';
181
+ packageJson.dependencies['graphql'] = '^16.8.1';
182
+ await fs_extra_1.default.writeJSON(path_1.default.join(backendDir, 'package.json'), packageJson, { spaces: 2 });
183
+ // GraphQL module
184
+ const graphqlModule = `import { Module } from '@nestjs/common';
185
+ import { GraphQLModule } from '@nestjs/graphql';
186
+ import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';
187
+ import { join } from 'path';
188
+
189
+ @Module({
190
+ imports: [
191
+ GraphQLModule.forRoot<ApolloDriverConfig>({
192
+ driver: ApolloDriver,
193
+ autoSchemaFile: join(process.cwd(), 'src/schema.gql'),
194
+ sortSchema: true,
195
+ playground: true,
196
+ context: ({ req }) => ({ req }),
197
+ }),
198
+ ],
199
+ })
200
+ export class GraphqlModule {}
201
+ `;
202
+ await fs_extra_1.default.writeFile(path_1.default.join(backendDir, 'src', 'graphql.module.ts'), graphqlModule);
203
+ // User resolver
204
+ const userResolver = `import { Resolver, Query, Mutation, Args } from '@nestjs/graphql';
205
+ import { UseGuards } from '@nestjs/common';
206
+ import { JwtAuthGuard } from './auth/guards/jwt-auth.guard';
207
+ import { UsersService } from './users/users.service';
208
+ import { AuthService } from './auth/auth.service';
209
+
210
+ @Resolver('User')
211
+ export class UserResolver {
212
+ constructor(
213
+ private usersService: UsersService,
214
+ private authService: AuthService,
215
+ ) {}
216
+
217
+ @Query()
218
+ @UseGuards(JwtAuthGuard)
219
+ async me(@Args('id') id: string) {
220
+ return this.usersService.findById(id);
221
+ }
222
+
223
+ @Mutation()
224
+ async register(
225
+ @Args('email') email: string,
226
+ @Args('password') password: string,
227
+ @Args('name') name?: string,
228
+ ) {
229
+ return this.authService.register({ email, password, name });
230
+ }
231
+
232
+ @Mutation()
233
+ async login(
234
+ @Args('email') email: string,
235
+ @Args('password') password: string,
236
+ ) {
237
+ return this.authService.login({ email, password });
238
+ }
239
+ }
240
+ `;
241
+ await fs_extra_1.default.writeFile(path_1.default.join(backendDir, 'src', 'users', 'users.resolver.ts'), userResolver);
242
+ }
243
+ async function generateTRPC(config, backendDir, frontendDir) {
244
+ // Backend setup
245
+ const packageJson = await fs_extra_1.default.readJSON(path_1.default.join(backendDir, 'package.json'));
246
+ packageJson.dependencies['@trpc/server'] = '^10.45.0';
247
+ packageJson.dependencies['zod'] = '^3.22.4';
248
+ await fs_extra_1.default.writeJSON(path_1.default.join(backendDir, 'package.json'), packageJson, { spaces: 2 });
249
+ // tRPC router
250
+ const trpcDir = path_1.default.join(backendDir, 'src', 'trpc');
251
+ await fs_extra_1.default.ensureDir(trpcDir);
252
+ await fs_extra_1.default.ensureDir(path_1.default.join(trpcDir, 'routers'));
253
+ const trpcSetup = `import { initTRPC } from '@trpc/server';
254
+ import { z } from 'zod';
255
+
256
+ const t = initTRPC.create();
257
+
258
+ export const router = t.router;
259
+ export const publicProcedure = t.procedure;
260
+ `;
261
+ await fs_extra_1.default.writeFile(path_1.default.join(trpcDir, 'trpc.ts'), trpcSetup);
262
+ const authRouter = `import { router, publicProcedure } from '../trpc';
263
+ import { z } from 'zod';
264
+ import bcrypt from 'bcrypt';
265
+ import jwt from 'jsonwebtoken';
266
+ ${config.database === 'mongodb' ? "import User from '../../models/User';" : "import prisma from '../../lib/prisma';"}
267
+
268
+ export const authRouter = router({
269
+ register: publicProcedure
270
+ .input(z.object({
271
+ email: z.string().email(),
272
+ password: z.string().min(8),
273
+ name: z.string().optional(),
274
+ }))
275
+ .mutation(async ({ input }) => {
276
+ const hashedPassword = await bcrypt.hash(input.password, 10);
277
+
278
+ ${config.database === 'mongodb' ? `
279
+ const user = await User.create({
280
+ email: input.email,
281
+ password: hashedPassword,
282
+ name: input.name,
283
+ });
284
+ ` : `
285
+ const user = await prisma.user.create({
286
+ data: {
287
+ email: input.email,
288
+ password: hashedPassword,
289
+ name: input.name,
290
+ },
291
+ });
292
+ `}
293
+
294
+ const token = jwt.sign(
295
+ { userId: user.id, email: user.email },
296
+ process.env.JWT_SECRET!,
297
+ { expiresIn: '7d' }
298
+ );
299
+
300
+ return { token, user: { id: user.id, email: user.email, name: user.name } };
301
+ }),
302
+
303
+ login: publicProcedure
304
+ .input(z.object({
305
+ email: z.string().email(),
306
+ password: z.string(),
307
+ }))
308
+ .mutation(async ({ input }) => {
309
+ ${config.database === 'mongodb' ? `
310
+ const user = await User.findOne({ email: input.email });
311
+ ` : `
312
+ const user = await prisma.user.findUnique({
313
+ where: { email: input.email },
314
+ });
315
+ `}
316
+
317
+ if (!user) throw new Error('Invalid credentials');
318
+
319
+ const valid = await bcrypt.compare(input.password, user.password);
320
+ if (!valid) throw new Error('Invalid credentials');
321
+
322
+ const token = jwt.sign(
323
+ { userId: user.id, email: user.email },
324
+ process.env.JWT_SECRET!,
325
+ { expiresIn: '7d' }
326
+ );
327
+
328
+ return { token, user: { id: user.id, email: user.email, name: user.name } };
329
+ }),
330
+ });
331
+ `;
332
+ await fs_extra_1.default.writeFile(path_1.default.join(trpcDir, 'routers', 'auth.ts'), authRouter);
333
+ // Frontend tRPC client
334
+ const frontendPackageJson = await fs_extra_1.default.readJSON(path_1.default.join(frontendDir, 'package.json'));
335
+ frontendPackageJson.dependencies['@trpc/client'] = '^10.45.0';
336
+ frontendPackageJson.dependencies['@trpc/react-query'] = '^10.45.0';
337
+ frontendPackageJson.dependencies['@tanstack/react-query'] = '^5.17.19';
338
+ await fs_extra_1.default.writeJSON(path_1.default.join(frontendDir, 'package.json'), frontendPackageJson, { spaces: 2 });
339
+ const trpcClient = `import { createTRPCReact } from '@trpc/react-query';
340
+ import type { AppRouter } from '../../../backend/src/trpc/routers';
341
+
342
+ export const trpc = createTRPCReact<AppRouter>();
343
+ `;
344
+ await fs_extra_1.default.writeFile(path_1.default.join(frontendDir, 'src', 'lib', 'trpc.ts'), trpcClient);
345
+ }
346
+ //# sourceMappingURL=api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/generators/api.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { StackConfig } from '../types';
2
+ export declare function generateAuth(config: StackConfig, frontendDir: string, backendDir: string): Promise<void>;
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/generators/auth.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAEvC,wBAAsB,YAAY,CAChC,MAAM,EAAE,WAAW,EACnB,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,iBAqBnB"}