-
Notifications
You must be signed in to change notification settings - Fork 12.2k
Expand file tree
/
Copy pathmain.ts
More file actions
124 lines (104 loc) · 4.17 KB
/
main.ts
File metadata and controls
124 lines (104 loc) · 4.17 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
import "dotenv/config";
import { IncomingMessage, Server, ServerResponse } from "node:http";
import process from "node:process";
import { Logger } from "@nestjs/common";
import { ConfigService } from "@nestjs/config";
import { NestFactory } from "@nestjs/core";
import type { NestExpressApplication } from "@nestjs/platform-express";
import type { Express, Request, Response } from "express";
import { WinstonModule } from "nest-winston";
import * as qs from "qs";
import type { AppConfig } from "@/config/type";
import { AppModule } from "./app.module";
import { bootstrap } from "./bootstrap";
import { loggerConfig } from "./lib/logger";
const logger: Logger = new Logger("App");
/**
* Singleton Class to manage the NestJS App instance.
* Ensures we only initialize the app once per container lifecycle.
*/
class NestServer {
private static server: Express; // The underlying Express instance
private constructor() {}
/**
* Returns the cached server instance.
* If it doesn't exist, it creates, bootstraps, and initializes it.
*/
public static async getInstance(): Promise<Express> {
if (!NestServer.server) {
const app = await createNestApp();
// Execute bootstrap (Pipes, Interceptors, CORS, etc.)
bootstrap(app);
// Initialize the app (connects to DB, resolves modules)
await app.init();
// extract the Express instance to pass to Vercel
NestServer.server = app.getHttpAdapter().getInstance();
}
return NestServer.server;
}
}
// -----------------------------------------------------------------------------
// LOCAL DEVELOPMENT STARTUP
// -----------------------------------------------------------------------------
if (!process.env.VERCEL) {
console.log("CALL RUN STARTUP");
run().catch((error: Error) => {
logger.error("Failed to start Cal Platform API", { error: error.stack });
process.exit(1);
});
}
async function run(): Promise<void> {
console.log("RUN LOCAL/FlightControl STARTUP");
const app = await createNestApp();
try {
bootstrap(app);
const config = app.get(ConfigService<AppConfig, true>);
const port = config.get("api.port", { infer: true });
if (config.get("env.type", { infer: true }) === "development") {
const { generateSwaggerForApp } = await import("./swagger/generate-swagger");
generateSwaggerForApp(app);
}
await app.listen(port);
logger.log(`Application started locally on port: ${port}`);
} catch (error) {
logger.error("Application crashed during local startup", { error });
}
}
// -----------------------------------------------------------------------------
// VERCEL SERVERLESS HANDLER
// -----------------------------------------------------------------------------
export default async (req: Request, res: Response): Promise<void> => {
console.log("VERCEL SERVERLESS HANDLER", process.env.VERCEL);
try {
const server = await NestServer.getInstance();
// Vercel/AWS specific: Re-parse query strings to support array formats
// (e.g., ?ids[]=1&ids[]=2) which Vercel's native parser might simplify.
if (req.url) {
const [_path, queryString] = req.url.split("?");
if (queryString) {
req.query = qs.parse(queryString, { arrayLimit: 1000, comma: true });
}
}
// Delegate request to the cached Express instance
return server(req, res);
} catch (error) {
console.error("Critical: Failed to initialize NestJS Serverless instance", error);
res.statusCode = 500;
res.end("Internal Server Error: Initialization Failed");
}
};
// -----------------------------------------------------------------------------
// APP FACTORY
// -----------------------------------------------------------------------------
export async function createNestApp(): Promise<
NestExpressApplication<Server<typeof IncomingMessage, typeof ServerResponse>>
> {
const app = await NestFactory.create<NestExpressApplication>(AppModule, {
logger: WinstonModule.createLogger(loggerConfig()),
// Preserved as requested:
bodyParser: false,
});
// Custom query parser configuration for the underlying Express app
app.set("query parser", (str: string) => qs.parse(str, { arrayLimit: 1000, comma: true }));
return app;
}