@exanderal/stackcraft 0.2.0 → 0.3.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 (56) hide show
  1. package/README.md +79 -28
  2. package/dist/create/index.d.ts.map +1 -1
  3. package/dist/create/index.js +12 -0
  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 +8 -0
  7. package/dist/create/scaffold.js.map +1 -1
  8. package/dist/create/scaffolders/__tests__/web-vite.test.js +1 -0
  9. package/dist/create/scaffolders/__tests__/web-vite.test.js.map +1 -1
  10. package/dist/create/scaffolders/api-nestjs-graphql.d.ts.map +1 -1
  11. package/dist/create/scaffolders/api-nestjs-graphql.js +13 -0
  12. package/dist/create/scaffolders/api-nestjs-graphql.js.map +1 -1
  13. package/dist/create/scaffolders/api-nestjs-rest.d.ts.map +1 -1
  14. package/dist/create/scaffolders/api-nestjs-rest.js +11 -1
  15. package/dist/create/scaffolders/api-nestjs-rest.js.map +1 -1
  16. package/dist/create/scaffolders/mobile-expo.d.ts +3 -0
  17. package/dist/create/scaffolders/mobile-expo.d.ts.map +1 -0
  18. package/dist/create/scaffolders/mobile-expo.js +14 -0
  19. package/dist/create/scaffolders/mobile-expo.js.map +1 -0
  20. package/dist/create/scaffolders/wire-client.d.ts +3 -0
  21. package/dist/create/scaffolders/wire-client.d.ts.map +1 -0
  22. package/dist/create/scaffolders/wire-client.js +91 -0
  23. package/dist/create/scaffolders/wire-client.js.map +1 -0
  24. package/dist/create/types.d.ts +2 -0
  25. package/dist/create/types.d.ts.map +1 -1
  26. package/package.json +1 -1
  27. package/templates/api-nestjs-rest/package.json +1 -0
  28. package/templates/api-nestjs-rest/src/main.ts +11 -0
  29. package/templates/base/package.json +3 -1
  30. package/templates/base/packages/types/package.json +10 -0
  31. package/templates/base/packages/types/tsconfig.json +10 -0
  32. package/templates/base/tools/generators/module/schema.json +2 -1
  33. package/templates/mobile-expo/app/(tabs)/_layout.tsx +31 -0
  34. package/templates/mobile-expo/app/(tabs)/index.tsx +23 -0
  35. package/templates/mobile-expo/app/+not-found.tsx +40 -0
  36. package/templates/mobile-expo/app/_layout.tsx +31 -0
  37. package/templates/mobile-expo/app.json +39 -0
  38. package/templates/mobile-expo/assets/images/adaptive-icon.png +0 -0
  39. package/templates/mobile-expo/assets/images/favicon.png +0 -0
  40. package/templates/mobile-expo/assets/images/icon.png +0 -0
  41. package/templates/mobile-expo/assets/images/splash-icon.png +0 -0
  42. package/templates/mobile-expo/components/ExternalLink.tsx +25 -0
  43. package/templates/mobile-expo/components/StyledText.tsx +5 -0
  44. package/templates/mobile-expo/components/Themed.tsx +45 -0
  45. package/templates/mobile-expo/components/useClientOnlyValue.ts +4 -0
  46. package/templates/mobile-expo/components/useClientOnlyValue.web.ts +12 -0
  47. package/templates/mobile-expo/components/useColorScheme.ts +1 -0
  48. package/templates/mobile-expo/components/useColorScheme.web.ts +8 -0
  49. package/templates/mobile-expo/constants/Colors.ts +19 -0
  50. package/templates/mobile-expo/package.json +37 -0
  51. package/templates/mobile-expo/project.json +17 -0
  52. package/templates/mobile-expo/tsconfig.json +20 -0
  53. package/templates/types-graphql/codegen.ts +17 -0
  54. package/templates/types-graphql/project.json +19 -0
  55. package/templates/types-rest/openapi-ts.config.ts +10 -0
  56. package/templates/types-rest/project.json +19 -0
package/README.md CHANGED
@@ -19,87 +19,138 @@ your-project/
19
19
  ├── apps/
20
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
 
29
- Choose between REST or GraphQL at setup time — both use the same underlying structure:
30
+ Choose between REST or GraphQL at setup — both share the same structure:
30
31
 
31
32
  ```
32
33
  src/
33
- ├── modules/ # domain layer — model, repository, service, module
34
- ├── api/ # REST controllers (REST only)
35
- ├── resolvers/ # GraphQL resolvers (GraphQL only)
36
- └── common/ # shared base classes
34
+ ├── modules/ # domain layer — model, repository, service, module
35
+ ├── api/ # REST controllers
36
+ ├── resolvers/ # GraphQL resolvers
37
+ └── common/ # shared base classes (EntityRepository, EntityService)
37
38
  ```
38
39
 
39
40
  - NestJS with TypeORM
40
41
  - PostgreSQL or MySQL
41
42
  - `EntityRepository` and `EntityService` base classes — extend them for each module
42
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)
43
46
 
44
47
  ### Frontend (`apps/web`)
45
48
 
46
49
  - Vite + React or Next.js
47
50
  - Tailwind CSS v4
48
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
49
60
 
