create-forgeon 0.1.2 → 0.1.6

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 (143) hide show
  1. package/README.md +19 -17
  2. package/bin/create-forgeon.mjs +22 -22
  3. package/package.json +1 -1
  4. package/src/cli/add-help.mjs +12 -12
  5. package/src/cli/add-options.mjs +54 -54
  6. package/src/cli/add-options.test.mjs +24 -24
  7. package/src/cli/help.mjs +20 -20
  8. package/src/cli/options.mjs +121 -121
  9. package/src/cli/options.test.mjs +41 -41
  10. package/src/cli/prompt-select.mjs +94 -94
  11. package/src/cli/prompt-select.test.mjs +148 -148
  12. package/src/constants.mjs +13 -13
  13. package/src/core/docs.mjs +128 -128
  14. package/src/core/docs.test.mjs +91 -91
  15. package/src/core/install.mjs +14 -14
  16. package/src/core/scaffold.mjs +48 -45
  17. package/src/core/validate.mjs +12 -12
  18. package/src/core/validate.test.mjs +73 -73
  19. package/src/databases/index.mjs +26 -26
  20. package/src/frameworks/index.mjs +32 -32
  21. package/src/infrastructure/proxy.mjs +12 -12
  22. package/src/modules/docs.mjs +70 -70
  23. package/src/modules/executor.mjs +39 -21
  24. package/src/modules/executor.test.mjs +95 -45
  25. package/src/modules/i18n.mjs +283 -0
  26. package/src/modules/registry.mjs +43 -35
  27. package/src/presets/i18n.mjs +228 -180
  28. package/src/presets/index.mjs +2 -2
  29. package/src/presets/proxy.mjs +32 -32
  30. package/src/run-add-module.mjs +47 -47
  31. package/src/run-create-forgeon.mjs +72 -72
  32. package/src/utils/fs.mjs +26 -26
  33. package/src/utils/values.mjs +20 -20
  34. package/templates/base/.dockerignore +7 -7
  35. package/templates/base/.editorconfig +11 -11
  36. package/templates/base/README.md +46 -46
  37. package/templates/base/apps/api/Dockerfile +24 -24
  38. package/templates/base/apps/api/package.json +39 -39
  39. package/templates/base/apps/api/prisma/migrations/0001_init/migration.sql +11 -11
  40. package/templates/base/apps/api/prisma/schema.prisma +14 -14
  41. package/templates/base/apps/api/prisma/seed.ts +19 -19
  42. package/templates/base/apps/api/src/app.module.ts +32 -32
  43. package/templates/base/apps/api/src/common/dto/echo-query.dto.ts +5 -5
  44. package/templates/base/apps/api/src/common/filters/app-exception.filter.ts +129 -129
  45. package/templates/base/apps/api/src/config/app.config.ts +12 -12
  46. package/templates/base/apps/api/src/health/health.controller.ts +30 -30
  47. package/templates/base/apps/api/src/main.ts +25 -25
  48. package/templates/base/apps/api/src/prisma/prisma.module.ts +8 -8
  49. package/templates/base/apps/api/src/prisma/prisma.service.ts +26 -26
  50. package/templates/base/apps/api/tsconfig.build.json +8 -8
  51. package/templates/base/apps/api/tsconfig.json +8 -8
  52. package/templates/base/apps/web/Dockerfile +12 -12
  53. package/templates/base/apps/web/index.html +11 -11
  54. package/templates/base/apps/web/package.json +21 -21
  55. package/templates/base/apps/web/src/App.tsx +35 -35
  56. package/templates/base/apps/web/src/main.tsx +8 -8
  57. package/templates/base/apps/web/src/styles.css +32 -32
  58. package/templates/base/apps/web/tsconfig.json +17 -17
  59. package/templates/base/apps/web/vite.config.ts +14 -14
  60. package/templates/base/docs/AI/ARCHITECTURE.md +37 -37
  61. package/templates/base/docs/AI/MODULE_SPEC.md +56 -56
  62. package/templates/base/docs/AI/PROJECT.md +31 -31
  63. package/templates/base/docs/AI/TASKS.md +57 -57
  64. package/templates/base/docs/README.md +6 -6
  65. package/templates/base/infra/caddy/Caddyfile +15 -15
  66. package/templates/base/infra/docker/.env.example +9 -9
  67. package/templates/base/infra/docker/caddy.Dockerfile +15 -15
  68. package/templates/base/infra/docker/compose.caddy.yml +44 -44
  69. package/templates/base/infra/docker/compose.nginx.yml +44 -44
  70. package/templates/base/infra/docker/compose.none.yml +37 -37
  71. package/templates/base/infra/docker/compose.yml +44 -44
  72. package/templates/base/infra/docker/nginx.Dockerfile +15 -15
  73. package/templates/base/infra/nginx/nginx.conf +31 -31
  74. package/templates/base/package.json +23 -23
  75. package/templates/base/packages/core/README.md +2 -2
  76. package/templates/base/packages/core/package.json +13 -13
  77. package/templates/base/packages/core/tsconfig.json +7 -7
  78. package/templates/base/packages/i18n/package.json +18 -18
  79. package/templates/base/packages/i18n/src/forgeon-i18n.module.ts +45 -45
  80. package/templates/base/packages/i18n/tsconfig.json +8 -8
  81. package/templates/base/pnpm-workspace.yaml +2 -2
  82. package/templates/base/resources/i18n/en/common.json +4 -4
  83. package/templates/base/resources/i18n/en/validation.json +2 -2
  84. package/templates/base/resources/i18n/uk/common.json +4 -4
  85. package/templates/base/resources/i18n/uk/validation.json +2 -2
  86. package/templates/base/tsconfig.base.json +16 -16
  87. package/templates/docs-fragments/AI_ARCHITECTURE/00_title.md +1 -1
  88. package/templates/docs-fragments/AI_ARCHITECTURE/10_layout_base.md +6 -6
  89. package/templates/docs-fragments/AI_ARCHITECTURE/11_layout_infra.md +1 -1
  90. package/templates/docs-fragments/AI_ARCHITECTURE/12_layout_i18n_resources.md +1 -1
  91. package/templates/docs-fragments/AI_ARCHITECTURE/20_env_base.md +4 -4
  92. package/templates/docs-fragments/AI_ARCHITECTURE/21_env_i18n.md +3 -3
  93. package/templates/docs-fragments/AI_ARCHITECTURE/30_default_db.md +7 -7
  94. package/templates/docs-fragments/AI_ARCHITECTURE/31_docker_runtime.md +5 -5
  95. package/templates/docs-fragments/AI_ARCHITECTURE/32_scope_freeze.md +5 -5
  96. package/templates/docs-fragments/AI_ARCHITECTURE/40_docs_generation.md +9 -9
  97. package/templates/docs-fragments/AI_ARCHITECTURE/50_extension_points.md +8 -8
  98. package/templates/docs-fragments/AI_PROJECT/00_title.md +1 -1
  99. package/templates/docs-fragments/AI_PROJECT/10_what_is.md +3 -3
  100. package/templates/docs-fragments/AI_PROJECT/20_structure_base.md +5 -5
  101. package/templates/docs-fragments/AI_PROJECT/21_structure_i18n.md +2 -0
  102. package/templates/docs-fragments/AI_PROJECT/22_structure_docker.md +1 -1
  103. package/templates/docs-fragments/AI_PROJECT/23_structure_docs.md +1 -1
  104. package/templates/docs-fragments/AI_PROJECT/30_run_dev.md +8 -8
  105. package/templates/docs-fragments/AI_PROJECT/31_run_docker.md +5 -5
  106. package/templates/docs-fragments/AI_PROJECT/32_proxy_notes.md +5 -5
  107. package/templates/docs-fragments/AI_PROJECT/32_proxy_notes_none.md +5 -5
  108. package/templates/docs-fragments/AI_PROJECT/33_i18n_notes.md +2 -0
  109. package/templates/docs-fragments/AI_PROJECT/40_change_boundaries_base.md +3 -3
  110. package/templates/docs-fragments/AI_PROJECT/41_change_boundaries_docker.md +1 -1
  111. package/templates/docs-fragments/README/00_title.md +3 -3
  112. package/templates/docs-fragments/README/10_stack.md +8 -8
  113. package/templates/docs-fragments/README/20_quick_start_dev_intro.md +6 -6
  114. package/templates/docs-fragments/README/21_quick_start_dev_db_docker.md +4 -4
  115. package/templates/docs-fragments/README/21_quick_start_dev_db_local.md +1 -1
  116. package/templates/docs-fragments/README/22_quick_start_dev_outro.md +7 -7
  117. package/templates/docs-fragments/README/30_quick_start_docker.md +7 -7
  118. package/templates/docs-fragments/README/30_quick_start_docker_none.md +9 -9
  119. package/templates/docs-fragments/README/31_proxy_preset_caddy.md +9 -9
  120. package/templates/docs-fragments/README/31_proxy_preset_nginx.md +8 -8
  121. package/templates/docs-fragments/README/31_proxy_preset_none.md +6 -6
  122. package/templates/docs-fragments/README/32_prisma_container_start.md +5 -5
  123. package/templates/docs-fragments/README/40_i18n.md +14 -8
  124. package/templates/docs-fragments/README/90_next_steps.md +7 -7
  125. package/templates/module-fragments/i18n/00_title.md +5 -0
  126. package/templates/module-fragments/i18n/10_overview.md +9 -0
  127. package/templates/module-fragments/i18n/20_scope.md +7 -0
  128. package/templates/module-fragments/i18n/90_status_implemented.md +3 -0
  129. package/templates/module-fragments/jwt-auth/00_title.md +1 -1
  130. package/templates/module-fragments/jwt-auth/10_overview.md +6 -6
  131. package/templates/module-fragments/jwt-auth/20_scope.md +7 -7
  132. package/templates/module-fragments/jwt-auth/90_status_planned.md +3 -3
  133. package/templates/module-fragments/queue/00_title.md +1 -1
  134. package/templates/module-fragments/queue/10_overview.md +6 -6
  135. package/templates/module-fragments/queue/20_scope.md +7 -7
  136. package/templates/module-fragments/queue/90_status_planned.md +3 -3
  137. package/templates/module-presets/i18n/apps/web/src/App.tsx +61 -0
  138. package/templates/module-presets/i18n/packages/i18n-contracts/package.json +14 -0
  139. package/templates/module-presets/i18n/packages/i18n-contracts/src/index.ts +7 -0
  140. package/templates/module-presets/i18n/packages/i18n-contracts/tsconfig.json +8 -0
  141. package/templates/module-presets/i18n/packages/i18n-web/package.json +17 -0
  142. package/templates/module-presets/i18n/packages/i18n-web/src/index.ts +50 -0
  143. package/templates/module-presets/i18n/packages/i18n-web/tsconfig.json +8 -0
