aws-lambda-layer-cli 1.4.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Yuk Chow
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,393 @@
1
+ # AWS Lambda Layer CLI Tool
2
+
3
+ A command-line tool for creating and publishing AWS Lambda layers for Node.js and Python.
4
+
5
+ ## Features
6
+
7
+ - **Create Layers**: Generate Lambda layer zip files for Node.js and Python
8
+ - **Publish to AWS**: Directly publish layers to AWS Lambda with IAM credentials
9
+ - **Version Management**: Support for package version specification
10
+ - **Security**: Input validation and sanitization
11
+ - **Smart Naming**: Automatic layer naming with package versions
12
+ - **Multiple Packages**: Support for multiple packages in a single layer
13
+ - **Runtime Versioning**: Specify Node.js or Python versions
14
+ - **Package Managers**: Support for npm (Node.js) and uv/pip (Python)
15
+ - **AWS Profile Support**: Use different AWS profiles for publishing
16
+ - **Region Specification**: Target specific AWS regions
17
+
18
+ ## Installation
19
+
20
+ ### Package managers (recommended)
21
+
22
+ These installs do **not** write to `/usr/local` and do **not** require `sudo`.
23
+
24
+ #### npm (Node.js)
25
+
26
+ ```bash
27
+ npm i -g aws-lambda-layer-cli
28
+ aws-lambda-layer --help
29
+ ```
30
+
31
+ #### pip (Python)
32
+
33
+ ```bash
34
+ python -m pip install --user aws-lambda-layer-cli
35
+ aws-lambda-layer --help
36
+ ```
37
+
38
+ #### uv (Python)
39
+
40
+ ```bash
41
+ uv tool install aws-lambda-layer-cli
42
+ aws-lambda-layer --help
43
+ ```
44
+
45
+ ### Linux/macOS
46
+
47
+ ```bash
48
+ # Clone or download the repository
49
+ git clone <repository-url>
50
+ cd aws-lambda-layer-cli
51
+
52
+ # Run installation script (requires sudo)
53
+ sudo ./scripts/install.sh
54
+ ```
55
+
56
+ The installation will:
57
+ - Copy scripts to `/usr/local/lib/aws-lambda-layer`
58
+ - Create a symlink in `/usr/local/bin` for global access
59
+ - Install shell completions for bash and zsh
60
+
61
+ ### Windows
62
+
63
+ #### Option 1: PowerShell (Recommended)
64
+
65
+ ```powershell
66
+ # One-liner installation
67
+ powershell -ExecutionPolicy ByPass -c "irm https://raw.githubusercontent.com/yukcw/aws-lambda-layer-cli/main/scripts/install.ps1 | iex"
68
+ ```
69
+
70
+ Or download and run manually:
71
+
72
+ ```powershell
73
+ # Download the installer
74
+ Invoke-WebRequest -Uri "https://raw.githubusercontent.com/yukcw/aws-lambda-layer-cli/main/scripts/install.ps1" -OutFile "install.ps1"
75
+
76
+ # Run the installer (as Administrator)
77
+ .\install.ps1
78
+ ```
79
+
80
+ This will:
81
+ - Download the tool to `%USERPROFILE%\.aws-lambda-layer`
82
+ - Add it to your PATH
83
+ - Create Windows wrapper scripts
84
+
85
+ #### Option 2: Manual Installation
86
+
87
+ 1. Install prerequisites:
88
+ - [Git for Windows](https://gitforwindows.org/) (includes Git Bash)
89
+ - [AWS CLI](https://aws.amazon.com/cli/) (for publish command)
90
+
91
+ 2. Download the scripts from the [repository](https://github.com/yukcw/aws-lambda-layer-cli)
92
+
93
+ 3. Extract to a directory and add to PATH
94
+
95
+ ### Requirements
96
+
97
+ - **Linux/macOS**: Bash shell
98
+ - **Windows**: Windows Subsystem for Linux (WSL) (recommended), or Git Bash/Cygwin
99
+ - **AWS CLI**: Required for `publish` command
100
+ - **Node.js**: Required for Node.js layer creation
101
+ - **Python**: Required for Python layer creation (uv recommended)
102
+ - **zip**: Required for creating zip archives
103
+
104
+ **Note**: If using WSL, ensure that AWS CLI, Node.js, Python, and zip are installed within WSL for proper functionality.
105
+
106
+ ## Uninstallation
107
+
108
+ ### Package managers
109
+
110
+ ```bash
111
+ # npm
112
+ npm uninstall -g aws-lambda-layer-cli
113
+
114
+ # pip
115
+ python -m pip uninstall aws-lambda-layer-cli
116
+
117
+ # uv
118
+ uv tool uninstall aws-lambda-layer-cli
119
+ ```
120
+
121
+ ### Linux/macOS
122
+
123
+ ```bash
124
+ sudo ./scripts/uninstall.sh
125
+ ```
126
+
127
+ ### Windows
128
+
129
+ #### Using PowerShell
130
+
131
+ ```powershell
132
+ # Download and run the uninstaller
133
+ Invoke-WebRequest -Uri "https://raw.githubusercontent.com/yukcw/aws-lambda-layer-cli/main/scripts/uninstall.ps1" -OutFile "uninstall.ps1"
134
+ .\uninstall.ps1
135
+ ```
136
+
137
+ Or run directly without downloading:
138
+
139
+ ```powershell
140
+ powershell -ExecutionPolicy ByPass -c "irm https://raw.githubusercontent.com/yukcw/aws-lambda-layer-cli/main/scripts/uninstall.ps1 | iex"
141
+ ```
142
+ #### Troubleshooting Windows Installation
143
+
144
+ If you encounter issues:
145
+
146
+ 1. **"bash: command not found"**
147
+ - Install [Git for Windows](https://gitforwindows.org/) or [WSL](https://docs.microsoft.com/en-us/windows/wsl/install)
148
+ - Restart PowerShell/Command Prompt after installation
149
+
150
+ 2. **"No such file or directory"**
151
+ - Try running: `bash "$env:USERPROFILE\.aws-lambda-layer\aws-lambda-layer" --help`
152
+ - Or reinstall: `powershell -ExecutionPolicy ByPass -c "irm https://raw.githubusercontent.com/yukcw/aws-lambda-layer-cli/main/scripts/install.ps1 | iex"`
153
+
154
+ 3. **Permission issues**
155
+ - Run PowerShell as Administrator
156
+ - Or run: `Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser`
157
+ ## Usage
158
+
159
+ ### Basic Syntax
160
+
161
+ ```bash
162
+ # Create a local zip file
163
+ aws-lambda-layer zip --nodejs <packages> [options]
164
+ aws-lambda-layer zip --python <packages> [options]
165
+
166
+ # Publish directly to AWS
167
+ aws-lambda-layer publish --nodejs <packages> [options]
168
+ aws-lambda-layer publish --python <packages> [options]
169
+ ```
170
+
171
+ ### Commands
172
+
173
+ - **zip**: Create and package a Lambda layer as zip file
174
+ - **publish**: Create and publish a Lambda layer to AWS (uses IAM credentials)
175
+ - **help**: Show help message
176
+
177
+ ### Runtime Options
178
+
179
+ - `--nodejs`, `--node`, `-n`: Create a Node.js Lambda layer
180
+ - `--python`, `--py`, `-p`: Create a Python Lambda layer
181
+ - `--runtime=RUNTIME`: Specify runtime (nodejs or python)
182
+
183
+ ### Common Options
184
+
185
+ - `--name`: Name for the output zip file / layer name
186
+ - `--description`: Description for the layer (publish command only)
187
+ - `-h`, `--help`: Show help message
188
+
189
+ ### AWS Options (publish command only)
190
+
191
+ - `--profile`: AWS CLI profile to use (default: default profile)
192
+ - `--region`: AWS region (e.g., us-east-1, ap-east-1)
193
+
194
+ ### Node.js Specific Options
195
+
196
+ - `--node-version`: Node.js version (default: 24)
197
+
198
+ ### Python Specific Options
199
+
200
+ - `--python-version`: Python version (default: 3.14)
201
+ - `--no-uv`: Use pip/venv instead of uv
202
+
203
+ ## Examples
204
+
205
+ ### Node.js Examples
206
+
207
+ #### Create Local Zip Files
208
+
209
+ ```bash
210
+ # Single package with version
211
+ aws-lambda-layer zip --nodejs express@4.18.2
212
+
213
+ # Multiple packages with versions
214
+ aws-lambda-layer zip --nodejs express@4.18.2,axios@1.6.2,lodash@4.17.21
215
+
216
+ # With custom name
217
+ aws-lambda-layer zip --nodejs axios,lodash --name utility-layer
218
+
219
+ # With specific Node.js version
220
+ aws-lambda-layer zip --nodejs express@4.18.2 --node-version 20
221
+
222
+ # Scoped packages
223
+ aws-lambda-layer zip --nodejs @babel/core@7.23.0,@babel/types@7.23.0
224
+ ```
225
+
226
+ #### Publish to AWS
227
+
228
+ ```bash
229
+ # Basic publish
230
+ aws-lambda-layer publish --nodejs express@4.18.2 --description "Express layer"
231
+
232
+ # With custom layer name
233
+ aws-lambda-layer publish --nodejs date-fns,uuid --name utility-layer --description "Utility packages"
234
+
235
+ # Using specific AWS profile
236
+ aws-lambda-layer publish --nodejs express@4.18.2 --profile production --description "Express layer"
237
+
238
+ # Specify AWS region
239
+ aws-lambda-layer publish --nodejs axios --region ap-east-1 --description "Axios layer"
240
+
241
+ # With both profile and region
242
+ aws-lambda-layer publish --nodejs lodash --profile dev --region us-east-1 --description "Lodash layer"
243
+ ```
244
+
245
+ ### Python Examples
246
+
247
+ #### Create Local Zip Files
248
+
249
+ ```bash
250
+ # Single package with version
251
+ aws-lambda-layer zip --python numpy==1.26.0
252
+
253
+ # Multiple packages
254
+ aws-lambda-layer zip --python numpy==1.26.0,pandas==2.1.3,requests>=2.31.0
255
+
256
+ # With custom name
257
+ aws-lambda-layer zip --python requests,pytz --name web-utils
258
+
259
+ # With specific Python version
260
+ aws-lambda-layer zip --python numpy==1.26.0 --python-version 3.12
261
+
262
+ # Using pip instead of uv
263
+ aws-lambda-layer zip --python pandas==2.1.3 --no-uv
264
+ ```
265
+
266
+ #### Publish to AWS
267
+
268
+ ```bash
269
+ # Basic publish
270
+ aws-lambda-layer publish --python numpy==1.26.0 --description "NumPy layer"
271
+
272
+ # Multiple packages with description
273
+ aws-lambda-layer publish --python requests==2.31.0,pytz==2023.3 --description "Web utilities"
274
+
275
+ # Using specific AWS profile
276
+ aws-lambda-layer publish --python pandas==2.1.3 --profile production --description "Pandas layer"
277
+
278
+ # Specify AWS region
279
+ aws-lambda-layer publish --python numpy==1.26.0 --region us-west-2 --description "NumPy layer"
280
+
281
+ # With both profile and region
282
+ aws-lambda-layer publish --python scikit-learn --profile ml-account --region eu-west-1 --description "ML layer"
283
+ ```
284
+
285
+ ## Package Version Formats
286
+
287
+ ### Node.js
288
+ - `express@4.18.2` - Exact version
289
+ - `axios` - Latest version
290
+ - `lodash@^4.17.0` - Compatible version
291
+ - `@babel/core@7.23.0,@babel/types@7.23.0` - Multiple scoped packages
292
+
293
+ ### Python
294
+ - `numpy==1.26.0` - Exact version
295
+ - `pandas` - Latest version
296
+ - `requests>=2.31.0` - Minimum version
297
+ - `pytz~=2023.3` - Compatible version
298
+
299
+ ## Publishing to AWS
300
+
301
+ ### Requirements
302
+
303
+ Before using the `publish` command, ensure you have:
304
+
305
+ 1. **AWS CLI installed and configured**
306
+ ```bash
307
+ aws configure
308
+ # or for specific profile
309
+ aws configure --profile production
310
+ ```
311
+
312
+ 2. **IAM Permissions**: Your IAM user/role needs:
313
+ - `lambda:PublishLayerVersion`
314
+ - `sts:GetCallerIdentity` (for account verification)
315
+ - `iam:ListAccountAliases` (optional, for account info)
316
+
317
+ 3. **Region Configuration**: Either:
318
+ - Set default region: `aws configure set region us-east-1`
319
+ - Or use `--region` flag when publishing
320
+
321
+ 4. **zip command installed**: Ensure the `zip` command is available on your system.
322
+
323
+ ### Confirmation Prompt
324
+
325
+ When publishing, you'll see:
326
+ 1. AWS Account ID
327
+ 2. AWS Profile (if specified)
328
+ 3. Account Aliases (if available)
329
+ 4. Target Region
330
+ 5. Confirmation prompt: `Do you want to proceed? [Y/n]:`
331
+
332
+ Press Y (or Enter for default Yes) to proceed, or N to cancel.
333
+
334
+ ## Output
335
+
336
+ ### Zip Command
337
+ Creates a zip file in the current directory with format:
338
+ - Node.js: `<package-name>-<version>-nodejs<node-version>.zip`
339
+ - Python: `<package-name>-<version>-python<python-version>.zip`
340
+
341
+ ### Publish Command
342
+ - Uploads layer to AWS Lambda
343
+ - Returns Layer ARN
344
+ - Shows usage examples
345
+ - Provides command to attach to existing Lambda functions
346
+
347
+ ## Troubleshooting
348
+
349
+ ### Common Issues
350
+
351
+ 1. **AWS credentials not configured**
352
+ ```bash
353
+ aws configure
354
+ # or
355
+ aws configure --profile your-profile
356
+ ```
357
+
358
+ 2. **IAM permissions missing**
359
+ - Ensure your AWS credentials has `lambda:PublishLayerVersion` permission
360
+
361
+ 3. **Layer name already exists**
362
+ - Use `--name` option to specify a different name
363
+ - Or delete the existing layer version
364
+
365
+ 4. **Zip file too large**
366
+ - AWS limit: 50MB for direct upload
367
+ - Consider using fewer packages or S3 upload for larger layers
368
+
369
+ 5. **Region not configured**
370
+ - Use `--region` flag or configure default region:
371
+ ```bash
372
+ aws configure set region us-east-1
373
+ ```
374
+
375
+ ## Shell Completion
376
+
377
+ Completions are installed for bash and zsh. Restart your shell or source the completion files:
378
+
379
+ ```bash
380
+ # Bash
381
+ source /etc/bash_completion.d/aws-lambda-layer-completion.bash
382
+
383
+ # Zsh
384
+ source /usr/local/share/zsh/site-functions/_aws-lambda-layer
385
+ ```
386
+
387
+ ## License
388
+
389
+ MIT License
390
+
391
+ ## Contributing
392
+
393
+ Contributions are welcome! Please feel free to submit a Pull Request.
@@ -0,0 +1,89 @@
1
+ #!/usr/bin/env node
2
+
3
+ 'use strict';
4
+
5
+ const { spawnSync } = require('child_process');
6
+ const fs = require('fs');
7
+ const path = require('path');
8
+
9
+ function which(cmd) {
10
+ const isWin = process.platform === 'win32';
11
+ const exts = isWin ? (process.env.PATHEXT || '.EXE;.CMD;.BAT;.COM').split(';') : [''];
12
+ const paths = (process.env.PATH || '').split(path.delimiter);
13
+
14
+ for (const p of paths) {
15
+ if (!p) continue;
16
+ for (const ext of exts) {
17
+ const full = path.join(p, isWin ? cmd + ext.toLowerCase() : cmd);
18
+ if (fs.existsSync(full)) return full;
19
+ // Also check original case on Windows
20
+ const full2 = path.join(p, cmd + ext);
21
+ if (fs.existsSync(full2)) return full2;
22
+ }
23
+ }
24
+ return null;
25
+ }
26
+
27
+ function shQuote(s) {
28
+ // Single-quote for bash -lc
29
+ return `'${String(s).replace(/'/g, `'\\''`)}'`;
30
+ }
31
+
32
+ function windowsPathToWsl(p) {
33
+ // C:\Users\me\x -> /mnt/c/Users/me/x
34
+ const m = /^([a-zA-Z]):\\(.*)$/.exec(p);
35
+ if (!m) return null;
36
+ return `/mnt/${m[1].toLowerCase()}/${m[2].replace(/\\/g, '/')}`;
37
+ }
38
+
39
+ function cygpathConvert(mode, p) {
40
+ const cygpath = which('cygpath');
41
+ if (!cygpath) return null;
42
+ const res = spawnSync(cygpath, [mode, p], { encoding: 'utf8' });
43
+ if (res.status !== 0) return null;
44
+ return (res.stdout || '').trim();
45
+ }
46
+
47
+ function run(cmd, args) {
48
+ const res = spawnSync(cmd, args, { stdio: 'inherit' });
49
+ process.exit(res.status ?? 1);
50
+ }
51
+
52
+ const args = process.argv.slice(2);
53
+ const bashScript = path.resolve(__dirname, '..', 'scripts', 'aws-lambda-layer');
54
+
55
+ if (!fs.existsSync(bashScript)) {
56
+ console.error('Error: packaged bash script not found:', bashScript);
57
+ process.exit(1);
58
+ }
59
+
60
+ // POSIX platforms
61
+ if (process.platform !== 'win32') {
62
+ run('bash', [bashScript, ...args]);
63
+ }
64
+
65
+ // Windows platforms:
66
+ // - Prefer Git Bash / MSYS / Cygwin: convert to POSIX path using cygpath -u
67
+ // - Else attempt WSL: convert to /mnt/<drive>/... and run via wsl.exe
68
+ // - Else give a clear message
69
+
70
+ const posixPath = cygpathConvert('-u', bashScript);
71
+ if (posixPath) {
72
+ run('bash', [posixPath, ...args]);
73
+ }
74
+
75
+ const wsl = which('wsl.exe') || which('wsl');
76
+ if (wsl) {
77
+ const wslPath = windowsPathToWsl(bashScript);
78
+ if (!wslPath) {
79
+ console.error('Error: unable to convert path for WSL:', bashScript);
80
+ process.exit(1);
81
+ }
82
+
83
+ const cmd = `bash ${shQuote(wslPath)} ${args.map(shQuote).join(' ')}`.trim();
84
+ run(wsl, ['bash', '-lc', cmd]);
85
+ }
86
+
87
+ console.error('Error: no compatible bash found on Windows.');
88
+ console.error('Install and run this tool inside WSL, or install Git Bash and ensure `bash`/`cygpath` are on PATH.');
89
+ process.exit(1);
@@ -0,0 +1,101 @@
1
+ # bash completion for aws-lambda-layer
2
+
3
+ _aws_lambda_layer() {
4
+ local cur prev words cword
5
+ _init_completion || return
6
+
7
+ local commands="zip publish help --help --version"
8
+ local runtime_opts="--nodejs --node -n --python --py -p --runtime"
9
+ local common_opts="--name -h --help"
10
+ local publish_opts="--description --layer-name --profile --region"
11
+ local node_opts="--node-version"
12
+ local python_opts="--python-version --no-uv"
13
+
14
+ case ${cword} in
15
+ 1)
16
+ # First argument: main command
17
+ COMPREPLY=($(compgen -W "${commands}" -- "${cur}"))
18
+ ;;
19
+ 2)
20
+ if [[ ${words[1]} == "zip" ]] || [[ ${words[1]} == "publish" ]]; then
21
+ # Second argument for zip/publish: runtime
22
+ COMPREPLY=($(compgen -W "${runtime_opts}" -- "${cur}"))
23
+ fi
24
+ ;;
25
+ 3)
26
+ # Third argument: packages (positional)
27
+ if [[ ${words[1]} == "zip" ]] || [[ ${words[1]} == "publish" ]]; then
28
+ # Suggest package format based on runtime
29
+ local has_runtime=""
30
+ for word in "${words[@]:2}"; do
31
+ case ${word} in
32
+ --nodejs|--node|-n|--runtime=nodejs)
33
+ COMPREPLY=("express@4.18.2,lodash")
34
+ return
35
+ ;;
36
+ --python|--py|-p|--runtime=python)
37
+ COMPREPLY=("numpy==1.26.0,pandas")
38
+ return
39
+ ;;
40
+ esac
41
+ done
42
+ fi
43
+ ;;
44
+ *)
45
+ if [[ ${words[1]} == "zip" ]] || [[ ${words[1]} == "publish" ]]; then
46
+ # Determine runtime
47
+ local runtime=""
48
+ for word in "${words[@]:2}"; do
49
+ case ${word} in
50
+ --nodejs|--node|-n)
51
+ runtime="nodejs"
52
+ break
53
+ ;;
54
+ --python|--py|-p)
55
+ runtime="python"
56
+ break
57
+ ;;
58
+ --runtime=nodejs)
59
+ runtime="nodejs"
60
+ break
61
+ ;;
62
+ --runtime=python)
63
+ runtime="python"
64
+ break
65
+ ;;
66
+ --runtime)
67
+ # Check next word for runtime value
68
+ local next_word="${words[cword]}"
69
+ if [[ ${next_word} == "nodejs" || ${next_word} == "python" ]]; then
70
+ runtime="${next_word}"
71
+ fi
72
+ break
73
+ ;;
74
+ esac
75
+ done
76
+
77
+ if [[ -z ${runtime} ]]; then
78
+ # Still need to choose runtime
79
+ COMPREPLY=($(compgen -W "${runtime_opts}" -- "${cur}"))
80
+ else
81
+ # Runtime chosen, now show appropriate options
82
+ local cmd_opts="${common_opts}"
83
+ if [[ ${words[1]} == "publish" ]]; then
84
+ cmd_opts="${cmd_opts} ${publish_opts}"
85
+ fi
86
+
87
+ case ${runtime} in
88
+ nodejs)
89
+ COMPREPLY=($(compgen -W "${cmd_opts} ${node_opts}" -- "${cur}"))
90
+ ;;
91
+ python)
92
+ COMPREPLY=($(compgen -W "${cmd_opts} ${python_opts}" -- "${cur}"))
93
+ ;;
94
+ esac
95
+ fi
96
+ fi
97
+ ;;
98
+ esac
99
+ }
100
+
101
+ complete -F _aws_lambda_layer aws-lambda-layer