@exanderal/stackcraft 0.1.2 → 0.2.1

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 (62) hide show
  1. package/README.md +96 -21
  2. package/dist/create/index.d.ts.map +1 -1
  3. package/dist/create/index.js +12 -1
  4. package/dist/create/index.js.map +1 -1
  5. package/dist/create/scaffold.d.ts.map +1 -1
  6. package/dist/create/scaffold.js +11 -2
  7. package/dist/create/scaffold.js.map +1 -1
  8. package/dist/create/scaffolders/api-nestjs-graphql.d.ts +3 -0
  9. package/dist/create/scaffolders/api-nestjs-graphql.d.ts.map +1 -0
  10. package/dist/create/scaffolders/api-nestjs-graphql.js +44 -0
  11. package/dist/create/scaffolders/api-nestjs-graphql.js.map +1 -0
  12. package/dist/create/scaffolders/api-nestjs-rest.d.ts.map +1 -1
  13. package/dist/create/scaffolders/api-nestjs-rest.js +11 -1
  14. package/dist/create/scaffolders/api-nestjs-rest.js.map +1 -1
  15. package/dist/create/scaffolders/wire-client.d.ts +3 -0
  16. package/dist/create/scaffolders/wire-client.d.ts.map +1 -0
  17. package/dist/create/scaffolders/wire-client.js +77 -0
  18. package/dist/create/scaffolders/wire-client.js.map +1 -0
  19. package/dist/create/types.d.ts +1 -1
  20. package/dist/create/types.d.ts.map +1 -1
  21. package/package.json +1 -1
  22. package/templates/api-nestjs-graphql/.prettierrc +4 -0
  23. package/templates/api-nestjs-graphql/eslint.config.mjs +34 -0
  24. package/templates/api-nestjs-graphql/nest-cli.json +8 -0
  25. package/templates/api-nestjs-graphql/package.json +81 -0
  26. package/templates/api-nestjs-graphql/project.json +21 -0
  27. package/templates/api-nestjs-graphql/src/app.module.ts +21 -0
  28. package/templates/api-nestjs-graphql/src/common/entities/base.entity.ts +21 -0
  29. package/templates/api-nestjs-graphql/src/common/repositories/entity.repository.ts +21 -0
  30. package/templates/api-nestjs-graphql/src/common/repositories/readonly-entity.repository.ts +22 -0
  31. package/templates/api-nestjs-graphql/src/common/services/entity.service.ts +24 -0
  32. package/templates/api-nestjs-graphql/src/common/services/readonly-entity.service.ts +23 -0
  33. package/templates/api-nestjs-graphql/src/main.ts +8 -0
  34. package/templates/api-nestjs-graphql/src/modules/database/database.module.ts +18 -0
  35. package/templates/api-nestjs-graphql/src/modules/health/__tests__/health.controller.spec.ts +20 -0
  36. package/templates/api-nestjs-graphql/src/modules/health/__tests__/health.service.spec.ts +18 -0
  37. package/templates/api-nestjs-graphql/src/modules/health/health.controller.ts +12 -0
  38. package/templates/api-nestjs-graphql/src/modules/health/health.module.ts +9 -0
  39. package/templates/api-nestjs-graphql/src/modules/health/health.service.ts +8 -0
  40. package/templates/api-nestjs-graphql/test/app.e2e-spec.ts +29 -0
  41. package/templates/api-nestjs-graphql/test/jest-e2e.json +9 -0
  42. package/templates/api-nestjs-graphql/tsconfig.build.json +4 -0
  43. package/templates/api-nestjs-graphql/tsconfig.json +21 -0
  44. package/templates/api-nestjs-rest/package.json +1 -0
  45. package/templates/api-nestjs-rest/src/main.ts +11 -0
  46. package/templates/base/package.json +5 -1
  47. package/templates/base/packages/types/package.json +10 -0
  48. package/templates/base/packages/types/tsconfig.json +10 -0
  49. package/templates/base/tools/generators/controller/index.js +22 -0
  50. package/templates/base/tools/generators/controller/schema.json +18 -0
  51. package/templates/base/tools/generators/generators.json +11 -1
  52. package/templates/base/tools/generators/module/graphql-files/__fileName__.model.ts__tmpl__ +11 -0
  53. package/templates/base/tools/generators/module/index.js +4 -22
  54. package/templates/base/tools/generators/module/schema.json +4 -5
  55. package/templates/base/tools/generators/resolver/files/__fileName__.resolver.ts__tmpl__ +28 -0
  56. package/templates/base/tools/generators/resolver/index.js +22 -0
  57. package/templates/base/tools/generators/resolver/schema.json +18 -0
  58. package/templates/types-graphql/codegen.ts +17 -0
  59. package/templates/types-graphql/project.json +19 -0
  60. package/templates/types-rest/openapi-ts.config.ts +10 -0
  61. package/templates/types-rest/project.json +19 -0
  62. /package/templates/base/tools/generators/{module/crud-files → controller/files}/__fileName__.controller.ts__tmpl__ +0 -0