50
61
  ## Running the project
51
62
 
52
63
  ```sh
53
- pnpm dev # start all apps in parallel
54
- pnpm build # build all apps
55
- pnpm test # run all tests
56
- pnpm lint # lint all apps
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
57
68
  ```
58
69
 
59
- Target a specific app:
70
+ ```sh
71
+ pnpm codegen # generate types once
72
+ pnpm codegen:watch # watch for schema/spec changes and regenerate automatically
73
+ ```
74
+
75
+ Typical dev workflow — run both in parallel:
60
76
 
61
77
  ```sh
62
- pnpm nx run backend:dev
63
- pnpm nx run web:dev
78
+ # terminal 1
79
+ pnpm dev
80
+
81
+ # terminal 2
82
+ pnpm codegen:watch
64
83
  ```
65
84
 
66
- ## Code generation
85
+ ## Code generators
67
86
 
68
- Generate a new domain module:
87
+ Generate a new domain module (model + repository + service):
69
88
 
70
89
  ```sh
71
90
  pnpm generate:module --name=trainer
72
- # add --graphql to include @ObjectType() on the model
73
- pnpm generate:module --name=trainer --graphql
91
+ pnpm generate:module --name=trainer --graphql # adds @ObjectType() to the model
74
92
  ```
75
93
 
76
- Generate a REST controller for an existing module:
94
+ Generate a REST controller:
77
95
 
78
96
  ```sh
79
97
  pnpm generate:controller --name=trainer
80
- # creates apps/backend/src/api/trainer/trainer.controller.ts
98
+ # apps/backend/src/api/trainer/trainer.controller.ts
81
99
  ```
82
100
 
83
- Generate a GraphQL resolver for an existing module:
101
+ Generate a GraphQL resolver:
84
102
 
85
103
  ```sh
86
104
  pnpm generate:resolver --name=trainer
87
- # creates apps/backend/src/resolvers/trainer/trainer.resolver.ts
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()
88
129
  ```
89
130
 
90
131
  ## Stack
91
132
 
92
- - **Monorepo** Nx
93
- - **Package manager** — pnpm or npm
94
- - **Backend** NestJS, TypeORM, PostgreSQL/MySQL
95
- - **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 |
96
144
 
97
145
  ## Roadmap
98
146
 
99
- - [x] NestJS REST API
100
- - [x] NestJS GraphQL API
147
+ - [x] NestJS REST API with Swagger
148
+ - [x] NestJS GraphQL API (code-first)
101
149
  - [x] Module, controller, and resolver generators
102
- - [ ] GraphQL codegen pipeline
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
103
154
  - [ ] Expo mobile
104
155
  - [ ] `stackcraft add` addon system (auth, Supabase, etc.)
105
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,kBA4E3B"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/create/index.ts"],"names":[],"mappings":"AAKA,wBAAsB,MAAM,kBAyF3B"}
@@ -34,6 +34,17 @@ export async function create() {
34
34
  cancel('Cancelled.');
35
35
  process.exit(0);
36
36
  }
