@hazeljs/serverless 0.2.0-beta.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.
- package/README.md +500 -0
- package/dist/cloud-function.adapter.d.ts +97 -0
- package/dist/cloud-function.adapter.d.ts.map +1 -0
- package/dist/cloud-function.adapter.js +252 -0
- package/dist/cold-start.optimizer.d.ts +67 -0
- package/dist/cold-start.optimizer.d.ts.map +1 -0
- package/dist/cold-start.optimizer.js +202 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +21 -0
- package/dist/lambda.adapter.d.ts +86 -0
- package/dist/lambda.adapter.d.ts.map +1 -0
- package/dist/lambda.adapter.js +208 -0
- package/dist/serverless.decorator.d.ts +166 -0
- package/dist/serverless.decorator.d.ts.map +1 -0
- package/dist/serverless.decorator.js +56 -0
- package/package.json +47 -0
|
@@ -0,0 +1,208 @@
|
|
|
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) {
|
|
17
|
+
this.moduleClass = moduleClass;
|
|
18
|
+
this.isColdStart = true;
|
|
19
|
+
this.optimizer = cold_start_optimizer_1.ColdStartOptimizer.getInstance();
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Initialize the HazelJS application
|
|
23
|
+
*/
|
|
24
|
+
async initialize() {
|
|
25
|
+
if (this.app) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const startTime = Date.now();
|
|
29
|
+
core_2.default.info('Initializing HazelJS application for Lambda...');
|
|
30
|
+
// Check if cold start optimization is enabled
|
|
31
|
+
const metadata = (0, serverless_decorator_1.getServerlessMetadata)(this.moduleClass);
|
|
32
|
+
if (metadata?.coldStartOptimization) {
|
|
33
|
+
await this.optimizer.warmUp();
|
|
34
|
+
}
|
|
35
|
+
// Create HazelJS application
|
|
36
|
+
this.app = new core_1.HazelApp(this.moduleClass);
|
|
37
|
+
const duration = Date.now() - startTime;
|
|
38
|
+
core_2.default.info(`Lambda initialization completed in ${duration}ms`);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Create Lambda handler
|
|
42
|
+
*/
|
|
43
|
+
createHandler() {
|
|
44
|
+
return async (event, context) => {
|
|
45
|
+
try {
|
|
46
|
+
// Log cold start
|
|
47
|
+
if (this.isColdStart) {
|
|
48
|
+
core_2.default.info('Lambda cold start detected');
|
|
49
|
+
this.isColdStart = false;
|
|
50
|
+
}
|
|
51
|
+
// Initialize application
|
|
52
|
+
await this.initialize();
|
|
53
|
+
// Convert Lambda event to HTTP request
|
|
54
|
+
const request = this.convertLambdaEventToRequest(event, context);
|
|
55
|
+
// Process request through HazelJS
|
|
56
|
+
const response = await this.processRequest(request);
|
|
57
|
+
return response;
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
core_2.default.error('Lambda handler error:', error);
|
|
61
|
+
return {
|
|
62
|
+
statusCode: 500,
|
|
63
|
+
body: JSON.stringify({
|
|
64
|
+
error: 'Internal Server Error',
|
|
65
|
+
message: error instanceof Error ? error.message : 'Unknown error',
|
|
66
|
+
}),
|
|
67
|
+
headers: {
|
|
68
|
+
'Content-Type': 'application/json',
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Convert Lambda event to HTTP request format
|
|
76
|
+
*/
|
|
77
|
+
convertLambdaEventToRequest(event, context) {
|
|
78
|
+
return {
|
|
79
|
+
method: event.httpMethod || 'GET',
|
|
80
|
+
url: event.path || '/',
|
|
81
|
+
headers: event.headers || {},
|
|
82
|
+
query: event.queryStringParameters || {},
|
|
83
|
+
params: event.pathParameters || {},
|
|
84
|
+
body: event.body ? this.parseBody(event.body, event.isBase64Encoded) : undefined,
|
|
85
|
+
context: {
|
|
86
|
+
requestId: context.awsRequestId,
|
|
87
|
+
functionName: context.functionName,
|
|
88
|
+
remainingTime: context.getRemainingTimeInMillis(),
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Parse request body
|
|
94
|
+
*/
|
|
95
|
+
parseBody(body, isBase64Encoded) {
|
|
96
|
+
try {
|
|
97
|
+
if (isBase64Encoded) {
|
|
98
|
+
const decoded = Buffer.from(body, 'base64').toString('utf-8');
|
|
99
|
+
return JSON.parse(decoded);
|
|
100
|
+
}
|
|
101
|
+
return JSON.parse(body);
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
return body;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Process request through HazelJS router
|
|
109
|
+
*/
|
|
110
|
+
async processRequest(request) {
|
|
111
|
+
if (!this.app) {
|
|
112
|
+
return {
|
|
113
|
+
statusCode: 500,
|
|
114
|
+
body: JSON.stringify({ message: 'Application not initialized' }),
|
|
115
|
+
headers: { 'Content-Type': 'application/json' },
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
const router = this.app.getRouter();
|
|
119
|
+
// Build request context for the router
|
|
120
|
+
const context = {
|
|
121
|
+
method: request.method,
|
|
122
|
+
url: request.url,
|
|
123
|
+
headers: request.headers,
|
|
124
|
+
query: request.query,
|
|
125
|
+
params: request.params,
|
|
126
|
+
body: request.body,
|
|
127
|
+
requestId: request.context.requestId,
|
|
128
|
+
};
|
|
129
|
+
try {
|
|
130
|
+
const route = await router.match(request.method, request.url, context);
|
|
131
|
+
if (!route) {
|
|
132
|
+
return {
|
|
133
|
+
statusCode: 404,
|
|
134
|
+
body: JSON.stringify({ statusCode: 404, message: 'Route not found' }),
|
|
135
|
+
headers: { 'Content-Type': 'application/json' },
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
// Create a synthetic request/response to capture the handler output
|
|
139
|
+
const syntheticReq = {
|
|
140
|
+
method: request.method,
|
|
141
|
+
url: request.url,
|
|
142
|
+
headers: request.headers,
|
|
143
|
+
query: request.query,
|
|
144
|
+
params: context.params || {},
|
|
145
|
+
body: request.body,
|
|
146
|
+
};
|
|
147
|
+
let responseBody;
|
|
148
|
+
let responseStatus = 200;
|
|
149
|
+
const responseHeaders = { 'Content-Type': 'application/json' };
|
|
150
|
+
const syntheticRes = {
|
|
151
|
+
statusCode: 200,
|
|
152
|
+
status(code) { responseStatus = code; return syntheticRes; },
|
|
153
|
+
json(data) { responseBody = data; responseStatus = responseStatus || 200; },
|
|
154
|
+
send(data) { responseBody = data; },
|
|
155
|
+
setHeader(key, value) { responseHeaders[key] = value; },
|
|
156
|
+
getHeader(key) { return responseHeaders[key]; },
|
|
157
|
+
};
|
|
158
|
+
const result = await route.handler(syntheticReq, syntheticRes);
|
|
159
|
+
// If handler returned a value directly, use it
|
|
160
|
+
if (result !== undefined && responseBody === undefined) {
|
|
161
|
+
responseBody = result;
|
|
162
|
+
}
|
|
163
|
+
return {
|
|
164
|
+
statusCode: responseStatus,
|
|
165
|
+
body: typeof responseBody === 'string' ? responseBody : JSON.stringify(responseBody),
|
|
166
|
+
headers: responseHeaders,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
catch (error) {
|
|
170
|
+
const statusCode = error.statusCode || 500;
|
|
171
|
+
const message = error instanceof Error ? error.message : 'Internal Server Error';
|
|
172
|
+
return {
|
|
173
|
+
statusCode,
|
|
174
|
+
body: JSON.stringify({ statusCode, message }),
|
|
175
|
+
headers: { 'Content-Type': 'application/json' },
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Get application instance
|
|
181
|
+
*/
|
|
182
|
+
getApp() {
|
|
183
|
+
return this.app;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Check if this is a cold start
|
|
187
|
+
*/
|
|
188
|
+
isCold() {
|
|
189
|
+
return this.isColdStart;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
exports.LambdaAdapter = LambdaAdapter;
|
|
193
|
+
/**
|
|
194
|
+
* Create a Lambda handler for a HazelJS module
|
|
195
|
+
*
|
|
196
|
+
* @example
|
|
197
|
+
* ```typescript
|
|
198
|
+
* // handler.ts
|
|
199
|
+
* import { createLambdaHandler } from '@hazeljs/core';
|
|
200
|
+
* import { AppModule } from './app.module';
|
|
201
|
+
*
|
|
202
|
+
* export const handler = createLambdaHandler(AppModule);
|
|
203
|
+
* ```
|
|
204
|
+
*/
|
|
205
|
+
function createLambdaHandler(moduleClass) {
|
|
206
|
+
const adapter = new LambdaAdapter(moduleClass);
|
|
207
|
+
return adapter.createHandler();
|
|
208
|
+
}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
/**
|
|
3
|
+
* Serverless configuration options
|
|
4
|
+
*/
|
|
5
|
+
export interface ServerlessOptions {
|
|
6
|
+
/**
|
|
7
|
+
* Memory allocation in MB
|
|
8
|
+
* @default 512
|
|
9
|
+
*/
|
|
10
|
+
memory?: number;
|
|
11
|
+
/**
|
|
12
|
+
* Timeout in seconds
|
|
13
|
+
* @default 30
|
|
14
|
+
*/
|
|
15
|
+
timeout?: number;
|
|
16
|
+
/**
|
|
17
|
+
* Enable cold start optimization
|
|
18
|
+
* @default true
|
|
19
|
+
*/
|
|
20
|
+
coldStartOptimization?: boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Environment variables
|
|
23
|
+
*/
|
|
24
|
+
environment?: Record<string, string>;
|
|
25
|
+
/**
|
|
26
|
+
* Runtime platform
|
|
27
|
+
*/
|
|
28
|
+
runtime?: 'aws-lambda' | 'gcp-functions' | 'azure-functions' | 'cloudflare-workers';
|
|
29
|
+
/**
|
|
30
|
+
* Enable automatic function splitting
|
|
31
|
+
* @default false
|
|
32
|
+
*/
|
|
33
|
+
autoSplit?: boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Reserved concurrent executions (AWS Lambda)
|
|
36
|
+
*/
|
|
37
|
+
reservedConcurrency?: number;
|
|
38
|
+
/**
|
|
39
|
+
* Provisioned concurrency (AWS Lambda)
|
|
40
|
+
*/
|
|
41
|
+
provisionedConcurrency?: number;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Decorator to mark a controller as serverless-optimized
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```typescript
|
|
48
|
+
* @Serverless({
|
|
49
|
+
* memory: 512,
|
|
50
|
+
* timeout: 30,
|
|
51
|
+
* coldStartOptimization: true
|
|
52
|
+
* })
|
|
53
|
+
* @Controller('/lambda')
|
|
54
|
+
* export class LambdaController {
|
|
55
|
+
* @Get()
|
|
56
|
+
* async handler() {
|
|
57
|
+
* return { message: 'Hello from serverless!' };
|
|
58
|
+
* }
|
|
59
|
+
* }
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
export declare function Serverless(options?: ServerlessOptions): ClassDecorator;
|
|
63
|
+
/**
|
|
64
|
+
* Get serverless metadata from a class
|
|
65
|
+
*/
|
|
66
|
+
export declare function getServerlessMetadata(target: object | (new (...args: unknown[]) => object)): ServerlessOptions | undefined;
|
|
67
|
+
/**
|
|
68
|
+
* Check if a class is marked as serverless
|
|
69
|
+
*/
|
|
70
|
+
export declare function isServerless(target: object | (new (...args: unknown[]) => object)): boolean;
|
|
71
|
+
/**
|
|
72
|
+
* Serverless function handler type
|
|
73
|
+
*/
|
|
74
|
+
export type ServerlessHandler<TEvent = unknown, TResult = unknown> = (event: TEvent, context: ServerlessContext) => Promise<TResult> | TResult;
|
|
75
|
+
/**
|
|
76
|
+
* Serverless execution context
|
|
77
|
+
*/
|
|
78
|
+
export interface ServerlessContext {
|
|
79
|
+
/**
|
|
80
|
+
* Request ID
|
|
81
|
+
*/
|
|
82
|
+
requestId: string;
|
|
83
|
+
/**
|
|
84
|
+
* Function name
|
|
85
|
+
*/
|
|
86
|
+
functionName: string;
|
|
87
|
+
/**
|
|
88
|
+
* Function version
|
|
89
|
+
*/
|
|
90
|
+
functionVersion: string;
|
|
91
|
+
/**
|
|
92
|
+
* Memory limit in MB
|
|
93
|
+
*/
|
|
94
|
+
memoryLimitInMB: number;
|
|
95
|
+
/**
|
|
96
|
+
* Remaining time in milliseconds
|
|
97
|
+
*/
|
|
98
|
+
getRemainingTimeInMillis(): number;
|
|
99
|
+
/**
|
|
100
|
+
* Log stream name
|
|
101
|
+
*/
|
|
102
|
+
logStreamName?: string;
|
|
103
|
+
/**
|
|
104
|
+
* Log group name
|
|
105
|
+
*/
|
|
106
|
+
logGroupName?: string;
|
|
107
|
+
/**
|
|
108
|
+
* Additional platform-specific context
|
|
109
|
+
*/
|
|
110
|
+
[key: string]: unknown;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Serverless event types
|
|
114
|
+
*/
|
|
115
|
+
export interface ServerlessEvent {
|
|
116
|
+
/**
|
|
117
|
+
* HTTP method
|
|
118
|
+
*/
|
|
119
|
+
httpMethod?: string;
|
|
120
|
+
/**
|
|
121
|
+
* Request path
|
|
122
|
+
*/
|
|
123
|
+
path?: string;
|
|
124
|
+
/**
|
|
125
|
+
* Query parameters
|
|
126
|
+
*/
|
|
127
|
+
queryStringParameters?: Record<string, string>;
|
|
128
|
+
/**
|
|
129
|
+
* Headers
|
|
130
|
+
*/
|
|
131
|
+
headers?: Record<string, string>;
|
|
132
|
+
/**
|
|
133
|
+
* Request body
|
|
134
|
+
*/
|
|
135
|
+
body?: string;
|
|
136
|
+
/**
|
|
137
|
+
* Is base64 encoded
|
|
138
|
+
*/
|
|
139
|
+
isBase64Encoded?: boolean;
|
|
140
|
+
/**
|
|
141
|
+
* Additional platform-specific event data
|
|
142
|
+
*/
|
|
143
|
+
[key: string]: unknown;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Serverless response
|
|
147
|
+
*/
|
|
148
|
+
export interface ServerlessResponse {
|
|
149
|
+
/**
|
|
150
|
+
* Status code
|
|
151
|
+
*/
|
|
152
|
+
statusCode: number;
|
|
153
|
+
/**
|
|
154
|
+
* Response headers
|
|
155
|
+
*/
|
|
156
|
+
headers?: Record<string, string>;
|
|
157
|
+
/**
|
|
158
|
+
* Response body
|
|
159
|
+
*/
|
|
160
|
+
body: string;
|
|
161
|
+
/**
|
|
162
|
+
* Is base64 encoded
|
|
163
|
+
*/
|
|
164
|
+
isBase64Encoded?: boolean;
|
|
165
|
+
}
|
|
166
|
+
//# sourceMappingURL=serverless.decorator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serverless.decorator.d.ts","sourceRoot":"","sources":["../src/serverless.decorator.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAG1B;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;;OAGG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAEhC;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAErC;;OAEG;IACH,OAAO,CAAC,EAAE,YAAY,GAAG,eAAe,GAAG,iBAAiB,GAAG,oBAAoB,CAAC;IAEpF;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB;;OAEG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAE7B;;OAEG;IACH,sBAAsB,CAAC,EAAE,MAAM,CAAC;CACjC;AAID;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,UAAU,CAAC,OAAO,GAAE,iBAAsB,GAAG,cAAc,CAc1E;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,MAAM,GAAG,CAAC,KAAK,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,MAAM,CAAC,GACpD,iBAAiB,GAAG,SAAS,CAE/B;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,CAAC,KAAK,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,MAAM,CAAC,GAAG,OAAO,CAE3F;AAED;;GAEG;AACH,MAAM,MAAM,iBAAiB,CAAC,MAAM,GAAG,OAAO,EAAE,OAAO,GAAG,OAAO,IAAI,CACnE,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,iBAAiB,KACvB,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;AAEhC;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,YAAY,EAAE,MAAM,CAAC;IAErB;;OAEG;IACH,eAAe,EAAE,MAAM,CAAC;IAExB;;OAEG;IACH,eAAe,EAAE,MAAM,CAAC;IAExB;;OAEG;IACH,wBAAwB,IAAI,MAAM,CAAC;IAEnC;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;OAEG;IACH,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,qBAAqB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAE/C;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEjC;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAE1B;;OAEG;IACH,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEjC;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;OAEG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B"}
|
|
@@ -0,0 +1,56 @@
|
|
|
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.Serverless = Serverless;
|
|
7
|
+
exports.getServerlessMetadata = getServerlessMetadata;
|
|
8
|
+
exports.isServerless = isServerless;
|
|
9
|
+
require("reflect-metadata");
|
|
10
|
+
const core_1 = __importDefault(require("@hazeljs/core"));
|
|
11
|
+
const SERVERLESS_METADATA_KEY = 'hazel:serverless';
|
|
12
|
+
/**
|
|
13
|
+
* Decorator to mark a controller as serverless-optimized
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```typescript
|
|
17
|
+
* @Serverless({
|
|
18
|
+
* memory: 512,
|
|
19
|
+
* timeout: 30,
|
|
20
|
+
* coldStartOptimization: true
|
|
21
|
+
* })
|
|
22
|
+
* @Controller('/lambda')
|
|
23
|
+
* export class LambdaController {
|
|
24
|
+
* @Get()
|
|
25
|
+
* async handler() {
|
|
26
|
+
* return { message: 'Hello from serverless!' };
|
|
27
|
+
* }
|
|
28
|
+
* }
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
function Serverless(options = {}) {
|
|
32
|
+
return (target) => {
|
|
33
|
+
const defaults = {
|
|
34
|
+
memory: 512,
|
|
35
|
+
timeout: 30,
|
|
36
|
+
coldStartOptimization: true,
|
|
37
|
+
autoSplit: false,
|
|
38
|
+
...options,
|
|
39
|
+
};
|
|
40
|
+
const targetName = typeof target === 'function' ? target.name : 'unknown';
|
|
41
|
+
core_1.default.debug(`Marking ${targetName} as serverless with options:`, defaults);
|
|
42
|
+
Reflect.defineMetadata(SERVERLESS_METADATA_KEY, defaults, target);
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Get serverless metadata from a class
|
|
47
|
+
*/
|
|
48
|
+
function getServerlessMetadata(target) {
|
|
49
|
+
return Reflect.getMetadata(SERVERLESS_METADATA_KEY, target);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Check if a class is marked as serverless
|
|
53
|
+
*/
|
|
54
|
+
function isServerless(target) {
|
|
55
|
+
return Reflect.hasMetadata(SERVERLESS_METADATA_KEY, target);
|
|
56
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@hazeljs/serverless",
|
|
3
|
+
"version": "0.2.0-beta.1",
|
|
4
|
+
"description": "Serverless adapters (AWS Lambda, Google Cloud Functions) for HazelJS framework",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist"
|
|
9
|
+
],
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsc",
|
|
12
|
+
"test": "jest --coverage",
|
|
13
|
+
"lint": "eslint \"src/**/*.ts\"",
|
|
14
|
+
"lint:fix": "eslint \"src/**/*.ts\" --fix",
|
|
15
|
+
"clean": "rm -rf dist"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@hazeljs/core": "file:../core"
|
|
19
|
+
},
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"@types/aws-lambda": "^8.10.145",
|
|
22
|
+
"@types/node": "^20.17.50",
|
|
23
|
+
"@typescript-eslint/eslint-plugin": "^8.18.2",
|
|
24
|
+
"@typescript-eslint/parser": "^8.18.2",
|
|
25
|
+
"eslint": "^8.56.0",
|
|
26
|
+
"jest": "^29.7.0",
|
|
27
|
+
"ts-jest": "^29.1.2",
|
|
28
|
+
"typescript": "^5.3.3"
|
|
29
|
+
},
|
|
30
|
+
"publishConfig": {
|
|
31
|
+
"access": "public"
|
|
32
|
+
},
|
|
33
|
+
"repository": {
|
|
34
|
+
"type": "git",
|
|
35
|
+
"url": "git+https://github.com/hazel-js/hazeljs.git",
|
|
36
|
+
"directory": "packages/serverless"
|
|
37
|
+
},
|
|
38
|
+
"keywords": [
|
|
39
|
+
"hazeljs",
|
|
40
|
+
"serverless",
|
|
41
|
+
"lambda",
|
|
42
|
+
"cloud-functions",
|
|
43
|
+
"aws"
|
|
44
|
+
],
|
|
45
|
+
"author": "Muhammad Arslan <marslan@hazeljs.com>",
|
|
46
|
+
"license": "MIT"
|
|
47
|
+
}
|