package/README.md CHANGED
@@ -17,65 +17,140 @@ Follow the prompts — you'll have an Nx monorepo with deps installed and ready
17
17
  ```
18
18
  your-project/
19
19
  ├── apps/
20
- │ ├── backend/ # NestJS REST API
20
+ │ ├── backend/ # NestJS REST or GraphQL API
21
21
  │ └── web/ # Vite + React or Next.js
22
- ├── packages/ # shared code
22
+ ├── packages/
23
+ │ └── types/ # auto-generated types shared across all apps
23
24
  └── tools/
24
25
  └── generators/ # local Nx code generators
25
26
  ```
26
27
 
27
28
  ### Backend (`apps/backend`)
28
29
 
30
+ Choose between REST or GraphQL at setup — both share the same structure:
31
+
32
+ ```
33
+ src/
34
+ ├── modules/ # domain layer — model, repository, service, module
35
+ ├── api/ # REST controllers
36
+ ├── resolvers/ # GraphQL resolvers
37
+ └── common/ # shared base classes (EntityRepository, EntityService)
38
+ ```
39
+
29
40
  - NestJS with TypeORM
30
41
  - PostgreSQL or MySQL
31
- - Repository/Service abstraction layer (`EntityRepository`, `EntityService`)
32
- - Module-based structure under `src/modules/` — each module owns its model, repository, and service
33
- - HTTP controllers live separately in `src/api/`
42
+ - `EntityRepository` and `EntityService` base classes — extend them for each module
43
+ - UUID primary keys
44
+ - REST: Swagger UI at `/api`, spec written to `swagger.json` on startup
45
+ - GraphQL: schema auto-generated to `schema.gql` on startup (code-first)
34
46
 
35
47
  ### Frontend (`apps/web`)
36
48
 
37
49
  - Vite + React or Next.js
38
50
  - Tailwind CSS v4
39
51
  - TypeScript
52
+ - GraphQL projects: Apollo Client pre-configured, `ApolloProvider` already wired at the app root
53
+
54
+ ### Types (`packages/types`)
55
+
56
+ Auto-generated TypeScript types shared across all apps — import from `@local/types/rest` or `@local/types/graphql`:
57
+
58
+ - REST → generated from `swagger.json` via `@hey-api/openapi-ts`
59
+ - GraphQL → generated from `schema.gql` + your `.graphql` operation files via `@graphql-codegen/cli`, outputs typed Apollo hooks
40
60
 
41
61
  ## Running the project
42
62
 
43
- Each app has the same scripts:
63
+ ```sh
64
+ pnpm dev # start all apps in parallel
65
+ pnpm build # build all apps
66
+ pnpm test # run all tests
67
+ pnpm lint # lint all apps
68
+ ```
44
69
 
45
70
  ```sh
46
- pnpm dev # start all apps in parallel
47
- pnpm build # build all apps
48
- pnpm test # run all tests
49
- pnpm lint # lint all apps
71
+ pnpm codegen # generate types once
72
+ pnpm codegen:watch # watch for schema/spec changes and regenerate automatically
50
73
  ```
51
74
 
52
- Or target a specific app:
75
+ Typical dev workflow run both in parallel:
53
76
 
54
77
  ```sh
55
- pnpm nx run backend:dev
56
- pnpm nx run web:dev
78
+ # terminal 1
79
+ pnpm dev
80
+
81
+ # terminal 2
82
+ pnpm codegen:watch
57
83
  ```
58
84
 
59
- ## Code generation
85
+ ## Code generators
60
86
 
61
- Generate a new backend module:
87
+ Generate a new domain module (model + repository + service):
62
88
 
63
89
  ```sh
64
90
  pnpm generate:module --name=trainer
91
+ pnpm generate:module --name=trainer --graphql # adds @ObjectType() to the model
92
+ ```
93
+
94
+ Generate a REST controller:
95
+
96
+ ```sh
97
+ pnpm generate:controller --name=trainer
98
+ # → apps/backend/src/api/trainer/trainer.controller.ts
65
99
  ```
66
100
 
67
- This creates `apps/backend/src/modules/trainer/` with a model, repository, service, module, and integration test. Add `--crud` to also generate a CRUD controller in `src/api/trainer/`.
101
+ Generate a GraphQL resolver:
102
+
103
+ ```sh
104
+ pnpm generate:resolver --name=trainer
105
+ # → apps/backend/src/resolvers/trainer/trainer.resolver.ts
106
+ ```
107
+
108
+ ## Using generated types
109
+
110
+ **REST** — import types directly:
111
+
112
+ ```ts
113
+ import type { Trainer } from '@local/types/rest'
114
+ ```
115
+
116
+ **GraphQL** — write `.graphql` files in `apps/web/src/graphql/`, run `pnpm codegen`, then use the generated hooks:
117
+
118
+ ```ts
119
+ // apps/web/src/graphql/trainer.graphql
120
+ query GetTrainers {
121
+ trainers { id createdAt updatedAt }
122
+ }
123
+ ```
124
+
125
+ ```ts
126
+ import { useGetTrainersQuery } from '@local/types/graphql'
127
+
128
+ const { data, loading } = useGetTrainersQuery()
129
+ ```
68
130
 
