aws-lambda-devkit 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +72 -0
- package/LICENSE +21 -0
- package/README.md +214 -0
- package/dist/aws/batch-response.d.ts +8 -0
- package/dist/aws/batch-response.d.ts.map +1 -0
- package/dist/aws/batch-response.js +12 -0
- package/dist/aws/batch-response.js.map +1 -0
- package/dist/aws/clients.d.ts +6 -0
- package/dist/aws/clients.d.ts.map +1 -0
- package/dist/aws/clients.js +30 -0
- package/dist/aws/clients.js.map +1 -0
- package/dist/aws/sns-publish.d.ts +10 -0
- package/dist/aws/sns-publish.d.ts.map +1 -0
- package/dist/aws/sns-publish.js +17 -0
- package/dist/aws/sns-publish.js.map +1 -0
- package/dist/aws/sqs-listen.d.ts +17 -0
- package/dist/aws/sqs-listen.d.ts.map +1 -0
- package/dist/aws/sqs-listen.js +113 -0
- package/dist/aws/sqs-listen.js.map +1 -0
- package/dist/aws/sqs-process.d.ts +39 -0
- package/dist/aws/sqs-process.d.ts.map +1 -0
- package/dist/aws/sqs-process.js +95 -0
- package/dist/aws/sqs-process.js.map +1 -0
- package/dist/aws/sqs-send.d.ts +15 -0
- package/dist/aws/sqs-send.d.ts.map +1 -0
- package/dist/aws/sqs-send.js +27 -0
- package/dist/aws/sqs-send.js.map +1 -0
- package/dist/aws/sqs-visibility.d.ts +10 -0
- package/dist/aws/sqs-visibility.d.ts.map +1 -0
- package/dist/aws/sqs-visibility.js +29 -0
- package/dist/aws/sqs-visibility.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +187 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/config-cmd.d.ts +5 -0
- package/dist/commands/config-cmd.d.ts.map +1 -0
- package/dist/commands/config-cmd.js +8 -0
- package/dist/commands/config-cmd.js.map +1 -0
- package/dist/commands/config.d.ts +2 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +24 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/init.d.ts +7 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +59 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/list.d.ts +4 -0
- package/dist/commands/list.d.ts.map +1 -0
- package/dist/commands/list.js +23 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/listen.d.ts +20 -0
- package/dist/commands/listen.d.ts.map +1 -0
- package/dist/commands/listen.js +36 -0
- package/dist/commands/listen.js.map +1 -0
- package/dist/commands/send.d.ts +17 -0
- package/dist/commands/send.d.ts.map +1 -0
- package/dist/commands/send.js +51 -0
- package/dist/commands/send.js.map +1 -0
- package/dist/commands/test.d.ts +23 -0
- package/dist/commands/test.d.ts.map +1 -0
- package/dist/commands/test.js +123 -0
- package/dist/commands/test.js.map +1 -0
- package/dist/config/env.d.ts +8 -0
- package/dist/config/env.d.ts.map +1 -0
- package/dist/config/env.js +16 -0
- package/dist/config/env.js.map +1 -0
- package/dist/config/load.d.ts +9 -0
- package/dist/config/load.d.ts.map +1 -0
- package/dist/config/load.js +72 -0
- package/dist/config/load.js.map +1 -0
- package/dist/config/merge.d.ts +36 -0
- package/dist/config/merge.d.ts.map +1 -0
- package/dist/config/merge.js +89 -0
- package/dist/config/merge.js.map +1 -0
- package/dist/config/project-env.d.ts +34 -0
- package/dist/config/project-env.d.ts.map +1 -0
- package/dist/config/project-env.js +90 -0
- package/dist/config/project-env.js.map +1 -0
- package/dist/config/schema.d.ts +27 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +123 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/config/types.d.ts +167 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config/types.js +2 -0
- package/dist/config/types.js.map +1 -0
- package/dist/events/apigw.d.ts +41 -0
- package/dist/events/apigw.d.ts.map +1 -0
- package/dist/events/apigw.js +43 -0
- package/dist/events/apigw.js.map +1 -0
- package/dist/events/eventbridge.d.ts +16 -0
- package/dist/events/eventbridge.d.ts.map +1 -0
- package/dist/events/eventbridge.js +19 -0
- package/dist/events/eventbridge.js.map +1 -0
- package/dist/events/index.d.ts +17 -0
- package/dist/events/index.d.ts.map +1 -0
- package/dist/events/index.js +50 -0
- package/dist/events/index.js.map +1 -0
- package/dist/events/s3.d.ts +45 -0
- package/dist/events/s3.d.ts.map +1 -0
- package/dist/events/s3.js +44 -0
- package/dist/events/s3.js.map +1 -0
- package/dist/events/schedule.d.ts +12 -0
- package/dist/events/schedule.d.ts.map +1 -0
- package/dist/events/schedule.js +15 -0
- package/dist/events/schedule.js.map +1 -0
- package/dist/events/sns.d.ts +24 -0
- package/dist/events/sns.d.ts.map +1 -0
- package/dist/events/sns.js +31 -0
- package/dist/events/sns.js.map +1 -0
- package/dist/events/sqs-record.d.ts +44 -0
- package/dist/events/sqs-record.d.ts.map +1 -0
- package/dist/events/sqs-record.js +75 -0
- package/dist/events/sqs-record.js.map +1 -0
- package/dist/events/sqs.d.ts +21 -0
- package/dist/events/sqs.d.ts.map +1 -0
- package/dist/events/sqs.js +28 -0
- package/dist/events/sqs.js.map +1 -0
- package/dist/events/util.d.ts +2 -0
- package/dist/events/util.d.ts.map +1 -0
- package/dist/events/util.js +7 -0
- package/dist/events/util.js.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -0
- package/dist/peer-resolve.d.ts +5 -0
- package/dist/peer-resolve.d.ts.map +1 -0
- package/dist/peer-resolve.js +44 -0
- package/dist/peer-resolve.js.map +1 -0
- package/dist/runtime/asset-links.d.ts +15 -0
- package/dist/runtime/asset-links.d.ts.map +1 -0
- package/dist/runtime/asset-links.js +42 -0
- package/dist/runtime/asset-links.js.map +1 -0
- package/dist/runtime/clear-caches.d.ts +5 -0
- package/dist/runtime/clear-caches.d.ts.map +1 -0
- package/dist/runtime/clear-caches.js +8 -0
- package/dist/runtime/clear-caches.js.map +1 -0
- package/dist/runtime/context.d.ts +10 -0
- package/dist/runtime/context.d.ts.map +1 -0
- package/dist/runtime/context.js +42 -0
- package/dist/runtime/context.js.map +1 -0
- package/dist/runtime/handler-cache.d.ts +6 -0
- package/dist/runtime/handler-cache.d.ts.map +1 -0
- package/dist/runtime/handler-cache.js +14 -0
- package/dist/runtime/handler-cache.js.map +1 -0
- package/dist/runtime/invoke.d.ts +32 -0
- package/dist/runtime/invoke.d.ts.map +1 -0
- package/dist/runtime/invoke.js +111 -0
- package/dist/runtime/invoke.js.map +1 -0
- package/dist/runtime/loader.d.ts +17 -0
- package/dist/runtime/loader.d.ts.map +1 -0
- package/dist/runtime/loader.js +76 -0
- package/dist/runtime/loader.js.map +1 -0
- package/dist/runtime/logs.d.ts +19 -0
- package/dist/runtime/logs.d.ts.map +1 -0
- package/dist/runtime/logs.js +125 -0
- package/dist/runtime/logs.js.map +1 -0
- package/dist/util/payload.d.ts +13 -0
- package/dist/util/payload.d.ts.map +1 -0
- package/dist/util/payload.js +40 -0
- package/dist/util/payload.js.map +1 -0
- package/dist/util/tsx-register.d.ts +4 -0
- package/dist/util/tsx-register.d.ts.map +1 -0
- package/dist/util/tsx-register.js +27 -0
- package/dist/util/tsx-register.js.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +2 -0
- package/dist/version.js.map +1 -0
- package/docs/README.md +23 -0
- package/docs/commands.md +294 -0
- package/docs/configuration.md +652 -0
- package/docs/getting-started.md +400 -0
- package/docs/recipes.md +743 -0
- package/docs/troubleshooting.md +393 -0
- package/package.json +76 -0
- package/templates/.env.example +5 -0
- package/templates/.vscode/launch.json +14 -0
- package/templates/events/sample.json +4 -0
- package/templates/lamkit.config.js +38 -0
- package/templates/lamkit.config.ts +27 -0
package/docs/recipes.md
ADDED
|
@@ -0,0 +1,743 @@
|
|
|
1
|
+
# Recipes
|
|
2
|
+
|
|
3
|
+
Copy-paste **end-to-end** setups. Each recipe includes folder layout, config, handler snippets, commands, and what to expect.
|
|
4
|
+
|
|
5
|
+
Replace generic names (`worker`, `WORKER_QUEUE_URL`, etc.) with your own.
|
|
6
|
+
|
|
7
|
+
**Index**
|
|
8
|
+
|
|
9
|
+
| # | Scenario |
|
|
10
|
+
|---|----------|
|
|
11
|
+
| [1](#recipe-1--single-sqs-worker-javascript) | Single SQS worker, plain JavaScript |
|
|
12
|
+
| [2](#recipe-2--compiled-typescript-dist) | Compiled TypeScript (`dist/`) |
|
|
13
|
+
| [3](#recipe-3--typescript-with-tsx-no-build) | TypeScript live via `tsx` |
|
|
14
|
+
| [4](#recipe-4--default-payload-in-config) | Default payload in config |
|
|
15
|
+
| [5](#recipe-5--payload-from-a-file) | Payload from JSON file |
|
|
16
|
+
| [6](#recipe-6--raw-captured-aws-event) | Raw captured AWS event |
|
|
17
|
+
| [7](#recipe-7--sqs-batch-multiple-records) | SQS batch (multiple records) |
|
|
18
|
+
| [8](#recipe-8--http-api-gateway-handler) | HTTP / API Gateway handler |
|
|
19
|
+
| [9](#recipe-9--sns-trigger-simulated) | SNS trigger (simulated) |
|
|
20
|
+
| [10](#recipe-10--monorepo-shared-root-env) | Monorepo + shared root `.env` |
|
|
21
|
+
| [11](#recipe-11--asset-links-for-contractsjson) | Asset links for `contracts/*.json` |
|
|
22
|
+
| [12](#recipe-12--real-sqs-send--listen-loop) | Real SQS send + listen loop |
|
|
23
|
+
| [13](#recipe-13--fifo-queue) | FIFO queue |
|
|
24
|
+
| [14](#recipe-14--sns-publish-real-aws) | SNS publish (real AWS) |
|
|
25
|
+
| [15](#recipe-15--json-structured-logs) | JSON structured logs |
|
|
26
|
+
| [16](#recipe-16--debug-with-breakpoints) | Debug with breakpoints |
|
|
27
|
+
| [17](#recipe-17--ci-smoke-test) | CI smoke test (no AWS) |
|
|
28
|
+
| [18](#recipe-18--sqs-partial-batch-failures) | SQS partial batch failures |
|
|
29
|
+
| [19](#recipe-19--multiple-functions) | Multiple functions |
|
|
30
|
+
| [20](#recipe-20--custom-aws-endpoint) | Custom AWS-compatible endpoint |
|
|
31
|
+
| [21](#recipe-21--per-invoke-env-overrides) | Per-invoke env overrides |
|
|
32
|
+
| [22](#recipe-22--reload-after-code-change) | Reload after code change |
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Recipe 1 — Single SQS worker (JavaScript)
|
|
37
|
+
|
|
38
|
+
**Goal:** Fastest possible setup — no TypeScript, no build step.
|
|
39
|
+
|
|
40
|
+
**Layout:**
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
order-worker/
|
|
44
|
+
├── package.json
|
|
45
|
+
├── lamkit.config.js
|
|
46
|
+
├── .env
|
|
47
|
+
└── src/
|
|
48
|
+
└── handler.js
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
**`package.json`:**
|
|
52
|
+
|
|
53
|
+
```json
|
|
54
|
+
{
|
|
55
|
+
"name": "order-worker",
|
|
56
|
+
"type": "module",
|
|
57
|
+
"scripts": {
|
|
58
|
+
"test:lambda": "lamkit test"
|
|
59
|
+
},
|
|
60
|
+
"devDependencies": {
|
|
61
|
+
"aws-lambda-devkit": "^0.1.0"
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
**`src/handler.js`:**
|
|
67
|
+
|
|
68
|
+
```js
|
|
69
|
+
export const handler = async (event) => {
|
|
70
|
+
for (const record of event.Records) {
|
|
71
|
+
const order = JSON.parse(record.body);
|
|
72
|
+
console.log('Processing order', order.orderId);
|
|
73
|
+
if (!order.orderId) throw new Error('orderId required');
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
**`lamkit.config.js`:**
|
|
79
|
+
|
|
80
|
+
```js
|
|
81
|
+
export default {
|
|
82
|
+
functions: [
|
|
83
|
+
{
|
|
84
|
+
name: 'worker',
|
|
85
|
+
entry: './src/handler.js',
|
|
86
|
+
trigger: 'sqs',
|
|
87
|
+
test: { data: { orderId: 'ord_local_1', amount: 10 } },
|
|
88
|
+
},
|
|
89
|
+
],
|
|
90
|
+
};
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
**Commands:**
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
npm install
|
|
97
|
+
npx lamkit init # optional if you already have config
|
|
98
|
+
npx lamkit test
|
|
99
|
+
npx lamkit test --data '{"orderId":"ord_999","amount":50}'
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
**Expect:** `✓ worker (sqs)` and logs showing your `orderId`.
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## Recipe 2 — Compiled TypeScript (`dist/`)
|
|
107
|
+
|
|
108
|
+
**Goal:** Match production — deploy `dist/`, test `dist/`.
|
|
109
|
+
|
|
110
|
+
**Layout:**
|
|
111
|
+
|
|
112
|
+
```
|
|
113
|
+
order-worker/
|
|
114
|
+
├── lamkit.config.js
|
|
115
|
+
├── src/handler.ts
|
|
116
|
+
├── dist/handler.js ← npm run build
|
|
117
|
+
└── tsconfig.json
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
**`src/handler.ts`:**
|
|
121
|
+
|
|
122
|
+
```ts
|
|
123
|
+
import type { SQSEvent, SQSHandler } from 'aws-lambda';
|
|
124
|
+
|
|
125
|
+
export const handler: SQSHandler = async (event: SQSEvent) => {
|
|
126
|
+
for (const record of event.Records) {
|
|
127
|
+
const body = JSON.parse(record.body);
|
|
128
|
+
console.log('Typed handler:', body);
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
**`lamkit.config.js`:**
|
|
134
|
+
|
|
135
|
+
```js
|
|
136
|
+
export default {
|
|
137
|
+
functions: [
|
|
138
|
+
{
|
|
139
|
+
name: 'worker',
|
|
140
|
+
entry: './dist/handler.js',
|
|
141
|
+
trigger: 'sqs',
|
|
142
|
+
},
|
|
143
|
+
],
|
|
144
|
+
};
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
**Commands:**
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
npm run build
|
|
151
|
+
npx lamkit test --data '{"orderId":"1"}'
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
**Tip:** Add `"test:lambda": "npm run build && lamkit test"` to run build before every test.
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## Recipe 3 — TypeScript with `tsx` (no build)
|
|
159
|
+
|
|
160
|
+
**Goal:** Iterate on `.ts` without compiling each time.
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
npm install -D aws-lambda-devkit tsx
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
**`lamkit.config.js`:**
|
|
167
|
+
|
|
168
|
+
```js
|
|
169
|
+
export default {
|
|
170
|
+
functions: [
|
|
171
|
+
{
|
|
172
|
+
name: 'worker',
|
|
173
|
+
entry: './src/handler.ts',
|
|
174
|
+
trigger: 'sqs',
|
|
175
|
+
},
|
|
176
|
+
],
|
|
177
|
+
};
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
npx lamkit test --data '{"id":"1"}'
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Lamkit uses the `tsx` peer to import `.ts` directly when `dist/` is missing.
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## Recipe 4 — Default payload in config
|
|
189
|
+
|
|
190
|
+
**Goal:** Run `lamkit test` with no CLI arguments.
|
|
191
|
+
|
|
192
|
+
```js
|
|
193
|
+
export default {
|
|
194
|
+
functions: [
|
|
195
|
+
{
|
|
196
|
+
name: 'worker',
|
|
197
|
+
entry: './src/handler.js',
|
|
198
|
+
trigger: 'sqs',
|
|
199
|
+
test: {
|
|
200
|
+
data: {
|
|
201
|
+
type: 'PING',
|
|
202
|
+
timestamp: '2026-01-15T12:00:00Z',
|
|
203
|
+
},
|
|
204
|
+
},
|
|
205
|
+
},
|
|
206
|
+
],
|
|
207
|
+
};
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
```bash
|
|
211
|
+
npx lamkit test
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
CLI `--data` still overrides config when provided.
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
## Recipe 5 — Payload from a file
|
|
219
|
+
|
|
220
|
+
**`events/order-created.json`:**
|
|
221
|
+
|
|
222
|
+
```json
|
|
223
|
+
{
|
|
224
|
+
"orderId": "ord_123",
|
|
225
|
+
"customerId": "cust_456",
|
|
226
|
+
"lines": [
|
|
227
|
+
{ "sku": "WIDGET-A", "quantity": 2, "price": 19.99 }
|
|
228
|
+
]
|
|
229
|
+
}
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
```bash
|
|
233
|
+
npx lamkit test --data-file events/order-created.json
|
|
234
|
+
npx lamkit test --data @events/order-created.json
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
Good for large payloads you do not want inline in the shell.
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
## Recipe 6 — Raw captured AWS event
|
|
242
|
+
|
|
243
|
+
**Goal:** Test with the **exact** event shape from production.
|
|
244
|
+
|
|
245
|
+
1. Copy an event from CloudWatch Logs or AWS documentation.
|
|
246
|
+
2. Save as **`events/sqs-production-sample.json`** (full `SQSEvent` with `Records` array).
|
|
247
|
+
3. Run:
|
|
248
|
+
|
|
249
|
+
```bash
|
|
250
|
+
npx lamkit test --event events/sqs-production-sample.json
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
This skips the event builder — useful when field names or attributes must match production exactly.
|
|
254
|
+
|
|
255
|
+
---
|
|
256
|
+
|
|
257
|
+
## Recipe 7 — SQS batch (multiple records)
|
|
258
|
+
|
|
259
|
+
**Goal:** Test batch handling and partial failure logic.
|
|
260
|
+
|
|
261
|
+
**Handler example:**
|
|
262
|
+
|
|
263
|
+
```js
|
|
264
|
+
export const handler = async (event) => {
|
|
265
|
+
const failures = [];
|
|
266
|
+
for (const record of event.Records) {
|
|
267
|
+
try {
|
|
268
|
+
const body = JSON.parse(record.body);
|
|
269
|
+
if (body.shouldFail) throw new Error('simulated failure');
|
|
270
|
+
} catch {
|
|
271
|
+
failures.push({ itemIdentifier: record.messageId });
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
return { batchItemFailures: failures };
|
|
275
|
+
};
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
**Commands:**
|
|
279
|
+
|
|
280
|
+
```bash
|
|
281
|
+
# One payload → 5 records
|
|
282
|
+
npx lamkit test --data '{"id":"1"}' --batch-size 5
|
|
283
|
+
|
|
284
|
+
# Array → one record per element
|
|
285
|
+
npx lamkit test --data '[{"id":"1"},{"id":"2"},{"id":"3"}]'
|
|
286
|
+
|
|
287
|
+
# Fail CI if batchItemFailures returned
|
|
288
|
+
npx lamkit test --strict-batch --data '[{"shouldFail":true}]'
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
---
|
|
292
|
+
|
|
293
|
+
## Recipe 8 — HTTP (API Gateway) handler
|
|
294
|
+
|
|
295
|
+
**`src/http.js`:**
|
|
296
|
+
|
|
297
|
+
```js
|
|
298
|
+
export const handler = async (event) => {
|
|
299
|
+
const body = event.body ? JSON.parse(event.body) : {};
|
|
300
|
+
return {
|
|
301
|
+
statusCode: 200,
|
|
302
|
+
headers: { 'Content-Type': 'application/json' },
|
|
303
|
+
body: JSON.stringify({ greeting: `Hello, ${body.name ?? 'world'}` }),
|
|
304
|
+
};
|
|
305
|
+
};
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
**`lamkit.config.js`:**
|
|
309
|
+
|
|
310
|
+
```js
|
|
311
|
+
export default {
|
|
312
|
+
functions: [
|
|
313
|
+
{
|
|
314
|
+
name: 'api',
|
|
315
|
+
entry: './src/http.js',
|
|
316
|
+
trigger: 'http',
|
|
317
|
+
test: { data: { name: 'Ada' } },
|
|
318
|
+
},
|
|
319
|
+
],
|
|
320
|
+
};
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
```bash
|
|
324
|
+
npx lamkit test api
|
|
325
|
+
npx lamkit test api --data '{"name":"Bob"}'
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
---
|
|
329
|
+
|
|
330
|
+
## Recipe 9 — SNS trigger (simulated)
|
|
331
|
+
|
|
332
|
+
**`lamkit.config.js`:**
|
|
333
|
+
|
|
334
|
+
```js
|
|
335
|
+
export default {
|
|
336
|
+
functions: [
|
|
337
|
+
{
|
|
338
|
+
name: 'subscriber',
|
|
339
|
+
entry: './dist/handler.js',
|
|
340
|
+
trigger: 'sns',
|
|
341
|
+
test: { data: { metric: 'cpu', value: 95, threshold: 90 } },
|
|
342
|
+
},
|
|
343
|
+
],
|
|
344
|
+
};
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
**Handler:**
|
|
348
|
+
|
|
349
|
+
```js
|
|
350
|
+
export const handler = async (event) => {
|
|
351
|
+
for (const record of event.Records) {
|
|
352
|
+
const message = JSON.parse(record.Sns.Message);
|
|
353
|
+
console.log('Alert:', message);
|
|
354
|
+
}
|
|
355
|
+
};
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
```bash
|
|
359
|
+
npx lamkit test subscriber
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
---
|
|
363
|
+
|
|
364
|
+
## Recipe 10 — Monorepo with shared root `.env`
|
|
365
|
+
|
|
366
|
+
**Goal:** Lambda package in `packages/worker/` but secrets in repo root `.env`.
|
|
367
|
+
|
|
368
|
+
**Layout:**
|
|
369
|
+
|
|
370
|
+
```
|
|
371
|
+
acme-platform/
|
|
372
|
+
├── .env
|
|
373
|
+
└── packages/
|
|
374
|
+
└── order-worker/
|
|
375
|
+
├── lamkit.config.mjs
|
|
376
|
+
├── dist/handler.js
|
|
377
|
+
└── package.json
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
**Root `.env`:**
|
|
381
|
+
|
|
382
|
+
```env
|
|
383
|
+
AWS_REGION=eu-west-1
|
|
384
|
+
WORKER_QUEUE_URL=https://sqs.eu-west-1.amazonaws.com/111222333/acme-dev-orders
|
|
385
|
+
APP_DB_NAME=orders_dev
|
|
386
|
+
APP_DB_PORT=5432
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
**`packages/order-worker/lamkit.config.mjs`:**
|
|
390
|
+
|
|
391
|
+
```js
|
|
392
|
+
import { loadProjectEnv } from 'aws-lambda-devkit';
|
|
393
|
+
|
|
394
|
+
loadProjectEnv({
|
|
395
|
+
files: ['../../.env'],
|
|
396
|
+
skipDotenv: true,
|
|
397
|
+
aliases: {
|
|
398
|
+
APP_DB_NAME: 'DB_NAME',
|
|
399
|
+
APP_DB_PORT: 'DB_PORT',
|
|
400
|
+
},
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
const region = process.env.AWS_REGION ?? 'eu-west-1';
|
|
404
|
+
|
|
405
|
+
export default {
|
|
406
|
+
defaults: { aws: { region } },
|
|
407
|
+
functions: [
|
|
408
|
+
{
|
|
409
|
+
name: 'worker',
|
|
410
|
+
entry: './dist/handler.js',
|
|
411
|
+
trigger: 'sqs',
|
|
412
|
+
aws: { queueUrl: process.env.WORKER_QUEUE_URL, region },
|
|
413
|
+
},
|
|
414
|
+
],
|
|
415
|
+
};
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
```bash
|
|
419
|
+
cd packages/order-worker
|
|
420
|
+
npm install -D aws-lambda-devkit
|
|
421
|
+
npx lamkit test --data '{"orderId":"1"}'
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
---
|
|
425
|
+
|
|
426
|
+
## Recipe 11 — Asset links for `contracts/*.json`
|
|
427
|
+
|
|
428
|
+
**Goal:** `dist/` code does `require('../../contracts/abi.json')` but files live in `src/contracts/`.
|
|
429
|
+
|
|
430
|
+
**Layout:**
|
|
431
|
+
|
|
432
|
+
```
|
|
433
|
+
worker/
|
|
434
|
+
├── src/contracts/abi.json
|
|
435
|
+
├── dist/handler.js
|
|
436
|
+
└── lamkit.config.js
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
**`lamkit.config.js`:**
|
|
440
|
+
|
|
441
|
+
```js
|
|
442
|
+
export default {
|
|
443
|
+
assetLinks: [{ path: 'contracts', target: 'src/contracts' }],
|
|
444
|
+
functions: [
|
|
445
|
+
{ name: 'worker', entry: './dist/handler.js', trigger: 'sqs' },
|
|
446
|
+
],
|
|
447
|
+
};
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
Lamkit creates `contracts → src/contracts` symlink before invoke if `contracts/` is missing.
|
|
451
|
+
|
|
452
|
+
---
|
|
453
|
+
|
|
454
|
+
## Recipe 12 — Real SQS: send then listen locally
|
|
455
|
+
|
|
456
|
+
**Goal:** End-to-end with a real dev queue; handler runs on your machine.
|
|
457
|
+
|
|
458
|
+
**Install:**
|
|
459
|
+
|
|
460
|
+
```bash
|
|
461
|
+
npm install -D @aws-sdk/client-sqs
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
**`.env`:**
|
|
465
|
+
|
|
466
|
+
```env
|
|
467
|
+
AWS_REGION=us-east-1
|
|
468
|
+
AWS_ACCESS_KEY_ID=AKIA...
|
|
469
|
+
AWS_SECRET_ACCESS_KEY=...
|
|
470
|
+
WORKER_QUEUE_URL=https://sqs.us-east-1.amazonaws.com/123456789012/acme-dev-orders
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
**`lamkit.config.js`:**
|
|
474
|
+
|
|
475
|
+
```js
|
|
476
|
+
export default {
|
|
477
|
+
defaults: { aws: { region: process.env.AWS_REGION } },
|
|
478
|
+
functions: [
|
|
479
|
+
{
|
|
480
|
+
name: 'worker',
|
|
481
|
+
entry: './dist/handler.js',
|
|
482
|
+
trigger: 'sqs',
|
|
483
|
+
aws: { queueUrl: process.env.WORKER_QUEUE_URL },
|
|
484
|
+
},
|
|
485
|
+
],
|
|
486
|
+
};
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
**Terminal 1 — listener:**
|
|
490
|
+
|
|
491
|
+
```bash
|
|
492
|
+
npx lamkit listen worker
|
|
493
|
+
```
|
|
494
|
+
|
|
495
|
+
**Terminal 2 — sender:**
|
|
496
|
+
|
|
497
|
+
```bash
|
|
498
|
+
npx lamkit send sqs worker --data '{"orderId":"live-1"}'
|
|
499
|
+
```
|
|
500
|
+
|
|
501
|
+
**Expect:** Terminal 1 prints `message <id>: success` and your handler logs.
|
|
502
|
+
|
|
503
|
+
**Safety:** Use a dev-only queue. Disable the deployed Lambda event source mapping while listening.
|
|
504
|
+
|
|
505
|
+
**One-shot:**
|
|
506
|
+
|
|
507
|
+
```bash
|
|
508
|
+
npx lamkit send sqs worker --data '{"orderId":"1"}'
|
|
509
|
+
npx lamkit listen worker --once --expect-messages
|
|
510
|
+
```
|
|
511
|
+
|
|
512
|
+
---
|
|
513
|
+
|
|
514
|
+
## Recipe 13 — FIFO queue
|
|
515
|
+
|
|
516
|
+
Same as Recipe 12, but `WORKER_QUEUE_URL` ends with `.fifo`:
|
|
517
|
+
|
|
518
|
+
```env
|
|
519
|
+
WORKER_QUEUE_URL=https://sqs.us-east-1.amazonaws.com/123456789012/acme-orders.fifo
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
```bash
|
|
523
|
+
npx lamkit send sqs worker --data '{"orderId":"1","group":"customer-A"}'
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
Lamkit sets `MessageGroupId` and `MessageDeduplicationId` automatically.
|
|
527
|
+
|
|
528
|
+
---
|
|
529
|
+
|
|
530
|
+
## Recipe 14 — SNS publish (real AWS)
|
|
531
|
+
|
|
532
|
+
```bash
|
|
533
|
+
npm install -D @aws-sdk/client-sns
|
|
534
|
+
```
|
|
535
|
+
|
|
536
|
+
```env
|
|
537
|
+
EVENTS_TOPIC_ARN=arn:aws:sns:us-east-1:123456789012:acme-dev-events
|
|
538
|
+
```
|
|
539
|
+
|
|
540
|
+
```js
|
|
541
|
+
export default {
|
|
542
|
+
functions: [
|
|
543
|
+
{
|
|
544
|
+
name: 'notifier',
|
|
545
|
+
entry: './dist/handler.js',
|
|
546
|
+
trigger: 'sns',
|
|
547
|
+
aws: { topicArn: process.env.EVENTS_TOPIC_ARN },
|
|
548
|
+
},
|
|
549
|
+
],
|
|
550
|
+
};
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
```bash
|
|
554
|
+
npx lamkit send sns notifier --data '{"event":"ORDER_PLACED","orderId":"1"}'
|
|
555
|
+
```
|
|
556
|
+
|
|
557
|
+
To invoke the handler offline with SNS event shape, use `lamkit test` with `trigger: 'sns'`.
|
|
558
|
+
|
|
559
|
+
---
|
|
560
|
+
|
|
561
|
+
## Recipe 15 — JSON structured logs
|
|
562
|
+
|
|
563
|
+
```js
|
|
564
|
+
export default {
|
|
565
|
+
defaults: { logFormat: 'json' },
|
|
566
|
+
functions: [
|
|
567
|
+
{ name: 'worker', entry: './src/handler.js', trigger: 'sqs' },
|
|
568
|
+
],
|
|
569
|
+
};
|
|
570
|
+
```
|
|
571
|
+
|
|
572
|
+
```bash
|
|
573
|
+
npx lamkit test --data '{"id":"1"}' | jq .
|
|
574
|
+
```
|
|
575
|
+
|
|
576
|
+
Each log line is a JSON object — easier for scripts and log aggregators locally.
|
|
577
|
+
|
|
578
|
+
---
|
|
579
|
+
|
|
580
|
+
## Recipe 16 — Debug with breakpoints
|
|
581
|
+
|
|
582
|
+
**VS Code:** Run **"lamkit test (inspect)"** from `.vscode/launch.json` (created by `lamkit init`).
|
|
583
|
+
|
|
584
|
+
**Terminal:**
|
|
585
|
+
|
|
586
|
+
```bash
|
|
587
|
+
npx lamkit test worker --inspect-brk --data '{"orderId":"1"}'
|
|
588
|
+
```
|
|
589
|
+
|
|
590
|
+
Set breakpoints in your handler, attach debugger, step through code.
|
|
591
|
+
|
|
592
|
+
---
|
|
593
|
+
|
|
594
|
+
## Recipe 17 — CI smoke test
|
|
595
|
+
|
|
596
|
+
**Goal:** GitHub Actions / GitLab CI runs handlers without AWS credentials.
|
|
597
|
+
|
|
598
|
+
**`package.json`:**
|
|
599
|
+
|
|
600
|
+
```json
|
|
601
|
+
{
|
|
602
|
+
"scripts": {
|
|
603
|
+
"test:lambda": "lamkit test --all"
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
```
|
|
607
|
+
|
|
608
|
+
**Config** — each function needs `test.data` or handlers must tolerate empty events:
|
|
609
|
+
|
|
610
|
+
```js
|
|
611
|
+
export default {
|
|
612
|
+
functions: [
|
|
613
|
+
{
|
|
614
|
+
name: 'worker',
|
|
615
|
+
entry: './dist/handler.js',
|
|
616
|
+
trigger: 'sqs',
|
|
617
|
+
test: { data: { type: 'CI_PING' } },
|
|
618
|
+
},
|
|
619
|
+
],
|
|
620
|
+
};
|
|
621
|
+
```
|
|
622
|
+
|
|
623
|
+
**CI step:**
|
|
624
|
+
|
|
625
|
+
```yaml
|
|
626
|
+
- run: npm ci
|
|
627
|
+
- run: npm run build
|
|
628
|
+
- run: npm run test:lambda
|
|
629
|
+
```
|
|
630
|
+
|
|
631
|
+
Handlers that call AWS/DB in CI may need mocks or `--dry-run` only.
|
|
632
|
+
|
|
633
|
+
---
|
|
634
|
+
|
|
635
|
+
## Recipe 18 — SQS partial batch failures
|
|
636
|
+
|
|
637
|
+
```bash
|
|
638
|
+
npx lamkit test worker --strict-batch --data '[{"id":"ok"},{"id":"bad"}]'
|
|
639
|
+
```
|
|
640
|
+
|
|
641
|
+
Exit code `1` if handler returns:
|
|
642
|
+
|
|
643
|
+
```js
|
|
644
|
+
return {
|
|
645
|
+
batchItemFailures: [{ itemIdentifier: 'message-id-here' }],
|
|
646
|
+
};
|
|
647
|
+
```
|
|
648
|
+
|
|
649
|
+
Useful in shell scripts and CI gates.
|
|
650
|
+
|
|
651
|
+
---
|
|
652
|
+
|
|
653
|
+
## Recipe 19 — Multiple functions
|
|
654
|
+
|
|
655
|
+
```js
|
|
656
|
+
export default {
|
|
657
|
+
functions: [
|
|
658
|
+
{
|
|
659
|
+
name: 'orders',
|
|
660
|
+
entry: './dist/orders.js',
|
|
661
|
+
trigger: 'sqs',
|
|
662
|
+
test: { data: { type: 'ORDER' } },
|
|
663
|
+
},
|
|
664
|
+
{
|
|
665
|
+
name: 'billing',
|
|
666
|
+
entry: './dist/billing.js',
|
|
667
|
+
trigger: 'sqs',
|
|
668
|
+
test: { data: { type: 'INVOICE' } },
|
|
669
|
+
},
|
|
670
|
+
],
|
|
671
|
+
};
|
|
672
|
+
```
|
|
673
|
+
|
|
674
|
+
```bash
|
|
675
|
+
npx lamkit list
|
|
676
|
+
npx lamkit test orders
|
|
677
|
+
npx lamkit test billing
|
|
678
|
+
npx lamkit test --all
|
|
679
|
+
```
|
|
680
|
+
|
|
681
|
+
---
|
|
682
|
+
|
|
683
|
+
## Recipe 20 — Custom AWS-compatible endpoint
|
|
684
|
+
|
|
685
|
+
```env
|
|
686
|
+
AWS_ENDPOINT_URL=https://internal-gateway.example.com
|
|
687
|
+
AWS_REGION=us-east-1
|
|
688
|
+
```
|
|
689
|
+
|
|
690
|
+
```js
|
|
691
|
+
export default {
|
|
692
|
+
defaults: {
|
|
693
|
+
aws: {
|
|
694
|
+
region: process.env.AWS_REGION,
|
|
695
|
+
endpoint: process.env.AWS_ENDPOINT_URL,
|
|
696
|
+
},
|
|
697
|
+
},
|
|
698
|
+
functions: [/* ... */],
|
|
699
|
+
};
|
|
700
|
+
```
|
|
701
|
+
|
|
702
|
+
When using real IAM keys (`AKIA*`), `loadProjectEnv()` strips endpoint overrides by default so SDK hits real AWS. Set `stripCustomEndpointForRealAws: false` to keep custom endpoints with real keys.
|
|
703
|
+
|
|
704
|
+
---
|
|
705
|
+
|
|
706
|
+
## Recipe 21 — Per-invoke env overrides
|
|
707
|
+
|
|
708
|
+
```bash
|
|
709
|
+
npx lamkit test worker \
|
|
710
|
+
--env FEATURE_NEW_PARSER=true \
|
|
711
|
+
--env LOG_LEVEL=debug \
|
|
712
|
+
--data '{"orderId":"1"}'
|
|
713
|
+
```
|
|
714
|
+
|
|
715
|
+
Does not modify `.env` — only the current process.
|
|
716
|
+
|
|
717
|
+
---
|
|
718
|
+
|
|
719
|
+
## Recipe 22 — Reload after code change
|
|
720
|
+
|
|
721
|
+
During a tight edit-test loop:
|
|
722
|
+
|
|
723
|
+
```bash
|
|
724
|
+
# terminal 1: edit src/handler.js
|
|
725
|
+
npx lamkit test worker --reload --data '{"orderId":"1"}'
|
|
726
|
+
```
|
|
727
|
+
|
|
728
|
+
`--reload` bypasses the handler module cache so you see fresh code without restarting the shell.
|
|
729
|
+
|
|
730
|
+
---
|
|
731
|
+
|
|
732
|
+
## Picking a recipe
|
|
733
|
+
|
|
734
|
+
| Your situation | Start with |
|
|
735
|
+
|----------------|------------|
|
|
736
|
+
| Brand new project | Recipe 1 |
|
|
737
|
+
| TypeScript + `tsc` | Recipe 2 |
|
|
738
|
+
| Monorepo | Recipe 10 |
|
|
739
|
+
| `require('../../contracts/...')` fails | Recipe 11 |
|
|
740
|
+
| Test against real dev queue | Recipe 12 |
|
|
741
|
+
| GitHub Actions | Recipe 17 |
|
|
742
|
+
|
|
743
|
+
More detail: [Configuration](configuration.md) · [Commands](commands.md) · [Troubleshooting](troubleshooting.md)
|