ac-lambda-deployment 0.0.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.
Files changed (3) hide show
  1. package/README.md +334 -0
  2. package/index.js +346 -0
  3. package/package.json +46 -0
package/README.md ADDED
@@ -0,0 +1,334 @@
1
+ # ac-lambda-deployment
2
+
3
+ Simple AWS Lambda deployment tool using AWS SDK v3. Deploys code, manages layers, and configures SQS triggers without the complexity of full infrastructure-as-code tools.
4
+
5
+ ## Features
6
+
7
+ - **Code-focused deployment** - Updates Lambda function code quickly
8
+ - **Layer management** - Attach and update Lambda layers
9
+ - **SQS trigger configuration** - Manage event source mappings
10
+ - **Multi-environment support** - Different configs for dev/prod
11
+ - **Automatic retry logic** - Handles concurrent update conflicts
12
+ - **Include-based packaging** - Only package specified files
13
+ - **AWS profile support** - Use different AWS profiles per environment
14
+
15
+ ## Installation
16
+
17
+ ```bash
18
+ npm install ac-lambda-deployment --save-dev
19
+ # or
20
+ yarn add ac-lambda-deployment --dev
21
+ ```
22
+
23
+ ## Quick Start
24
+
25
+ **1. Create a configuration file:**
26
+
27
+ ```javascript
28
+ // lambda.config.js
29
+ module.exports = {
30
+ functionName: 'my-lambda-function',
31
+ roleArn: 'arn:aws:iam::123456789012:role/lambda-execution-role',
32
+ handler: 'lambda.handler',
33
+ includes: ['lambda.js'],
34
+ layers: [
35
+ 'arn:aws:lambda:eu-central-1:123456789012:layer:my-utils:1'
36
+ ]
37
+ }
38
+ ```
39
+
40
+ **2. Add to package.json scripts:**
41
+
42
+ ```json
43
+ {
44
+ "scripts": {
45
+ "deploy": "lambda-deploy",
46
+ "deploy:prod": "NODE_ENV=production lambda-deploy --profile=prod"
47
+ }
48
+ }
49
+ ```
50
+
51
+ **3. Deploy:**
52
+
53
+ ```bash
54
+ npm run deploy
55
+ ```
56
+
57
+ ## Configuration
58
+
59
+ ### Basic Configuration
60
+
61
+ Create `lambda.config.js` in your project root:
62
+
63
+ ```javascript
64
+ module.exports = {
65
+ functionName: 'my-function',
66
+ roleArn: 'arn:aws:iam::123456789012:role/lambda-role',
67
+ handler: 'lambda.handler',
68
+ runtime: 'nodejs18.x',
69
+ timeout: 30,
70
+ memorySize: 128,
71
+ includes: ['lambda.js', 'config.json'],
72
+ environment: {
73
+ NODE_ENV: 'production',
74
+ API_KEY: 'your-api-key'
75
+ }
76
+ }
77
+ ```
78
+
79
+ ### Multi-Environment Configuration
80
+
81
+ ```javascript
82
+ // lambda.config.js
83
+ const env = process.env.NODE_ENV || 'dev'
84
+
85
+ const environments = {
86
+ dev: {
87
+ functionName: 'my-function-dev',
88
+ roleArn: 'arn:aws:iam::123456789012:role/lambda-dev-role',
89
+ profile: 'default',
90
+ layers: [
91
+ 'arn:aws:lambda:eu-central-1:123456789012:layer:dev-utils:1'
92
+ ]
93
+ },
94
+ production: {
95
+ functionName: 'my-function-prod',
96
+ roleArn: 'arn:aws:iam::123456789012:role/lambda-prod-role',
97
+ profile: 'production',
98
+ layers: [
99
+ 'arn:aws:lambda:eu-central-1:123456789012:layer:prod-utils:2'
100
+ ]
101
+ }
102
+ }
103
+
104
+ module.exports = {
105
+ handler: 'lambda.handler',
106
+ runtime: 'nodejs18.x',
107
+ includes: ['lambda.js'],
108
+ ...environments[env]
109
+ }
110
+ ```
111
+
112
+ ### SQS Triggers
113
+
114
+ ```javascript
115
+ module.exports = {
116
+ functionName: 'my-sqs-processor',
117
+ roleArn: 'arn:aws:iam::123456789012:role/lambda-sqs-role',
118
+ sqsTriggers: [
119
+ {
120
+ queueArn: 'arn:aws:sqs:eu-central-1:123456789012:my-queue',
121
+ batchSize: 10,
122
+ maxBatchingWindow: 5,
123
+ enabled: true
124
+ }
125
+ ]
126
+ }
127
+ ```
128
+
129
+ ## Configuration Options
130
+
131
+ | Option | Type | Default | Description |
132
+ |--------|------|---------|-------------|
133
+ | `functionName` | string | **required** | Lambda function name |
134
+ | `roleArn` | string | **required** | IAM role ARN for the function |
135
+ | `handler` | string | `lambda.handler` | Function entry point |
136
+ | `runtime` | string | `nodejs18.x` | Lambda runtime |
137
+ | `timeout` | number | `30` | Function timeout in seconds |
138
+ | `memorySize` | number | `128` | Memory allocation in MB |
139
+ | `includes` | array | `['lambda.js']` | Files to include in deployment package |
140
+ | `layers` | array | `[]` | Lambda layer ARNs |
141
+ | `environment` | object | `{}` | Environment variables |
142
+ | `profile` | string | default | AWS profile to use |
143
+ | `region` | string | `eu-central-1` | AWS region |
144
+ | `sqsTriggers` | array | `[]` | SQS event source mappings |
145
+
146
+ ## Usage
147
+
148
+ ### Command Line
149
+
150
+ ```bash
151
+ # Deploy with default configuration
152
+ npx lambda-deploy
153
+
154
+ # Deploy with specific AWS profile
155
+ npx lambda-deploy --profile=production
156
+
157
+ # Deploy with different region
158
+ npx lambda-deploy --region=us-east-1
159
+
160
+ # Deploy with custom config file
161
+ npx lambda-deploy --config=prod.config.js
162
+
163
+ # Multi-environment
164
+ NODE_ENV=production npx lambda-deploy --profile=prod
165
+ ```
166
+
167
+ ### Programmatic Usage
168
+
169
+ ```javascript
170
+ const LambdaDeployer = require('ac-lambda-deployment')
171
+
172
+ async function deploy() {
173
+ const deployer = new LambdaDeployer({
174
+ region: 'eu-central-1',
175
+ profile: 'production'
176
+ })
177
+
178
+ await deployer.deploy()
179
+ }
180
+
181
+ deploy().catch(console.error)
182
+ ```
183
+
184
+ ## Package Structure
185
+
186
+ The tool uses an **include-based** approach - only specified files are packaged:
187
+
188
+ ```
189
+ project/
190
+ ├── lambda.js # Your Lambda function (included)
191
+ ├── lambda.config.js # Configuration (not included)
192
+ ├── package.json # Dependencies info (not included)
193
+ ├── node_modules/ # Always included in package
194
+ └── other-files.js # Only if specified in includes
195
+ ```
196
+
197
+ **Default includes:** `['lambda.js']`
198
+ **Always included:** `node_modules/` (production dependencies)
199
+
200
+ ## AWS Permissions
201
+
202
+ Your Lambda execution role needs these permissions for SQS triggers:
203
+
204
+ ```json
205
+ {
206
+ "Version": "2012-10-17",
207
+ "Statement": [
208
+ {
209
+ "Effect": "Allow",
210
+ "Action": [
211
+ "sqs:ReceiveMessage",
212
+ "sqs:DeleteMessage",
213
+ "sqs:GetQueueAttributes"
214
+ ],
215
+ "Resource": "arn:aws:sqs:*:*:*"
216
+ }
217
+ ]
218
+ }
219
+ ```
220
+
221
+ ## Alternative Configuration
222
+
223
+ You can also configure in `package.json`:
224
+
225
+ ```json
226
+ {
227
+ "name": "my-project",
228
+ "lambda": {
229
+ "functionName": "my-function",
230
+ "roleArn": "arn:aws:iam::123456789012:role/lambda-role",
231
+ "includes": ["lambda.js", "utils.js"]
232
+ }
233
+ }
234
+ ```
235
+
236
+ ## Security
237
+
238
+ **Important:** Never commit `lambda.config.js` to version control if it contains sensitive data.
239
+
240
+ ```bash
241
+ # .gitignore
242
+ lambda.config.js
243
+ lambda.*.config.js
244
+ ```
245
+
246
+ Create a template instead:
247
+
248
+ ```javascript
249
+ // lambda.config.example.js
250
+ module.exports = {
251
+ functionName: 'your-function-name',
252
+ roleArn: 'arn:aws:iam::YOUR-ACCOUNT:role/YOUR-ROLE',
253
+ environment: {
254
+ API_KEY: 'your-api-key'
255
+ }
256
+ }
257
+ ```
258
+
259
+ ## Comparison with Other Tools
260
+
261
+ | Tool | Code Deploy | Infrastructure | Complexity |
262
+ |------|-------------|----------------|------------|
263
+ | **ac-lambda-deployment** | ✅ Fast | Layers, SQS only | Low |
264
+ | Serverless Framework | ✅ | ✅ Full | High |
265
+ | AWS SAM | ✅ | ✅ Full | Medium |
266
+ | Terraform | ❌ | ✅ Full | High |
267
+ | ClaudiaJS | ✅ Fast | Basic | Low (deprecated) |
268
+
269
+ **Use ac-lambda-deployment when:**
270
+ - You want fast code deployments
271
+ - Infrastructure is managed separately (Terraform/CDK)
272
+ - You need simple layer and SQS trigger management
273
+ - You want ClaudiaJS-like simplicity with modern AWS SDK
274
+
275
+ ## Examples
276
+
277
+ ### Simple API Function
278
+
279
+ ```javascript
280
+ // lambda.config.js
281
+ module.exports = {
282
+ functionName: 'api-handler',
283
+ roleArn: 'arn:aws:iam::123456789012:role/api-lambda-role',
284
+ handler: 'lambda.handler',
285
+ timeout: 10,
286
+ memorySize: 256,
287
+ environment: {
288
+ DATABASE_URL: process.env.DATABASE_URL
289
+ }
290
+ }
291
+ ```
292
+
293
+ ### SQS Message Processor
294
+
295
+ ```javascript
296
+ // lambda.config.js
297
+ module.exports = {
298
+ functionName: 'queue-processor',
299
+ roleArn: 'arn:aws:iam::123456789012:role/sqs-lambda-role',
300
+ sqsTriggers: [
301
+ {
302
+ queueArn: 'arn:aws:sqs:eu-central-1:123456789012:process-queue',
303
+ batchSize: 5,
304
+ maxBatchingWindow: 10
305
+ }
306
+ ],
307
+ layers: [
308
+ 'arn:aws:lambda:eu-central-1:123456789012:layer:shared-utils:1'
309
+ ]
310
+ }
311
+ ```
312
+
313
+ ## Troubleshooting
314
+
315
+ ### Permission Denied
316
+ ```bash
317
+ chmod +x ./node_modules/ac-lambda-deployment/index.js
318
+ ```
319
+
320
+ ### Concurrent Update Error
321
+ The tool automatically retries when Lambda is being updated. Wait 30-60 seconds between deployments.
322
+
323
+ ### Function Not Found
324
+ Make sure the function exists or provide `roleArn` to create it automatically.
325
+
326
+ ## License
327
+
328
+ MIT © 2025 AdmiralCloud AG, Mark Poepping
329
+
330
+ ## Support
331
+
332
+ - Check AWS credentials: `aws sts get-caller-identity`
333
+ - Verify function exists: `aws lambda get-function --function-name your-function`
334
+ - Enable debug logging: `AWS_SDK_LOAD_CONFIG=1 DEBUG=* npx lambda-deploy`
package/index.js ADDED
@@ -0,0 +1,346 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { LambdaClient, UpdateFunctionCodeCommand, CreateFunctionCommand, GetFunctionCommand, UpdateFunctionConfigurationCommand, CreateEventSourceMappingCommand, ListEventSourceMappingsCommand, UpdateEventSourceMappingCommand, DeleteEventSourceMappingCommand } = require('@aws-sdk/client-lambda')
4
+ const { fromIni } = require('@aws-sdk/credential-provider-ini')
5
+ const fs = require('fs')
6
+ const path = require('path')
7
+ const archiver = require('archiver')
8
+ const { execSync } = require('child_process')
9
+
10
+ class LambdaDeployer {
11
+ constructor(options = {}) {
12
+ const { region = 'eu-central-1', profile } = options
13
+
14
+ const clientConfig = { region }
15
+ if (profile) {
16
+ clientConfig.credentials = fromIni({ profile })
17
+ }
18
+
19
+ this.lambda = new LambdaClient(clientConfig)
20
+ }
21
+
22
+ // Load configuration from lambda.config.js or package.json
23
+ loadConfig(configPath) {
24
+ const cwd = process.cwd()
25
+
26
+ // Try lambda.config.js first
27
+ const configFile = path.join(cwd, configPath || 'lambda.config.js')
28
+ if (fs.existsSync(configFile)) {
29
+ delete require.cache[require.resolve(configFile)]
30
+ return require(configFile)
31
+ }
32
+
33
+ // Try package.json lambda section
34
+ const packageFile = path.join(cwd, 'package.json')
35
+ if (fs.existsSync(packageFile)) {
36
+ const pkg = JSON.parse(fs.readFileSync(packageFile, 'utf8'))
37
+ if (pkg.lambda) {
38
+ return pkg.lambda
39
+ }
40
+ }
41
+
42
+ throw new Error('No configuration found. Create lambda.config.js or add "lambda" section to package.json')
43
+ }
44
+
45
+ // Create ZIP archive with code and dependencies
46
+ createZip(sourceDir, outputPath, includes = ['lambda.js']) {
47
+ return new Promise((resolve, reject) => {
48
+ const output = fs.createWriteStream(outputPath)
49
+ const archive = archiver('zip', { zlib: { level: 9 } })
50
+
51
+ output.on('close', () => resolve(outputPath))
52
+ archive.on('error', reject)
53
+
54
+ archive.pipe(output)
55
+
56
+ // Add specified files only
57
+ includes.forEach(pattern => {
58
+ const fullPath = path.join(sourceDir, pattern)
59
+ if (fs.existsSync(fullPath) && fs.statSync(fullPath).isFile()) {
60
+ archive.file(fullPath, { name: pattern })
61
+ }
62
+ else {
63
+ // Handle glob patterns
64
+ archive.glob(pattern, { cwd: sourceDir })
65
+ }
66
+ })
67
+
68
+ // Install and add production dependencies
69
+ console.log('Installing production dependencies...')
70
+ try {
71
+ // Detect package manager
72
+ const hasYarnLock = fs.existsSync(path.join(sourceDir, 'yarn.lock'))
73
+ const hasPnpmLock = fs.existsSync(path.join(sourceDir, 'pnpm-lock.yaml'))
74
+
75
+ let installCmd
76
+ if (hasYarnLock) {
77
+ installCmd = 'yarn install --production --silent'
78
+ }
79
+ else if (hasPnpmLock) {
80
+ installCmd = 'pnpm install --production'
81
+ }
82
+ else {
83
+ installCmd = 'npm install --production --silent'
84
+ }
85
+
86
+ execSync(installCmd, { cwd: sourceDir })
87
+ archive.directory(path.join(sourceDir, 'node_modules'), 'node_modules')
88
+ }
89
+ catch {
90
+ console.warn('Warning: dependency installation failed, continuing without dependencies')
91
+ }
92
+
93
+ archive.finalize()
94
+ })
95
+ }
96
+
97
+ // Check if function exists
98
+ async functionExists(functionName) {
99
+ try {
100
+ await this.lambda.send(new GetFunctionCommand({ FunctionName: functionName }))
101
+ return true
102
+ }
103
+ catch (err) {
104
+ if (err.name === 'ResourceNotFoundException') {
105
+ return false
106
+ }
107
+ throw err
108
+ }
109
+ }
110
+
111
+ // Create new Lambda function
112
+ createFunction(config) {
113
+ const zipBuffer = fs.readFileSync(config.zipPath)
114
+
115
+ const params = {
116
+ FunctionName: config.functionName,
117
+ Runtime: config.runtime || 'nodejs18.x',
118
+ Role: config.roleArn,
119
+ Handler: config.handler || 'lambda.handler',
120
+ Code: { ZipFile: zipBuffer },
121
+ Description: config.description || 'Deployed with lambda-deployer',
122
+ Timeout: config.timeout || 30,
123
+ MemorySize: config.memorySize || 128,
124
+ Environment: config.environment ? { Variables: config.environment } : undefined,
125
+ Layers: config.layers || []
126
+ }
127
+
128
+ const command = new CreateFunctionCommand(params)
129
+ return this.lambda.send(command)
130
+ }
131
+
132
+ // Update existing Lambda function code with retry
133
+ async updateFunction(functionName, zipPath) {
134
+ const zipBuffer = fs.readFileSync(zipPath)
135
+
136
+ const params = {
137
+ FunctionName: functionName,
138
+ ZipFile: zipBuffer
139
+ }
140
+
141
+ const command = new UpdateFunctionCodeCommand(params)
142
+
143
+ // Retry logic for concurrent updates
144
+ for (let i = 0; i < 3; i++) {
145
+ try {
146
+ return this.lambda.send(command)
147
+ }
148
+ catch (err) {
149
+ if (err.name === 'ResourceConflictException' && i < 2) {
150
+ console.log(`Function is being updated, waiting 30 seconds... (attempt ${i + 1}/3)`)
151
+ await new Promise(resolve => setTimeout(resolve, 30000))
152
+ continue
153
+ }
154
+ throw err
155
+ }
156
+ }
157
+ }
158
+
159
+ // Update function configuration (layers, environment, etc.) with retry
160
+ async updateFunctionConfig(config) {
161
+ const params = {
162
+ FunctionName: config.functionName,
163
+ Runtime: config.runtime,
164
+ Handler: config.handler,
165
+ Description: config.description,
166
+ Timeout: config.timeout,
167
+ MemorySize: config.memorySize,
168
+ Environment: config.environment ? { Variables: config.environment } : undefined,
169
+ Layers: config.layers || []
170
+ }
171
+
172
+ const command = new UpdateFunctionConfigurationCommand(params)
173
+
174
+ // Retry logic for concurrent updates
175
+ for (let i = 0; i < 3; i++) {
176
+ try {
177
+ return this.lambda.send(command)
178
+ }
179
+ catch (err) {
180
+ if (err.name === 'ResourceConflictException' && i < 2) {
181
+ console.log(`Function config is being updated, waiting 20 seconds... (attempt ${i + 1}/3)`)
182
+ await new Promise(resolve => setTimeout(resolve, 20000))
183
+ continue
184
+ }
185
+ throw err
186
+ }
187
+ }
188
+ }
189
+
190
+ // Manage SQS event source mappings
191
+ async updateEventSourceMappings(functionName, sqsTriggers = []) {
192
+ if (sqsTriggers.length === 0) return
193
+
194
+ // Get existing mappings
195
+ const listCommand = new ListEventSourceMappingsCommand({
196
+ FunctionName: functionName
197
+ })
198
+ const existing = await this.lambda.send(listCommand)
199
+
200
+ // Process each SQS trigger
201
+ for (const trigger of sqsTriggers) {
202
+ const existingMapping = existing.EventSourceMappings?.find(
203
+ m => m.EventSourceArn === trigger.queueArn
204
+ )
205
+
206
+ if (existingMapping) {
207
+ // Update existing mapping
208
+ console.log(`Updating SQS trigger: ${trigger.queueArn}`)
209
+ const updateCommand = new UpdateEventSourceMappingCommand({
210
+ UUID: existingMapping.UUID,
211
+ BatchSize: trigger.batchSize || 10,
212
+ MaximumBatchingWindowInSeconds: trigger.maxBatchingWindow || 0,
213
+ Enabled: trigger.enabled !== false
214
+ })
215
+ await this.lambda.send(updateCommand)
216
+ }
217
+ else {
218
+ // Create new mapping
219
+ console.log(`Creating SQS trigger: ${trigger.queueArn}`)
220
+ const createCommand = new CreateEventSourceMappingCommand({
221
+ EventSourceArn: trigger.queueArn,
222
+ FunctionName: functionName,
223
+ BatchSize: trigger.batchSize || 10,
224
+ MaximumBatchingWindowInSeconds: trigger.maxBatchingWindow || 0,
225
+ Enabled: trigger.enabled !== false
226
+ })
227
+ await this.lambda.send(createCommand)
228
+ }
229
+ }
230
+
231
+ // Remove mappings not in config
232
+ const configuredArns = sqsTriggers.map(t => t.queueArn)
233
+ for (const mapping of existing.EventSourceMappings || []) {
234
+ if (!configuredArns.includes(mapping.EventSourceArn)) {
235
+ console.log(`Removing SQS trigger: ${mapping.EventSourceArn}`)
236
+ const deleteCommand = new DeleteEventSourceMappingCommand({
237
+ UUID: mapping.UUID
238
+ })
239
+ await this.lambda.send(deleteCommand)
240
+ }
241
+ }
242
+ }
243
+
244
+ // Main deployment function
245
+ async deploy(configPath) {
246
+ const config = this.loadConfig(configPath)
247
+
248
+ const {
249
+ functionName,
250
+ sourceDir = '.',
251
+ roleArn,
252
+ includes = ['lambda.js'],
253
+ region,
254
+ profile
255
+ } = config
256
+
257
+ // Override AWS config if specified in config file
258
+ if (region || profile) {
259
+ const clientConfig = { region: region || 'eu-central-1' }
260
+ if (profile) {
261
+ clientConfig.credentials = fromIni({ profile })
262
+ }
263
+ this.lambda = new LambdaClient(clientConfig)
264
+ }
265
+
266
+ if (!functionName) {
267
+ throw new Error('functionName is required in configuration')
268
+ }
269
+
270
+ console.log(`Deploying Lambda function: ${functionName}`)
271
+
272
+ // Create ZIP
273
+ const zipPath = path.join(sourceDir, `${functionName}.zip`)
274
+ console.log('Creating deployment package...')
275
+ await this.createZip(sourceDir, zipPath, includes)
276
+
277
+ try {
278
+ const exists = await this.functionExists(functionName)
279
+
280
+ if (exists) {
281
+ console.log('Updating existing function...')
282
+ await this.updateFunction(functionName, zipPath)
283
+
284
+ // Update function configuration (layers, environment, etc.)
285
+ if (config.layers || config.environment || config.timeout || config.memorySize) {
286
+ console.log('Updating function configuration...')
287
+ await this.updateFunctionConfig(config)
288
+ }
289
+
290
+ // Update SQS triggers
291
+ if (config.sqsTriggers) {
292
+ console.log('Updating SQS triggers...')
293
+ await this.updateEventSourceMappings(functionName, config.sqsTriggers)
294
+ }
295
+
296
+ console.log('Function updated successfully!')
297
+ }
298
+ else {
299
+ if (!roleArn) {
300
+ throw new Error('roleArn is required for creating new functions')
301
+ }
302
+ console.log('Creating new function...')
303
+ await this.createFunction({ ...config, zipPath })
304
+
305
+ // Add SQS triggers after function creation
306
+ if (config.sqsTriggers) {
307
+ console.log('Creating SQS triggers...')
308
+ await this.updateEventSourceMappings(functionName, config.sqsTriggers)
309
+ }
310
+
311
+ console.log('Function created successfully!')
312
+ }
313
+ }
314
+ finally {
315
+ // Cleanup ZIP file
316
+ if (fs.existsSync(zipPath)) {
317
+ fs.unlinkSync(zipPath)
318
+ }
319
+ }
320
+ }
321
+ }
322
+
323
+ // CLI interface
324
+ async function cli() {
325
+ const args = process.argv.slice(2)
326
+ const profile = args.find(arg => arg.startsWith('--profile='))?.split('=')[1]
327
+ const region = args.find(arg => arg.startsWith('--region='))?.split('=')[1]
328
+ const config = args.find(arg => arg.startsWith('--config='))?.split('=')[1]
329
+
330
+ const deployer = new LambdaDeployer({ region, profile })
331
+
332
+ try {
333
+ await deployer.deploy(config)
334
+ }
335
+ catch (err) {
336
+ console.error('Deployment failed:', err.message)
337
+ process.exit(1)
338
+ }
339
+ }
340
+
341
+ // Run CLI if called directly
342
+ if (require.main === module) {
343
+ cli()
344
+ }
345
+
346
+ module.exports = LambdaDeployer
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "ac-lambda-deployment",
3
+ "version": "0.0.1",
4
+ "description": "Simple AWS Lambda deployment tool using AWS SDK v3",
5
+ "main": "index.js",
6
+ "bin": {
7
+ "lambda-deploy": "./index.js"
8
+ },
9
+ "author": "Mark Poepping (https://www.admiralcloud.com)",
10
+ "license": "MIT",
11
+ "packageManager": "yarn@1.22.22",
12
+ "keywords": [
13
+ "aws",
14
+ "lambda",
15
+ "deployment",
16
+ "serverless",
17
+ "aws-sdk-v3"
18
+ ],
19
+ "repository": {
20
+ "type": "git",
21
+ "url": "https://github.com/admiralcloud/ac-lambda-deployment"
22
+ },
23
+ "bugs": {
24
+ "url": "https://github.com/admiralcloud/ac-lambda-deployment/issues"
25
+ },
26
+ "homepage": "https://github.com/admiralcloud/ac-lambda-deployment#readme",
27
+ "files": [
28
+ "index.js",
29
+ "README.md"
30
+ ],
31
+ "scripts": {
32
+ "lint": "eslint index.js",
33
+ "test": "echo \"Error: no test specified\" && exit 1"
34
+ },
35
+ "dependencies": {
36
+ "@aws-sdk/client-lambda": "^3.848.0",
37
+ "@aws-sdk/credential-provider-ini": "^3.848.0",
38
+ "archiver": "^7.0.1"
39
+ },
40
+ "engines": {
41
+ "node": ">=20.0.0"
42
+ },
43
+ "devDependencies": {
44
+ "eslint": "^9.31.0"
45
+ }
46
+ }