simpledi-app-generator 0.0.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 (71) hide show
  1. package/README.md +96 -0
  2. package/dist/cli.d.ts +3 -0
  3. package/dist/cli.d.ts.map +1 -0
  4. package/dist/cli.js +53 -0
  5. package/dist/cli.js.map +1 -0
  6. package/dist/create_module.d.ts +2 -0
  7. package/dist/create_module.d.ts.map +1 -0
  8. package/dist/create_module.js +439 -0
  9. package/dist/create_module.js.map +1 -0
  10. package/dist/generate_skeleton.d.ts +2 -0
  11. package/dist/generate_skeleton.d.ts.map +1 -0
  12. package/dist/generate_skeleton.js +249 -0
  13. package/dist/generate_skeleton.js.map +1 -0
  14. package/dist/index.d.ts +3 -0
  15. package/dist/index.d.ts.map +1 -0
  16. package/dist/index.js +3 -0
  17. package/dist/index.js.map +1 -0
  18. package/dist/templates/.env.development +3 -0
  19. package/dist/templates/AppModule.ts +7 -0
  20. package/dist/templates/Config.ts +98 -0
  21. package/dist/templates/UseCaseModule.ts +5 -0
  22. package/dist/templates/config/getConfigModule.ts +12 -0
  23. package/dist/templates/db/DbService.ts +18 -0
  24. package/dist/templates/db/getDb.ts +11 -0
  25. package/dist/templates/db/getDbModule.ts +15 -0
  26. package/dist/templates/db/initDb.ts +11 -0
  27. package/dist/templates/main.routes.ts +10 -0
  28. package/dist/templates/main.ts +91 -0
  29. package/dist/templates/package.json +51 -0
  30. package/dist/templates/schema.ts +1 -0
  31. package/dist/templates/src/BaseRepository.ts +136 -0
  32. package/dist/templates/src/BaseService.ts +78 -0
  33. package/dist/templates/src/IRepository.ts +11 -0
  34. package/dist/templates/src/IService.ts +6 -0
  35. package/dist/templates/src/core/baseSchema.ts +13 -0
  36. package/dist/templates/src/lib/AuthenticationUtils.ts +49 -0
  37. package/dist/templates/src/lib/errors/BadRequestException.ts +11 -0
  38. package/dist/templates/src/lib/errors/ConflictException.ts +9 -0
  39. package/dist/templates/src/lib/errors/ForbiddenException.ts +11 -0
  40. package/dist/templates/src/lib/errors/HttpException.ts +22 -0
  41. package/dist/templates/src/lib/errors/InternalServerException.ts +13 -0
  42. package/dist/templates/src/lib/errors/NotFoundException.ts +11 -0
  43. package/dist/templates/src/lib/errors/UnauthorizedException.ts +11 -0
  44. package/dist/templates/src/lib/functions/getEnvFile.ts +19 -0
  45. package/dist/templates/src/lib/functions/getHostname.ts +18 -0
  46. package/dist/templates/src/lib/functions/isNotNullNorUndefined.ts +5 -0
  47. package/dist/templates/src/lib/functions/tableName.ts +5 -0
  48. package/dist/templates/src/lib/functions/withBaseSchema.ts +30 -0
  49. package/dist/templates/src/lib/types/BaseEntityInterface.ts +9 -0
  50. package/dist/templates/src/lib/types/EnvFileNames.ts +7 -0
  51. package/dist/templates/src/lib/types/Envs.ts +7 -0
  52. package/dist/templates/src/lib/types/FailedOperation.ts +9 -0
  53. package/dist/templates/src/lib/types/OperationResult.ts +5 -0
  54. package/dist/templates/src/lib/types/SharedStubs.ts +16 -0
  55. package/dist/templates/src/lib/types/SuccessfullOperation.ts +9 -0
  56. package/dist/templates/src/lib/types/TableNameToken.ts +1 -0
  57. package/dist/templates/src/lib/types/TokenPayload.ts +6 -0
  58. package/dist/templates/src/lib/types/UserInterface.ts +10 -0
  59. package/dist/templates/src/lib/types/getCorsOrigin.ts +20 -0
  60. package/dist/templates/src/main.routes.ts +11 -0
  61. package/dist/templates/src/use-case/IUseCase.ts +3 -0
  62. package/dist/templates/src/use-case/UseCaseModule.ts +6 -0
  63. package/dist/templates/src/use-case/health-check/HealthCheck.ts +24 -0
  64. package/dist/templates/src/use-case/health-check/healthCheckRoutes.ts +23 -0
  65. package/dist/templates/src/use-case/health-check/outputs/HealthCheckSuccess.ts +14 -0
  66. package/dist/templates/tsconfig.json +46 -0
  67. package/package.json +41 -0
  68. package/src/templates/.env.development +3 -0
  69. package/src/templates/package.json +51 -0
  70. package/src/templates/tsconfig.json +46 -0
  71. package/tsconfig.json +40 -0
