@geek-fun/serverlessinsight 0.3.3 → 0.4.0

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.
@@ -3,36 +3,143 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.startEvents = void 0;
7
- const node_http_1 = __importDefault(require("node:http"));
8
- const common_1 = require("../../common");
6
+ exports.eventsHandler = void 0;
9
7
  const types_1 = require("../../types");
10
8
  const lodash_1 = require("lodash");
11
- const startApiGatewayServer = (event) => {
12
- const server = node_http_1.default.createServer((req, res) => {
13
- const matchedTrigger = event.triggers.find((trigger) => trigger.method === req.method && trigger.path === req.url);
14
- if (!matchedTrigger) {
15
- res.writeHead(404, { 'Content-Type': 'text/plain; charset=utf-8' });
16
- res.end('Not Found\n');
17
- common_1.logger.warn(`API Gateway Event - ${req.method} ${req.url} -> Not Found`);
18
- return;
9
+ const common_1 = require("../../common");
10
+ const function_1 = require("./function");
11
+ const aliyunFc_1 = require("./aliyunFc");
12
+ const functionRunner_1 = require("./functionRunner");
13
+ const node_path_1 = __importDefault(require("node:path"));
14
+ const node_fs_1 = __importDefault(require("node:fs"));
15
+ const utils_1 = require("./utils");
16
+ const matchTrigger = (req, trigger) => {
17
+ if (req.method !== 'ANY' && req.method !== trigger.method) {
18
+ return false;
19
+ }
20
+ const normalize = (s) => s.replace(/^\/+|\/+$/g, '');
21
+ const [pathSegments, triggerSegments] = [
22
+ normalize(req.path).split('/'),
23
+ normalize(trigger.path).split('/'),
24
+ ];
25
+ const hasWildcard = triggerSegments[triggerSegments.length - 1] === '*';
26
+ const prefixSegments = hasWildcard ? triggerSegments.slice(0, -1) : triggerSegments;
27
+ const minRequiredSegments = prefixSegments.length;
28
+ if (pathSegments.length < minRequiredSegments)
29
+ return false;
30
+ return prefixSegments.every((triggerSegment, index) => {
31
+ const pathSegment = pathSegments[index];
32
+ if (triggerSegment.startsWith('[') && triggerSegment.endsWith(']')) {
33
+ return pathSegment !== '';
19
34
  }
20
- res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' });
21
- res.end(`Invoked backend: ${matchedTrigger.backend}\n`);
22
- common_1.logger.info(`API Gateway Event - ${req.method} ${req.url} -> ${matchedTrigger.backend}`);
23
- });
24
- const port = 3000 + Math.floor(Math.random() * 1000);
25
- server.listen(port, () => {
26
- common_1.logger.info(`API Gateway "${event.name}" listening on http://localhost:${port}`);
35
+ return triggerSegment === pathSegment;
27
36
  });
28
37
  };
29
- const startEvents = (events) => {
30
- const apiGateways = events?.filter((event) => event.type === types_1.EventTypes.API_GATEWAY);
31
- if ((0, lodash_1.isEmpty)(apiGateways)) {
32
- return;
38
+ const servEvent = async (req, parsed, iac) => {
39
+ const startTime = new Date();
40
+ const requestId = (0, aliyunFc_1.generateRequestId)();
41
+ const sourceIp = req.socket?.remoteAddress || '127.0.0.1';
42
+ const isAliyun = iac.provider.name === common_1.ProviderEnum.ALIYUN;
43
+ const event = iac.events?.find((event) => event.type === types_1.EventTypes.API_GATEWAY && event.key === parsed.identifier);
44
+ if ((0, lodash_1.isEmpty)(event)) {
45
+ return {
46
+ statusCode: 404,
47
+ body: { error: 'API Gateway event not found', event: parsed.identifier },
48
+ };
33
49
  }
34
- apiGateways.forEach((gateway) => {
35
- startApiGatewayServer(gateway);
36
- });
50
+ common_1.logger.info(`Event trigger ${JSON.stringify(event.triggers)}, req method: ${req.method}, req url${req.url}`);
51
+ const matchedTrigger = event.triggers.find((trigger) => matchTrigger({ method: parsed.method, path: parsed.url }, trigger));
52
+ if (!matchedTrigger) {
53
+ const endTime = new Date();
54
+ if (isAliyun) {
55
+ (0, aliyunFc_1.logApiGatewayRequest)(requestId, parsed.url, 404, startTime, endTime, sourceIp);
56
+ }
57
+ return { statusCode: 404, body: { error: 'No matching trigger found' } };
58
+ }
59
+ if (matchedTrigger.backend) {
60
+ const backendDef = (0, common_1.getIacDefinition)(iac, matchedTrigger.backend);
61
+ if (!backendDef) {
62
+ const endTime = new Date();
63
+ if (isAliyun) {
64
+ (0, aliyunFc_1.logApiGatewayRequest)(requestId, parsed.url, 500, startTime, endTime, sourceIp);
65
+ }
66
+ return {
67
+ statusCode: 500,
68
+ body: { error: 'Backend definition missing', backend: matchedTrigger.backend },
69
+ };
70
+ }
71
+ // For Aliyun, handle the function execution with proper event transformation
72
+ if (isAliyun && backendDef.code) {
73
+ let tempDir = null;
74
+ try {
75
+ const { event: aliyunEvent } = await (0, aliyunFc_1.transformToAliyunEvent)(req, parsed.url, parsed.query);
76
+ const codePath = node_path_1.default.resolve(process.cwd(), backendDef.code.path);
77
+ let codeDir;
78
+ if (codePath.endsWith('.zip') && node_fs_1.default.existsSync(codePath)) {
79
+ tempDir = await (0, utils_1.extractZipFile)(codePath);
80
+ codeDir = tempDir;
81
+ }
82
+ else if (node_fs_1.default.existsSync(codePath) && node_fs_1.default.statSync(codePath).isDirectory()) {
83
+ codeDir = codePath;
84
+ }
85
+ else {
86
+ codeDir = node_path_1.default.dirname(codePath);
87
+ }
88
+ const funOptions = {
89
+ codeDir,
90
+ functionKey: backendDef.key,
91
+ handler: backendDef.code.handler,
92
+ servicePath: '',
93
+ timeout: backendDef.timeout * 1000,
94
+ };
95
+ const aliyunContext = (0, aliyunFc_1.createAliyunContextSerializable)(iac, backendDef.name, backendDef.code.handler, backendDef.memory, backendDef.timeout, requestId);
96
+ const env = {
97
+ ...backendDef.environment,
98
+ };
99
+ common_1.logger.debug(`Invoking FC function with Aliyun event format`);
100
+ const result = await (0, functionRunner_1.invokeFunction)(funOptions, env, aliyunEvent, aliyunContext);
101
+ const endTime = new Date();
102
+ const transformed = (0, aliyunFc_1.transformFCResponse)(result);
103
+ // Log API Gateway request
104
+ (0, aliyunFc_1.logApiGatewayRequest)(requestId, parsed.url, transformed.statusCode, startTime, endTime, sourceIp);
105
+ return {
106
+ statusCode: transformed.statusCode,
107
+ headers: transformed.headers,
108
+ body: transformed.body,
109
+ };
110
+ }
111
+ catch (error) {
112
+ const endTime = new Date();
113
+ (0, aliyunFc_1.logApiGatewayRequest)(requestId, parsed.url, 500, startTime, endTime, sourceIp);
114
+ common_1.logger.error(`Function execution error: ${error}`);
115
+ return {
116
+ statusCode: 500,
117
+ body: {
118
+ error: 'Function execution failed',
119
+ message: error instanceof Error ? error.message : String(error),
120
+ },
121
+ };
122
+ }
123
+ finally {
124
+ if (tempDir && node_fs_1.default.existsSync(tempDir)) {
125
+ node_fs_1.default.rmSync(tempDir, { recursive: true, force: true });
126
+ }
127
+ }
128
+ }
129
+ // For non-Aliyun or when using functionsHandler
130
+ const result = await (0, function_1.functionsHandler)(req, { ...parsed, identifier: backendDef?.key }, iac);
131
+ const endTime = new Date();
132
+ if (isAliyun) {
133
+ (0, aliyunFc_1.logApiGatewayRequest)(requestId, parsed.url, result.statusCode, startTime, endTime, sourceIp);
134
+ }
135
+ return result;
136
+ }
137
+ return {
138
+ statusCode: 202,
139
+ body: { message: 'Trigger matched but no backend configured' },
140
+ };
141
+ };
142
+ const eventsHandler = async (req, parsed, iac) => {
143
+ return await servEvent(req, parsed, iac);
37
144
  };
38
- exports.startEvents = startEvents;
145
+ exports.eventsHandler = eventsHandler;
@@ -0,0 +1,120 @@
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.functionsHandler = void 0;
7
+ const common_1 = require("../../common");
8
+ const functionRunner_1 = require("./functionRunner");
9
+ const node_path_1 = __importDefault(require("node:path"));
10
+ const node_fs_1 = __importDefault(require("node:fs"));
11
+ const aliyunFc_1 = require("./aliyunFc");
12
+ const utils_1 = require("./utils");
13
+ const functionsHandler = async (req, parsed, iac) => {
14
+ common_1.logger.info(`Function request received by local server -> ${req.method} ${parsed.identifier ?? '/'} `);
15
+ const fcDef = iac.functions?.find((fn) => fn.key === parsed.identifier);
16
+ if (!fcDef) {
17
+ return {
18
+ statusCode: 404,
19
+ body: { error: 'Function not found', functionKey: parsed.identifier },
20
+ };
21
+ }
22
+ if (!fcDef.code) {
23
+ return {
24
+ statusCode: 400,
25
+ body: { error: 'Function code configuration not found', functionKey: fcDef.key },
26
+ };
27
+ }
28
+ let tempDir = null;
29
+ try {
30
+ const codePath = node_path_1.default.resolve(process.cwd(), fcDef.code.path);
31
+ let codeDir;
32
+ if (codePath.endsWith('.zip') && node_fs_1.default.existsSync(codePath)) {
33
+ tempDir = await (0, utils_1.extractZipFile)(codePath);
34
+ codeDir = tempDir;
35
+ }
36
+ else if (node_fs_1.default.existsSync(codePath) && node_fs_1.default.statSync(codePath).isDirectory()) {
37
+ codeDir = codePath;
38
+ }
39
+ else {
40
+ codeDir = node_path_1.default.dirname(codePath);
41
+ }
42
+ const funOptions = {
43
+ codeDir,
44
+ functionKey: fcDef.key,
45
+ handler: fcDef.code.handler,
46
+ servicePath: '',
47
+ timeout: fcDef.timeout * 1000,
48
+ };
49
+ // Check if provider is Aliyun to use Aliyun FC format
50
+ const isAliyun = iac.provider.name === common_1.ProviderEnum.ALIYUN;
51
+ let event;
52
+ let fcContext;
53
+ let env;
54
+ if (isAliyun) {
55
+ // Aliyun FC format: event is a Buffer containing JSON
56
+ const requestId = (0, aliyunFc_1.generateRequestId)();
57
+ const { event: aliyunEvent } = await (0, aliyunFc_1.transformToAliyunEvent)(req, parsed.url, parsed.query);
58
+ event = aliyunEvent;
59
+ // Use serializable context for worker thread (logger will be added inside worker)
60
+ fcContext = (0, aliyunFc_1.createAliyunContextSerializable)(iac, fcDef.name, fcDef.code.handler, fcDef.memory, fcDef.timeout, requestId);
61
+ env = {
62
+ ...fcDef.environment,
63
+ };
64
+ }
65
+ else {
66
+ // AWS Lambda format (default)
67
+ const rawBody = await (0, common_1.readRequestBody)(req);
68
+ event = rawBody ? JSON.parse(rawBody) : {};
69
+ env = {
70
+ ...fcDef.environment,
71
+ AWS_REGION: iac.provider.region || 'us-east-1',
72
+ FUNCTION_NAME: fcDef.name,
73
+ FUNCTION_MEMORY_SIZE: String(fcDef.memory),
74
+ FUNCTION_TIMEOUT: String(fcDef.timeout),
75
+ };
76
+ fcContext = {
77
+ functionName: fcDef.name,
78
+ functionVersion: '$LATEST',
79
+ memoryLimitInMB: fcDef.memory,
80
+ logGroupName: `/aws/lambda/${fcDef.name}`,
81
+ logStreamName: `${new Date().toISOString().split('T')[0]}/[$LATEST]${Math.random().toString(36).substring(7)}`,
82
+ invokedFunctionArn: `arn:aws:lambda:${iac.provider.region}:000000000000:function:${fcDef.name}`,
83
+ awsRequestId: Math.random().toString(36).substring(2, 15),
84
+ };
85
+ }
86
+ common_1.logger.debug(`Invoking worker with event type: ${isAliyun ? 'Buffer' : 'Object'} and context`);
87
+ common_1.logger.debug(`Worker codeDir: ${codeDir}, handler: ${funOptions.handler}`);
88
+ const result = await (0, functionRunner_1.invokeFunction)(funOptions, env, event, fcContext);
89
+ common_1.logger.info(`Function execution result: ${JSON.stringify(result)}`);
90
+ // For Aliyun, transform FC response to HTTP response if needed
91
+ if (isAliyun && result) {
92
+ const transformed = (0, aliyunFc_1.transformFCResponse)(result);
93
+ return {
94
+ statusCode: transformed.statusCode,
95
+ headers: transformed.headers,
96
+ body: transformed.body,
97
+ };
98
+ }
99
+ return {
100
+ statusCode: 200,
101
+ body: result,
102
+ };
103
+ }
104
+ catch (error) {
105
+ common_1.logger.error(`Function execution error: ${error}`);
106
+ return {
107
+ statusCode: 500,
108
+ body: {
109
+ error: 'Function execution failed',
110
+ message: error instanceof Error ? error.message : String(error),
111
+ },
112
+ };
113
+ }
114
+ finally {
115
+ if (tempDir && node_fs_1.default.existsSync(tempDir)) {
116
+ node_fs_1.default.rmSync(tempDir, { recursive: true, force: true });
117
+ }
118
+ }
119
+ };
120
+ exports.functionsHandler = functionsHandler;
@@ -0,0 +1,270 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.invokeFunction = exports.runFunction = void 0;
37
+ const node_fs_1 = require("node:fs");
38
+ const node_path_1 = __importStar(require("node:path"));
39
+ const node_url_1 = require("node:url");
40
+ const node_worker_threads_1 = require("node:worker_threads");
41
+ // ============================================================================
42
+ // Worker Thread Code (runs in worker context)
43
+ // ============================================================================
44
+ const parseHandler = (handler) => {
45
+ const [handlerFile, handlerMethod] = handler.split('.');
46
+ return [handlerFile, handlerMethod];
47
+ };
48
+ const resolveHandlerPath = (codeDir, servicePath, handlerFile) => servicePath
49
+ ? node_path_1.default.resolve(servicePath, codeDir, handlerFile)
50
+ : node_path_1.default.resolve(codeDir, handlerFile);
51
+ const loadHandlerModule = async (handlerPath) => {
52
+ try {
53
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
54
+ return require(handlerPath);
55
+ }
56
+ catch {
57
+ const fileUrl = (0, node_url_1.pathToFileURL)(handlerPath + '.js').href;
58
+ return (await Promise.resolve(`${fileUrl}`).then(s => __importStar(require(s))));
59
+ }
60
+ };
61
+ const getHandlerFunction = (handlerModule, handlerMethod, handlerPath) => {
62
+ const handlerFn = handlerModule[handlerMethod];
63
+ if (typeof handlerFn !== 'function') {
64
+ throw new Error(`Handler "${handlerMethod}" not found or is not a function in ${handlerPath}`);
65
+ }
66
+ return handlerFn;
67
+ };
68
+ const invokeHandler = (handlerFn, event, context) => new Promise((resolve, reject) => {
69
+ // Callback-style handler (3+ parameters)
70
+ if (handlerFn.length >= 3) {
71
+ try {
72
+ handlerFn(event, context, (error, result) => {
73
+ return error ? reject(error) : resolve(result);
74
+ });
75
+ }
76
+ catch (error) {
77
+ reject(error);
78
+ }
79
+ }
80
+ else {
81
+ return Promise.resolve(handlerFn(event, context)).then(resolve).catch(reject);
82
+ }
83
+ });
84
+ const createTimeoutHandler = (port, timeoutMs) => {
85
+ const timeoutId = setTimeout(() => {
86
+ port.postMessage(new Error(`Function execution timed out after ${timeoutMs}ms`));
87
+ port.close();
88
+ }, timeoutMs);
89
+ return {
90
+ timeoutId,
91
+ clearTimer: () => clearTimeout(timeoutId),
92
+ };
93
+ };
94
+ const executeHandler = async ({ event, context, port }) => {
95
+ let clearTimer;
96
+ try {
97
+ const wd = node_worker_threads_1.workerData;
98
+ const { codeDir, handler, servicePath, timeout } = wd;
99
+ const timer = createTimeoutHandler(port, timeout);
100
+ clearTimer = timer.clearTimer;
101
+ // Convert Uint8Array back to Buffer if needed (worker thread serialization converts Buffers to Uint8Arrays)
102
+ let actualEvent = event;
103
+ if (event instanceof Uint8Array && !Buffer.isBuffer(event)) {
104
+ actualEvent = Buffer.from(event);
105
+ }
106
+ // Reconstruct logger and tracing function for Aliyun FC contexts
107
+ let actualContext = context;
108
+ if (context &&
109
+ typeof context === 'object' &&
110
+ 'requestId' in context &&
111
+ !('logger' in context) &&
112
+ 'function' in context &&
113
+ 'service' in context) {
114
+ const requestId = context.requestId;
115
+ const formatLog = (level, message) => {
116
+ const timestamp = new Date().toISOString();
117
+ console.log(`${timestamp} ${requestId} [${level}] ${message}`);
118
+ };
119
+ const baseContext = context;
120
+ actualContext = {
121
+ ...baseContext,
122
+ tracing: {
123
+ ...baseContext.tracing,
124
+ parseOpenTracingBaggages: () => ({}),
125
+ },
126
+ logger: {
127
+ debug: (message) => formatLog('DEBUG', message),
128
+ info: (message) => formatLog('INFO', message),
129
+ warn: (message) => formatLog('WARNING', message),
130
+ error: (message) => formatLog('ERROR', message),
131
+ log: (message) => formatLog('INFO', message),
132
+ },
133
+ };
134
+ }
135
+ const [handlerFile, handlerMethod] = parseHandler(handler);
136
+ const handlerPath = resolveHandlerPath(codeDir, servicePath, handlerFile);
137
+ const handlerModule = await loadHandlerModule(handlerPath);
138
+ const handlerFn = getHandlerFunction(handlerModule, handlerMethod, handlerPath);
139
+ const result = await invokeHandler(handlerFn, actualEvent, actualContext);
140
+ clearTimer();
141
+ port.postMessage(result);
142
+ port.close();
143
+ }
144
+ catch (error) {
145
+ if (clearTimer)
146
+ clearTimer();
147
+ port.postMessage(error instanceof Error ? error : new Error(String(error)));
148
+ port.close();
149
+ }
150
+ };
151
+ // Initialize worker thread message handler
152
+ if (!node_worker_threads_1.isMainThread) {
153
+ node_worker_threads_1.parentPort?.on('message', async (message) => {
154
+ try {
155
+ await executeHandler(message);
156
+ }
157
+ catch (error) {
158
+ message.port.postMessage(error instanceof Error ? error : new Error(String(error)));
159
+ message.port.close();
160
+ }
161
+ });
162
+ }
163
+ // ============================================================================
164
+ // Main Thread Code (functional API)
165
+ // ============================================================================
166
+ const resolveWorkerPath = () => {
167
+ const localPath = (0, node_path_1.join)(__dirname, 'functionRunner.js');
168
+ if ((0, node_fs_1.existsSync)(localPath)) {
169
+ return localPath;
170
+ }
171
+ // Fallback to dist directory
172
+ const distPath = __dirname.replace(/src\/stack\/localStack$/, 'dist/src/stack/localStack');
173
+ return (0, node_path_1.join)(distPath, 'functionRunner.js');
174
+ };
175
+ const createWorker = (funOptions, env) => {
176
+ const { codeDir, functionKey, handler, servicePath, timeout } = funOptions;
177
+ const workerPath = resolveWorkerPath();
178
+ return new node_worker_threads_1.Worker(workerPath, {
179
+ env,
180
+ workerData: {
181
+ codeDir,
182
+ functionKey,
183
+ handler,
184
+ servicePath,
185
+ timeout,
186
+ },
187
+ });
188
+ };
189
+ const createMessageHandler = (port, resolve, reject) => {
190
+ let resolved = false;
191
+ const handleMessage = (value) => {
192
+ if (resolved)
193
+ return;
194
+ resolved = true;
195
+ port.close();
196
+ return value instanceof Error ? reject(value) : resolve(value);
197
+ };
198
+ const handleError = (err) => {
199
+ if (resolved)
200
+ return;
201
+ resolved = true;
202
+ port.close();
203
+ reject(err);
204
+ };
205
+ const handleClose = () => {
206
+ if (resolved)
207
+ return;
208
+ resolved = true;
209
+ reject(new Error('Port closed before receiving response'));
210
+ };
211
+ port.on('message', handleMessage).on('error', handleError).on('close', handleClose);
212
+ return () => {
213
+ port.off('message', handleMessage);
214
+ port.off('error', handleError);
215
+ port.off('close', handleClose);
216
+ port.close();
217
+ };
218
+ };
219
+ const sendMessage = (worker, event, context, port2) => {
220
+ worker.postMessage({
221
+ context,
222
+ event,
223
+ port: port2,
224
+ }, [port2]);
225
+ };
226
+ const runFunction = (funOptions, env) => {
227
+ const worker = createWorker(funOptions, env);
228
+ const execute = (event, context) => new Promise((resolve, reject) => {
229
+ const { port1, port2 } = new node_worker_threads_1.MessageChannel();
230
+ const cleanup = createMessageHandler(port1, resolve, reject);
231
+ // Handle worker errors/exit
232
+ const handleWorkerError = (err) => {
233
+ cleanup();
234
+ reject(err);
235
+ };
236
+ const handleWorkerExit = (code) => {
237
+ if (code !== 0) {
238
+ cleanup();
239
+ reject(new Error(`Worker stopped with exit code ${code}`));
240
+ }
241
+ };
242
+ worker.once('error', handleWorkerError);
243
+ worker.once('exit', handleWorkerExit);
244
+ try {
245
+ sendMessage(worker, event, context, port2);
246
+ }
247
+ catch (error) {
248
+ worker.off('error', handleWorkerError);
249
+ worker.off('exit', handleWorkerExit);
250
+ cleanup();
251
+ reject(error instanceof Error ? error : new Error(String(error)));
252
+ }
253
+ });
254
+ const terminate = () => worker.terminate();
255
+ return {
256
+ execute,
257
+ terminate,
258
+ };
259
+ };
260
+ exports.runFunction = runFunction;
261
+ const invokeFunction = async (funOptions, env, event, context) => {
262
+ const runner = (0, exports.runFunction)(funOptions, env);
263
+ try {
264
+ return await runner.execute(event, context);
265
+ }
266
+ finally {
267
+ await runner.terminate();
268
+ }
269
+ };
270
+ exports.invokeFunction = invokeFunction;
@@ -1,2 +1,5 @@
1
+ import { stopLocal } from './localServer';
2
+ import { ServerlessIac } from '../../types';
1
3
  export * from './event';
2
- export declare const startLocalStack: () => Promise<void>;
4
+ export { stopLocal };
5
+ export declare const startLocalStack: (iac: ServerlessIac) => Promise<void>;
@@ -14,10 +14,20 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- exports.startLocalStack = void 0;
17
+ exports.startLocalStack = exports.stopLocal = void 0;
18
+ const localStack_1 = require("../../types/localStack");
19
+ const localServer_1 = require("./localServer");
20
+ Object.defineProperty(exports, "stopLocal", { enumerable: true, get: function () { return localServer_1.stopLocal; } });
21
+ const event_1 = require("./event");
22
+ const function_1 = require("./function");
23
+ const bucket_1 = require("./bucket");
18
24
  __exportStar(require("./event"), exports);
19
- const startLocalStack = async () => {
20
- // Placeholder for starting local stack logic
21
- console.log('Local stack started');
25
+ const handlers = [
26
+ { kind: localStack_1.RouteKind.SI_FUNCTIONS, handler: function_1.functionsHandler },
27
+ { kind: localStack_1.RouteKind.SI_EVENTS, handler: event_1.eventsHandler },
28
+ { kind: localStack_1.RouteKind.SI_BUCKETS, handler: bucket_1.bucketsHandler },
29
+ ];
30
+ const startLocalStack = async (iac) => {
31
+ await (0, localServer_1.servLocal)(handlers, iac);
22
32
  };
23
33
  exports.startLocalStack = startLocalStack;