@lambda-kata/cdk 0.1.3-rc.2 → 0.1.3-rc.21

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,640 @@
1
+ /**
2
+ * AWS Lambda Layer Manager with SDK v3 Integration
3
+ *
4
+ * This module provides AWS Lambda Layer management functionality using AWS SDK v3.
5
+ * It handles layer creation, searching, and compatibility validation for Node.js
6
+ * runtime layers used by Lambda Kata.
7
+ *
8
+ * Key features:
9
+ * - AWS SDK v3 Lambda client integration with configurable options
10
+ * - Automatic pagination handling for layer listing operations
11
+ * - Layer compatibility validation based on Node.js version and architecture
12
+ * - Comprehensive error handling with retry logic
13
+ * - Idempotent operations to prevent duplicate layer creation
14
+ *
15
+ * @module aws-layer-manager
16
+ */
17
+ import { LambdaClientConfig } from '@aws-sdk/client-lambda';
18
+ import { S3ClientConfig } from '@aws-sdk/client-s3';
19
+ import { LayerCreationOptions, LayerInfo, LayerManager, LayerRequirements, LayerSearchOptions, Logger, MultiArchitectureDeploymentResult, NodejsLayerDeploymentOptions, NodejsLayerDeploymentResult } from './nodejs-layer-manager';
20
+ /**
21
+ * Configuration options for AWSLayerManager.
22
+ */
23
+ export interface AWSLayerManagerOptions {
24
+ /**
25
+ * AWS SDK configuration for Lambda client.
26
+ * If not provided, uses default AWS SDK configuration.
27
+ */
28
+ awsSdkConfig?: LambdaClientConfig;
29
+ /**
30
+ * AWS SDK configuration for S3 client.
31
+ * If not provided, uses the same configuration as Lambda client.
32
+ */
33
+ s3SdkConfig?: S3ClientConfig;
34
+ /**
35
+ * Logger for debugging and monitoring.
36
+ * If not provided, uses createDefaultLogger().
37
+ */
38
+ logger?: Logger;
39
+ /**
40
+ * Maximum age in milliseconds for layers to be considered fresh.
41
+ * Layers older than this may be recreated.
42
+ * Default: 7 days (604800000ms)
43
+ */
44
+ maxLayerAge?: number;
45
+ /**
46
+ * Maximum number of retries for AWS API operations.
47
+ * Default: 3
48
+ */
49
+ maxRetries?: number;
50
+ /**
51
+ * Base delay in milliseconds for exponential backoff.
52
+ * Default: 1000ms (1 second)
53
+ */
54
+ retryBaseDelay?: number;
55
+ /**
56
+ * Circuit breaker failure threshold.
57
+ * Number of consecutive failures before opening the circuit.
58
+ * Default: 5
59
+ */
60
+ circuitBreakerFailureThreshold?: number;
61
+ /**
62
+ * Circuit breaker timeout in milliseconds.
63
+ * How long to wait before transitioning from OPEN to HALF_OPEN.
64
+ * Default: 60000ms (1 minute)
65
+ */
66
+ circuitBreakerTimeout?: number;
67
+ /**
68
+ * Circuit breaker success threshold for HALF_OPEN state.
69
+ * Number of consecutive successes needed to close the circuit.
70
+ * Default: 2
71
+ */
72
+ circuitBreakerSuccessThreshold?: number;
73
+ /**
74
+ * Enable S3 support for large layer uploads.
75
+ * If true, creates S3Client for handling layers >50MB.
76
+ * Default: true
77
+ */
78
+ enableS3Support?: boolean;
79
+ }
80
+ /**
81
+ * AWS Lambda Layer Manager implementation using AWS SDK v3.
82
+ *
83
+ * Provides comprehensive layer management functionality including:
84
+ * - Layer searching with pagination support
85
+ * - Layer compatibility validation
86
+ * - Layer creation with proper metadata
87
+ * - Error handling with exponential backoff retry logic
88
+ * - Circuit breaker pattern for AWS API resilience
89
+ * - Concurrent operation coordination to prevent duplicate layer creation
90
+ *
91
+ * @example
92
+ * ```typescript
93
+ * const manager = new AWSLayerManager({
94
+ * awsSdkConfig: { region: 'us-east-1' },
95
+ * logger: new ConsoleLogger()
96
+ * });
97
+ *
98
+ * const layer = await manager.findExistingLayer({
99
+ * layerName: 'lambda-kata-nodejs-nodejs20.x-x86_64',
100
+ * requirements: {
101
+ * nodeVersion: '20.10.0',
102
+ * architecture: 'x86_64'
103
+ * }
104
+ * });
105
+ * ```
106
+ */
107
+ export declare class AWSLayerManager implements LayerManager {
108
+ private readonly lambdaClient;
109
+ private readonly s3Client;
110
+ private readonly logger;
111
+ private readonly maxLayerAge;
112
+ private readonly maxRetries;
113
+ private readonly retryBaseDelay;
114
+ private readonly circuitBreaker;
115
+ /**
116
+ * Map of layer names to in-progress creation operations.
117
+ * Used to coordinate concurrent calls and prevent duplicate layer creation.
118
+ */
119
+ private readonly layerCreationLocks;
120
+ /**
121
+ * AWS Lambda Layer size limits (in bytes).
122
+ * These are AWS service limits that cannot be exceeded.
123
+ */
124
+ private static readonly MAX_LAYER_SIZE_UNZIPPED;
125
+ private static readonly MAX_LAYER_SIZE_ZIPPED;
126
+ /**
127
+ * Docker operation timeout in milliseconds.
128
+ */
129
+ private static readonly DOCKER_TIMEOUT;
130
+ constructor(options?: AWSLayerManagerOptions);
131
+ /**
132
+ * Searches for an existing compatible Node.js layer.
133
+ *
134
+ * Uses AWS SDK v3 pagination to efficiently search through all layers
135
+ * in the account and region. Validates compatibility based on layer
136
+ * metadata and requirements.
137
+ *
138
+ * @param options - Search criteria and requirements
139
+ * @returns Promise resolving to layer info if found, null otherwise
140
+ * @throws NodeRuntimeLayerError if search fails
141
+ */
142
+ findExistingLayer(options: LayerSearchOptions): Promise<LayerInfo | null>;
143
+ /**
144
+ * Creates a new Node.js Lambda Layer with concurrent operation coordination.
145
+ *
146
+ * This method extracts the Node.js binary from the corresponding AWS Lambda
147
+ * Docker image, packages it in the proper Lambda Layer directory structure,
148
+ * and publishes it to AWS Lambda with appropriate metadata.
149
+ *
150
+ * Enhanced with concurrent operation coordination to prevent duplicate layer
151
+ * creation when multiple calls are made with identical parameters. If a layer
152
+ * creation is already in progress for the same layer name, subsequent calls
153
+ * will wait for the existing operation to complete rather than starting a
154
+ * duplicate operation.
155
+ *
156
+ * Process:
157
+ * 1. Check for existing in-progress layer creation operation
158
+ * 2. If operation exists, wait for its completion
159
+ * 3. If no operation exists, start new layer creation with lock
160
+ * 4. Create temporary directory for layer contents
161
+ * 5. Extract Node.js binary from Docker container
162
+ * 6. Create proper Lambda Layer directory structure (/opt/nodejs/bin/)
163
+ * 7. Create ZIP archive with correct permissions
164
+ * 8. Validate size limits
165
+ * 9. Publish to AWS Lambda
166
+ * 10. Clean up temporary files and release lock
167
+ *
168
+ * Enhanced with comprehensive resource cleanup on failure to prevent orphaned resources.
169
+ *
170
+ * @param options - Layer creation configuration
171
+ * @returns Promise resolving to information about the created layer
172
+ * @throws NodeRuntimeLayerError if creation fails
173
+ */
174
+ createNodeLayer(options: LayerCreationOptions): Promise<LayerInfo>;
175
+ /**
176
+ * Performs the actual layer creation operation without concurrent coordination.
177
+ *
178
+ * This is the core layer creation logic extracted from the original createNodeLayer
179
+ * method to separate concerns between concurrent coordination and actual creation.
180
+ *
181
+ * @param options - Layer creation configuration
182
+ * @returns Promise resolving to information about the created layer
183
+ * @throws NodeRuntimeLayerError if creation fails
184
+ */
185
+ private performLayerCreation;
186
+ /**
187
+ * Deploys a pre-built Node.js Lambda Layer from ZIP file.
188
+ *
189
+ * This method bypasses Docker binary extraction and deploys existing
190
+ * layer ZIP files directly to AWS Lambda. Handles large layers via S3
191
+ * temporary bucket upload with automatic cleanup.
192
+ *
193
+ * Process:
194
+ * 1. Validate input parameters and architecture
195
+ * 2. Search for existing layer ZIP files with fallback naming patterns
196
+ * 3. Read and validate layer ZIP file size
197
+ * 4. Deploy via direct upload (<50MB) or S3 upload (≥50MB)
198
+ * 5. Clean up temporary S3 resources if used
199
+ * 6. Return deployment result with layer ARN and metadata
200
+ *
201
+ * @param options - Deployment configuration
202
+ * @returns Promise resolving to deployment result
203
+ * @throws NodeRuntimeLayerError if deployment fails
204
+ */
205
+ deployNodejsLayer(options: NodejsLayerDeploymentOptions): Promise<NodejsLayerDeploymentResult>;
206
+ /**
207
+ * Deploys Node.js layers for all supported architectures.
208
+ *
209
+ * Attempts to deploy layers for both arm64 and x86_64 architectures,
210
+ * continuing on individual failures to maximize successful deployments.
211
+ * This matches the behavior of the Python deployment script.
212
+ *
213
+ * @param options - Base deployment configuration (architecture will be overridden)
214
+ * @returns Promise resolving to multi-architecture deployment results
215
+ */
216
+ deployAllArchitectures(options: Omit<NodejsLayerDeploymentOptions, 'architecture'>): Promise<MultiArchitectureDeploymentResult>;
217
+ /**
218
+ * Generates a standard layer name for the given architecture.
219
+ *
220
+ * @param architecture - Target architecture
221
+ * @returns Standard layer name following the pattern: nodejs-18-{architecture}
222
+ */
223
+ private generateLayerName;
224
+ /**
225
+ * Searches for layer ZIP files with fallback naming patterns.
226
+ *
227
+ * Implements the same search logic as the Python script with multiple
228
+ * naming conventions for maximum compatibility.
229
+ *
230
+ * @param architecture - Target architecture
231
+ * @param baseDirectory - Directory to search in
232
+ * @returns Promise resolving to ZIP file path or null if not found
233
+ */
234
+ private findLayerZipFile;
235
+ /**
236
+ * Deploys a large layer (>50MB) via S3 temporary bucket.
237
+ *
238
+ * Creates a temporary S3 bucket, uploads the layer, publishes from S3,
239
+ * and cleans up the bucket. Implements the same logic as the Python script.
240
+ *
241
+ * @param layerName - Name of the layer
242
+ * @param layerContent - ZIP file content
243
+ * @param architecture - Target architecture
244
+ * @param region - AWS region
245
+ * @param description - Optional layer description
246
+ * @param zipFilePath - Original ZIP file path for metadata
247
+ * @returns Promise resolving to deployment result
248
+ */
249
+ private deployLargeLayerViaS3;
250
+ /**
251
+ * Deploys a layer directly to Lambda (for layers <50MB).
252
+ *
253
+ * @param layerName - Name of the layer
254
+ * @param layerContent - ZIP file content
255
+ * @param architecture - Target architecture
256
+ * @param description - Optional layer description
257
+ * @param zipFilePath - Original ZIP file path for metadata
258
+ * @returns Promise resolving to deployment result
259
+ */
260
+ private deployLayerDirect;
261
+ /**
262
+ * Creates an S3 bucket for temporary layer storage.
263
+ *
264
+ * @param bucketName - Name of the bucket to create
265
+ * @param region - AWS region
266
+ */
267
+ private createS3Bucket;
268
+ /**
269
+ * Uploads layer content to S3.
270
+ *
271
+ * @param bucketName - S3 bucket name
272
+ * @param keyName - S3 object key
273
+ * @param layerContent - Layer ZIP content
274
+ */
275
+ private uploadLayerToS3;
276
+ /**
277
+ * Cleans up S3 resources (bucket and objects).
278
+ *
279
+ * @param bucketName - S3 bucket name
280
+ * @param keyName - S3 object key
281
+ */
282
+ private cleanupS3Resources;
283
+ /**
284
+ * Validates whether a layer meets the specified requirements.
285
+ *
286
+ * Checks layer compatibility based on:
287
+ * - Node.js version exact match
288
+ * - Architecture compatibility
289
+ * - Layer age (if maxAge is specified in requirements)
290
+ *
291
+ * @param layer - The layer to validate
292
+ * @param requirements - The requirements to check against
293
+ * @returns true if the layer is compatible, false otherwise
294
+ */
295
+ validateLayerCompatibility(layer: LayerInfo, requirements: LayerRequirements): boolean;
296
+ /**
297
+ * Lists layers by name using AWS SDK v3 pagination with retry logic.
298
+ *
299
+ * Efficiently searches through all layers in the account and region
300
+ * to find layers matching the specified name pattern. Uses retry logic
301
+ * to handle transient pagination failures.
302
+ *
303
+ * @param layerName - The layer name to search for
304
+ * @returns Promise resolving to array of matching layers
305
+ * @throws Error if AWS API operations fail
306
+ */
307
+ private listLayersByName;
308
+ /**
309
+ * Gets detailed information about a specific layer version.
310
+ *
311
+ * Retrieves layer metadata and extracts Node.js version and architecture
312
+ * information from the layer description or other metadata.
313
+ *
314
+ * @param layerName - The name of the layer
315
+ * @param version - The version number of the layer
316
+ * @returns Promise resolving to LayerInfo
317
+ * @throws Error if layer information cannot be retrieved
318
+ */
319
+ private getLayerInfo;
320
+ /**
321
+ * Parses layer metadata to extract Node.js version and architecture.
322
+ *
323
+ * Attempts to extract information from layer description or falls back
324
+ * to parsing the layer name if description doesn't contain the required data.
325
+ *
326
+ * @param description - The layer description
327
+ * @param layerName - The layer name as fallback
328
+ * @returns Object containing nodeVersion and architecture
329
+ */
330
+ private parseLayerMetadata;
331
+ /**
332
+ * Executes an AWS API operation with exponential backoff retry logic and circuit breaker protection.
333
+ *
334
+ * Implements retry logic for transient AWS API failures with exponential
335
+ * backoff and jitter to avoid thundering herd problems. Uses circuit breaker
336
+ * pattern to prevent cascading failures during AWS service outages.
337
+ *
338
+ * @param operation - The async operation to execute
339
+ * @returns Promise resolving to the operation result
340
+ * @throws Error if all retries are exhausted or circuit breaker is open
341
+ */
342
+ private executeWithRetry;
343
+ /**
344
+ * Determines if an error is retryable.
345
+ *
346
+ * @param error - The error to check
347
+ * @returns true if the error is retryable, false otherwise
348
+ */
349
+ private isRetryableError;
350
+ /**
351
+ * Checks if an error is a network-related error that should be retried.
352
+ *
353
+ * @param error - The error to check
354
+ * @returns true if it's a retryable network error
355
+ */
356
+ private isNetworkError;
357
+ /**
358
+ * Calculates retry delay with exponential backoff and jitter.
359
+ *
360
+ * @param attempt - The current attempt number (0-based)
361
+ * @returns Delay in milliseconds
362
+ */
363
+ private calculateRetryDelay;
364
+ /**
365
+ * Sleeps for the specified number of milliseconds.
366
+ *
367
+ * @param ms - Milliseconds to sleep
368
+ * @returns Promise that resolves after the delay
369
+ */
370
+ private sleep;
371
+ /**
372
+ * Gets the current circuit breaker state for monitoring and debugging.
373
+ *
374
+ * @returns Object containing circuit breaker state information
375
+ */
376
+ getCircuitBreakerState(): {
377
+ state: string;
378
+ failureCount: number;
379
+ successCount: number;
380
+ };
381
+ /**
382
+ * Gets the current concurrent operation state for monitoring and debugging.
383
+ *
384
+ * @returns Object containing information about in-progress layer creation operations
385
+ */
386
+ getConcurrentOperationState(): {
387
+ activeOperations: number;
388
+ operations: Array<{
389
+ layerName: string;
390
+ startTime: number;
391
+ duration: number;
392
+ waiters: number;
393
+ nodeVersion: string;
394
+ architecture: string;
395
+ }>;
396
+ };
397
+ /**
398
+ * Destroys the AWS Lambda client and cleans up resources.
399
+ *
400
+ * Should be called when the manager is no longer needed to prevent
401
+ * resource leaks. Also cleans up any remaining concurrent operation locks.
402
+ */
403
+ destroy(): void;
404
+ /**
405
+ * Creates a temporary directory for layer creation operations.
406
+ *
407
+ * @returns Promise resolving to the temporary directory path
408
+ * @throws Error if directory creation fails
409
+ */
410
+ private createTempDirectory;
411
+ /**
412
+ * Extracts Node.js binary from AWS Lambda Docker image with resource tracking.
413
+ *
414
+ * Uses ONLY AWS Lambda Docker images to extract the Node.js binary from the
415
+ * official Lambda runtime environment. This ensures compatibility with the
416
+ * Lambda execution environment while extracting only the minimal binary needed.
417
+ *
418
+ * CRITICAL: Uses ONLY AWS Lambda Docker images as required by user specifications.
419
+ * Docker image format: public.ecr.aws/lambda/nodejs:{version}-{arch}
420
+ * Extracts ONLY: /var/lang/bin/node
421
+ *
422
+ * @param nodeVersion - The Node.js version (e.g., "20.10.0")
423
+ * @param architecture - The target architecture
424
+ * @param tempDir - Temporary directory for extraction
425
+ * @param resourceTracker - Resource tracker for cleanup
426
+ * @returns Promise resolving to the path of the extracted binary
427
+ * @throws NodeRuntimeLayerError if extraction fails
428
+ */
429
+ private extractNodeBinaryFromDockerWithTracking;
430
+ /**
431
+ * Optimizes Node.js binary to reduce size while preserving functionality.
432
+ *
433
+ * Multi-stage optimization approach:
434
+ * 1. Strip debug symbols using 'strip' command (30-50% reduction)
435
+ * 2. UPX compression if still >50MB (50-70% additional reduction)
436
+ * 3. System Node.js replacement if still >60MB
437
+ * 4. Verify binary functionality after each stage
438
+ * 5. Fallback to original if within 250MB limit
439
+ *
440
+ * @param originalBinaryPath - Path to the original Node.js binary
441
+ * @param tempDir - Temporary directory for optimization work
442
+ * @returns Promise resolving to path of optimized binary
443
+ * @throws Error if optimization fails and original exceeds 250MB limit
444
+ */
445
+ private optimizeNodeBinary;
446
+ /**
447
+ * Attempts strip-based optimization with progressive aggressiveness.
448
+ *
449
+ * @param originalBinaryPath - Path to original binary
450
+ * @param tempDir - Working directory
451
+ * @returns Path to stripped binary or original if stripping fails
452
+ */
453
+ private tryStripOptimization;
454
+ /**
455
+ * Attempts UPX compression optimization.
456
+ *
457
+ * @param binaryPath - Path to binary to compress
458
+ * @param tempDir - Working directory
459
+ * @returns Path to compressed binary or null if UPX unavailable/fails
460
+ */
461
+ private tryUPXOptimization;
462
+ /**
463
+ * Attempts to use system Node.js binary as replacement.
464
+ *
465
+ * @param tempDir - Working directory
466
+ * @returns Path to system Node.js copy or null if unavailable/unsuitable
467
+ */
468
+ private trySystemNodeReplacement;
469
+ /**
470
+ * Verifies that a Node.js binary is functional after optimization.
471
+ *
472
+ * Runs basic Node.js commands to ensure the binary works correctly.
473
+ * This prevents shipping broken binaries after optimization.
474
+ *
475
+ * @param binaryPath - Path to the Node.js binary to verify
476
+ * @throws Error if verification fails
477
+ */
478
+ private verifyNodeBinary;
479
+ /**
480
+ * Verifies Node.js binary with graceful fallback for spawn errors.
481
+ *
482
+ * This method attempts full verification but falls back to basic checks
483
+ * if spawn fails (e.g., error -8). This prevents blocking deployment for
484
+ * binaries that are valid but fail verification due to system issues.
485
+ *
486
+ * @param binaryPath - Path to the Node.js binary to verify
487
+ * @returns Promise resolving to verification result with success flag and optional error
488
+ */
489
+ private verifyNodeBinaryWithFallback;
490
+ /**
491
+ * Creates the proper Lambda Layer directory structure.
492
+ *
493
+ * Lambda Layers for Node.js binary should use minimal structure:
494
+ * - bin/node (uncompressed binary)
495
+ * - bin/node.gz (compressed binary with decompression script)
496
+ *
497
+ * @param tempDir - Base temporary directory
498
+ * @param nodeBinaryPath - Path to the Node.js binary (may be compressed)
499
+ * @returns Promise resolving to the layer directory path
500
+ * @throws Error if directory creation fails
501
+ */
502
+ private createLayerDirectoryStructure;
503
+ /**
504
+ * Creates a ZIP archive of the layer contents with compression optimization.
505
+ *
506
+ * Uses Python's zipfile module to create a properly compressed ZIP file with
507
+ * file permissions preserved for the Node.js binary. Implements compression
508
+ * optimization to minimize storage and transfer costs.
509
+ *
510
+ * @param layerDir - Directory containing the layer contents
511
+ * @param layerName - Name of the layer (used for ZIP filename)
512
+ * @returns Promise resolving to the ZIP file path
513
+ * @throws Error if ZIP creation fails
514
+ */
515
+ private createLayerZipArchive;
516
+ /**
517
+ * Calculates the total size of all files in a directory.
518
+ *
519
+ * @param dirPath - Directory path to analyze
520
+ * @returns Promise resolving to total size in bytes
521
+ */
522
+ private calculateDirectorySize;
523
+ /**
524
+ * Fallback ZIP creation using system zip command.
525
+ *
526
+ * @param layerDir - Directory containing the layer contents
527
+ * @param zipFilePath - Target ZIP file path
528
+ * @returns Promise resolving to the ZIP file path
529
+ * @throws Error if ZIP creation fails
530
+ */
531
+ private createZipFallback;
532
+ /**
533
+ * Validates that the layer ZIP file meets AWS size limits.
534
+ *
535
+ * AWS Lambda has strict size limits for layers:
536
+ * - 50MB for zipped layer
537
+ * - 250MB for unzipped layer
538
+ *
539
+ * Enhanced to check both zipped and unzipped sizes with comprehensive
540
+ * error reporting and optimization suggestions.
541
+ *
542
+ * @param zipFilePath - Path to the ZIP file
543
+ * @throws NodeRuntimeLayerError if size limits are exceeded
544
+ */
545
+ private preValidateLayerContent;
546
+ /**
547
+ * Validates layer size limits after ZIP creation.
548
+ *
549
+ * @param zipFilePath - Path to the ZIP file
550
+ * @throws NodeRuntimeLayerError if size limits are exceeded
551
+ */
552
+ private validateLayerSize;
553
+ /**
554
+ * Calculates the unzipped size of a ZIP file by examining its contents.
555
+ *
556
+ * Uses Python's zipfile module to read ZIP metadata and calculate
557
+ * the total uncompressed size without extracting files.
558
+ *
559
+ * @param zipFilePath - Path to the ZIP file
560
+ * @returns Promise resolving to unzipped size in bytes
561
+ * @throws Error if size calculation fails
562
+ */
563
+ private calculateUnzippedSize;
564
+ /**
565
+ * Publishes the layer to AWS Lambda.
566
+ *
567
+ * Uses the AWS SDK v3 Lambda client to publish the layer with proper
568
+ * metadata including compatible runtimes and architectures.
569
+ *
570
+ * @param options - Layer creation options
571
+ * @param zipFilePath - Path to the ZIP file
572
+ * @returns Promise resolving to LayerInfo
573
+ * @throws NodeRuntimeLayerError if publishing fails
574
+ */
575
+ private publishLayerToAWS;
576
+ /**
577
+ * Executes a Docker command with timeout and error handling.
578
+ *
579
+ * @param args - Docker command arguments
580
+ * @returns Promise that resolves when command completes successfully
581
+ * @throws Error if command fails
582
+ */
583
+ private executeDockerCommand;
584
+ /**
585
+ * Executes a system command with timeout and error handling, capturing output.
586
+ *
587
+ * @param command - Command to execute
588
+ * @param args - Command arguments
589
+ * @param options - Execution options including working directory
590
+ * @returns Promise resolving to command output (stdout and stderr)
591
+ * @throws Error if command fails
592
+ */
593
+ private executeCommandWithOutput;
594
+ /**
595
+ * Executes a system command with timeout and error handling.
596
+ *
597
+ * @param command - Command to execute
598
+ * @param args - Command arguments
599
+ * @param options - Execution options including working directory
600
+ * @returns Promise that resolves when command completes successfully
601
+ * @throws Error if command fails
602
+ */
603
+ private executeCommand;
604
+ /**
605
+ * Legacy cleanup method for backward compatibility.
606
+ *
607
+ * @deprecated Use performComprehensiveCleanup with ResourceTracker instead
608
+ * @param tempDir - Temporary directory to remove (if exists)
609
+ * @param zipFilePath - ZIP file to remove (if exists)
610
+ */
611
+ private cleanupTempResources;
612
+ /**
613
+ * Legacy Docker extraction method for backward compatibility.
614
+ *
615
+ * @deprecated Use extractNodeBinaryFromDockerWithTracking instead
616
+ */
617
+ private extractNodeBinaryFromDocker;
618
+ /**
619
+ * Creates an enhanced error with cleanup context preservation.
620
+ *
621
+ * Preserves the original error while adding context about the layer creation
622
+ * operation that failed. This maintains debugging capability while providing
623
+ * additional context for troubleshooting.
624
+ *
625
+ * @param originalError - The original error that occurred
626
+ * @param options - Layer creation options for context
627
+ * @returns Enhanced NodeRuntimeLayerError with preserved context
628
+ */
629
+ private createEnhancedError;
630
+ /**
631
+ * Performs comprehensive cleanup of all tracked resources.
632
+ *
633
+ * Cleans up Docker containers, temporary directories, and ZIP files.
634
+ * Cleanup failures are logged as warnings but do not prevent the cleanup
635
+ * of other resources or mask the original error.
636
+ *
637
+ * @param resourceTracker - Tracker containing all resources to clean up
638
+ */
639
+ private performComprehensiveCleanup;
640
+ }