cdk-local-lambda 0.0.2

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 (53) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +94 -0
  3. package/lib/aspect/docker-function-hook.d.ts +18 -0
  4. package/lib/aspect/docker-function-hook.js +31 -0
  5. package/lib/aspect/live-lambda-aspect.d.ts +85 -0
  6. package/lib/aspect/live-lambda-aspect.js +277 -0
  7. package/lib/aspect/live-lambda-bootstrap.d.ts +17 -0
  8. package/lib/aspect/live-lambda-bootstrap.js +260 -0
  9. package/lib/aspect/nodejs-function-hook.d.ts +20 -0
  10. package/lib/aspect/nodejs-function-hook.js +27 -0
  11. package/lib/bootstrap-stack/bootstrap-stack.d.ts +60 -0
  12. package/lib/bootstrap-stack/bootstrap-stack.js +338 -0
  13. package/lib/cli/appsync/client.d.ts +30 -0
  14. package/lib/cli/appsync/client.js +227 -0
  15. package/lib/cli/cdk-app.d.ts +7 -0
  16. package/lib/cli/cdk-app.js +25 -0
  17. package/lib/cli/commands/bootstrap.d.ts +9 -0
  18. package/lib/cli/commands/bootstrap.js +50 -0
  19. package/lib/cli/commands/local.d.ts +40 -0
  20. package/lib/cli/commands/local.js +1172 -0
  21. package/lib/cli/daemon.d.ts +22 -0
  22. package/lib/cli/daemon.js +18 -0
  23. package/lib/cli/docker/container.d.ts +116 -0
  24. package/lib/cli/docker/container.js +414 -0
  25. package/lib/cli/docker/types.d.ts +71 -0
  26. package/lib/cli/docker/types.js +5 -0
  27. package/lib/cli/docker/watcher.d.ts +44 -0
  28. package/lib/cli/docker/watcher.js +115 -0
  29. package/lib/cli/index.d.ts +9 -0
  30. package/lib/cli/index.js +26 -0
  31. package/lib/cli/runtime-api/server.d.ts +102 -0
  32. package/lib/cli/runtime-api/server.js +396 -0
  33. package/lib/cli/runtime-api/types.d.ts +149 -0
  34. package/lib/cli/runtime-api/types.js +10 -0
  35. package/lib/cli/runtime-wrapper/nodejs-runtime.d.ts +16 -0
  36. package/lib/cli/runtime-wrapper/nodejs-runtime.js +248 -0
  37. package/lib/cli/watcher/file-watcher.d.ts +32 -0
  38. package/lib/cli/watcher/file-watcher.js +57 -0
  39. package/lib/functions/bridge/appsync-client.d.ts +73 -0
  40. package/lib/functions/bridge/appsync-client.js +345 -0
  41. package/lib/functions/bridge/handler.d.ts +17 -0
  42. package/lib/functions/bridge/handler.js +79 -0
  43. package/lib/functions/bridge/ssm-config.d.ts +19 -0
  44. package/lib/functions/bridge/ssm-config.js +45 -0
  45. package/lib/functions/bridge-builder/handler.d.ts +12 -0
  46. package/lib/functions/bridge-builder/handler.js +181 -0
  47. package/lib/functions/bridge-docker/runtime.d.ts +9 -0
  48. package/lib/functions/bridge-docker/runtime.js +127 -0
  49. package/lib/index.d.ts +24 -0
  50. package/lib/index.js +28 -0
  51. package/lib/shared/types.d.ts +102 -0
  52. package/lib/shared/types.js +125 -0
  53. package/package.json +111 -0