@@ -0,0 +1,249 @@
1
+ import { cp, mkdir, writeFile, readdir } from 'fs/promises';
2
+ import { join, resolve } from 'path';
3
+ import { existsSync } from 'fs';
4
+ import { fileURLToPath } from 'url';
5
+ import { dirname } from 'path';
6
+ // Get the directory where this script is located (works in both dev and dist)
7
+ const __filename = fileURLToPath(import.meta.url);
8
+ const __dirname = dirname(__filename);
9
+ export async function generateSkeleton(projectName) {
10
+ if (!projectName) {
11
+ throw new Error('Project name is required');
12
+ }
13
+ const targetDir = resolve(process.cwd(), projectName);
14
+ const templatesDir = join(__dirname, 'templates');
15
+ console.log(`Generating skeleton in: ${targetDir}`);
16
+ if (existsSync(targetDir)) {
17
+ throw new Error(`Directory ${targetDir} already exists`);
18
+ }
19
+ await mkdir(targetDir, { recursive: true });
20
+ // Templates Mapping
21
+ // Define all templates and their destination
22
+ const templates = [
23
+ // Root Files
24
+ { src: 'package.json', dest: 'package.json' },
25
+ { src: 'tsconfig.json', dest: 'tsconfig.json' },
26
+ { src: '.env.development', dest: '.env.development' },
27
+ { src: 'main.ts', dest: 'main.ts' },
28
+ // Config
29
+ { src: 'Config.ts', dest: 'config/Config.ts' },
30
+ { src: 'config/getConfigModule.ts', dest: 'config/getConfigModule.ts' },
31
+ // Src Root
32
+ { src: 'AppModule.ts', dest: 'src/AppModule.ts' },
33
+ { src: 'schema.ts', dest: 'src/schema.ts' },
34
+ { src: 'src/main.routes.ts', dest: 'src/main.routes.ts' },
35
+ // Base Classes
36
+ { src: 'src/BaseRepository.ts', dest: 'src/BaseRepository.ts' },
37
+ { src: 'src/BaseService.ts', dest: 'src/BaseService.ts' },
38
+ { src: 'src/IRepository.ts', dest: 'src/IRepository.ts' },
39
+ { src: 'src/IService.ts', dest: 'src/IService.ts' },
40
+ // Use Case Root
41
+ {
42
+ src: 'src/use-case/UseCaseModule.ts',
43
+ dest: 'src/use-case/UseCaseModule.ts',
44
+ },
45
+ { src: 'src/use-case/IUseCase.ts', dest: 'src/use-case/IUseCase.ts' },
46
+ // HealthCheck Use Case
47
+ {
48
+ src: 'src/use-case/health-check/outputs/HealthCheckSuccess.ts',
49
+ dest: 'src/use-case/health-check/outputs/HealthCheckSuccess.ts',
50
+ },
51
+ {
52
+ src: 'src/use-case/health-check/HealthCheck.ts',
53
+ dest: 'src/use-case/health-check/HealthCheck.ts',
54
+ },
55
+ {
56
+ src: 'src/use-case/health-check/healthCheckRoutes.ts',
57
+ dest: 'src/use-case/health-check/healthCheckRoutes.ts',
58
+ },
59
+ // DB
60
+ { src: 'db/DbService.ts', dest: 'db/DbService.ts' },
61
+ { src: 'db/getDb.ts', dest: 'db/getDb.ts' },
62
+ { src: 'db/getDbModule.ts', dest: 'db/getDbModule.ts' },
63
+ { src: 'db/initDb.ts', dest: 'db/initDb.ts' },
64
+ // Lib - Types
65
+ {
66
+ src: 'src/lib/types/BaseEntityInterface.ts',
67
+ dest: 'src/lib/types/BaseEntityInterface.ts',
68
+ },
69
+ {
70
+ src: 'src/lib/types/EnvFileNames.ts',
71
+ dest: 'src/lib/types/EnvFileNames.ts',
72
+ },
73
+ { src: 'src/lib/types/Envs.ts', dest: 'src/lib/types/Envs.ts' },
74
+ {
75
+ src: 'src/lib/types/FailedOperation.ts',
76
+ dest: 'src/lib/types/FailedOperation.ts',
77
+ },
78
+ {
79
+ src: 'src/lib/types/OperationResult.ts',
80
+ dest: 'src/lib/types/OperationResult.ts',
81
+ },
82
+ {
83
+ src: 'src/lib/types/SharedStubs.ts',
84
+ dest: 'src/lib/types/SharedStubs.ts',
85
+ },
86
+ {
87
+ src: 'src/lib/types/SuccessfullOperation.ts',
88
+ dest: 'src/lib/types/SuccessfullOperation.ts',
89
+ },
90
+ {
91
+ src: 'src/lib/types/TableNameToken.ts',
92
+ dest: 'src/lib/types/TableNameToken.ts',
93
+ },
94
+ {
95
+ src: 'src/lib/types/TokenPayload.ts',
96
+ dest: 'src/lib/types/TokenPayload.ts',
97
+ },
98
+ {
99
+ src: 'src/lib/types/UserInterface.ts',
100
+ dest: 'src/lib/types/UserInterface.ts',
101
+ },
102
+ {
103
+ src: 'src/lib/types/getCorsOrigin.ts',
104
+ dest: 'src/lib/types/getCorsOrigin.ts',
105
+ },
106
+ // Lib - Functions
107
+ {
108
+ src: 'src/lib/functions/getEnvFile.ts',
109
+ dest: 'src/lib/functions/getEnvFile.ts',
110
+ },
111
+ {
112
+ src: 'src/lib/functions/getHostname.ts',
113
+ dest: 'src/lib/functions/getHostname.ts',
114
+ },
115
+ {
116
+ src: 'src/lib/functions/isNotNullNorUndefined.ts',
117
+ dest: 'src/lib/functions/isNotNullNorUndefined.ts',
118
+ },
119
+ {
120
+ src: 'src/lib/functions/tableName.ts',
121
+ dest: 'src/lib/functions/tableName.ts',
122
+ },
123
+ {
124
+ src: 'src/lib/functions/withBaseSchema.ts',
125
+ dest: 'src/lib/functions/withBaseSchema.ts',
126
+ },
127
+ // Lib - Errors
128
+ {
129
+ src: 'src/lib/errors/BadRequestException.ts',
130
+ dest: 'src/lib/errors/BadRequestException.ts',
131
+ },
132
+ {
133
+ src: 'src/lib/errors/ConflictException.ts',
134
+ dest: 'src/lib/errors/ConflictException.ts',
135
+ },
136
+ {
137
+ src: 'src/lib/errors/ForbiddenException.ts',
138
+ dest: 'src/lib/errors/ForbiddenException.ts',
139
+ },
140
+ {
141
+ src: 'src/lib/errors/HttpException.ts',
142
+ dest: 'src/lib/errors/HttpException.ts',
143
+ },
144
+ {
145
+ src: 'src/lib/errors/InternalServerException.ts',
146
+ dest: 'src/lib/errors/InternalServerException.ts',
147
+ },
148
+ {
149
+ src: 'src/lib/errors/NotFoundException.ts',
150
+ dest: 'src/lib/errors/NotFoundException.ts',
151
+ },
152
+ {
153
+ src: 'src/lib/errors/UnauthorizedException.ts',
154
+ dest: 'src/lib/errors/UnauthorizedException.ts',
155
+ },
156
+ // Lib - Root
157
+ {
158
+ src: 'src/lib/AuthenticationUtils.ts',
159
+ dest: 'src/lib/AuthenticationUtils.ts',
160
+ },
161
+ // Core
162
+ {
163
+ src: 'src/core/baseSchema.ts',
164
+ dest: 'src/core/baseSchema.ts',
165
+ },
166
+ ];
167
+ // Helper function to read template and write to dest
168
+ const applyTemplate = async (tpl) => {
169
+ const srcPath = join(templatesDir, tpl.src);
170
+ const destPath = join(targetDir, tpl.dest);
171
+ // Ensure parent dir exists
172
+ const parentDir = resolve(destPath, '..');
173
+ if (!existsSync(parentDir)) {
174
+ await mkdir(parentDir, { recursive: true });
175
+ }
176
+ if (existsSync(srcPath)) {
177
+ await cp(srcPath, destPath);
178
+ console.log(`Created ${tpl.dest}`);
179
+ }
180
+ else {
181
+ console.error(`Error: Template ${tpl.src} not found at ${srcPath}`);
182
+ }
183
+ };
184
+ for (const tpl of templates) {
185
+ await applyTemplate(tpl);
186
+ }
187
+ // Generate Indices
188
+ const libTypesDest = join(targetDir, 'src/lib/types');
189
+ const libFunctionsDest = join(targetDir, 'src/lib/functions');
190
+ const libErrorsDest = join(targetDir, 'src/lib/errors');
191
+ const libDest = join(targetDir, 'src/lib');
192
+ const coreDir = join(targetDir, 'src/core');
193
+ await mkdir(coreDir, { recursive: true });
194
+ // lib/types/index.ts
195
+ const createIndex = async (dir) => {
196
+ if (!existsSync(dir))
197
+ return;
198
+ const files = await readdir(dir);
199
+ const indexContent = files
200
+ .filter((f) => f.endsWith('.ts') && f !== 'index.ts')
201
+ .map((f) => `export * from './${f.replace('.ts', '')}';`)
202
+ .join('\n');
203
+ await writeFile(join(dir, 'index.ts'), indexContent);
204
+ console.log(`Created index for ${dir}`);
205
+ };
206
+ await createIndex(libTypesDest);
207
+ await createIndex(libFunctionsDest);
208
+ await createIndex(libErrorsDest);
209
+ // lib/index.ts
210
+ const libIndexContent = `export * from "./functions";
211
+ export * from "./types";
212
+ export * from "./errors";`;
213
+ await writeFile(join(libDest, 'index.ts'), libIndexContent);
214
+ console.log('Created lib/index.ts');
215
+ // Create CoreModule.ts
216
+ const coreModuleContent = `import { Module } from '@kanian77/simple-di';
217
+ import { getConfigModule } from 'config/getConfigModule';
218
+ import { getDbModule } from 'db/getDbModule';
219
+
220
+ export const CoreModule = new Module({
221
+ imports: [
222
+ getConfigModule(),
223
+ getDbModule(),
224
+ ],
225
+ });
226
+ `;
227
+ await writeFile(join(coreDir, 'CoreModule.ts'), coreModuleContent);
228
+ console.log('Created src/core/CoreModule.ts');
229
+ // Create src/core/baseZodSchema.ts
230
+ const baseZodSchemaContent = `import { z } from "zod";
231
+
232
+ export const baseZodSchema = z.object({
233
+ id: z.string().uuid(),
234
+ deleted: z.boolean().default(false),
235
+ deletedAt: z.date().nullable(),
236
+ createdAt: z.date().nullable(),
237
+ updatedAt: z.date().nullable(),
238
+ createdBy: z.string().uuid().nullable(),
239
+ updatedBy: z.string().uuid().nullable(),
240
+ });`;
241
+ await writeFile(join(coreDir, 'baseZodSchema.ts'), baseZodSchemaContent);
242
+ console.log('Created src/core/baseZodSchema.ts');
243
+ console.log(`\n✅ Skeleton generation complete!`);
244
+ console.log(`\nNext steps:`);
245
+ console.log(` cd ${projectName}`);
246
+ console.log(` bun install`);
247
+ console.log(` bun run dev`);
248
+ }
249
+ //# sourceMappingURL=generate_skeleton.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate_skeleton.js","sourceRoot":"","sources":["../src/generate_skeleton.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export { generateSkeleton } from './generate_skeleton.js';
2
+ export { createModule } from './create_module.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export { generateSkeleton } from './generate_skeleton.js';
2
+ export { createModule } from './create_module.js';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,3 @@
1
+ PORT=3000
2
+ CONNECTION_STRING=placeholder
3
+ JWT_SECRET=asecret
@@ -0,0 +1,7 @@
1
+ import { Module } from '@kanian77/simple-di';
2
+ import { CoreModule } from './core/CoreModule';
3
+ import { UseCaseModule } from './use-case/UseCaseModule';
4
+
5
+ export const AppModule = new Module({
6
+ imports: [CoreModule, UseCaseModule],
7
+ });
@@ -0,0 +1,98 @@
1
+ import { config } from 'dotenv';
2
+ import type { Server } from 'bun';
3
+ import { EnvFileNames, Envs, isNotNullNorUndefined } from '@root/lib';
4
+ import { Service } from '@kanian77/simple-di';
5
+
6
+ export const CONFIG = 'Config';
7
+ @Service({ token: CONFIG })
8
+ export class Config {
9
+ private _server?: Server | undefined;
10
+
11
+ private configLoaded: boolean = false;
12
+ private _loadedEnvFile?: EnvFileNames;
13
+ private _connectionString: string = 'placeholder';
14
+
15
+ private _port: number = 3000;
16
+
17
+ private _jwtSecret: string = 'placeholder';
18
+
19
+ constructor(envFile?: EnvFileNames) {
20
+ this.loadEnvFile(envFile);
21
+ this._connectionString = process.env.CONNECTION_STRING ?? 'undefined';
22
+ this._port = process.env.PORT ? Number.parseInt(process.env.PORT) : 3000;
23
+ this._jwtSecret = process.env.JWT_SECRET ?? 'undefined';
24
+ }
25
+
26
+ set server(s: Server) {
27
+ this._server = this.server;
28
+ }
29
+
30
+ get server(): Server | undefined {
31
+ return this._server;
32
+ }
33
+
34
+ get loadedEnvFile() {
35
+ return this._loadedEnvFile;
36
+ }
37
+
38
+ set connectionString(name: string) {
39
+ this._connectionString = name;
40
+ }
41
+ get connectionString() {
42
+ return this._connectionString;
43
+ }
44
+
45
+ set port(p: number) {
46
+ this._port = p;
47
+ }
48
+ get port() {
49
+ return this._port;
50
+ }
51
+
52
+ set jwtSecret(s: string) {
53
+ this._jwtSecret = s;
54
+ }
55
+ get jwtSecret() {
56
+ return this._jwtSecret;
57
+ }
58
+
59
+ getConfig() {
60
+ if (!this.configLoaded) {
61
+ this.loadEnvFile();
62
+ this.configLoaded = true;
63
+ }
64
+ return {
65
+ connectionString: this._connectionString,
66
+ port: this._port,
67
+
68
+ jwtSecret: this._jwtSecret,
69
+ };
70
+ }
71
+
72
+ public loadEnvFile = (envFile?: EnvFileNames) => {
73
+ if (isNotNullNorUndefined(envFile)) {
74
+ config({ path: envFile });
75
+ this._loadedEnvFile = envFile;
76
+ return;
77
+ }
78
+ switch (process.env.BUN_ENV) {
79
+ case Envs.PRODUCTION:
80
+ this._loadedEnvFile = EnvFileNames.PRODUCTION;
81
+ break;
82
+ case Envs.STAGING:
83
+ this._loadedEnvFile = EnvFileNames.STAGING;
84
+ break;
85
+ case Envs.TESTING:
86
+ config({ path: EnvFileNames.TESTING });
87
+ this._loadedEnvFile = EnvFileNames.TESTING;
88
+ break;
89
+ case Envs.DEBUGGING:
90
+ this._loadedEnvFile = EnvFileNames.DEBUGGING;
91
+ break;
92
+ case Envs.DEVELOPMENT:
93
+ default:
94
+ config({ path: EnvFileNames.DEVELOPMENT });
95
+ this._loadedEnvFile = EnvFileNames.DEVELOPMENT;
96
+ }
97
+ };
98
+ }
@@ -0,0 +1,5 @@
1
+ import { Module } from '@kanian77/simple-di';
2
+
3
+ export const UseCaseModule = new Module({
4
+ imports: [],
5
+ });
@@ -0,0 +1,12 @@
1
+ import { Module } from '@kanian77/simple-di';
2
+ import { Config, CONFIG } from './Config';
3
+ import { getEnvFile, type EnvFileNames } from '@root/lib';
4
+ export const getConfigModule = (envFile?: EnvFileNames) =>
5
+ new Module({
6
+ providers: [
7
+ {
8
+ provide: CONFIG,
9
+ useFactory: () => new Config(envFile || getEnvFile()),
10
+ },
11
+ ],
12
+ });
@@ -0,0 +1,18 @@
1
+ import { inject, Inject, Service } from '@kanian77/simple-di';
2
+ import { neon } from '@neondatabase/serverless';
3
+ import { Config, CONFIG } from 'config/Config';
4
+ import { drizzle } from 'drizzle-orm/neon-http';
5
+ import * as schema from '@root/schema';
6
+
7
+ export const DB_SERVICE = 'DbService';
8
+ @Service({ token: DB_SERVICE })
9
+ export class DbService {
10
+ private db: any;
11
+ constructor(@Inject(CONFIG) private config: Config) {
12
+ const client = neon(this.config.connectionString);
13
+ this.db = drizzle(client, { schema: schema });
14
+ }
15
+ getDb() {
16
+ return this.db;
17
+ }
18
+ }
@@ -0,0 +1,11 @@
1
+ import { inject } from '@kanian77/simple-di';
2
+ import { initDb } from './initDb';
3
+ let db: any = null;
4
+
5
+ export function getDb() {
6
+ if (!db) {
7
+ db = initDb();
8
+ return db;
9
+ }
10
+ return inject('db');
11
+ }
@@ -0,0 +1,15 @@
1
+ import { Module } from '@kanian77/simple-di';
2
+ import { DB_SERVICE, DbService } from './DbService';
3
+ import { getConfigModule } from 'config/getConfigModule';
4
+ import { EnvFileNames, getEnvFile } from '@root/lib';
5
+
6
+ export const getDbModule = (envFile?: EnvFileNames) =>
7
+ new Module({
8
+ imports: [getConfigModule(envFile || getEnvFile())],
9
+ providers: [
10
+ {
11
+ provide: DB_SERVICE,
12
+ useClass: DbService,
13
+ },
14
+ ],
15
+ });
@@ -0,0 +1,11 @@
1
+ import { drizzle } from 'drizzle-orm/neon-http';
2
+ import { neon } from '@neondatabase/serverless';
3
+ import * as schema from '@root/schema';
4
+ import { CONFIG, Config } from 'config/Config';
5
+ import { inject, registerValue } from '@kanian77/simple-di';
6
+ export function initDb() {
7
+ const client = neon(inject<Config>(CONFIG).connectionString);
8
+ const db = drizzle(client, { schema });
9
+ registerValue('db', db);
10
+ return db;
11
+ }
@@ -0,0 +1,10 @@
1
+ import { Hono } from 'hono';
2
+ import { StatusCodes } from 'http-status-codes';
3
+
4
+ const mainRoutes = new Hono();
5
+
6
+ mainRoutes.get('/health', (c) => {
7
+ return c.json({ status: 'healthy' }, StatusCodes.OK);
8
+ });
9
+
10
+ export { mainRoutes };
@@ -0,0 +1,91 @@
1
+ import 'reflect-metadata';
2
+ import { Hono } from 'hono';
3
+ import { cors } from 'hono/cors';
4
+ import { mainRoutes } from '@root/main.routes';
5
+ import { logger } from 'hono/logger';
6
+ import { prettyJSON } from 'hono/pretty-json';
7
+ import { CONFIG, Config } from 'config/Config';
8
+ import { bootstrap, inject } from '@kanian77/simple-di';
9
+ import { AppModule } from '@root/AppModule';
10
+ import { getCorsOrigin } from '@root/lib/types/getCorsOrigin';
11
+ import { getHostname } from '@root/lib/functions/getHostname';
12
+
13
+ // bootstraps DI container
14
+ console.log('Bootstrapping DI container...');
15
+ bootstrap(AppModule);
16
+ console.log('DI container bootstrapped.');
17
+
18
+ const app = new Hono();
19
+ console.log('created Hono');
20
+
21
+ // cors to accept from origin 'http://localhost:5173'
22
+ console.log('setting up cors');
23
+ console.log('CORS origin:', getCorsOrigin());
24
+ app
25
+ .use(
26
+ '*',
27
+ cors({
28
+ origin: (requestOriginValue, c) => {
29
+ const allowedOrigins = getCorsOrigin(); // Get current allowed origins
30
+
31
+ if (!requestOriginValue) {
32
+ return null;
33
+ }
34
+
35
+ if (allowedOrigins.includes(requestOriginValue)) {
36
+ console.log(`[CORS Check] Origin ${requestOriginValue} IS ALLOWED.`);
37
+ return requestOriginValue;
38
+ } else {
39
+ console.warn(
40
+ `[CORS Check] Origin ${requestOriginValue} IS NOT ALLOWED.`,
41
+ );
42
+ return null;
43
+ }
44
+ },
45
+ allowMethods: ['GET', 'POST', 'PATCH', 'PUT', 'DELETE', 'OPTIONS'], // Includes OPTIONS for preflight
46
+ allowHeaders: [
47
+ 'Content-Type',
48
+ 'Authorization',
49
+ 'content-type',
50
+ 'authorization',
51
+ 'X-Requested-With',
52
+ 'X-Pinggy-No-Screen',
53
+ ],
54
+ maxAge: 600,
55
+ credentials: true,
56
+ }),
57
+ )
58
+ .use('*', (c, next) => {
59
+ // Log the request method and URL
60
+ console.log(`[Request] ${c.req.method} ${c.req.url}`);
61
+ return next();
62
+ });
63
+
64
+ app.route('/', mainRoutes);
65
+ app.use('*', logger());
66
+ app.use('*', prettyJSON());
67
+
68
+ console.log('about to create Bun server');
69
+
70
+ console.log('Debug info:');
71
+ console.log('process.env.BUN_ENV:', process.env.BUN_ENV);
72
+ console.log('process.env.NODE_ENV:', process.env.NODE_ENV);
73
+ console.log('Resolved hostname:', getHostname());
74
+ console.log(
75
+ 'About to start server on hostname:',
76
+ getHostname(),
77
+ `port: ${process.env.PORT || 3000}`,
78
+ );
79
+ const server = Bun.serve({
80
+ fetch: app.fetch,
81
+ hostname: getHostname(),
82
+ port: process.env.PORT || 3000,
83
+ });
84
+
85
+ inject<Config>(CONFIG).server = server;
86
+
87
+ process.on('SIGINT', () => {
88
+ console.log('Shutting down server...');
89
+ server.stop();
90
+ process.exit(0);
91
+ });
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "testing-stric",
3
+ "module": "main.ts",
4
+ "type": "module",
5
+ "devDependencies": {
6
+ "@hono/node-server": "^1.13.7",
7
+ "@types/bun": "latest",
8
+ "@types/jsdom": "^21.1.7",
9
+ "@types/jsonwebtoken": "^9.0.7",
10
+ "@types/supertest": "^6.0.2",
11
+ "bun-types": "^1.2.5",
12
+ "drizzle-kit": "^0.30.1",
13
+ "husky": "^9.1.7",
14
+ "jsdom": "^26.0.0",
15
+ "slugify": "^1.6.6",
16
+ "supertest": "^7.0.0"
17
+ },
18
+ "peerDependencies": {
19
+ "typescript": "^5.0.0"
20
+ },
21
+ "dependencies": {
22
+ "@kanian77/simple-di": "^0.1.1",
23
+ "@neondatabase/serverless": "^0.10.4",
24
+ "concurrently": "^9.1.0",
25
+ "dotenv": "^16.4.7",
26
+ "drizzle-orm": "^0.38.2",
27
+ "drizzle-zod": "^0.6.0",
28
+ "hono": "^4.8.0",
29
+ "http-status-codes": "^2.3.0",
30
+ "jsonwebtoken": "^9.0.2",
31
+ "reflect-metadata": "^0.2.2",
32
+ "uuid": "^11.1.0",
33
+ "zod": "3.24.2"
34
+ },
35
+ "scripts": {
36
+ "dev": "BUN_ENV=dev bun run --hot --watch ./main.ts ",
37
+ "debug": "concurrently 'BUN_ENV=debug bun run --hot --watch --inspect ./main.ts'",
38
+ "create-module": "bun run scripts/create_module.ts",
39
+ "migrate:dev": "BUN_ENV=dev bunx drizzle-kit --config=drizzle.dev.config.ts migrate",
40
+ "generate:dev": "BUN_ENV=dev bunx drizzle-kit --config=drizzle.dev.config.ts generate",
41
+ "migrate:prod": "BUN_ENV=prod bunx drizzle-kit --config=drizzle.prod.config.ts migrate",
42
+ "generate:prod": "BUN_ENV=prod bunx drizzle-kit --config=drizzle.prod.config.ts generate",
43
+ "studio:dev": "BUN_ENV=dev bunx drizzle-kit --config=drizzle.dev.config.ts studio",
44
+ "seed-dev": "BUN_ENV=dev bun run ./db/seeds/plan-seeds.ts",
45
+ "build:staging": "BUN_ENV=staging bun build ./main.ts --target=bun --outdir ./dist",
46
+ "build:prod": "BUN_ENV=prod bun build ./main.ts --target=bun --outdir ./dist",
47
+ "start": "bun run ./dist/main.js",
48
+ "test": "BUN_ENV=test bun test",
49
+ "clean": "rm -rf dist && rm -rf node_modules"
50
+ }
51
+ }
@@ -0,0 +1 @@
1
+ // Empty schema