@@ -1,6 +1,6 @@
1
- import { IsNotEmpty } from 'class-validator';
2
-
3
- export class EchoQueryDto {
4
- @IsNotEmpty({ message: 'validation.required' })
5
- value!: string;
1
+ import { IsNotEmpty } from 'class-validator';
2
+
3
+ export class EchoQueryDto {
4
+ @IsNotEmpty({ message: 'validation.required' })
5
+ value!: string;
6
6
  }
@@ -1,130 +1,130 @@
1
- import {
2
- ArgumentsHost,
3
- Catch,
4
- ExceptionFilter,
5
- HttpException,
6
- HttpStatus,
7
- Injectable,
8
- Optional,
9
- } from '@nestjs/common';
10
- import { I18nService } from 'nestjs-i18n';
11
- import { Request, Response } from 'express';
12
-
13
- @Injectable()
14
- @Catch()
15
- export class AppExceptionFilter implements ExceptionFilter {
16
- constructor(@Optional() private readonly i18n?: I18nService) {}
17
-
18
- catch(exception: unknown, host: ArgumentsHost): void {
19
- const context = host.switchToHttp();
20
- const response = context.getResponse<Response>();
21
- const request = context.getRequest<Request>();
22
-
23
- const status =
24
- exception instanceof HttpException
25
- ? exception.getStatus()
26
- : HttpStatus.INTERNAL_SERVER_ERROR;
27
-
28
- const payload =
29
- exception instanceof HttpException
30
- ? exception.getResponse()
31
- : { message: 'Internal server error' };
32
-
33
- const code = this.resolveCode(status);
34
- const message = this.resolveMessage(payload, status, request);
35
- const details = this.resolveDetails(payload);
36
-
37
- response.status(status).json({
38
- error: {
39
- code,
40
- message,
41
- ...(details !== undefined ? { details } : {}),
42
- },
43
- });
44
- }
45
-
46
- private resolveCode(status: number): string {
47
- switch (status) {
48
- case HttpStatus.BAD_REQUEST:
49
- return 'validation_error';
50
- case HttpStatus.UNAUTHORIZED:
51
- return 'unauthorized';
52
- case HttpStatus.FORBIDDEN:
53
- return 'forbidden';
54
- case HttpStatus.NOT_FOUND:
55
- return 'not_found';
56
- case HttpStatus.CONFLICT:
57
- return 'conflict';
58
- default:
59
- return 'internal_error';
60
- }
61
- }
62
-
63
- private resolveMessage(
64
- payload: unknown,
65
- status: number,
66
- request: Request,
67
- ): string {
68
- const lang = this.resolveLang(request);
69
-
70
- if (status === HttpStatus.NOT_FOUND) {
71
- return this.translate('errors.notFound', lang);
72
- }
73
-
74
- if (typeof payload === 'string') {
75
- return this.translate(payload, lang);
76
- }
77
-
78
- if (typeof payload === 'object' && payload !== null) {
79
- const obj = payload as { message?: string | string[] };
80
- if (Array.isArray(obj.message) && obj.message.length > 0) {
81
- return this.translate(obj.message[0], lang);
82
- }
83
- if (typeof obj.message === 'string') {
84
- return this.translate(obj.message, lang);
85
- }
86
- }
87
-
88
- return 'Internal server error';
89
- }
90
-
91
- private resolveDetails(payload: unknown): unknown {
92
- if (typeof payload !== 'object' || payload === null) {
93
- return undefined;
94
- }
95
-
96
- const obj = payload as { message?: string | string[]; error?: string };
97
- if (Array.isArray(obj.message) && obj.message.length > 1) {
98
- return obj.message;
99
- }
100
-
101
- return undefined;
102
- }
103
-
104
- private resolveLang(request: Request): string | undefined {
105
- const queryLang = request.query?.lang;
106
- if (typeof queryLang === 'string' && queryLang.length > 0) {
107
- return queryLang;
108
- }
109
-
110
- const header = request.headers['accept-language'];
111
- if (typeof header === 'string' && header.length > 0) {
112
- return header.split(',')[0].trim();
113
- }
114
-
115
- return undefined;
116
- }
117
-
118
- private translate(keyOrMessage: string, lang?: string): string {
119
- if (!this.i18n) {
120
- return keyOrMessage;
121
- }
122
-
123
- const translated = this.i18n.t(keyOrMessage, {
124
- lang,
125
- defaultValue: keyOrMessage,
126
- });
127
-
128
- return typeof translated === 'string' ? translated : keyOrMessage;
129
- }
1
+ import {
2
+ ArgumentsHost,
3
+ Catch,
4
+ ExceptionFilter,
5
+ HttpException,
6
+ HttpStatus,
7
+ Injectable,
8
+ Optional,
9
+ } from '@nestjs/common';
10
+ import { I18nService } from 'nestjs-i18n';
11
+ import { Request, Response } from 'express';
12
+
13
+ @Injectable()
14
+ @Catch()
15
+ export class AppExceptionFilter implements ExceptionFilter {
16
+ constructor(@Optional() private readonly i18n?: I18nService) {}
17
+
18
+ catch(exception: unknown, host: ArgumentsHost): void {
19
+ const context = host.switchToHttp();
20
+ const response = context.getResponse<Response>();
21
+ const request = context.getRequest<Request>();
22
+
23
+ const status =
24
+ exception instanceof HttpException
25
+ ? exception.getStatus()
26
+ : HttpStatus.INTERNAL_SERVER_ERROR;
27
+
28
+ const payload =
29
+ exception instanceof HttpException
30
+ ? exception.getResponse()
31
+ : { message: 'Internal server error' };
32
+
33
+ const code = this.resolveCode(status);
34
+ const message = this.resolveMessage(payload, status, request);
35
+ const details = this.resolveDetails(payload);
36
+
37
+ response.status(status).json({
38
+ error: {
39
+ code,
40
+ message,
41
+ ...(details !== undefined ? { details } : {}),
42
+ },
43
+ });
44
+ }
45
+
46
+ private resolveCode(status: number): string {
47
+ switch (status) {
48
+ case HttpStatus.BAD_REQUEST:
49
+ return 'validation_error';
50
+ case HttpStatus.UNAUTHORIZED:
51
+ return 'unauthorized';
52
+ case HttpStatus.FORBIDDEN:
53
+ return 'forbidden';
54
+ case HttpStatus.NOT_FOUND:
55
+ return 'not_found';
56
+ case HttpStatus.CONFLICT:
57
+ return 'conflict';
58
+ default:
59
+ return 'internal_error';
60
+ }
61
+ }
62
+
63
+ private resolveMessage(
64
+ payload: unknown,
65
+ status: number,
66
+ request: Request,
67
+ ): string {
68
+ const lang = this.resolveLang(request);
69
+
70
+ if (status === HttpStatus.NOT_FOUND) {
71
+ return this.translate('errors.notFound', lang);
72
+ }
73
+
74
+ if (typeof payload === 'string') {
75
+ return this.translate(payload, lang);
76
+ }
77
+
78
+ if (typeof payload === 'object' && payload !== null) {
79
+ const obj = payload as { message?: string | string[] };
80
+ if (Array.isArray(obj.message) && obj.message.length > 0) {
81
+ return this.translate(obj.message[0], lang);
82
+ }
83
+ if (typeof obj.message === 'string') {
84
+ return this.translate(obj.message, lang);
85
+ }
86
+ }
87
+
88
+ return 'Internal server error';
89
+ }
90
+
91
+ private resolveDetails(payload: unknown): unknown {
92
+ if (typeof payload !== 'object' || payload === null) {
93
+ return undefined;
94
+ }
95
+
96
+ const obj = payload as { message?: string | string[]; error?: string };
97
+ if (Array.isArray(obj.message) && obj.message.length > 1) {
98
+ return obj.message;
99
+ }
100
+
101
+ return undefined;
102
+ }
103
+
104
+ private resolveLang(request: Request): string | undefined {
105
+ const queryLang = request.query?.lang;
106
+ if (typeof queryLang === 'string' && queryLang.length > 0) {
107
+ return queryLang;
108
+ }
109
+
110
+ const header = request.headers['accept-language'];
111
+ if (typeof header === 'string' && header.length > 0) {
112
+ return header.split(',')[0].trim();
113
+ }
114
+
115
+ return undefined;
116
+ }
117
+
118
+ private translate(keyOrMessage: string, lang?: string): string {
119
+ if (!this.i18n) {
120
+ return keyOrMessage;
121
+ }
122
+
123
+ const translated = this.i18n.t(keyOrMessage, {
124
+ lang,
125
+ defaultValue: keyOrMessage,
126
+ });
127
+
128
+ return typeof translated === 'string' ? translated : keyOrMessage;
129
+ }
130
130
  }
@@ -1,13 +1,13 @@
1
- import { registerAs } from '@nestjs/config';
2
-
3
- const toBoolean = (value: string | undefined, defaultValue: boolean): boolean => {
4
- if (value === undefined) return defaultValue;
5
- return value.toLowerCase() === 'true';
6
- };
7
-
8
- export default registerAs('app', () => ({
9
- port: Number(process.env.PORT ?? 3000),
10
- i18nEnabled: toBoolean(process.env.I18N_ENABLED, true),
11
- i18nDefaultLang: process.env.I18N_DEFAULT_LANG ?? 'en',
12
- i18nFallbackLang: process.env.I18N_FALLBACK_LANG ?? 'en',
1
+ import { registerAs } from '@nestjs/config';
2
+
3
+ const toBoolean = (value: string | undefined, defaultValue: boolean): boolean => {
4
+ if (value === undefined) return defaultValue;
5
+ return value.toLowerCase() === 'true';
6
+ };
7
+
8
+ export default registerAs('app', () => ({
9
+ port: Number(process.env.PORT ?? 3000),
10
+ i18nEnabled: toBoolean(process.env.I18N_ENABLED, true),
11
+ i18nDefaultLang: process.env.I18N_DEFAULT_LANG ?? 'en',
12
+ i18nFallbackLang: process.env.I18N_FALLBACK_LANG ?? 'en',
13
13
  }));
@@ -1,31 +1,31 @@
1
- import { Controller, Get, Optional, Query } from '@nestjs/common';
2
- import { I18nService } from 'nestjs-i18n';
3
- import { EchoQueryDto } from '../common/dto/echo-query.dto';
4
-
5
- @Controller('health')
6
- export class HealthController {
7
- constructor(@Optional() private readonly i18n?: I18nService) {}
8
-
9
- @Get()
10
- getHealth(@Query('lang') lang?: string) {
11
- return {
12
- status: 'ok',
13
- message: this.translate('common.ok', lang),
14
- };
15
- }
16
-
17
- @Get('echo')
18
- getEcho(@Query() query: EchoQueryDto) {
19
- return { value: query.value };
20
- }
21
-
22
- private translate(key: string, lang?: string): string {
23
- if (!this.i18n) {
24
- if (key === 'common.ok') return 'OK';
25
- return key;
26
- }
27
-
28
- const value = this.i18n.t(key, { lang, defaultValue: key });
29
- return typeof value === 'string' ? value : key;
30
- }
1
+ import { Controller, Get, Optional, Query } from '@nestjs/common';
2
+ import { I18nService } from 'nestjs-i18n';
3
+ import { EchoQueryDto } from '../common/dto/echo-query.dto';
4
+
5
+ @Controller('health')
6
+ export class HealthController {
7
+ constructor(@Optional() private readonly i18n?: I18nService) {}
8
+
9
+ @Get()
10
+ getHealth(@Query('lang') lang?: string) {
11
+ return {
12
+ status: 'ok',
13
+ message: this.translate('common.ok', lang),
14
+ };
15
+ }
16
+
17
+ @Get('echo')
18
+ getEcho(@Query() query: EchoQueryDto) {
19
+ return { value: query.value };
20
+ }
21
+
22
+ private translate(key: string, lang?: string): string {
23
+ if (!this.i18n) {
24
+ if (key === 'common.ok') return 'OK';
25
+ return key;
26
+ }
27
+
28
+ const value = this.i18n.t(key, { lang, defaultValue: key });
29
+ return typeof value === 'string' ? value : key;
30
+ }
31
31
  }
@@ -1,26 +1,26 @@
1
- import 'reflect-metadata';
2
- import { ValidationPipe } from '@nestjs/common';
3
- import { ConfigService } from '@nestjs/config';
4
- import { NestFactory } from '@nestjs/core';
5
- import { AppModule } from './app.module';
6
- import { AppExceptionFilter } from './common/filters/app-exception.filter';
7
-
8
- async function bootstrap() {
9
- const app = await NestFactory.create(AppModule);
10
-
11
- app.setGlobalPrefix('api');
12
- app.useGlobalPipes(
13
- new ValidationPipe({
14
- whitelist: true,
15
- transform: true,
16
- }),
17
- );
18
- app.useGlobalFilters(app.get(AppExceptionFilter));
19
-
20
- const configService = app.get(ConfigService);
21
- const port = configService.get<number>('app.port') ?? 3000;
22
-
23
- await app.listen(port);
24
- }
25
-
1
+ import 'reflect-metadata';
2
+ import { ValidationPipe } from '@nestjs/common';
3
+ import { ConfigService } from '@nestjs/config';
4
+ import { NestFactory } from '@nestjs/core';
5
+ import { AppModule } from './app.module';
6
+ import { AppExceptionFilter } from './common/filters/app-exception.filter';
7
+
8
+ async function bootstrap() {
9
+ const app = await NestFactory.create(AppModule);
10
+
11
+ app.setGlobalPrefix('api');
12
+ app.useGlobalPipes(
13
+ new ValidationPipe({
14
+ whitelist: true,
15
+ transform: true,
16
+ }),
17
+ );
18
+ app.useGlobalFilters(app.get(AppExceptionFilter));
19
+
20
+ const configService = app.get(ConfigService);
21
+ const port = configService.get<number>('app.port') ?? 3000;
22
+
23
+ await app.listen(port);
24
+ }
25
+
26
26
  bootstrap();
@@ -1,9 +1,9 @@
1
- import { Global, Module } from '@nestjs/common';
2
- import { PrismaService } from './prisma.service';
3
-
4
- @Global()
5
- @Module({
6
- providers: [PrismaService],
7
- exports: [PrismaService],
8
- })
1
+ import { Global, Module } from '@nestjs/common';
2
+ import { PrismaService } from './prisma.service';
3
+
4
+ @Global()
5
+ @Module({
6
+ providers: [PrismaService],
7
+ exports: [PrismaService],
8
+ })
9
9
  export class PrismaModule {}
@@ -1,27 +1,27 @@
1
- import { Injectable, OnModuleDestroy, OnModuleInit } from '@nestjs/common';
2
- import { PrismaClient } from '@prisma/client';
3
-
4
- @Injectable()
5
- export class PrismaService extends PrismaClient implements OnModuleInit, OnModuleDestroy {
6
- constructor() {
7
- const databaseUrl =
8
- process.env.DATABASE_URL ??
9
- 'postgresql://postgres:postgres@localhost:5432/app?schema=public';
10
-
11
- super({
12
- datasources: {
13
- db: {
14
- url: databaseUrl,
15
- },
16
- },
17
- });
18
- }
19
-
20
- async onModuleInit(): Promise<void> {
21
- await this.$connect();
22
- }
23
-
24
- async onModuleDestroy(): Promise<void> {
25
- await this.$disconnect();
26
- }
1
+ import { Injectable, OnModuleDestroy, OnModuleInit } from '@nestjs/common';
2
+ import { PrismaClient } from '@prisma/client';
3
+
4
+ @Injectable()
5
+ export class PrismaService extends PrismaClient implements OnModuleInit, OnModuleDestroy {
6
+ constructor() {
7
+ const databaseUrl =
8
+ process.env.DATABASE_URL ??
9
+ 'postgresql://postgres:postgres@localhost:5432/app?schema=public';
10
+
11
+ super({
12
+ datasources: {
13
+ db: {
14
+ url: databaseUrl,
15
+ },
16
+ },
17
+ });
18
+ }
19
+
20
+ async onModuleInit(): Promise<void> {
21
+ await this.$connect();
22
+ }
23
+
24
+ async onModuleDestroy(): Promise<void> {
25
+ await this.$disconnect();
26
+ }
27
27
  }
@@ -1,9 +1,9 @@
1
- {
2
- "extends": "./tsconfig.json",
3
- "compilerOptions": {
4
- "rootDir": "src",
5
- "outDir": "dist"
6
- },
7
- "include": ["src/**/*.ts"],
8
- "exclude": ["**/*.spec.ts", "test", "dist", "node_modules"]
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": {
4
+ "rootDir": "src",
5
+ "outDir": "dist"
6
+ },
7
+ "include": ["src/**/*.ts"],
8
+ "exclude": ["**/*.spec.ts", "test", "dist", "node_modules"]
9
9
  }
@@ -1,9 +1,9 @@
1
- {
2
- "extends": "../../tsconfig.base.json",
3
- "compilerOptions": {
4
- "rootDir": "src",
5
- "outDir": "dist"
6
- },
7
- "include": ["src/**/*.ts", "prisma/**/*.ts"],
8
- "exclude": ["dist", "node_modules"]
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "rootDir": "src",
5
+ "outDir": "dist"
6
+ },
7
+ "include": ["src/**/*.ts", "prisma/**/*.ts"],
8
+ "exclude": ["dist", "node_modules"]
9
9
  }
@@ -1,13 +1,13 @@
1
- FROM node:20-alpine
2
- WORKDIR /app
3
- RUN corepack enable
4
-
5
- COPY package.json pnpm-workspace.yaml ./
6
- COPY apps/web/package.json apps/web/package.json
7
- RUN pnpm install --frozen-lockfile=false
8
-
9
- COPY apps/web apps/web
10
- WORKDIR /app/apps/web
11
- RUN pnpm build
12
-
1
+ FROM node:20-alpine
2
+ WORKDIR /app
3
+ RUN corepack enable
4
+
5
+ COPY package.json pnpm-workspace.yaml ./
6
+ COPY apps/web/package.json apps/web/package.json
7
+ RUN pnpm install --frozen-lockfile=false
8
+
9
+ COPY apps/web apps/web
10
+ WORKDIR /app/apps/web
11
+ RUN pnpm build
12
+
13
13
  CMD ["pnpm", "preview", "--host", "0.0.0.0", "--port", "5173"]
@@ -1,13 +1,13 @@
1
- <!doctype html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
- <title>Forgeon Web</title>
7
- </head>
8
- <body>
9
- <div id="root"></div>
10
- <script type="module" src="/src/main.tsx"></script>
11
- </body>
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>Forgeon Web</title>
7
+ </head>
8
+ <body>
9
+ <div id="root"></div>
10
+ <script type="module" src="/src/main.tsx"></script>
11
+ </body>
12
12
  </html>
13
13
 
@@ -1,23 +1,23 @@
1
- {
2
- "name": "@forgeon/web",
3
- "version": "0.1.0",
4
- "private": true,
5
- "type": "module",
6
- "scripts": {
7
- "dev": "vite",
8
- "build": "tsc -b && vite build",
9
- "preview": "vite preview"
10
- },
11
- "dependencies": {
12
- "react": "^18.3.1",
13
- "react-dom": "^18.3.1"
14
- },
15
- "devDependencies": {
16
- "@types/react": "^18.3.3",
17
- "@types/react-dom": "^18.3.0",
18
- "@vitejs/plugin-react": "^4.3.1",
19
- "typescript": "^5.7.3",
20
- "vite": "^5.4.11"
21
- }
1
+ {
2
+ "name": "@forgeon/web",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "vite",
8
+ "build": "tsc -b && vite build",
9
+ "preview": "vite preview"
10
+ },
11
+ "dependencies": {
12
+ "react": "^18.3.1",
13
+ "react-dom": "^18.3.1"
14
+ },
15
+ "devDependencies": {
16
+ "@types/react": "^18.3.3",
17
+ "@types/react-dom": "^18.3.0",
18
+ "@vitejs/plugin-react": "^4.3.1",
19
+ "typescript": "^5.7.3",
20
+ "vite": "^5.4.11"
21
+ }
22
22
  }
23
23