@hazeljs/serverless 0.2.0-alpha.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.
@@ -0,0 +1,191 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ /**
16
+ * Integration tests: real HazelJS app through Lambda and Cloud Function adapters.
17
+ * No mocks of @hazeljs/core — uses real HazelApp, router, and controllers.
18
+ */
19
+ require("reflect-metadata");
20
+ const core_1 = require("@hazeljs/core");
21
+ const lambda_adapter_1 = require("./lambda.adapter");
22
+ const cloud_function_adapter_1 = require("./cloud-function.adapter");
23
+ const cold_start_optimizer_1 = require("./cold-start.optimizer");
24
+ // ─── Minimal app for integration ───────────────────────────────────────────
25
+ let IntegrationController = class IntegrationController {
26
+ ping() {
27
+ return { ok: true, message: 'pong' };
28
+ }
29
+ getById(id) {
30
+ return { id };
31
+ }
32
+ echo(body) {
33
+ return { echoed: body };
34
+ }
35
+ };
36
+ __decorate([
37
+ (0, core_1.Get)('/ping'),
38
+ __metadata("design:type", Function),
39
+ __metadata("design:paramtypes", []),
40
+ __metadata("design:returntype", void 0)
41
+ ], IntegrationController.prototype, "ping", null);
42
+ __decorate([
43
+ (0, core_1.Get)('/params/:id'),
44
+ __param(0, (0, core_1.Param)('id')),
45
+ __metadata("design:type", Function),
46
+ __metadata("design:paramtypes", [String]),
47
+ __metadata("design:returntype", void 0)
48
+ ], IntegrationController.prototype, "getById", null);
49
+ __decorate([
50
+ (0, core_1.Post)('/echo'),
51
+ __param(0, (0, core_1.Body)()),
52
+ __metadata("design:type", Function),
53
+ __metadata("design:paramtypes", [Object]),
54
+ __metadata("design:returntype", void 0)
55
+ ], IntegrationController.prototype, "echo", null);
56
+ IntegrationController = __decorate([
57
+ (0, core_1.Controller)('/api')
58
+ ], IntegrationController);
59
+ let IntegrationTestModule = class IntegrationTestModule {
60
+ };
61
+ IntegrationTestModule = __decorate([
62
+ (0, core_1.HazelModule)({
63
+ controllers: [IntegrationController],
64
+ })
65
+ ], IntegrationTestModule);
66
+ // ─── Lambda helpers ──────────────────────────────────────────────────────────
67
+ function makeLambdaEvent(overrides = {}) {
68
+ return {
69
+ httpMethod: 'GET',
70
+ path: '/api/ping',
71
+ headers: { 'content-type': 'application/json' },
72
+ queryStringParameters: null,
73
+ body: null,
74
+ isBase64Encoded: false,
75
+ ...overrides,
76
+ };
77
+ }
78
+ function makeLambdaContext(overrides = {}) {
79
+ return {
80
+ awsRequestId: 'int-test-req-1',
81
+ invokedFunctionArn: 'arn:aws:lambda:us-east-1:000:function:integration-test',
82
+ functionName: 'integration-test',
83
+ functionVersion: '$LATEST',
84
+ getRemainingTimeInMillis: () => 30000,
85
+ callbackWaitsForEmptyEventLoop: true,
86
+ ...overrides,
87
+ };
88
+ }
89
+ // ─── Cloud Function helpers ──────────────────────────────────────────────────
90
+ function makeCloudReq(overrides = {}) {
91
+ return {
92
+ method: 'GET',
93
+ url: '/api/ping',
94
+ path: '/api/ping',
95
+ headers: { 'content-type': 'application/json' },
96
+ query: {},
97
+ ...overrides,
98
+ };
99
+ }
100
+ function makeCloudRes() {
101
+ const state = {
102
+ _status: 200,
103
+ _body: undefined,
104
+ _headers: {},
105
+ };
106
+ return Object.assign(state, {
107
+ status(code) {
108
+ state._status = code;
109
+ return this;
110
+ },
111
+ set(field, value) {
112
+ state._headers[field] = value;
113
+ return this;
114
+ },
115
+ send(body) {
116
+ state._body = body;
117
+ },
118
+ json(body) {
119
+ state._body = body;
120
+ },
121
+ end() { },
122
+ });
123
+ }
124
+ // ─── Integration tests ───────────────────────────────────────────────────────
125
+ describe('integration (real HazelApp)', () => {
126
+ beforeEach(() => {
127
+ cold_start_optimizer_1.ColdStartOptimizer.getInstance().reset();
128
+ });
129
+ describe('createLambdaHandler', () => {
130
+ const handler = (0, lambda_adapter_1.createLambdaHandler)(IntegrationTestModule);
131
+ it('GET /api/ping returns 200 and pong', async () => {
132
+ const result = await handler(makeLambdaEvent({ httpMethod: 'GET', path: '/api/ping' }), makeLambdaContext());
133
+ expect(result.statusCode).toBe(200);
134
+ const data = JSON.parse(result.body);
135
+ expect(data).toEqual({ ok: true, message: 'pong' });
136
+ });
137
+ it('GET /api/params/123 returns 200 and id', async () => {
138
+ const result = await handler(makeLambdaEvent({
139
+ httpMethod: 'GET',
140
+ path: '/api/params/123',
141
+ pathParameters: { id: '123' },
142
+ }), makeLambdaContext());
143
+ expect(result.statusCode).toBe(200);
144
+ const data = JSON.parse(result.body);
145
+ expect(data).toEqual({ id: '123' });
146
+ });
147
+ it('POST /api/echo returns 200 and echoed body', async () => {
148
+ const result = await handler(makeLambdaEvent({
149
+ httpMethod: 'POST',
150
+ path: '/api/echo',
151
+ body: JSON.stringify({ x: 1, text: 'hello' }),
152
+ }), makeLambdaContext());
153
+ expect(result.statusCode).toBe(200);
154
+ const data = JSON.parse(result.body);
155
+ expect(data).toEqual({ echoed: { x: 1, text: 'hello' } });
156
+ });
157
+ it('GET /api/missing returns 404', async () => {
158
+ const result = await handler(makeLambdaEvent({ httpMethod: 'GET', path: '/api/missing' }), makeLambdaContext());
159
+ expect(result.statusCode).toBe(404);
160
+ const data = JSON.parse(result.body);
161
+ expect(data.message).toBe('Route not found');
162
+ });
163
+ });
164
+ describe('createCloudFunctionHandler', () => {
165
+ const handler = (0, cloud_function_adapter_1.createCloudFunctionHandler)(IntegrationTestModule);
166
+ it('GET /api/ping returns 200 and pong', async () => {
167
+ const res = makeCloudRes();
168
+ await handler(makeCloudReq({ method: 'GET', url: '/api/ping', path: '/api/ping' }), res);
169
+ expect(res._status).toBe(200);
170
+ const body = typeof res._body === 'string' ? JSON.parse(res._body) : res._body;
171
+ expect(body).toEqual({ ok: true, message: 'pong' });
172
+ });
173
+ it('POST /api/echo returns 200 and echoed body', async () => {
174
+ const res = makeCloudRes();
175
+ await handler(makeCloudReq({
176
+ method: 'POST',
177
+ url: '/api/echo',
178
+ path: '/api/echo',
179
+ body: { x: 2, text: 'world' },
180
+ }), res);
181
+ expect(res._status).toBe(200);
182
+ const body = typeof res._body === 'string' ? JSON.parse(res._body) : res._body;
183
+ expect(body).toEqual({ echoed: { x: 2, text: 'world' } });
184
+ });
185
+ it('GET /api/missing returns 404', async () => {
186
+ const res = makeCloudRes();
187
+ await handler(makeCloudReq({ method: 'GET', url: '/api/missing', path: '/api/missing' }), res);
188
+ expect(res._status).toBe(404);
189
+ });
190
+ });
191
+ });
@@ -0,0 +1,102 @@
1
+ import { HazelApp } from '@hazeljs/core';
2
+ import { Type } from '@hazeljs/core';
3
+ import { ServerlessEvent, ServerlessResponse, ServerlessContext } from './serverless.decorator';
4
+ /**
5
+ * AWS Lambda event types
6
+ */
7
+ export interface LambdaEvent extends ServerlessEvent {
8
+ resource?: string;
9
+ pathParameters?: Record<string, string>;
10
+ stageVariables?: Record<string, string>;
11
+ requestContext?: {
12
+ accountId: string;
13
+ apiId: string;
14
+ protocol: string;
15
+ httpMethod: string;
16
+ path: string;
17
+ stage: string;
18
+ requestId: string;
19
+ requestTime: string;
20
+ requestTimeEpoch: number;
21
+ identity: {
22
+ sourceIp: string;
23
+ userAgent: string;
24
+ };
25
+ };
26
+ }
27
+ /**
28
+ * AWS Lambda context
29
+ */
30
+ export interface LambdaContext extends ServerlessContext {
31
+ awsRequestId: string;
32
+ invokedFunctionArn: string;
33
+ callbackWaitsForEmptyEventLoop: boolean;
34
+ }
35
+ /**
36
+ * Options for createLambdaHandler
37
+ */
38
+ export interface LambdaHandlerOptions {
39
+ /** Called after the HazelJS app is initialized (e.g. for custom setup). */
40
+ onInit?: (app: HazelApp) => Promise<void>;
41
+ /** Called when the handler throws (e.g. for custom logging or reporting). */
42
+ onError?: (error: unknown) => void;
43
+ /** MIME types (e.g. 'image/png', 'image/*') that trigger base64 encoding of Buffer body for Lambda. */
44
+ binaryMimeTypes?: string[];
45
+ }
46
+ /**
47
+ * Lambda adapter for HazelJS
48
+ */
49
+ export declare class LambdaAdapter {
50
+ private moduleClass;
51
+ private options;
52
+ private app?;
53
+ private optimizer;
54
+ private isColdStart;
55
+ constructor(moduleClass: Type<unknown>, options?: LambdaHandlerOptions);
56
+ /**
57
+ * Initialize the HazelJS application
58
+ */
59
+ private initialize;
60
+ /**
61
+ * Create Lambda handler
62
+ */
63
+ createHandler(): (event: LambdaEvent, context: LambdaContext) => Promise<ServerlessResponse>;
64
+ /**
65
+ * Convert Lambda event to HTTP request format
66
+ */
67
+ private convertLambdaEventToRequest;
68
+ /**
69
+ * Parse request body
70
+ */
71
+ private parseBody;
72
+ /**
73
+ * Process request through HazelJS router
74
+ */
75
+ private processRequest;
76
+ /**
77
+ * Whether the given Content-Type matches any of the binaryMimeTypes patterns.
78
+ */
79
+ private isBinaryContentType;
80
+ /**
81
+ * Get application instance
82
+ */
83
+ getApp(): HazelApp | undefined;
84
+ /**
85
+ * Check if this is a cold start
86
+ */
87
+ isCold(): boolean;
88
+ }
89
+ /**
90
+ * Create a Lambda handler for a HazelJS module
91
+ *
92
+ * @example
93
+ * ```typescript
94
+ * // handler.ts
95
+ * import { createLambdaHandler } from '@hazeljs/core';
96
+ * import { AppModule } from './app.module';
97
+ *
98
+ * export const handler = createLambdaHandler(AppModule);
99
+ * ```
100
+ */
101
+ export declare function createLambdaHandler(moduleClass: Type<unknown>, options?: LambdaHandlerOptions): (event: LambdaEvent, context: LambdaContext) => Promise<ServerlessResponse>;
102
+ //# sourceMappingURL=lambda.adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lambda.adapter.d.ts","sourceRoot":"","sources":["../src/lambda.adapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAErC,OAAO,EACL,eAAe,EACf,kBAAkB,EAClB,iBAAiB,EAElB,MAAM,wBAAwB,CAAC;AAGhC;;GAEG;AACH,MAAM,WAAW,WAAY,SAAQ,eAAe;IAClD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,cAAc,CAAC,EAAE;QACf,SAAS,EAAE,MAAM,CAAC;QAClB,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,EAAE,MAAM,CAAC;QACjB,UAAU,EAAE,MAAM,CAAC;QACnB,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;QACd,SAAS,EAAE,MAAM,CAAC;QAClB,WAAW,EAAE,MAAM,CAAC;QACpB,gBAAgB,EAAE,MAAM,CAAC;QACzB,QAAQ,EAAE;YACR,QAAQ,EAAE,MAAM,CAAC;YACjB,SAAS,EAAE,MAAM,CAAC;SACnB,CAAC;KACH,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,aAAc,SAAQ,iBAAiB;IACtD,YAAY,EAAE,MAAM,CAAC;IACrB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,8BAA8B,EAAE,OAAO,CAAC;CACzC;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,2EAA2E;IAC3E,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,QAAQ,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1C,6EAA6E;IAC7E,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACnC,uGAAuG;IACvG,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;CAC5B;AAED;;GAEG;AACH,qBAAa,aAAa;IAMtB,OAAO,CAAC,WAAW;IACnB,OAAO,CAAC,OAAO;IANjB,OAAO,CAAC,GAAG,CAAC,CAAW;IACvB,OAAO,CAAC,SAAS,CAAqB;IACtC,OAAO,CAAC,WAAW,CAAQ;gBAGjB,WAAW,EAAE,IAAI,CAAC,OAAO,CAAC,EAC1B,OAAO,GAAE,oBAAyB;IAK5C;;OAEG;YACW,UAAU;IAyBxB;;OAEG;IACH,aAAa,KACG,OAAO,WAAW,EAAE,SAAS,aAAa,KAAG,OAAO,CAAC,kBAAkB,CAAC;IAmCxF;;OAEG;IACH,OAAO,CAAC,2BAA2B;IA+BnC;;OAEG;IACH,OAAO,CAAC,SAAS;IAYjB;;OAEG;YACW,cAAc;IAqI5B;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAc3B;;OAEG;IACH,MAAM,IAAI,QAAQ,GAAG,SAAS;IAI9B;;OAEG;IACH,MAAM,IAAI,OAAO;CAGlB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CACjC,WAAW,EAAE,IAAI,CAAC,OAAO,CAAC,EAC1B,OAAO,CAAC,EAAE,oBAAoB,GAC7B,CAAC,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,aAAa,KAAK,OAAO,CAAC,kBAAkB,CAAC,CAG7E"}
@@ -0,0 +1,258 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.LambdaAdapter = void 0;
7
+ exports.createLambdaHandler = createLambdaHandler;
8
+ const core_1 = require("@hazeljs/core");
9
+ const core_2 = __importDefault(require("@hazeljs/core"));
10
+ const serverless_decorator_1 = require("./serverless.decorator");
11
+ const cold_start_optimizer_1 = require("./cold-start.optimizer");
12
+ /**
13
+ * Lambda adapter for HazelJS
14
+ */
15
+ class LambdaAdapter {
16
+ constructor(moduleClass, options = {}) {
17
+ this.moduleClass = moduleClass;
18
+ this.options = options;
19
+ this.isColdStart = true;
20
+ this.optimizer = cold_start_optimizer_1.ColdStartOptimizer.getInstance();
21
+ }
22
+ /**
23
+ * Initialize the HazelJS application
24
+ */
25
+ async initialize() {
26
+ if (this.app) {
27
+ return;
28
+ }
29
+ const startTime = Date.now();
30
+ core_2.default.info('Initializing HazelJS application for Lambda...');
31
+ // Check if cold start optimization is enabled
32
+ const metadata = (0, serverless_decorator_1.getServerlessMetadata)(this.moduleClass);
33
+ if (metadata?.coldStartOptimization) {
34
+ await this.optimizer.warmUp();
35
+ }
36
+ // Create HazelJS application
37
+ this.app = new core_1.HazelApp(this.moduleClass);
38
+ if (this.options.onInit && this.app) {
39
+ await this.options.onInit(this.app);
40
+ }
41
+ const duration = Date.now() - startTime;
42
+ core_2.default.info(`Lambda initialization completed in ${duration}ms`);
43
+ }
44
+ /**
45
+ * Create Lambda handler
46
+ */
47
+ createHandler() {
48
+ return async (event, context) => {
49
+ try {
50
+ // Log cold start
51
+ if (this.isColdStart) {
52
+ core_2.default.info('Lambda cold start detected');
53
+ this.isColdStart = false;
54
+ }
55
+ // Initialize application
56
+ await this.initialize();
57
+ // Convert Lambda event to HTTP request
58
+ const request = this.convertLambdaEventToRequest(event, context);
59
+ // Process request through HazelJS
60
+ const response = await this.processRequest(request);
61
+ return response;
62
+ }
63
+ catch (error) {
64
+ this.options.onError?.(error);
65
+ core_2.default.error('Lambda handler error:', error);
66
+ return {
67
+ statusCode: 500,
68
+ body: JSON.stringify({
69
+ error: 'Internal Server Error',
70
+ message: error instanceof Error ? error.message : 'Unknown error',
71
+ }),
72
+ headers: {
73
+ 'Content-Type': 'application/json',
74
+ },
75
+ };
76
+ }
77
+ };
78
+ }
79
+ /**
80
+ * Convert Lambda event to HTTP request format
81
+ */
82
+ convertLambdaEventToRequest(event, context) {
83
+ return {
84
+ method: event.httpMethod || 'GET',
85
+ url: event.path || '/',
86
+ headers: event.headers || {},
87
+ query: event.queryStringParameters || {},
88
+ params: event.pathParameters || {},
89
+ body: event.body ? this.parseBody(event.body, event.isBase64Encoded) : undefined,
90
+ context: {
91
+ requestId: context.awsRequestId,
92
+ functionName: context.functionName,
93
+ remainingTime: context.getRemainingTimeInMillis(),
94
+ },
95
+ };
96
+ }
97
+ /**
98
+ * Parse request body
99
+ */
100
+ parseBody(body, isBase64Encoded) {
101
+ try {
102
+ if (isBase64Encoded) {
103
+ const decoded = Buffer.from(body, 'base64').toString('utf-8');
104
+ return JSON.parse(decoded);
105
+ }
106
+ return JSON.parse(body);
107
+ }
108
+ catch {
109
+ return body;
110
+ }
111
+ }
112
+ /**
113
+ * Process request through HazelJS router
114
+ */
115
+ async processRequest(request) {
116
+ if (!this.app) {
117
+ return {
118
+ statusCode: 500,
119
+ body: JSON.stringify({ message: 'Application not initialized' }),
120
+ headers: { 'Content-Type': 'application/json' },
121
+ };
122
+ }
123
+ const router = this.app.getRouter();
124
+ // Build request context for the router
125
+ const context = {
126
+ method: request.method,
127
+ url: request.url,
128
+ headers: request.headers,
129
+ query: request.query,
130
+ params: request.params,
131
+ body: request.body,
132
+ requestId: request.context.requestId,
133
+ };
134
+ try {
135
+ const route = await router.match(request.method, request.url, context);
136
+ if (!route) {
137
+ return {
138
+ statusCode: 404,
139
+ body: JSON.stringify({ statusCode: 404, message: 'Route not found' }),
140
+ headers: { 'Content-Type': 'application/json' },
141
+ };
142
+ }
143
+ // Create a synthetic request/response to capture the handler output
144
+ const syntheticReq = {
145
+ method: request.method,
146
+ url: request.url,
147
+ headers: request.headers,
148
+ query: request.query,
149
+ params: route.context?.params ?? context.params ?? {},
150
+ body: request.body,
151
+ };
152
+ let responseBody;
153
+ let responseStatus = 200;
154
+ const responseHeaders = { 'Content-Type': 'application/json' };
155
+ const syntheticRes = {
156
+ statusCode: 200,
157
+ status(code) {
158
+ responseStatus = code;
159
+ return syntheticRes;
160
+ },
161
+ json(data) {
162
+ responseBody = data;
163
+ responseStatus = responseStatus || 200;
164
+ },
165
+ send(data) {
166
+ responseBody = data;
167
+ },
168
+ setHeader(key, value) {
169
+ responseHeaders[key] = value;
170
+ },
171
+ getHeader(key) {
172
+ return responseHeaders[key];
173
+ },
174
+ };
175
+ const result = await route.handler(syntheticReq, syntheticRes, route.context);
176
+ // If handler returned a value directly, use it
177
+ if (result !== undefined && responseBody === undefined) {
178
+ responseBody = result;
179
+ }
180
+ const contentType = responseHeaders['content-type'] ?? responseHeaders['Content-Type'] ?? '';
181
+ const isBinary = this.options.binaryMimeTypes?.length &&
182
+ this.isBinaryContentType(contentType) &&
183
+ (Buffer.isBuffer(responseBody) || responseBody instanceof Uint8Array);
184
+ let body;
185
+ let isBase64Encoded = false;
186
+ if (isBinary) {
187
+ body = Buffer.from(responseBody).toString('base64');
188
+ isBase64Encoded = true;
189
+ }
190
+ else {
191
+ body = typeof responseBody === 'string' ? responseBody : JSON.stringify(responseBody);
192
+ }
193
+ return {
194
+ statusCode: responseStatus,
195
+ body,
196
+ headers: responseHeaders,
197
+ ...(isBase64Encoded && { isBase64Encoded: true }),
198
+ };
199
+ }
200
+ catch (error) {
201
+ const statusCode = error.statusCode || 500;
202
+ const message = error instanceof Error ? error.message : 'Internal Server Error';
203
+ return {
204
+ statusCode,
205
+ body: JSON.stringify({ statusCode, message }),
206
+ headers: { 'Content-Type': 'application/json' },
207
+ };
208
+ }
209
+ }
210
+ /**
211
+ * Whether the given Content-Type matches any of the binaryMimeTypes patterns.
212
+ */
213
+ isBinaryContentType(contentType) {
214
+ if (!this.options.binaryMimeTypes?.length || !contentType)
215
+ return false;
216
+ const ct = contentType.split(';')[0].trim().toLowerCase();
217
+ for (const pattern of this.options.binaryMimeTypes) {
218
+ const p = pattern.toLowerCase();
219
+ if (p.endsWith('/*')) {
220
+ if (ct.startsWith(p.slice(0, -1)))
221
+ return true;
222
+ }
223
+ else if (ct === p || ct.startsWith(p + '/')) {
224
+ return true;
225
+ }
226
+ }
227
+ return false;
228
+ }
229
+ /**
230
+ * Get application instance
231
+ */
232
+ getApp() {
233
+ return this.app;
234
+ }
235
+ /**
236
+ * Check if this is a cold start
237
+ */
238
+ isCold() {
239
+ return this.isColdStart;
240
+ }
241
+ }
242
+ exports.LambdaAdapter = LambdaAdapter;
243
+ /**
244
+ * Create a Lambda handler for a HazelJS module
245
+ *
246
+ * @example
247
+ * ```typescript
248
+ * // handler.ts
249
+ * import { createLambdaHandler } from '@hazeljs/core';
250
+ * import { AppModule } from './app.module';
251
+ *
252
+ * export const handler = createLambdaHandler(AppModule);
253
+ * ```
254
+ */
255
+ function createLambdaHandler(moduleClass, options) {
256
+ const adapter = new LambdaAdapter(moduleClass, options ?? {});
257
+ return adapter.createHandler();
258
+ }