69
131
  ## Stack
70
132
 
71
- - **Monorepo** Nx
72
- - **Package manager** — pnpm or npm
73
- - **Backend** NestJS, TypeORM, PostgreSQL/MySQL
74
- - **Frontend** Vite + React or Next.js, Tailwind CSS v4
133
+ | Layer | Technology |
134
+ |---|---|
135
+ | Monorepo | Nx |
136
+ | Package manager | pnpm or npm |
137
+ | Backend | NestJS, TypeORM |
138
+ | Database | PostgreSQL or MySQL |
139
+ | Frontend | Vite + React or Next.js |
140
+ | Styles | Tailwind CSS v4 |
141
+ | GraphQL client | Apollo Client |
142
+ | REST types | @hey-api/openapi-ts |
143
+ | GraphQL types + hooks | @graphql-codegen/cli |
75
144
 
76
145
  ## Roadmap
77
146
 
78
- - [ ] NestJS GraphQL + codegen
147
+ - [x] NestJS REST API with Swagger
148
+ - [x] NestJS GraphQL API (code-first)
149
+ - [x] Module, controller, and resolver generators
150
+ - [x] Auto-generated types in `packages/types`
151
+ - [x] `codegen:watch` for live type generation during dev
152
+ - [x] Apollo Client pre-configured in GraphQL projects
153
+ - [x] Typed Apollo hooks from `.graphql` operation files
79
154
  - [ ] Expo mobile
80
155
  - [ ] `stackcraft add` addon system (auth, Supabase, etc.)
81
156
  - [ ] Presets and `--config` for non-interactive use
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/create/index.ts"],"names":[],"mappings":"AAKA,wBAAsB,MAAM,kBAgE3B"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/create/index.ts"],"names":[],"mappings":"AAKA,wBAAsB,MAAM,kBA4E3B"}
@@ -12,6 +12,17 @@ export async function create() {
12
12
  cancel('Cancelled.');
13
13
  process.exit(0);
14
14
  }