37
+ const mobile = await select({
38
+ message: 'Mobile',
39
+ options: [
40
+ { value: 'none', label: 'None' },
41
+ { value: 'expo', label: 'Expo', hint: 'React Native with Expo Router' },
42
+ ],
43
+ });
44
+ if (isCancel(mobile)) {
45
+ cancel('Cancelled.');
46
+ process.exit(0);
47
+ }
37
48
  const database = await select({
38
49
  message: 'Database',
39
50
  options: [
@@ -61,6 +72,7 @@ export async function create() {
61
72
  frontend: frontend,
62
73
  backend: backend,
63
74
  database: database,
75
+ mobile: mobile,
64
76
  packageManager: packageManager,
65
77
  targetDir: resolve(process.cwd(), projectName),
66
78
  };
@@ -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":"AAMA,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,iBAqBlF"}
1
+ {"version":3,"file":"scaffold.d.ts","sourceRoot":"","sources":["../../src/create/scaffold.ts"],"names":[],"mappings":"AAQA,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,iBA6BlF"}
@@ -2,8 +2,10 @@ import { execa } from 'execa';
2
2
  import { scaffoldNestjsGraphql } from './scaffolders/api-nestjs-graphql.js';
3
3
  import { scaffoldNestjsRest } from './scaffolders/api-nestjs-rest.js';
4
4
  import { scaffoldBase } from './scaffolders/base.js';
5
+ import { scaffoldExpo } from './scaffolders/mobile-expo.js';
5
6
  import { scaffoldNextjs } from './scaffolders/web-nextjs.js';
6
7
  import { scaffoldVite } from './scaffolders/web-vite.js';
8
+ import { wireClientIntegration } from './scaffolders/wire-client.js';
7
9
  export async function scaffold(config, onStep) {
8
10
  onStep('Creating workspace...');
9
11
  await scaffoldBase(config);
@@ -22,6 +24,12 @@ export async function scaffold(config, onStep) {
22
24
  onStep('Adding Next.js app...');
23
25
  await scaffoldNextjs(config);
24
26
  }
27
+ if (config.mobile === 'expo') {
28
+ onStep('Adding Expo mobile app...');
29
+ await scaffoldExpo(config);
30
+ }
31
+ onStep('Wiring client integration...');
32
+ await wireClientIntegration(config);
25
33
  onStep('Installing dependencies...');
26
34
  await execa(config.packageManager, ['install'], { cwd: config.targetDir });
27
35
  }
@@ -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,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;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,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,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,YAAY,EAAE,MAAM,8BAA8B,CAAA;AAC3D,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,IAAI,MAAM,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;QAC7B,MAAM,CAAC,2BAA2B,CAAC,CAAA;QACnC,MAAM,YAAY,CAAC,MAAM,CAAC,CAAA;IAC5B,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"}
@@ -11,6 +11,7 @@ const CONFIG = {
11
11
  frontend: 'vite',
12
12
  backend: 'nestjs-rest',
13
13
  database: 'postgres',
14
+ mobile: 'none',
14
15
  packageManager: 'pnpm',
15
16
  targetDir: '/tmp/my-app',
16
17
  };
@@ -1 +1 @@
1
- {"version":3,"file":"web-vite.test.js","sourceRoot":"","sources":["../../../../src/create/scaffolders/__tests__/web-vite.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AAE5D,EAAE,CAAC,IAAI,CAAC,kBAAkB,EAAE,GAAG,EAAE,CAAC,CAAC;IACjC,KAAK,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,SAAS,CAAC;IAC3C,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,SAAS,CAAC;IACxC,OAAO,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,EAAE,CAAC;IACtC,QAAQ,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,EAAE,CAAC;IACvC,SAAS,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,SAAS,CAAC;CAChD,CAAC,CAAC,CAAA;AAEH,MAAM,MAAM,GAAG;IACb,WAAW,EAAE,QAAQ;IACrB,QAAQ,EAAE,MAAe;IACzB,OAAO,EAAE,aAAsB;IAC/B,QAAQ,EAAE,UAAmB;IAC7B,cAAc,EAAE,MAAe;IAC/B,SAAS,EAAE,aAAa;CACzB,CAAA;AAED,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;IAC5B,SAAS,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,aAAa,EAAE,CAAC,CAAA;IAEnC,EAAE,CAAC,gCAAgC,EAAE,KAAK,IAAI,EAAE;QAC9C,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,CAAA;QAClD,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,MAAM,CAAC,gBAAgB,CAAC,CAAA;QAEvD,MAAM,YAAY,CAAC,MAAM,CAAC,CAAA;QAE1B,MAAM,CAAC,KAAK,CAAC,CAAC,oBAAoB,CAChC,MAAM,CAAC,gBAAgB,CAAC,UAAU,CAAC,EACnC,EAAE,SAAS,EAAE,IAAI,EAAE,CACpB,CAAA;IACH,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,4CAA4C,EAAE,KAAK,IAAI,EAAE;QAC1D,MAAM,EAAE,EAAE,EAAE,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,CAAA;QAC/C,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,MAAM,CAAC,gBAAgB,CAAC,CAAA;QAEvD,MAAM,YAAY,CAAC,MAAM,CAAC,CAAA;QAE1B,MAAM,CAAC,EAAE,CAAC,CAAC,oBAAoB,CAC7B,MAAM,CAAC,gBAAgB,CAAC,UAAU,CAAC,EACnC,MAAM,CAAC,gBAAgB,CAAC,UAAU,CAAC,EACnC,EAAE,SAAS,EAAE,IAAI,EAAE,CACpB,CAAA;IACH,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
1
+ {"version":3,"file":"web-vite.test.js","sourceRoot":"","sources":["../../../../src/create/scaffolders/__tests__/web-vite.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AAE5D,EAAE,CAAC,IAAI,CAAC,kBAAkB,EAAE,GAAG,EAAE,CAAC,CAAC;IACjC,KAAK,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,SAAS,CAAC;IAC3C,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,SAAS,CAAC;IACxC,OAAO,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,EAAE,CAAC;IACtC,QAAQ,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,EAAE,CAAC;IACvC,SAAS,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,SAAS,CAAC;CAChD,CAAC,CAAC,CAAA;AAEH,MAAM,MAAM,GAAG;IACb,WAAW,EAAE,QAAQ;IACrB,QAAQ,EAAE,MAAe;IACzB,OAAO,EAAE,aAAsB;IAC/B,QAAQ,EAAE,UAAmB;IAC7B,MAAM,EAAE,MAAe;IACvB,cAAc,EAAE,MAAe;IAC/B,SAAS,EAAE,aAAa;CACzB,CAAA;AAED,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;IAC5B,SAAS,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,aAAa,EAAE,CAAC,CAAA;IAEnC,EAAE,CAAC,gCAAgC,EAAE,KAAK,IAAI,EAAE;QAC9C,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,CAAA;QAClD,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,MAAM,CAAC,gBAAgB,CAAC,CAAA;QAEvD,MAAM,YAAY,CAAC,MAAM,CAAC,CAAA;QAE1B,MAAM,CAAC,KAAK,CAAC,CAAC,oBAAoB,CAChC,MAAM,CAAC,gBAAgB,CAAC,UAAU,CAAC,EACnC,EAAE,SAAS,EAAE,IAAI,EAAE,CACpB,CAAA;IACH,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,4CAA4C,EAAE,KAAK,IAAI,EAAE;QAC1D,MAAM,EAAE,EAAE,EAAE,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,CAAA;QAC/C,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,MAAM,CAAC,gBAAgB,CAAC,CAAA;QAEvD,MAAM,YAAY,CAAC,MAAM,CAAC,CAAA;QAE1B,MAAM,CAAC,EAAE,CAAC,CAAC,oBAAoB,CAC7B,MAAM,CAAC,gBAAgB,CAAC,UAAU,CAAC,EACnC,MAAM,CAAC,gBAAgB,CAAC,UAAU,CAAC,EACnC,EAAE,SAAS,EAAE,IAAI,EAAE,CACpB,CAAA;IACH,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
@@ -1 +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,iBAahE"}
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"}
@@ -18,6 +18,7 @@ export async function scaffoldNestjsGraphql(config) {
18
18
  dbPort: db.port,
19
19
  });
20
20
  await injectDbDriver(appDir, db);
21
+ await setupGraphqlCodegen(config.targetDir);
21
22
  }
22
23
  async function injectDbDriver(appDir, db) {
23
24
  const pkgPath = join(appDir, 'package.json');
@@ -28,4 +29,16 @@ 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 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
+ }
31
44
  //# sourceMappingURL=api-nestjs-graphql.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"api-nestjs-graphql.js","sourceRoot":"","sources":["../../../src/create/scaffolders/api-nestjs-graphql.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,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,qBAAqB,CAAC,MAAqB;IAC/D,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,oBAAoB,CAAC,EAAE,MAAM,EAAE;QACpE,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-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 scaffoldExpo(config: ProjectConfig): Promise<void>;
3
+ //# sourceMappingURL=mobile-expo.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mobile-expo.d.ts","sourceRoot":"","sources":["../../../src/create/scaffolders/mobile-expo.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAMhD,wBAAsB,YAAY,CAAC,MAAM,EAAE,aAAa,iBAOvD"}
@@ -0,0 +1,14 @@
1
+ import { mkdir } 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
+ export async function scaffoldExpo(config) {
8
+ const appDir = join(config.targetDir, 'apps', 'mobile');
9
+ await mkdir(appDir, { recursive: true });
10
+ await copyTemplate(join(TEMPLATES_DIR, 'mobile-expo'), appDir, {
11
+ projectName: config.projectName,
12
+ });
13
+ }
14
+ //# sourceMappingURL=mobile-expo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mobile-expo.js","sourceRoot":"","sources":["../../../src/create/scaffolders/mobile-expo.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAA;AACxC,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,CAAC,KAAK,UAAU,YAAY,CAAC,MAAqB;IACtD,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAA;IACvD,MAAM,KAAK,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAExC,MAAM,YAAY,CAAC,IAAI,CAAC,aAAa,EAAE,aAAa,CAAC,EAAE,MAAM,EAAE;QAC7D,WAAW,EAAE,MAAM,CAAC,WAAW;KAChC,CAAC,CAAA;AACJ,CAAC"}
@@ -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,iBAmBhE"}
@@ -0,0 +1,91 @@
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
+ if (config.mobile === 'expo') {
18
+ await wireMobileTypes(config);
19
+ }
20
+ }
21
+ async function wireMobileTypes(config) {
22
+ const mobileDir = join(config.targetDir, 'apps', 'mobile');
23
+ const mobilePkgPath = join(mobileDir, 'package.json');
24
+ const pkg = JSON.parse(await readFile(mobilePkgPath, 'utf-8'));
25
+ pkg.dependencies['@local/types'] = 'workspace:*';
26
+ if (config.backend === 'nestjs-graphql') {
27
+ pkg.dependencies['@apollo/client'] = '^3.13.0';
28
+ pkg.dependencies['graphql'] = '^16.0.0';
29
+ }
30
+ await writeFile(mobilePkgPath, JSON.stringify(pkg, null, 2) + '\n', 'utf-8');
31
+ }
32
+ async function setupApolloClient(config, webDir) {
33
+ await mkdir(join(webDir, 'src', 'lib'), { recursive: true });
34
+ await mkdir(join(webDir, 'src', 'graphql'), { recursive: true });
35
+ if (config.frontend === 'vite') {
36
+ await writeFile(join(webDir, 'src', 'lib', 'apollo.ts'), apolloViteClient(), 'utf-8');
37
+ await patchViteMain(webDir);
38
+ }
39
+ else if (config.frontend === 'nextjs') {
40
+ await writeFile(join(webDir, 'src', 'lib', 'apollo.ts'), apolloNextClient(), 'utf-8');
41
+ await writeFile(join(webDir, 'src', 'app', 'providers.tsx'), apolloNextProviders(), 'utf-8');
42
+ await patchNextLayout(webDir);
43
+ }
44
+ }
45
+ async function patchViteMain(webDir) {
46
+ const mainPath = join(webDir, 'src', 'main.tsx');
47
+ const content = await readFile(mainPath, 'utf-8');
48
+ const patched = content
49
+ .replace(`import { StrictMode } from 'react'`, `import { ApolloProvider } from '@apollo/client'\nimport { StrictMode } from 'react'\nimport { client } from './lib/apollo'`)
50
+ .replace(`<App />`, `<ApolloProvider client={client}>\n <App />\n </ApolloProvider>`);
51
+ await writeFile(mainPath, patched, 'utf-8');
52
+ }
53
+ async function patchNextLayout(webDir) {
54
+ const layoutPath = join(webDir, 'src', 'app', 'layout.tsx');
55
+ const content = await readFile(layoutPath, 'utf-8');
56
+ const patched = content
57
+ .replace(`import type { Metadata } from "next";`, `import type { Metadata } from "next";\nimport { Providers } from './providers';`)
58
+ .replace(`<body>`, `<body>\n <Providers>`)
59
+ .replace(`</body>`, `</Providers>\n </body>`);
60
+ await writeFile(layoutPath, patched, 'utf-8');
61
+ }
62
+ function apolloViteClient() {
63
+ return `import { ApolloClient, InMemoryCache } from '@apollo/client'
64
+
65
+ export const client = new ApolloClient({
66
+ uri: import.meta.env.VITE_API_URL ?? 'http://localhost:3000/graphql',
67
+ cache: new InMemoryCache(),
68
+ })
69
+ `;
70
+ }
71
+ function apolloNextClient() {
72
+ return `import { ApolloClient, InMemoryCache } from '@apollo/client'
73
+
74
+ export const client = new ApolloClient({
75
+ uri: process.env.NEXT_PUBLIC_API_URL ?? 'http://localhost:3000/graphql',
76
+ cache: new InMemoryCache(),
77
+ })
78
+ `;
79
+ }
80
+ function apolloNextProviders() {
81
+ return `'use client'
82
+
83
+ import { ApolloProvider } from '@apollo/client'
84
+ import { client } from '../lib/apollo'
85
+
86
+ export function Providers({ children }: { children: React.ReactNode }) {
87
+ return <ApolloProvider client={client}>{children}</ApolloProvider>
88
+ }
89
+ `;
90
+ }
91
+ //# 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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"}
@@ -2,11 +2,13 @@ export type PackageManager = 'pnpm' | 'npm';
2
2
  export type Frontend = 'vite' | 'nextjs';
3
3
  export type Backend = 'nestjs-rest' | 'nestjs-graphql';
4
4
  export type Database = 'postgres' | 'mysql';
5
+ export type Mobile = 'expo' | 'none';
5
6
  export interface ProjectConfig {
6
7
  projectName: string;
7
8
  frontend: Frontend;
8
9
  backend: Backend;
9
10
  database: Database;
11
+ mobile: Mobile;
10
12
  packageManager: PackageManager;
11
13
  targetDir: string;
12
14
  }
@@ -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,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"}
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;AAC3C,MAAM,MAAM,MAAM,GAAG,MAAM,GAAG,MAAM,CAAA;AAEpC,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,MAAM,CAAA;IACnB,QAAQ,EAAE,QAAQ,CAAA;IAClB,OAAO,EAAE,OAAO,CAAA;IAChB,QAAQ,EAAE,QAAQ,CAAA;IAClB,MAAM,EAAE,MAAM,CAAA;IACd,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.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Opinionated full-stack project scaffolding CLI",
5
5
  "type": "module",
6
6
  "bin": {
@@ -25,6 +25,7 @@
25
25
  "@nestjs/config": "^3.0.0",
26
26
  "@nestjs/core": "^11.0.1",
27
27
  "@nestjs/platform-express": "^11.0.1",
28
+ "@nestjs/swagger": "^11.0.0",
28
29
  "@nestjs/typeorm": "^10.0.0",
29
30
  "reflect-metadata": "^0.2.2",
30
31
  "rxjs": "^7.8.1",
@@ -1,8 +1,19 @@
1
+ import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
1
2
  import { NestFactory } from '@nestjs/core';
3
+ import { writeFileSync } from 'node:fs';
2
4
  import { AppModule } from './app.module';
3
5
 
4
6
  async function bootstrap() {
5
7
  const app = await NestFactory.create(AppModule);
8
+
9
+ const config = new DocumentBuilder()
10
+ .setTitle('{{projectName}}')
11
+ .setVersion('1.0')
12
+ .build();
13
+ const document = SwaggerModule.createDocument(app, config);
14
+ SwaggerModule.setup('api', app, document);
15
+ writeFileSync('./swagger.json', JSON.stringify(document, null, 2));
16
+
6
17
  await app.listen(process.env.PORT ?? 3000);
7
18
  }
8
19
  bootstrap();
@@ -9,7 +9,9 @@
9
9
  "lint": "nx run-many -t lint",
10
10
  "generate:module": "nx g @local/generators:module",
11
11
  "generate:resolver": "nx g @local/generators:resolver",
12
- "generate:controller": "nx g @local/generators:controller"
12
+ "generate:controller": "nx g @local/generators:controller",
13
+ "codegen": "nx run types:codegen",
14
+ "codegen:watch": "nx run types:codegen:watch"
13
15
  },
14
16
  "devDependencies": {
15
17
  "@nx/devkit": "^20.0.0",
@@ -0,0 +1,10 @@
1
+ {
2
+ "name": "@local/types",
3
+ "version": "0.0.1",
4
+ "private": true,
5
+ "exports": {
6
+ "./rest": "./src/rest/index.ts",
7
+ "./graphql": "./src/graphql/index.ts"
8
+ },
9
+ "devDependencies": {}
10
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "compilerOptions": {
3
+ "module": "NodeNext",
4
+ "moduleResolution": "NodeNext",
5
+ "target": "ES2022",
6
+ "strict": true,
7
+ "esModuleInterop": true,
8
+ "skipLibCheck": true
9
+ }
10
+ }
@@ -16,7 +16,8 @@
16
16
  "graphql": {
17
17
  "type": "boolean",
18
18
  "description": "Add @ObjectType() to the model (required for GraphQL resolvers)",
19
- "default": false
19
+ "default": false,
20
+ "x-prompt": "Add @ObjectType() to the model? (required for GraphQL resolvers)"
20
21
  }
21
22
  },
22
23
  "required": ["name"]
@@ -0,0 +1,31 @@
1
+ import FontAwesome from '@expo/vector-icons/FontAwesome';
2
+ import { Tabs } from 'expo-router';
3
+
4
+ import Colors from '@/constants/Colors';
5
+ import { useColorScheme } from '@/components/useColorScheme';
6
+
7
+ function TabBarIcon(props: {
8
+ name: React.ComponentProps<typeof FontAwesome>['name'];
9
+ color: string;
10
+ }) {
11
+ return <FontAwesome size={28} style={{ marginBottom: -3 }} {...props} />;
12
+ }
13
+
14
+ export default function TabLayout() {
15
+ const colorScheme = useColorScheme();
16
+
17
+ return (
18
+ <Tabs
19
+ screenOptions={{
20
+ tabBarActiveTintColor: Colors[colorScheme ?? 'light'].tint,
21
+ }}>
22
+ <Tabs.Screen
23
+ name="index"
24
+ options={{
25
+ title: 'Home',
26
+ tabBarIcon: ({ color }) => <TabBarIcon name="home" color={color} />,
27
+ }}
28
+ />
29
+ </Tabs>
30
+ );
31
+ }
@@ -0,0 +1,23 @@
1
+ import { StyleSheet } from 'react-native';
2
+
3
+ import { Text, View } from '@/components/Themed';
4
+
5
+ export default function HomeScreen() {
6
+ return (
7
+ <View style={styles.container}>
8
+ <Text style={styles.title}>Home</Text>
9
+ </View>
10
+ );
11
+ }
12
+
13
+ const styles = StyleSheet.create({
14
+ container: {
15
+ flex: 1,
16
+ alignItems: 'center',
17
+ justifyContent: 'center',
18
+ },
19
+ title: {
20
+ fontSize: 20,
21
+ fontWeight: 'bold',
22
+ },
23
+ });
@@ -0,0 +1,40 @@
1
+ import { Link, Stack } from 'expo-router';
2
+ import { StyleSheet } from 'react-native';
3
+
4
+ import { Text, View } from '@/components/Themed';
5
+
6
+ export default function NotFoundScreen() {
7
+ return (
8
+ <>
9
+ <Stack.Screen options={{ title: 'Oops!' }} />
10
+ <View style={styles.container}>
11
+ <Text style={styles.title}>This screen doesn't exist.</Text>
12
+
13
+ <Link href="/" style={styles.link}>
14
+ <Text style={styles.linkText}>Go to home screen!</Text>
15
+ </Link>
16
+ </View>
17
+ </>
18
+ );
19
+ }
20
+
21
+ const styles = StyleSheet.create({
22
+ container: {
23
+ flex: 1,
24
+ alignItems: 'center',
25
+ justifyContent: 'center',
26
+ padding: 20,
27
+ },
28
+ title: {
29
+ fontSize: 20,
30
+ fontWeight: 'bold',
31
+ },
32
+ link: {
33
+ marginTop: 15,
34
+ paddingVertical: 15,
35
+ },
36
+ linkText: {
37
+ fontSize: 14,
38
+ color: '#2e78b7',
39
+ },
40
+ });
@@ -0,0 +1,31 @@
1
+ import { DarkTheme, DefaultTheme, ThemeProvider } from '@react-navigation/native';
2
+ import { Stack } from 'expo-router';
3
+ import * as SplashScreen from 'expo-splash-screen';
4
+ import { useEffect } from 'react';
5
+ import 'react-native-reanimated';
6
+
7
+ import { useColorScheme } from '@/components/useColorScheme';
8
+
9
+ export { ErrorBoundary } from 'expo-router';
10
+
11
+ export const unstable_settings = {
12
+ initialRouteName: '(tabs)',
13
+ };
14
+
15
+ SplashScreen.preventAutoHideAsync();
16
+
17
+ export default function RootLayout() {
18
+ const colorScheme = useColorScheme();
19
+
20
+ useEffect(() => {
21
+ SplashScreen.hideAsync();
22
+ }, []);
23
+
24
+ return (
25
+ <ThemeProvider value={colorScheme === 'dark' ? DarkTheme : DefaultTheme}>
26
+ <Stack>
27
+ <Stack.Screen name="(tabs)" options={{ headerShown: false }} />
28
+ </Stack>
29
+ </ThemeProvider>
30
+ );
31
+ }
@@ -0,0 +1,39 @@
1
+ {
2
+ "expo": {
3
+ "name": "{{projectName}}",
4
+ "slug": "{{projectName}}",
5
+ "version": "1.0.0",
6
+ "orientation": "portrait",
7
+ "icon": "./assets/images/icon.png",
8
+ "scheme": "{{projectName}}",
9
+ "userInterfaceStyle": "automatic",
10
+ "newArchEnabled": true,
11
+ "splash": {
12
+ "image": "./assets/images/splash-icon.png",
13
+ "resizeMode": "contain",
14
+ "backgroundColor": "#ffffff"
15
+ },
16
+ "ios": {
17
+ "supportsTablet": true
18
+ },
19
+ "android": {
20
+ "adaptiveIcon": {
21
+ "foregroundImage": "./assets/images/adaptive-icon.png",
22
+ "backgroundColor": "#ffffff"
23
+ },
24
+ "edgeToEdgeEnabled": true,
25
+ "predictiveBackGestureEnabled": false
26
+ },
27
+ "web": {
28
+ "bundler": "metro",
29
+ "output": "static",
30
+ "favicon": "./assets/images/favicon.png"
31
+ },
32
+ "plugins": [
33
+ "expo-router"
34
+ ],
35
+ "experiments": {
36
+ "typedRoutes": true
37
+ }
38
+ }
39
+ }
@@ -0,0 +1,25 @@
1
+ import { Link } from 'expo-router';
2
+ import * as WebBrowser from 'expo-web-browser';
3
+ import React from 'react';
4
+ import { Platform } from 'react-native';
5
+
6
+ export function ExternalLink(
7
+ props: Omit<React.ComponentProps<typeof Link>, 'href'> & { href: string }
8
+ ) {
9
+ return (
10
+ <Link
11
+ target="_blank"
12
+ {...props}
13
+ // @ts-expect-error: External URLs are not typed.
14
+ href={props.href}
15
+ onPress={(e) => {
16
+ if (Platform.OS !== 'web') {
17
+ // Prevent the default behavior of linking to the default browser on native.
18
+ e.preventDefault();
19
+ // Open the link in an in-app browser.
20
+ WebBrowser.openBrowserAsync(props.href as string);
21
+ }
22
+ }}
23
+ />
24
+ );
25
+ }
@@ -0,0 +1,5 @@
1
+ import { Text, TextProps } from './Themed';
2
+
3
+ export function MonoText(props: TextProps) {
4
+ return <Text {...props} style={[props.style, { fontFamily: 'SpaceMono' }]} />;
5
+ }
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Learn more about Light and Dark modes:
3
+ * https://docs.expo.io/guides/color-schemes/
4
+ */
5
+
6
+ import { Text as DefaultText, View as DefaultView } from 'react-native';
7
+
8
+ import Colors from '@/constants/Colors';
9
+ import { useColorScheme } from './useColorScheme';
10
+
11
+ type ThemeProps = {
12
+ lightColor?: string;
13
+ darkColor?: string;
14
+ };
15
+
16
+ export type TextProps = ThemeProps & DefaultText['props'];
17
+ export type ViewProps = ThemeProps & DefaultView['props'];
18
+
19
+ export function useThemeColor(
20
+ props: { light?: string; dark?: string },
21
+ colorName: keyof typeof Colors.light & keyof typeof Colors.dark
22
+ ) {
23
+ const theme = useColorScheme() ?? 'light';
24
+ const colorFromProps = props[theme];
25
+
26
+ if (colorFromProps) {
27
+ return colorFromProps;
28
+ } else {
29
+ return Colors[theme][colorName];
30
+ }
31
+ }
32
+
33
+ export function Text(props: TextProps) {
34
+ const { style, lightColor, darkColor, ...otherProps } = props;
35
+ const color = useThemeColor({ light: lightColor, dark: darkColor }, 'text');
36
+
37
+ return <DefaultText style={[{ color }, style]} {...otherProps} />;
38
+ }
39
+
40
+ export function View(props: ViewProps) {
41
+ const { style, lightColor, darkColor, ...otherProps } = props;
42
+ const backgroundColor = useThemeColor({ light: lightColor, dark: darkColor }, 'background');
43
+
44
+ return <DefaultView style={[{ backgroundColor }, style]} {...otherProps} />;
45
+ }
@@ -0,0 +1,4 @@
1
+ // This function is web-only as native doesn't currently support server (or build-time) rendering.
2
+ export function useClientOnlyValue<S, C>(server: S, client: C): S | C {
3
+ return client;
4
+ }
@@ -0,0 +1,12 @@
1
+ import React from 'react';
2
+
3
+ // `useEffect` is not invoked during server rendering, meaning
4
+ // we can use this to determine if we're on the server or not.
5
+ export function useClientOnlyValue<S, C>(server: S, client: C): S | C {
6
+ const [value, setValue] = React.useState<S | C>(server);
7
+ React.useEffect(() => {
8
+ setValue(client);
9
+ }, [client]);
10
+
11
+ return value;
12
+ }
@@ -0,0 +1 @@
1
+ export { useColorScheme } from 'react-native';
@@ -0,0 +1,8 @@
1
+ // NOTE: The default React Native styling doesn't support server rendering.
2
+ // Server rendered styles should not change between the first render of the HTML
3
+ // and the first render on the client. Typically, web developers will use CSS media queries
4
+ // to render different styles on the client and server, these aren't directly supported in React Native
5
+ // but can be achieved using a styling library like Nativewind.
6
+ export function useColorScheme() {
7
+ return 'light';
8
+ }
@@ -0,0 +1,19 @@
1
+ const tintColorLight = '#2f95dc';
2
+ const tintColorDark = '#fff';
3
+
4
+ export default {
5
+ light: {
6
+ text: '#000',
7
+ background: '#fff',
8
+ tint: tintColorLight,
9
+ tabIconDefault: '#ccc',
10
+ tabIconSelected: tintColorLight,
11
+ },
12
+ dark: {
13
+ text: '#fff',
14
+ background: '#000',
15
+ tint: tintColorDark,
16
+ tabIconDefault: '#ccc',
17
+ tabIconSelected: tintColorDark,
18
+ },
19
+ };
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "{{projectName}}-mobile",
3
+ "main": "expo-router/entry",
4
+ "version": "1.0.0",
5
+ "scripts": {
6
+ "dev": "expo start",
7
+ "android": "expo start --android",
8
+ "ios": "expo start --ios",
9
+ "web": "expo start --web",
10
+ "build": "expo export"
11
+ },
12
+ "dependencies": {
13
+ "@expo/vector-icons": "^15.0.3",
14
+ "@react-navigation/native": "^7.1.8",
15
+ "expo": "~54.0.33",
16
+ "expo-constants": "~18.0.13",
17
+ "expo-font": "~14.0.11",
18
+ "expo-linking": "~8.0.11",
19
+ "expo-router": "~6.0.23",
20
+ "expo-splash-screen": "~31.0.13",
21
+ "expo-status-bar": "~3.0.9",
22
+ "expo-web-browser": "~15.0.10",
23
+ "react": "19.1.0",
24
+ "react-dom": "19.1.0",
25
+ "react-native": "0.81.5",
26
+ "react-native-worklets": "0.5.1",
27
+ "react-native-reanimated": "~4.1.1",
28
+ "react-native-safe-area-context": "~5.6.0",
29
+ "react-native-screens": "~4.16.0",
30
+ "react-native-web": "~0.21.0"
31
+ },
32
+ "devDependencies": {
33
+ "@types/react": "~19.1.0",
34
+ "typescript": "~5.9.2"
35
+ },
36
+ "private": true
37
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "mobile",
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
+ }
17
+ }
@@ -0,0 +1,20 @@
1
+ {
2
+ "extends": "expo/tsconfig.base",
3
+ "compilerOptions": {
4
+ "strict": true,
5
+ "paths": {
6
+ "@/*": [
7
+ "./*"
8
+ ],
9
+ "@local/types/*": [
10
+ "../../packages/types/src/*"
11
+ ]
12
+ }
13
+ },
14
+ "include": [
15
+ "**/*.ts",
16
+ "**/*.tsx",
17
+ ".expo/types/**/*.ts",
18
+ "expo-env.d.ts"
19
+ ]
20
+ }
@@ -0,0 +1,17 @@
1
+ import type { CodegenConfig } from '@graphql-codegen/cli';
2
+
3
+ const config: CodegenConfig = {
4
+ schema: '../../apps/backend/src/schema.gql',
5
+ documents: ['../../apps/web/src/**/*.graphql'],
6
+ generates: {
7
+ './src/graphql/index.ts': {
8
+ plugins: [
9
+ 'typescript',
10
+ 'typescript-operations',
11
+ 'typescript-react-apollo',
12
+ ],
13
+ },
14
+ },
15
+ };
16
+
17
+ export default config;
@@ -0,0 +1,19 @@
1
+ {
2
+ "name": "types",
3
+ "targets": {
4
+ "codegen": {
5
+ "executor": "nx:run-commands",
6
+ "options": {
7
+ "command": "graphql-codegen --config codegen.ts",
8
+ "cwd": "{projectRoot}"
9
+ }
10
+ },
11
+ "codegen:watch": {
12
+ "executor": "nx:run-commands",
13
+ "options": {
14
+ "command": "graphql-codegen --config codegen.ts --watch",
15
+ "cwd": "{projectRoot}"
16
+ }
17
+ }
18
+ }
19
+ }
@@ -0,0 +1,10 @@
1
+ import { defineConfig } from '@hey-api/openapi-ts';
2
+
3
+ export default defineConfig({
4
+ input: '../../apps/backend/swagger.json',
5
+ output: {
6
+ path: './src/rest',
7
+ format: 'prettier',
8
+ },
9
+ plugins: ['@hey-api/typescript'],
10
+ });
@@ -0,0 +1,19 @@
1
+ {
2
+ "name": "types",
3
+ "targets": {
4
+ "codegen": {
5
+ "executor": "nx:run-commands",
6
+ "options": {
7
+ "command": "openapi-ts",
8
+ "cwd": "{projectRoot}"
9
+ }
10
+ },
11
+ "codegen:watch": {
12
+ "executor": "nx:run-commands",
13
+ "options": {
14
+ "command": "chokidar '../../apps/backend/swagger.json' --initial -c 'openapi-ts'",
15
+ "cwd": "{projectRoot}"
16
+ }
17
+ }
18
+ }
19
+ }