@@ -0,0 +1,115 @@
1
+ /**
2
+ * Docker context file watching for automatic container rebuilds.
3
+ *
4
+ * Watches Docker context directories and emits events when files change,
5
+ * triggering container rebuilds for Docker-based Lambda functions.
6
+ */
7
+ import * as path from "node:path";
8
+ import chokidar from "chokidar";
9
+ import { Effect, Stream } from "effect";
10
+ /**
11
+ * Default patterns to ignore when watching Docker contexts.
12
+ * These are common directories/files that shouldn't trigger rebuilds.
13
+ */
14
+ const DEFAULT_IGNORED_PATTERNS = [
15
+ /(^|[/\\])\.git([/\\]|$)/, // .git directory
16
+ /(^|[/\\])node_modules([/\\]|$)/, // node_modules
17
+ /(^|[/\\])\.[^/\\]+$/, // dotfiles (but not directories like .docker)
18
+ /\.pyc$/, // Python bytecode
19
+ /__pycache__/, // Python cache
20
+ /\.class$/, // Java bytecode
21
+ /\.o$/, // Object files
22
+ /\.log$/, // Log files
23
+ ];
24
+ /**
25
+ * Watch multiple Docker context directories for file changes.
26
+ *
27
+ * Creates a single chokidar watcher that monitors all registered Docker
28
+ * contexts and emits events when files change. The events are debounced
29
+ * to prevent rapid successive rebuilds during batch operations.
30
+ *
31
+ * @param functions - Array of Docker functions to watch
32
+ * @param debounceMs - Debounce delay in milliseconds (default: 500)
33
+ * @returns Stream of change events with function ownership resolved
34
+ */
35
+ export const watchDockerContexts = (functions, debounceMs = 500) => {
36
+ if (functions.length === 0) {
37
+ return Stream.empty;
38
+ }
39
+ // Build a map of normalized context paths to function IDs for quick lookup
40
+ const contextToFunction = new Map();
41
+ const pathsToWatch = [];
42
+ for (const fn of functions) {
43
+ const normalizedPath = path.normalize(fn.dockerContextPath);
44
+ contextToFunction.set(normalizedPath, fn.functionId);
45
+ pathsToWatch.push(fn.dockerContextPath);
46
+ }
47
+ return Stream.asyncScoped((emit) => Effect.gen(function* () {
48
+ const watcher = chokidar.watch(pathsToWatch, {
49
+ ignored: DEFAULT_IGNORED_PATTERNS,
50
+ persistent: true,
51
+ ignoreInitial: true,
52
+ // Use polling on some systems for better reliability
53
+ usePolling: process.platform === "linux",
54
+ interval: 300,
55
+ });
56
+ /**
57
+ * Find which function owns a given file path.
58
+ */
59
+ const findOwningFunction = (filePath) => {
60
+ const normalizedFilePath = path.normalize(filePath);
61
+ for (const [contextPath, functionId] of contextToFunction) {
62
+ if (normalizedFilePath.startsWith(contextPath + path.sep)) {
63
+ return functionId;
64
+ }
65
+ // Also match if the file IS the context directory (shouldn't happen but handle it)
66
+ if (normalizedFilePath === contextPath) {
67
+ return functionId;
68
+ }
69
+ }
70
+ return undefined;
71
+ };
72
+ /**
73
+ * Handle a file change event.
74
+ */
75
+ const handleChange = (type, filePath) => {
76
+ const functionId = findOwningFunction(filePath);
77
+ if (functionId) {
78
+ emit.single({
79
+ functionId,
80
+ filePath,
81
+ type,
82
+ });
83
+ }
84
+ };
85
+ watcher.on("add", (filePath) => handleChange("add", filePath));
86
+ watcher.on("change", (filePath) => handleChange("change", filePath));
87
+ watcher.on("unlink", (filePath) => handleChange("unlink", filePath));
88
+ watcher.on("error", (err) => {
89
+ const error = err;
90
+ Effect.runSync(Effect.logWarning(`DockerWatcher error: ${error.message}`));
91
+ // Don't fail the stream on transient errors, just log
92
+ });
93
+ watcher.on("ready", () => {
94
+ Effect.runSync(Effect.logDebug(`Watching ${functions.length} Docker context(s) for changes`));
95
+ for (const fn of functions) {
96
+ Effect.runSync(Effect.logDebug(` - ${fn.functionId}: ${fn.dockerContextPath}`));
97
+ }
98
+ });
99
+ // Cleanup when scope closes
100
+ yield* Effect.addFinalizer(() => Effect.gen(function* () {
101
+ yield* Effect.promise(async () => {
102
+ await watcher.close();
103
+ });
104
+ yield* Effect.logDebug("DockerWatcher file watcher closed");
105
+ }));
106
+ })).pipe(
107
+ // Debounce to handle batch file changes (e.g., git checkout, IDE save-all)
108
+ Stream.debounce(`${debounceMs} millis`));
109
+ };
110
+ /**
111
+ * Create a watcher for a single Docker function.
112
+ * Convenience wrapper around watchDockerContexts for single-function use.
113
+ */
114
+ export const watchSingleDockerContext = (functionId, dockerContextPath, debounceMs = 500) => watchDockerContexts([{ functionId, dockerContextPath }], debounceMs);
115
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid2F0Y2hlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9jbGkvZG9ja2VyL3dhdGNoZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7O0dBS0c7QUFFSCxPQUFPLEtBQUssSUFBSSxNQUFNLFdBQVcsQ0FBQTtBQUNqQyxPQUFPLFFBQVEsTUFBTSxVQUFVLENBQUE7QUFDL0IsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLEVBQUUsTUFBTSxRQUFRLENBQUE7QUF3QnZDOzs7R0FHRztBQUNILE1BQU0sd0JBQXdCLEdBQUc7SUFDL0IseUJBQXlCLEVBQUUsaUJBQWlCO0lBQzVDLGdDQUFnQyxFQUFFLGVBQWU7SUFDakQscUJBQXFCLEVBQUUsOENBQThDO0lBQ3JFLFFBQVEsRUFBRSxrQkFBa0I7SUFDNUIsYUFBYSxFQUFFLGVBQWU7SUFDOUIsVUFBVSxFQUFFLGdCQUFnQjtJQUM1QixNQUFNLEVBQUUsZUFBZTtJQUN2QixRQUFRLEVBQUUsWUFBWTtDQUN2QixDQUFBO0FBRUQ7Ozs7Ozs7Ozs7R0FVRztBQUNILE1BQU0sQ0FBQyxNQUFNLG1CQUFtQixHQUFHLENBQ2pDLFNBQWtDLEVBQ2xDLFVBQVUsR0FBRyxHQUFHLEVBQ2dDLEVBQUU7SUFDbEQsSUFBSSxTQUFTLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRSxDQUFDO1FBQzNCLE9BQU8sTUFBTSxDQUFDLEtBQUssQ0FBQTtJQUNyQixDQUFDO0lBRUQsMkVBQTJFO0lBQzNFLE1BQU0saUJBQWlCLEdBQUcsSUFBSSxHQUFHLEVBQWtCLENBQUE7SUFDbkQsTUFBTSxZQUFZLEdBQWEsRUFBRSxDQUFBO0lBRWpDLEtBQUssTUFBTSxFQUFFLElBQUksU0FBUyxFQUFFLENBQUM7UUFDM0IsTUFBTSxjQUFjLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUMsaUJBQWlCLENBQUMsQ0FBQTtRQUMzRCxpQkFBaUIsQ0FBQyxHQUFHLENBQUMsY0FBYyxFQUFFLEVB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QyxpQkFBaUIsRUFBRSxDQUFDLENBQ2pFLENBQUE7WUFDSCxDQUFDO1FBQ0gsQ0FBQyxDQUFDLENBQUE7UUFFRiw0QkFBNEI7UUFDNUIsS0FBSyxDQUFDLENBQUMsTUFBTSxDQUFDLFlBQVksQ0FBQyxHQUFHLEVBQUUsQ0FDOUIsTUFBTSxDQUFDLEdBQUcsQ0FBQyxRQUFRLENBQUM7WUFDbEIsS0FBSyxDQUFDLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxLQUFLLElBQUksRUFBRTtnQkFDL0IsTUFBTSxPQUFPLENBQUMsS0FBSyxFQUFFLENBQUE7WUFDdkIsQ0FBQyxDQUFDLENBQUE7WUFDRixLQUFLLENBQUMsQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLG1DQUFtQyxDQUFDLENBQUE7UUFDN0QsQ0FBQyxDQUFDLENBQ0gsQ0FBQTtJQUNILENBQUMsQ0FBQyxDQUNILENBQUMsSUFBSTtJQUNKLDJFQUEyRTtJQUMzRSxNQUFNLENBQUMsUUFBUSxDQUFDLEdBQUcsVUFBVSxTQUFTLENBQUMsQ0FDeEMsQ0FBQTtBQUNILENBQUMsQ0FBQTtBQUVEOzs7R0FHRztBQUNILE1BQU0sQ0FBQyxNQUFNLHdCQUF3QixHQUFHLENBQ3RDLFVBQWtCLEVBQ2xCLGlCQUF5QixFQUN6QixVQUFVLEdBQUcsR0FBRyxFQUNnQyxFQUFFLENBQ2xELG1CQUFtQixDQUFDLENBQUMsRUFBRSxVQUFVLEVBQUUsaUJBQWlCLEVBQUUsQ0FBQyxFQUFFLFVBQVUsQ0FBQyxDQUFBIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBEb2NrZXIgY29udGV4dCBmaWxlIHdhdGNoaW5nIGZvciBhdXRvbWF0aWMgY29udGFpbmVyIHJlYnVpbGRzLlxuICpcbiAqIFdhdGNoZXMgRG9ja2VyIGNvbnRleHQgZGlyZWN0b3JpZXMgYW5kIGVtaXRzIGV2ZW50cyB3aGVuIGZpbGVzIGNoYW5nZSxcbiAqIHRyaWdnZXJpbmcgY29udGFpbmVyIHJlYnVpbGRzIGZvciBEb2NrZXItYmFzZWQgTGFtYmRhIGZ1bmN0aW9ucy5cbiAqL1xuXG5pbXBvcnQgKiBhcyBwYXRoIGZyb20gXCJub2RlOnBhdGhcIlxuaW1wb3J0IGNob2tpZGFyIGZyb20gXCJjaG9raWRhclwiXG5pbXBvcnQgeyBFZmZlY3QsIFN0cmVhbSB9IGZyb20gXCJlZmZlY3RcIlxuXG4vKipcbiAqIEV2ZW50IGVtaXR0ZWQgd2hlbiBhIGZpbGUgY2hhbmdlcyBpbiBhIERvY2tlciBjb250ZXh0LlxuICovXG5leHBvcnQgaW50ZXJmYWNlIERvY2tlckNvbnRleHRDaGFuZ2VFdmVudCB7XG4gIC8qKiBUaGUgZnVuY3Rpb24gSUQgdGhhdCBvd25zIHRoaXMgRG9ja2VyIGNvbnRleHQgKi9cbiAgZnVuY3Rpb25JZDogc3RyaW5nXG4gIC8qKiBUaGUgYWJzb2x1dGUgcGF0aCB0byB0aGUgZmlsZSB0aGF0IGNoYW5nZWQgKi9cbiAgZmlsZVBhdGg6IHN0cmluZ1xuICAvKiogVHlwZSBvZiBjaGFuZ2UgKi9cbiAgdHlwZTogXCJhZGRcIiB8IFwiY2hhbmdlXCIgfCBcInVubGlua1wiXG59XG5cbi8qKlxuICogQ29uZmlndXJhdGlvbiBmb3IgYSBEb2NrZXIgZnVuY3Rpb24gdG8gd2F0Y2guXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgV2F0Y2hlZERvY2tlckZ1bmN0aW9uIHtcbiAgLyoqIFVuaXF1ZSBmdW5jdGlvbiBpZGVudGlmaWVyIChMYW1iZGEgZnVuY3Rpb24gbmFtZSkgKi9cbiAgZnVuY3Rpb25JZDogc3RyaW5nXG4gIC8qKiBBYnNvbHV0ZSBwYXRoIHRvIHRoZSBEb2NrZXIgY29udGV4dCBkaXJlY3RvcnkgKi9cbiAgZG9ja2VyQ29udGV4dFBhdGg6IHN0cmluZ1xufVxuXG4vKipcbiAqIERlZmF1bHQgcGF0dGVybnMgdG8gaWdub3JlIHdoZW4gd2F0Y2hpbmcgRG9ja2VyIGNvbnRleHRzLlxuICogVGhlc2UgYXJlIGNvbW1vbiBkaXJlY3Rvcmllcy9maWxlcyB0aGF0IHNob3VsZG4ndCB0cmlnZ2VyIHJlYnVpbGRzLlxuICovXG5jb25zdCBERUZBVUxUX0lHTk9SRURfUEFUVEVSTlMgPSBbXG4gIC8oXnxbL1xcXFxdKVxcLmdpdChbL1xcXFxdfCQpLywgLy8gLmdpdCBkaXJlY3RvcnlcbiAgLyhefFsvXFxcXF0pbm9kZV9tb2R1bGVzKFsvXFxcXF18JCkvLCAvLyBub2RlX21vZHVsZXNcbiAgLyhefFsvXFxcXF0pXFwuW14vXFxcXF0rJC8sIC8vIGRvdGZpbGVzIChidXQgbm90IGRpcmVjdG9yaWVzIGxpa2UgLmRvY2tlcilcbiAgL1xcLnB5YyQvLCAvLyBQeXRob24gYnl0ZWNvZGVcbiAgL19fcHljYWNoZV9fLywgLy8gUHl0aG9uIGNhY2hlXG4gIC9cXC5jbGFzcyQvLCAvLyBKYXZhIGJ5dGVjb2RlXG4gIC9cXC5vJC8sIC8vIE9iamVjdCBmaWxlc1xuICAvXFwubG9nJC8sIC8vIExvZyBmaWxlc1xuXVxuXG4vKipcbiAqIFdhdGNoIG11bHRpcGxlIERvY2tlciBjb250ZXh0IGRpcmVjdG9yaWVzIGZvciBmaWxlIGNoYW5nZXMuXG4gKlxuICogQ3JlYXRlcyBhIHNpbmdsZSBjaG9raWRhciB3YXRjaGVyIHRoYXQgbW9uaXRvcnMgYWxsIHJlZ2lzdGVyZWQgRG9ja2VyXG4gKiBjb250ZXh0cyBhbmQgZW1pdHMgZXZlbnRzIHdoZW4gZmlsZXMgY2hhbmdlLiBUaGUgZXZlbnRzIGFyZSBkZWJvdW5jZWRcbiAqIHRvIHByZXZlbnQgcmFwaWQgc3VjY2Vzc2l2ZSByZWJ1aWxkcyBkdXJpbmcgYmF0Y2ggb3BlcmF0aW9ucy5cbiAqXG4gKiBAcGFyYW0gZnVuY3Rpb25zIC0gQXJyYXkgb2YgRG9ja2VyIGZ1bmN0aW9ucyB0byB3YXRjaFxuICogQHBhcmFtIGRlYm91bmNlTXMgLSBEZWJvdW5jZSBkZWxheSBpbiBtaWxsaXNlY29uZHMgKGRlZmF1bHQ6IDUwMClcbiAqIEByZXR1cm5zIFN0cmVhbSBvZiBjaGFuZ2UgZXZlbnRzIHdpdGggZnVuY3Rpb24gb3duZXJzaGlwIHJlc29sdmVkXG4gKi9cbmV4cG9ydCBjb25zdCB3YXRjaERvY2tlckNvbnRleHRzID0gKFxuICBmdW5jdGlvbnM6IFdhdGNoZWREb2NrZXJGdW5jdGlvbltdLFxuICBkZWJvdW5jZU1zID0gNTAwLFxuKTogU3RyZWFtLlN0cmVhbTxEb2NrZXJDb250ZXh0Q2hhbmdlRXZlbnQsIEVycm9yPiA9PiB7XG4gIGlmIChmdW5jdGlvbnMubGVuZ3RoID09PSAwKSB7XG4gICAgcmV0dXJuIFN0cmVhbS5lbXB0eVxuICB9XG5cbiAgLy8gQnVpbGQgYSBtYXAgb2Ygbm9ybWFsaXplZCBjb250ZXh0IHBhdGhzIHRvIGZ1bmN0aW9uIElEcyBmb3IgcXVpY2sgbG9va3VwXG4gIGNvbnN0IGNvbnRleHRUb0Z1bmN0aW9uID0gbmV3IE1hcDxzdHJpbmcsIHN0cmluZz4oKVxuICBjb25zdCBwYXRoc1RvV2F0Y2g6IHN0cmluZ1tdID0gW11cblxuICBmb3IgKGNvbnN0IGZuIG9mIGZ1bmN0aW9ucykge1xuICAgIGNvbnN0IG5vcm1hbGl6ZWRQYXRoID0gcGF0aC5ub3JtYWxpemUoZm4uZG9ja2VyQ29udGV4dFBhdGgpXG4gICAgY29udGV4dFRvRnVuY3Rpb24uc2V0KG5vcm1hbGl6ZWRQYXRoLCBmbi5mdW5jdGlvbklkKVxuICAgIHBhdGhzVG9XYXRjaC5wdXNoKGZuLmRvY2tlckNvbnRleHRQYXRoKVxuICB9XG5cbiAgcmV0dXJuIFN0cmVhbS5hc3luY1Njb3BlZDxEb2NrZXJDb250ZXh0Q2hhbmdlRXZlbnQsIEVycm9yPigoZW1pdCkgPT5cbiAgICBFZmZlY3QuZ2VuKGZ1bmN0aW9uKiAoKSB7XG4gICAgICBjb25zdCB3YXRjaGVyID0gY2hva2lkYXIud2F0Y2gocGF0aHNUb1dhdGNoLCB7XG4gICAgICAgIGlnbm9yZWQ6IERFRkFVTFRfSUdOT1JFRF9QQVRURVJOUyxcbiAgICAgICAgcGVyc2lzdGVudDogdHJ1ZSxcbiAgICAgICAgaWdub3JlSW5pdGlhbDogdHJ1ZSxcbiAgICAgICAgLy8gVXNlIHBvbGxpbmcgb24gc29tZSBzeXN0ZW1zIGZvciBiZXR0ZXIgcmVsaWFiaWxpdHlcbiAgICAgICAgdXNlUG9sbGluZzogcHJvY2Vzcy5wbGF0Zm9ybSA9PT0gXCJsaW51eFwiLFxuICAgICAgICBpbnRlcnZhbDogMzAwLFxuICAgICAgfSlcblxuICAgICAgLyoqXG4gICAgICAgKiBGaW5kIHdoaWNoIGZ1bmN0aW9uIG93bnMgYSBnaXZlbiBmaWxlIHBhdGguXG4gICAgICAgKi9cbiAgICAgIGNvbnN0IGZpbmRPd25pbmdGdW5jdGlvbiA9IChmaWxlUGF0aDogc3RyaW5nKTogc3RyaW5nIHwgdW5kZWZpbmVkID0+IHtcbiAgICAgICAgY29uc3Qgbm9ybWFsaXplZEZpbGVQYXRoID0gcGF0aC5ub3JtYWxpemUoZmlsZVBhdGgpXG5cbiAgICAgICAgZm9yIChjb25zdCBbY29udGV4dFBhdGgsIGZ1bmN0aW9uSWRdIG9mIGNvbnRleHRUb0Z1bmN0aW9uKSB7XG4gICAgICAgICAgaWYgKG5vcm1hbGl6ZWRGaWxlUGF0aC5zdGFydHNXaXRoKGNvbnRleHRQYXRoICsgcGF0aC5zZXApKSB7XG4gICAgICAgICAgICByZXR1cm4gZnVuY3Rpb25JZFxuICAgICAgICAgIH1cbiAgICAgICAgICAvLyBBbHNvIG1hdGNoIGlmIHRoZSBmaWxlIElTIHRoZSBjb250ZXh0IGRpcmVjdG9yeSAoc2hvdWxkbid0IGhhcHBlbiBidXQgaGFuZGxlIGl0KVxuICAgICAgICAgIGlmIChub3JtYWxpemVkRmlsZVBhdGggPT09IGNvbnRleHRQYXRoKSB7XG4gICAgICAgICAgICByZXR1cm4gZnVuY3Rpb25JZFxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdW5kZWZpbmVkXG4gICAgICB9XG5cbiAgICAgIC8qKlxuICAgICAgICogSGFuZGxlIGEgZmlsZSBjaGFuZ2UgZXZlbnQuXG4gICAgICAgKi9cbiAgICAgIGNvbnN0IGhhbmRsZUNoYW5nZSA9IChcbiAgICAgICAgdHlwZTogXCJhZGRcIiB8IFwiY2hhbmdlXCIgfCBcInVubGlua1wiLFxuICAgICAgICBmaWxlUGF0aDogc3RyaW5nLFxuICAgICAgKSA9PiB7XG4gICAgICAgIGNvbnN0IGZ1bmN0aW9uSWQgPSBmaW5kT3duaW5nRnVuY3Rpb24oZmlsZVBhdGgpXG4gICAgICAgIGlmIChmdW5jdGlvbklkKSB7XG4gICAgICAgICAgZW1pdC5zaW5nbGUoe1xuICAgICAgICAgICAgZnVuY3Rpb25JZCxcbiAgICAgICAgICAgIGZpbGVQYXRoLFxuICAgICAgICAgICAgdHlwZSxcbiAgICAgICAgICB9KVxuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHdhdGNoZXIub24oXCJhZGRcIiwgKGZpbGVQYXRoKSA9PiBoYW5kbGVDaGFuZ2UoXCJhZGRcIiwgZmlsZVBhdGgpKVxuICAgICAgd2F0Y2hlci5vbihcImNoYW5nZVwiLCAoZmlsZVBhdGgpID0+IGhhbmRsZUNoYW5nZShcImNoYW5nZVwiLCBmaWxlUGF0aCkpXG4gICAgICB3YXRjaGVyLm9uKFwidW5saW5rXCIsIChmaWxlUGF0aCkgPT4gaGFuZGxlQ2hhbmdlKFwidW5saW5rXCIsIGZpbGVQYXRoKSlcblxuICAgICAgd2F0Y2hlci5vbihcImVycm9yXCIsIChlcnIpID0+IHtcbiAgICAgICAgY29uc3QgZXJyb3IgPSBlcnIgYXMgRXJyb3JcbiAgICAgICAgRWZmZWN0LnJ1blN5bmMoXG4gICAgICAgICAgRWZmZWN0LmxvZ1dhcm5pbmcoYERvY2tlcldhdGNoZXIgZXJyb3I6ICR7ZXJyb3IubWVzc2FnZX1gKSxcbiAgICAgICAgKVxuICAgICAgICAvLyBEb24ndCBmYWlsIHRoZSBzdHJlYW0gb24gdHJhbnNpZW50IGVycm9ycywganVzdCBsb2dcbiAgICAgIH0pXG5cbiAgICAgIHdhdGNoZXIub24oXCJyZWFkeVwiLCAoKSA9PiB7XG4gICAgICAgIEVmZmVjdC5ydW5TeW5jKFxuICAgICAgICAgIEVmZmVjdC5sb2dEZWJ1ZyhcbiAgICAgICAgICAgIGBXYXRjaGluZyAke2Z1bmN0aW9ucy5sZW5ndGh9IERvY2tlciBjb250ZXh0KHMpIGZvciBjaGFuZ2VzYCxcbiAgICAgICAgICApLFxuICAgICAgICApXG4gICAgICAgIGZvciAoY29uc3QgZm4gb2YgZnVuY3Rpb25zKSB7XG4gICAgICAgICAgRWZmZWN0LnJ1blN5bmMoXG4gICAgICAgICAgICBFZmZlY3QubG9nRGVidWcoYCAgLSAke2ZuLmZ1bmN0aW9uSWR9OiAke2ZuLmRvY2tlckNvbnRleHRQYXRofWApLFxuICAgICAgICAgIClcbiAgICAgICAgfVxuICAgICAgfSlcblxuICAgICAgLy8gQ2xlYW51cCB3aGVuIHNjb3BlIGNsb3Nlc1xuICAgICAgeWllbGQqIEVmZmVjdC5hZGRGaW5hbGl6ZXIoKCkgPT5cbiAgICAgICAgRWZmZWN0LmdlbihmdW5jdGlvbiogKCkge1xuICAgICAgICAgIHlpZWxkKiBFZmZlY3QucHJvbWlzZShhc3luYyAoKSA9PiB7XG4gICAgICAgICAgICBhd2FpdCB3YXRjaGVyLmNsb3NlKClcbiAgICAgICAgICB9KVxuICAgICAgICAgIHlpZWxkKiBFZmZlY3QubG9nRGVidWcoXCJEb2NrZXJXYXRjaGVyIGZpbGUgd2F0Y2hlciBjbG9zZWRcIilcbiAgICAgICAgfSksXG4gICAgICApXG4gICAgfSksXG4gICkucGlwZShcbiAgICAvLyBEZWJvdW5jZSB0byBoYW5kbGUgYmF0Y2ggZmlsZSBjaGFuZ2VzIChlLmcuLCBnaXQgY2hlY2tvdXQsIElERSBzYXZlLWFsbClcbiAgICBTdHJlYW0uZGVib3VuY2UoYCR7ZGVib3VuY2VNc30gbWlsbGlzYCksXG4gIClcbn1cblxuLyoqXG4gKiBDcmVhdGUgYSB3YXRjaGVyIGZvciBhIHNpbmdsZSBEb2NrZXIgZnVuY3Rpb24uXG4gKiBDb252ZW5pZW5jZSB3cmFwcGVyIGFyb3VuZCB3YXRjaERvY2tlckNvbnRleHRzIGZvciBzaW5nbGUtZnVuY3Rpb24gdXNlLlxuICovXG5leHBvcnQgY29uc3Qgd2F0Y2hTaW5nbGVEb2NrZXJDb250ZXh0ID0gKFxuICBmdW5jdGlvbklkOiBzdHJpbmcsXG4gIGRvY2tlckNvbnRleHRQYXRoOiBzdHJpbmcsXG4gIGRlYm91bmNlTXMgPSA1MDAsXG4pOiBTdHJlYW0uU3RyZWFtPERvY2tlckNvbnRleHRDaGFuZ2VFdmVudCwgRXJyb3I+ID0+XG4gIHdhdGNoRG9ja2VyQ29udGV4dHMoW3sgZnVuY3Rpb25JZCwgZG9ja2VyQ29udGV4dFBhdGggfV0sIGRlYm91bmNlTXMpXG4iXX0=
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * Effect CLI entry point for cdk-local-lambda.
4
+ *
5
+ * Commands:
6
+ * - bootstrap: Deploy the CdkLocalLambdaBootstrapStack
7
+ * - local: Run Lambda functions locally using Docker
8
+ */
9
+ export {};
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * Effect CLI entry point for cdk-local-lambda.
4
+ *
5
+ * Commands:
6
+ * - bootstrap: Deploy the CdkLocalLambdaBootstrapStack
7
+ * - local: Run Lambda functions locally using Docker
8
+ */
9
+ import { Command } from "@effect/cli";
10
+ import { BunContext, BunRuntime } from "@effect/platform-bun";
11
+ import { Effect } from "effect";
12
+ import { bootstrapCommand } from "./commands/bootstrap.js";
13
+ import { localCommand } from "./commands/local.js";
14
+ /**
15
+ * Root command
16
+ */
17
+ const rootCommand = Command.make("local-lambda", {}).pipe(Command.withSubcommands([bootstrapCommand, localCommand]), Command.withDescription("CLI for developing AWS Lambda functions locally"));
18
+ /**
19
+ * Run the CLI
20
+ */
21
+ const cli = Command.run(rootCommand, {
22
+ name: "local-lambda",
23
+ version: "0.1.0",
24
+ });
25
+ cli(process.argv).pipe(Effect.provide(BunContext.layer), BunRuntime.runMain);
26
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvY2xpL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFFQTs7Ozs7O0dBTUc7QUFFSCxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sYUFBYSxDQUFBO0FBQ3JDLE9BQU8sRUFBRSxVQUFVLEVBQUUsVUFBVSxFQUFFLE1BQU0sc0JBQXNCLENBQUE7QUFDN0QsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLFFBQVEsQ0FBQTtBQUMvQixPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQTtBQUMxRCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0scUJBQXFCLENBQUE7QUFFbEQ7O0dBRUc7QUFDSCxNQUFNLFdBQVcsR0FBRyxPQUFPLENBQUMsSUFBSSxDQUFDLGNBQWMsRUFBRSxFQUFFLENBQUMsQ0FBQyxJQUFJLENBQ3ZELE9BQU8sQ0FBQyxlQUFlLENBQUMsQ0FBQyxnQkFBZ0IsRUFBRSxZQUFZLENBQUMsQ0FBQyxFQUN6RCxPQUFPLENBQUMsZUFBZSxDQUFDLGlEQUFpRCxDQUFDLENBQzNFLENBQUE7QUFFRDs7R0FFRztBQUNILE1BQU0sR0FBRyxHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUMsV0FBVyxFQUFFO0lBQ25DLElBQUksRUFBRSxjQUFjO0lBQ3BCLE9BQU8sRUFBRSxPQUFPO0NBQ2pCLENBQUMsQ0FBQTtBQUVGLEdBQUcsQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsVUFBVSxDQUFDLEtBQUssQ0FBQyxFQUFFLFVBQVUsQ0FBQyxPQUFPLENBQUMsQ0FBQSIsInNvdXJjZXNDb250ZW50IjpbIiMhL3Vzci9iaW4vZW52IGJ1blxuXG4vKipcbiAqIEVmZmVjdCBDTEkgZW50cnkgcG9pbnQgZm9yIGNkay1sb2NhbC1sYW1iZGEuXG4gKlxuICogQ29tbWFuZHM6XG4gKiAtIGJvb3RzdHJhcDogRGVwbG95IHRoZSBDZGtMb2NhbExhbWJkYUJvb3RzdHJhcFN0YWNrXG4gKiAtIGxvY2FsOiBSdW4gTGFtYmRhIGZ1bmN0aW9ucyBsb2NhbGx5IHVzaW5nIERvY2tlclxuICovXG5cbmltcG9ydCB7IENvbW1hbmQgfSBmcm9tIFwiQGVmZmVjdC9jbGlcIlxuaW1wb3J0IHsgQnVuQ29udGV4dCwgQnVuUnVudGltZSB9IGZyb20gXCJAZWZmZWN0L3BsYXRmb3JtLWJ1blwiXG5pbXBvcnQgeyBFZmZlY3QgfSBmcm9tIFwiZWZmZWN0XCJcbmltcG9ydCB7IGJvb3RzdHJhcENvbW1hbmQgfSBmcm9tIFwiLi9jb21tYW5kcy9ib290c3RyYXAuanNcIlxuaW1wb3J0IHsgbG9jYWxDb21tYW5kIH0gZnJvbSBcIi4vY29tbWFuZHMvbG9jYWwuanNcIlxuXG4vKipcbiAqIFJvb3QgY29tbWFuZFxuICovXG5jb25zdCByb290Q29tbWFuZCA9IENvbW1hbmQubWFrZShcImxvY2FsLWxhbWJkYVwiLCB7fSkucGlwZShcbiAgQ29tbWFuZC53aXRoU3ViY29tbWFuZHMoW2Jvb3RzdHJhcENvbW1hbmQsIGxvY2FsQ29tbWFuZF0pLFxuICBDb21tYW5kLndpdGhEZXNjcmlwdGlvbihcIkNMSSBmb3IgZGV2ZWxvcGluZyBBV1MgTGFtYmRhIGZ1bmN0aW9ucyBsb2NhbGx5XCIpLFxuKVxuXG4vKipcbiAqIFJ1biB0aGUgQ0xJXG4gKi9cbmNvbnN0IGNsaSA9IENvbW1hbmQucnVuKHJvb3RDb21tYW5kLCB7XG4gIG5hbWU6IFwibG9jYWwtbGFtYmRhXCIsXG4gIHZlcnNpb246IFwiMC4xLjBcIixcbn0pXG5cbmNsaShwcm9jZXNzLmFyZ3YpLnBpcGUoRWZmZWN0LnByb3ZpZGUoQnVuQ29udGV4dC5sYXllciksIEJ1blJ1bnRpbWUucnVuTWFpbilcbiJdfQ==
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Lambda Runtime API HTTP server using Effect HttpServer.
3
+ *
4
+ * This server emulates the AWS Lambda Runtime API that Docker containers
5
+ * use to receive invocations and send responses.
6
+ *
7
+ * Each Lambda function gets its own server on an ephemeral port. The server
8
+ * maintains a queue of pending invocations. When a container polls
9
+ * /invocation/next, it blocks until an invocation is available.
10
+ *
11
+ * @see https://docs.aws.amazon.com/lambda/latest/dg/runtimes-api.html
12
+ */
13
+ import { Effect, HashMap, Queue, Ref, type Scope } from "effect";
14
+ import type { ExtensionEvent, LambdaError, LambdaInitError, LambdaInvocation, LambdaResponse, RegisteredExtension } from "./types.js";
15
+ /**
16
+ * State for a registered extension.
17
+ */
18
+ interface ExtensionState {
19
+ /** Extension info */
20
+ extension: RegisteredExtension;
21
+ /** Queue of events for this extension */
22
+ eventQueue: Queue.Queue<ExtensionEvent>;
23
+ }
24
+ /**
25
+ * Function metadata for extension registration responses.
26
+ */
27
+ export interface FunctionMetadata {
28
+ functionName: string;
29
+ functionVersion: string;
30
+ handler: string;
31
+ }
32
+ /**
33
+ * State for a Runtime API server session.
34
+ * Supports multiple invocations with a queue-based model.
35
+ */
36
+ export interface RuntimeApiState {
37
+ /** Queue of pending invocations waiting to be fetched by the container */
38
+ invocationQueue: Queue.Queue<LambdaInvocation>;
39
+ /** Queue for responses/errors from the container */
40
+ responseQueue: Queue.Queue<LambdaResponse | LambdaError | LambdaInitError>;
41
+ /** Registered extensions by extension ID */
42
+ extensions: Ref.Ref<HashMap.HashMap<string, ExtensionState>>;
43
+ /** Function metadata for extension registration */
44
+ functionMetadata: FunctionMetadata;
45
+ }
46
+ /**
47
+ * Result from starting a Runtime API server.
48
+ */
49
+ export interface RuntimeApiServer {
50
+ /** The actual port the server is listening on */
51
+ port: number;
52
+ /** The state containing the invocation and response queues */
53
+ state: RuntimeApiState;
54
+ }
55
+ /**
56
+ * Create a new Runtime API state (queues only, no port).
57
+ *
58
+ * @param functionMetadata - Function metadata for extension registration responses
59
+ */
60
+ export declare const makeRuntimeApiState: (functionMetadata: FunctionMetadata) => Effect.Effect<{
61
+ invocationQueue: Queue.Queue<LambdaInvocation>;
62
+ responseQueue: Queue.Queue<LambdaResponse | LambdaError | LambdaInitError>;
63
+ extensions: Ref.Ref<HashMap.HashMap<string, ExtensionState>>;
64
+ functionMetadata: FunctionMetadata;
65
+ }, never, never>;
66
+ /**
67
+ * Options for starting a Runtime API server.
68
+ */
69
+ export interface RuntimeApiServerOptions {
70
+ /** How long to wait for an invocation before returning 503 */
71
+ pollTimeoutMs?: number;
72
+ /** Function metadata for extension registration */
73
+ functionMetadata?: FunctionMetadata;
74
+ }
75
+ /**
76
+ * Start a Runtime API server on an ephemeral port.
77
+ * Returns the actual port and state for this server instance.
78
+ *
79
+ * The server is scoped - it will be stopped when the scope closes.
80
+ *
81
+ * @param options - Server configuration options
82
+ */
83
+ export declare const startRuntimeApiServer: (options?: RuntimeApiServerOptions) => Effect.Effect<RuntimeApiServer, never, Scope.Scope>;
84
+ /**
85
+ * Queue an invocation for the container to process.
86
+ */
87
+ export declare const queueInvocation: (state: RuntimeApiState, invocation: LambdaInvocation) => Effect.Effect<void>;
88
+ /**
89
+ * Wait for the response to a specific invocation.
90
+ */
91
+ export declare const waitForResponse: (state: RuntimeApiState) => Effect.Effect<LambdaResponse | LambdaError | LambdaInitError>;
92
+ /**
93
+ * Notify all registered extensions about an invocation.
94
+ * This sends an INVOKE event to all extensions that registered for it.
95
+ */
96
+ export declare const notifyExtensionsInvoke: (state: RuntimeApiState, invocation: LambdaInvocation) => Effect.Effect<void>;
97
+ /**
98
+ * Notify all registered extensions about shutdown.
99
+ * This sends a SHUTDOWN event to all extensions that registered for it.
100
+ */
101
+ export declare const notifyExtensionsShutdown: (state: RuntimeApiState, reason?: "SPINDOWN" | "TIMEOUT" | "FAILURE") => Effect.Effect<void>;
102
+ export {};