15
+ const backend = await select({
16
+ message: 'Backend',
17
+ options: [
18
+ { value: 'nestjs-rest', label: 'NestJS REST', hint: 'REST API with TypeORM' },
19
+ { value: 'nestjs-graphql', label: 'NestJS GraphQL', hint: 'Code-first GraphQL with TypeORM' },
20
+ ],
21
+ });
22
+ if (isCancel(backend)) {
23
+ cancel('Cancelled.');
24
+ process.exit(0);
25
+ }
15
26
  const frontend = await select({
16
27
  message: 'Frontend',
17
28
  options: [
@@ -48,7 +59,7 @@ export async function create() {
48
59
  const config = {
49
60
  projectName: projectName,
50
61
  frontend: frontend,
51
- backend: 'nestjs-rest',
62
+ backend: backend,
52
63
  database: database,
53
64
  packageManager: packageManager,
54
65
  targetDir: resolve(process.cwd(), projectName),
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/create/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/create/index.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"scaffold.d.ts","sourceRoot":"","sources":["../../src/create/scaffold.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAE/C,wBAAsB,QAAQ,CAAC,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,iBAiBlF"}
1
+ {"version":3,"file":"scaffold.d.ts","sourceRoot":"","sources":["../../src/create/scaffold.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAE/C,wBAAsB,QAAQ,CAAC,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,iBAwBlF"}
@@ -1,13 +1,20 @@
1
1
  import { execa } from 'execa';
2
+ import { scaffoldNestjsGraphql } from './scaffolders/api-nestjs-graphql.js';
2
3
  import { scaffoldNestjsRest } from './scaffolders/api-nestjs-rest.js';
3
4
  import { scaffoldBase } from './scaffolders/base.js';
4
5
  import { scaffoldNextjs } from './scaffolders/web-nextjs.js';
5
6
  import { scaffoldVite } from './scaffolders/web-vite.js';
7
+ import { wireClientIntegration } from './scaffolders/wire-client.js';
6
8
  export async function scaffold(config, onStep) {
7
9
  onStep('Creating workspace...');
8
10
  await scaffoldBase(config);
9
- onStep('Adding API...');
10
- await scaffoldNestjsRest(config);
11
+ onStep('Adding backend...');
12
+ if (config.backend === 'nestjs-graphql') {
13
+ await scaffoldNestjsGraphql(config);
14
+ }
15
+ else {
16
+ await scaffoldNestjsRest(config);
17
+ }
11
18
  if (config.frontend === 'vite') {
12
19
  onStep('Adding Vite + React app...');
13
20
  await scaffoldVite(config);
@@ -16,6 +23,8 @@ export async function scaffold(config, onStep) {
16
23
  onStep('Adding Next.js app...');
17
24
  await scaffoldNextjs(config);
18
25
  }
26
+ onStep('Wiring client integration...');
27
+ await wireClientIntegration(config);
19
28
  onStep('Installing dependencies...');
20
29
  await execa(config.packageManager, ['install'], { cwd: config.targetDir });
21
30
  }
@@ -1 +1 @@
1
- {"version":3,"file":"scaffold.js","sourceRoot":"","sources":["../../src/create/scaffold.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,OAAO,CAAA;AAC7B,OAAO,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAA;AACrE,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAA;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AAGxD,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,MAAqB,EAAE,MAA6B;IACjF,MAAM,CAAC,uBAAuB,CAAC,CAAA;IAC/B,MAAM,YAAY,CAAC,MAAM,CAAC,CAAA;IAE1B,MAAM,CAAC,eAAe,CAAC,CAAA;IACvB,MAAM,kBAAkB,CAAC,MAAM,CAAC,CAAA;IAEhC,IAAI,MAAM,CAAC,QAAQ,KAAK,MAAM,EAAE,CAAC;QAC/B,MAAM,CAAC,4BAA4B,CAAC,CAAA;QACpC,MAAM,YAAY,CAAC,MAAM,CAAC,CAAA;IAC5B,CAAC;SAAM,IAAI,MAAM,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACxC,MAAM,CAAC,uBAAuB,CAAC,CAAA;QAC/B,MAAM,cAAc,CAAC,MAAM,CAAC,CAAA;IAC9B,CAAC;IAED,MAAM,CAAC,4BAA4B,CAAC,CAAA;IACpC,MAAM,KAAK,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC,SAAS,CAAC,EAAE,EAAE,GAAG,EAAE,MAAM,CAAC,SAAS,EAAE,CAAC,CAAA;AAC5E,CAAC"}
1
+ {"version":3,"file":"scaffold.js","sourceRoot":"","sources":["../../src/create/scaffold.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,OAAO,CAAA;AAC7B,OAAO,EAAE,qBAAqB,EAAE,MAAM,qCAAqC,CAAA;AAC3E,OAAO,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAA;AACrE,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAA;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AACxD,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAA;AAGpE,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,MAAqB,EAAE,MAA6B;IACjF,MAAM,CAAC,uBAAuB,CAAC,CAAA;IAC/B,MAAM,YAAY,CAAC,MAAM,CAAC,CAAA;IAE1B,MAAM,CAAC,mBAAmB,CAAC,CAAA;IAC3B,IAAI,MAAM,CAAC,OAAO,KAAK,gBAAgB,EAAE,CAAC;QACxC,MAAM,qBAAqB,CAAC,MAAM,CAAC,CAAA;IACrC,CAAC;SAAM,CAAC;QACN,MAAM,kBAAkB,CAAC,MAAM,CAAC,CAAA;IAClC,CAAC;IAED,IAAI,MAAM,CAAC,QAAQ,KAAK,MAAM,EAAE,CAAC;QAC/B,MAAM,CAAC,4BAA4B,CAAC,CAAA;QACpC,MAAM,YAAY,CAAC,MAAM,CAAC,CAAA;IAC5B,CAAC;SAAM,IAAI,MAAM,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACxC,MAAM,CAAC,uBAAuB,CAAC,CAAA;QAC/B,MAAM,cAAc,CAAC,MAAM,CAAC,CAAA;IAC9B,CAAC;IAED,MAAM,CAAC,8BAA8B,CAAC,CAAA;IACtC,MAAM,qBAAqB,CAAC,MAAM,CAAC,CAAA;IAEnC,MAAM,CAAC,4BAA4B,CAAC,CAAA;IACpC,MAAM,KAAK,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC,SAAS,CAAC,EAAE,EAAE,GAAG,EAAE,MAAM,CAAC,SAAS,EAAE,CAAC,CAAA;AAC5E,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { ProjectConfig } from '../types.js';
2
+ export declare function scaffoldNestjsGraphql(config: ProjectConfig): Promise<void>;
3
+ //# sourceMappingURL=api-nestjs-graphql.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-nestjs-graphql.d.ts","sourceRoot":"","sources":["../../../src/create/scaffolders/api-nestjs-graphql.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAWhD,wBAAsB,qBAAqB,CAAC,MAAM,EAAE,aAAa,iBAchE"}
@@ -0,0 +1,44 @@
1
+ import { mkdir, readFile, writeFile } from 'node:fs/promises';
2
+ import { dirname, join } from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { copyTemplate } from './utils/copy.js';
5
+ const __dirname = dirname(fileURLToPath(import.meta.url));
6
+ const TEMPLATES_DIR = join(__dirname, '..', '..', '..', 'templates');
7
+ const DB_CONFIG = {
8
+ postgres: { type: 'postgres', port: '5432', driver: 'pg', driverVersion: '^8.0.0', typesPackage: '@types/pg', typesVersion: '^8.0.0' },
9
+ mysql: { type: 'mysql', port: '3306', driver: 'mysql2', driverVersion: '^3.0.0', typesPackage: null, typesVersion: null },
10
+ };
11
+ export async function scaffoldNestjsGraphql(config) {
12
+ const appDir = join(config.targetDir, 'apps', 'backend');
13
+ await mkdir(appDir, { recursive: true });
14
+ const db = DB_CONFIG[config.database];
15
+ await copyTemplate(join(TEMPLATES_DIR, 'api-nestjs-graphql'), appDir, {
16
+ projectName: config.projectName,
17
+ dbType: db.type,
18
+ dbPort: db.port,
19
+ });
20
+ await injectDbDriver(appDir, db);
21
+ await setupGraphqlCodegen(config.targetDir);
22
+ }
23
+ async function injectDbDriver(appDir, db) {
24
+ const pkgPath = join(appDir, 'package.json');
25
+ const pkg = JSON.parse(await readFile(pkgPath, 'utf-8'));
26
+ pkg.dependencies[db.driver] = db.driverVersion;
27
+ if (db.typesPackage) {
28
+ pkg.devDependencies[db.typesPackage] = db.typesVersion;
29
+ }
30
+ await writeFile(pkgPath, JSON.stringify(pkg, null, 2) + '\n', 'utf-8');
31
+ }
32
+ async function setupGraphqlCodegen(targetDir) {
33
+ const typesDir = join(targetDir, 'packages', 'types');
34
+ await copyTemplate(join(TEMPLATES_DIR, 'types-graphql'), typesDir, {});
35
+ const pkgPath = join(typesDir, 'package.json');
36
+ const pkg = JSON.parse(await readFile(pkgPath, 'utf-8'));
37
+ pkg.devDependencies['@graphql-codegen/cli'] = '^5.0.0';
38
+ pkg.devDependencies['@graphql-codegen/typescript'] = '^4.0.0';
39
+ pkg.devDependencies['@graphql-codegen/typescript-operations'] = '^4.0.0';
40
+ pkg.devDependencies['@graphql-codegen/typescript-react-apollo'] = '^4.0.0';
41
+ pkg.devDependencies['@parcel/watcher'] = '^2.0.0';
42
+ await writeFile(pkgPath, JSON.stringify(pkg, null, 2) + '\n', 'utf-8');
43
+ }
44
+ //# sourceMappingURL=api-nestjs-graphql.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-nestjs-graphql.js","sourceRoot":"","sources":["../../../src/create/scaffolders/api-nestjs-graphql.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"api-nestjs-rest.d.ts","sourceRoot":"","sources":["../../../src/create/scaffolders/api-nestjs-rest.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAWhD,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,aAAa,iBAa7D"}
1
+ {"version":3,"file":"api-nestjs-rest.d.ts","sourceRoot":"","sources":["../../../src/create/scaffolders/api-nestjs-rest.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAWhD,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,aAAa,iBAc7D"}
@@ -1,4 +1,4 @@
1
- import { readFile, writeFile, mkdir } from 'node:fs/promises';
1
+ import { mkdir, readFile, writeFile } from 'node:fs/promises';
2
2
  import { dirname, join } from 'node:path';
3
3
  import { fileURLToPath } from 'node:url';
4
4
  import { copyTemplate } from './utils/copy.js';
@@ -18,6 +18,7 @@ export async function scaffoldNestjsRest(config) {
18
18
  dbPort: db.port,
19
19
  });
20
20
  await injectDbDriver(appDir, db);
21
+ await setupRestCodegen(config.targetDir);
21
22
  }
22
23
  async function injectDbDriver(appDir, db) {
23
24
  const pkgPath = join(appDir, 'package.json');
@@ -28,4 +29,13 @@ async function injectDbDriver(appDir, db) {
28
29
  }
29
30
  await writeFile(pkgPath, JSON.stringify(pkg, null, 2) + '\n', 'utf-8');
30
31
  }
32
+ async function setupRestCodegen(targetDir) {
33
+ const typesDir = join(targetDir, 'packages', 'types');
34
+ await copyTemplate(join(TEMPLATES_DIR, 'types-rest'), typesDir, {});
35
+ const pkgPath = join(typesDir, 'package.json');
36
+ const pkg = JSON.parse(await readFile(pkgPath, 'utf-8'));
37
+ pkg.devDependencies['@hey-api/openapi-ts'] = '^0.64.0';
38
+ pkg.devDependencies['chokidar-cli'] = '^3.0.0';
39
+ await writeFile(pkgPath, JSON.stringify(pkg, null, 2) + '\n', 'utf-8');
40
+ }
31
41
  //# sourceMappingURL=api-nestjs-rest.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"api-nestjs-rest.js","sourceRoot":"","sources":["../../../src/create/scaffolders/api-nestjs-rest.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAA;AAC7D,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAExC,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAE9C,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAA;AACzD,MAAM,aAAa,GAAG,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,CAAC,CAAA;AAEpE,MAAM,SAAS,GAAG;IAChB,QAAQ,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,EAAE,QAAQ,EAAE,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,QAAQ,EAAE;IACtI,KAAK,EAAK,EAAE,IAAI,EAAE,OAAO,EAAK,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,EAAE,QAAQ,EAAE,YAAY,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE;CACvH,CAAA;AAEV,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,MAAqB;IAC5D,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,CAAC,CAAA;IACxD,MAAM,KAAK,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAExC,MAAM,EAAE,GAAG,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;IAErC,MAAM,YAAY,CAAC,IAAI,CAAC,aAAa,EAAE,iBAAiB,CAAC,EAAE,MAAM,EAAE;QACjE,WAAW,EAAE,MAAM,CAAC,WAAW;QAC/B,MAAM,EAAE,EAAE,CAAC,IAAI;QACf,MAAM,EAAE,EAAE,CAAC,IAAI;KAChB,CAAC,CAAA;IAEF,MAAM,cAAc,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;AAClC,CAAC;AAED,KAAK,UAAU,cAAc,CAAC,MAAc,EAAE,EAA4C;IACxF,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,EAAE,cAAc,CAAC,CAAA;IAC5C,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAA;IAExD,GAAG,CAAC,YAAY,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,aAAa,CAAA;IAE9C,IAAI,EAAE,CAAC,YAAY,EAAE,CAAC;QACpB,GAAG,CAAC,eAAe,CAAC,EAAE,CAAC,YAAY,CAAC,GAAG,EAAE,CAAC,YAAY,CAAA;IACxD,CAAC;IAED,MAAM,SAAS,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,CAAC,CAAA;AACxE,CAAC"}
1
+ {"version":3,"file":"api-nestjs-rest.js","sourceRoot":"","sources":["../../../src/create/scaffolders/api-nestjs-rest.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { ProjectConfig } from '../types.js';
2
+ export declare function wireClientIntegration(config: ProjectConfig): Promise<void>;
3
+ //# sourceMappingURL=wire-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wire-client.d.ts","sourceRoot":"","sources":["../../../src/create/scaffolders/wire-client.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAEhD,wBAAsB,qBAAqB,CAAC,MAAM,EAAE,aAAa,iBAehE"}
@@ -0,0 +1,77 @@
1
+ import { mkdir, readFile, writeFile } from 'node:fs/promises';
2
+ import { join } from 'node:path';
3
+ export async function wireClientIntegration(config) {
4
+ const webDir = join(config.targetDir, 'apps', 'web');
5
+ const webPkgPath = join(webDir, 'package.json');
6
+ const pkg = JSON.parse(await readFile(webPkgPath, 'utf-8'));
7
+ pkg.dependencies['@local/types'] = 'workspace:*';
8
+ if (config.backend === 'nestjs-graphql') {
9
+ pkg.dependencies['@apollo/client'] = '^3.13.0';
10
+ pkg.dependencies['graphql'] = '^16.0.0';
11
+ await writeFile(webPkgPath, JSON.stringify(pkg, null, 2) + '\n', 'utf-8');
12
+ await setupApolloClient(config, webDir);
13
+ }
14
+ else {
15
+ await writeFile(webPkgPath, JSON.stringify(pkg, null, 2) + '\n', 'utf-8');
16
+ }
17
+ }
18
+ async function setupApolloClient(config, webDir) {
19
+ await mkdir(join(webDir, 'src', 'lib'), { recursive: true });
20
+ await mkdir(join(webDir, 'src', 'graphql'), { recursive: true });
21
+ if (config.frontend === 'vite') {
22
+ await writeFile(join(webDir, 'src', 'lib', 'apollo.ts'), apolloViteClient(), 'utf-8');
23
+ await patchViteMain(webDir);
24
+ }
25
+ else if (config.frontend === 'nextjs') {
26
+ await writeFile(join(webDir, 'src', 'lib', 'apollo.ts'), apolloNextClient(), 'utf-8');
27
+ await writeFile(join(webDir, 'src', 'app', 'providers.tsx'), apolloNextProviders(), 'utf-8');
28
+ await patchNextLayout(webDir);
29
+ }
30
+ }
31
+ async function patchViteMain(webDir) {
32
+ const mainPath = join(webDir, 'src', 'main.tsx');
33
+ const content = await readFile(mainPath, 'utf-8');
34
+ const patched = content
35
+ .replace(`import { StrictMode } from 'react'`, `import { ApolloProvider } from '@apollo/client'\nimport { StrictMode } from 'react'\nimport { client } from './lib/apollo'`)
36
+ .replace(`<App />`, `<ApolloProvider client={client}>\n <App />\n </ApolloProvider>`);
37
+ await writeFile(mainPath, patched, 'utf-8');
38
+ }
39
+ async function patchNextLayout(webDir) {
40
+ const layoutPath = join(webDir, 'src', 'app', 'layout.tsx');
41
+ const content = await readFile(layoutPath, 'utf-8');
42
+ const patched = content
43
+ .replace(`import type { Metadata } from "next";`, `import type { Metadata } from "next";\nimport { Providers } from './providers';`)
44
+ .replace(`<body>`, `<body>\n <Providers>`)
45
+ .replace(`</body>`, `</Providers>\n </body>`);
46
+ await writeFile(layoutPath, patched, 'utf-8');
47
+ }
48
+ function apolloViteClient() {
49
+ return `import { ApolloClient, InMemoryCache } from '@apollo/client'
50
+
51
+ export const client = new ApolloClient({
52
+ uri: import.meta.env.VITE_API_URL ?? 'http://localhost:3000/graphql',
53
+ cache: new InMemoryCache(),
54
+ })
55
+ `;
56
+ }
57
+ function apolloNextClient() {
58
+ return `import { ApolloClient, InMemoryCache } from '@apollo/client'
59
+
60
+ export const client = new ApolloClient({
61
+ uri: process.env.NEXT_PUBLIC_API_URL ?? 'http://localhost:3000/graphql',
62
+ cache: new InMemoryCache(),
63
+ })
64
+ `;
65
+ }
66
+ function apolloNextProviders() {
67
+ return `'use client'
68
+
69
+ import { ApolloProvider } from '@apollo/client'
70
+ import { client } from '../lib/apollo'
71
+
72
+ export function Providers({ children }: { children: React.ReactNode }) {
73
+ return <ApolloProvider client={client}>{children}</ApolloProvider>
74
+ }
75
+ `;
76
+ }
77
+ //# sourceMappingURL=wire-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wire-client.js","sourceRoot":"","sources":["../../../src/create/scaffolders/wire-client.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  export type PackageManager = 'pnpm' | 'npm';
2
2
  export type Frontend = 'vite' | 'nextjs';
3
- export type Backend = 'nestjs-rest';
3
+ export type Backend = 'nestjs-rest' | 'nestjs-graphql';
4
4
  export type Database = 'postgres' | 'mysql';
5
5
  export interface ProjectConfig {
6
6
  projectName: string;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/create/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,KAAK,CAAA;AAC3C,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,QAAQ,CAAA;AACxC,MAAM,MAAM,OAAO,GAAG,aAAa,CAAA;AACnC,MAAM,MAAM,QAAQ,GAAG,UAAU,GAAG,OAAO,CAAA;AAE3C,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,MAAM,CAAA;IACnB,QAAQ,EAAE,QAAQ,CAAA;IAClB,OAAO,EAAE,OAAO,CAAA;IAChB,QAAQ,EAAE,QAAQ,CAAA;IAClB,cAAc,EAAE,cAAc,CAAA;IAC9B,SAAS,EAAE,MAAM,CAAA;CAClB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/create/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,KAAK,CAAA;AAC3C,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,QAAQ,CAAA;AACxC,MAAM,MAAM,OAAO,GAAG,aAAa,GAAG,gBAAgB,CAAA;AACtD,MAAM,MAAM,QAAQ,GAAG,UAAU,GAAG,OAAO,CAAA;AAE3C,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,MAAM,CAAA;IACnB,QAAQ,EAAE,QAAQ,CAAA;IAClB,OAAO,EAAE,OAAO,CAAA;IAChB,QAAQ,EAAE,QAAQ,CAAA;IAClB,cAAc,EAAE,cAAc,CAAA;IAC9B,SAAS,EAAE,MAAM,CAAA;CAClB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@exanderal/stackcraft",
3
- "version": "0.1.2",
3
+ "version": "0.2.1",
4
4
  "description": "Opinionated full-stack project scaffolding CLI",
5
5
  "type": "module",
6
6
  "bin": {
@@ -0,0 +1,4 @@
1
+ {
2
+ "singleQuote": true,
3
+ "trailingComma": "all"
4
+ }
@@ -0,0 +1,34 @@
1
+ // @ts-check
2
+ import eslint from '@eslint/js';
3
+ import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended';
4
+ import globals from 'globals';
5
+ import tseslint from 'typescript-eslint';
6
+
7
+ export default tseslint.config(
8
+ {
9
+ ignores: ['eslint.config.mjs'],
10
+ },
11
+ eslint.configs.recommended,
12
+ ...tseslint.configs.recommendedTypeChecked,
13
+ eslintPluginPrettierRecommended,
14
+ {
15
+ languageOptions: {
16
+ globals: {
17
+ ...globals.node,
18
+ ...globals.jest,
19
+ },
20
+ sourceType: 'commonjs',
21
+ parserOptions: {
22
+ projectService: true,
23
+ tsconfigRootDir: import.meta.dirname,
24
+ },
25
+ },
26
+ },
27
+ {
28
+ rules: {
29
+ '@typescript-eslint/no-explicit-any': 'off',
30
+ '@typescript-eslint/no-floating-promises': 'warn',
31
+ '@typescript-eslint/no-unsafe-argument': 'warn'
32
+ },
33
+ },
34
+ );
@@ -0,0 +1,8 @@
1
+ {
2
+ "$schema": "https://json.schemastore.org/nest-cli",
3
+ "collection": "@nestjs/schematics",
4
+ "sourceRoot": "src",
5
+ "compilerOptions": {
6
+ "deleteOutDir": true
7
+ }
8
+ }
@@ -0,0 +1,81 @@
1
+ {
2
+ "name": "{{projectName}}-backend",
3
+ "version": "0.0.1",
4
+ "description": "",
5
+ "author": "",
6
+ "private": true,
7
+ "license": "UNLICENSED",
8
+ "scripts": {
9
+ "dev": "nest start --watch",
10
+ "build": "nest build",
11
+ "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
12
+ "start": "nest start",
13
+ "start:dev": "nest start --watch",
14
+ "start:debug": "nest start --debug --watch",
15
+ "start:prod": "node dist/main",
16
+ "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
17
+ "test": "jest",
18
+ "test:watch": "jest --watch",
19
+ "test:cov": "jest --coverage",
20
+ "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
21
+ "test:e2e": "jest --config ./test/jest-e2e.json"
22
+ },
23
+ "dependencies": {
24
+ "@apollo/server": "^4.0.0",
25
+ "@nestjs/apollo": "^13.0.0",
26
+ "@nestjs/common": "^11.0.1",
27
+ "@nestjs/config": "^3.0.0",
28
+ "@nestjs/core": "^11.0.1",
29
+ "@nestjs/graphql": "^13.0.0",
30
+ "@nestjs/platform-express": "^11.0.1",
31
+ "@nestjs/typeorm": "^10.0.0",
32
+ "graphql": "^16.0.0",
33
+ "reflect-metadata": "^0.2.2",
34
+ "rxjs": "^7.8.1",
35
+ "typeorm": "^0.3.0"
36
+ },
37
+ "devDependencies": {
38
+ "@eslint/eslintrc": "^3.2.0",
39
+ "@eslint/js": "^9.18.0",
40
+ "@nestjs/cli": "^11.0.0",
41
+ "@nestjs/schematics": "^11.0.0",
42
+ "@nestjs/testing": "^11.0.1",
43
+ "@swc/cli": "^0.6.0",
44
+ "@swc/core": "^1.10.7",
45
+ "@types/express": "^5.0.0",
46
+ "@types/jest": "^29.5.14",
47
+ "@types/node": "^22.10.7",
48
+ "@types/supertest": "^6.0.2",
49
+ "eslint": "^9.18.0",
50
+ "eslint-config-prettier": "^10.0.1",
51
+ "eslint-plugin-prettier": "^5.2.2",
52
+ "globals": "^16.0.0",
53
+ "jest": "^29.7.0",
54
+ "prettier": "^3.4.2",
55
+ "source-map-support": "^0.5.21",
56
+ "supertest": "^7.0.0",
57
+ "ts-jest": "^29.2.5",
58
+ "ts-loader": "^9.5.2",
59
+ "ts-node": "^10.9.2",
60
+ "tsconfig-paths": "^4.2.0",
61
+ "typescript": "^5.7.3",
62
+ "typescript-eslint": "^8.20.0"
63
+ },
64
+ "jest": {
65
+ "moduleFileExtensions": [
66
+ "js",
67
+ "json",
68
+ "ts"
69
+ ],
70
+ "rootDir": "src",
71
+ "testRegex": ".*\\.spec\\.ts$",
72
+ "transform": {
73
+ "^.+\\.(t|j)s$": "ts-jest"
74
+ },
75
+ "collectCoverageFrom": [
76
+ "**/*.(t|j)s"
77
+ ],
78
+ "coverageDirectory": "../coverage",
79
+ "testEnvironment": "node"
80
+ }
81
+ }
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "backend",
3
+ "targets": {
4
+ "dev": {
5
+ "executor": "nx:run-commands",
6
+ "options": { "command": "pnpm run dev", "cwd": "{projectRoot}" }
7
+ },
8
+ "build": {
9
+ "executor": "nx:run-commands",
10
+ "options": { "command": "pnpm run build", "cwd": "{projectRoot}" }
11
+ },
12
+ "lint": {
13
+ "executor": "nx:run-commands",
14
+ "options": { "command": "pnpm run lint", "cwd": "{projectRoot}" }
15
+ },
16
+ "test": {
17
+ "executor": "nx:run-commands",
18
+ "options": { "command": "pnpm run test", "cwd": "{projectRoot}" }
19
+ }
20
+ }
21
+ }