@jaypie/mcp 0.2.2 → 0.2.4
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/dist/index.js +208 -3
- package/dist/index.js.map +1 -1
- package/dist/llm.d.ts +41 -0
- package/package.json +3 -2
- package/prompts/Jaypie_CDK_Constructs_and_Patterns.md +51 -0
- package/prompts/Jaypie_DynamoDB_Package.md +547 -0
- package/prompts/Jaypie_Express_Package.md +91 -0
- package/prompts/Jaypie_Init_Lambda_Package.md +134 -1
- package/prompts/Jaypie_Llm_Calls.md +339 -3
- package/prompts/Jaypie_Llm_Tools.md +43 -12
- package/prompts/Jaypie_Vocabulary_Commander.md +411 -0
- package/prompts/Jaypie_Vocabulary_LLM.md +312 -0
- package/prompts/Jaypie_Vocabulary_Lambda.md +310 -0
- package/prompts/Jaypie_Vocabulary_MCP.md +296 -0
- package/prompts/Jaypie_Vocabulary_Package.md +141 -183
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: LLM tool creation from serviceHandler for use with @jaypie/llm Toolkit
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Jaypie Vocabulary LLM Adapter
|
|
6
|
+
|
|
7
|
+
The LLM adapter (`@jaypie/vocabulary/llm`) creates LLM tools from Jaypie service handlers for use with `@jaypie/llm` Toolkit, automatically generating JSON Schema from input definitions.
|
|
8
|
+
|
|
9
|
+
**See also:** [Jaypie_Vocabulary_Package.md](Jaypie_Vocabulary_Package.md) for core serviceHandler documentation.
|
|
10
|
+
|
|
11
|
+
## Installation
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install @jaypie/vocabulary @jaypie/llm
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Quick Start
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
import { serviceHandler } from "@jaypie/vocabulary";
|
|
21
|
+
import { createLlmTool } from "@jaypie/vocabulary/llm";
|
|
22
|
+
import { Toolkit } from "@jaypie/llm";
|
|
23
|
+
|
|
24
|
+
const handler = serviceHandler({
|
|
25
|
+
alias: "greet",
|
|
26
|
+
description: "Greet a user by name",
|
|
27
|
+
input: {
|
|
28
|
+
userName: { type: String, description: "The user's name" },
|
|
29
|
+
loud: { type: Boolean, default: false, description: "Shout the greeting" },
|
|
30
|
+
},
|
|
31
|
+
service: ({ userName, loud }) => {
|
|
32
|
+
const greeting = `Hello, ${userName}!`;
|
|
33
|
+
return loud ? greeting.toUpperCase() : greeting;
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
const { tool } = createLlmTool({ handler });
|
|
38
|
+
const toolkit = new Toolkit([tool]);
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## createLlmTool
|
|
42
|
+
|
|
43
|
+
Creates an LLM tool from a serviceHandler.
|
|
44
|
+
|
|
45
|
+
### Options
|
|
46
|
+
|
|
47
|
+
| Option | Type | Description |
|
|
48
|
+
|--------|------|-------------|
|
|
49
|
+
| `handler` | `ServiceHandlerFunction` | Required. The service handler to adapt |
|
|
50
|
+
| `name` | `string` | Override tool name (defaults to handler.alias) |
|
|
51
|
+
| `description` | `string` | Override tool description (defaults to handler.description) |
|
|
52
|
+
| `message` | `string \| function` | Custom message for logging |
|
|
53
|
+
| `exclude` | `string[]` | Fields to exclude from tool parameters |
|
|
54
|
+
| `onComplete` | `OnCompleteCallback` | Called with tool's return value on success |
|
|
55
|
+
| `onError` | `OnErrorCallback` | Receives errors reported via `context.onError()` in service |
|
|
56
|
+
| `onFatal` | `OnFatalCallback` | Receives fatal errors (thrown or via `context.onFatal()`) |
|
|
57
|
+
| `onMessage` | `OnMessageCallback` | Receives messages from `context.sendMessage` in service |
|
|
58
|
+
|
|
59
|
+
### Basic Usage
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
import { serviceHandler } from "@jaypie/vocabulary";
|
|
63
|
+
import { createLlmTool } from "@jaypie/vocabulary/llm";
|
|
64
|
+
|
|
65
|
+
const calculateHandler = serviceHandler({
|
|
66
|
+
alias: "calculate",
|
|
67
|
+
description: "Perform a mathematical calculation",
|
|
68
|
+
input: {
|
|
69
|
+
operation: { type: ["add", "subtract", "multiply", "divide"] },
|
|
70
|
+
a: { type: Number, description: "First operand" },
|
|
71
|
+
b: { type: Number, description: "Second operand" },
|
|
72
|
+
},
|
|
73
|
+
service: ({ operation, a, b }) => {
|
|
74
|
+
switch (operation) {
|
|
75
|
+
case "add": return a + b;
|
|
76
|
+
case "subtract": return a - b;
|
|
77
|
+
case "multiply": return a * b;
|
|
78
|
+
case "divide": return a / b;
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
const { tool } = createLlmTool({ handler: calculateHandler });
|
|
84
|
+
|
|
85
|
+
// Tool has these properties:
|
|
86
|
+
// tool.name: "calculate"
|
|
87
|
+
// tool.description: "Perform a mathematical calculation"
|
|
88
|
+
// tool.parameters: JSON Schema for inputs
|
|
89
|
+
// tool.function: The callable function
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Overriding Name and Description
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
const { tool } = createLlmTool({
|
|
96
|
+
handler,
|
|
97
|
+
name: "math_calculator",
|
|
98
|
+
description: "A tool for performing basic math operations",
|
|
99
|
+
});
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Excluding Fields
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
const handler = serviceHandler({
|
|
106
|
+
alias: "search",
|
|
107
|
+
input: {
|
|
108
|
+
query: { type: String },
|
|
109
|
+
limit: { type: Number, default: 10 },
|
|
110
|
+
_internalId: { type: String }, // Internal field
|
|
111
|
+
},
|
|
112
|
+
service: async (params) => { /* ... */ },
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
const { tool } = createLlmTool({
|
|
116
|
+
handler,
|
|
117
|
+
exclude: ["_internalId"], // Not exposed to LLM
|
|
118
|
+
});
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Lifecycle Callbacks
|
|
122
|
+
|
|
123
|
+
Services can use context callbacks to report progress, errors, and completion:
|
|
124
|
+
|
|
125
|
+
```typescript
|
|
126
|
+
const handler = serviceHandler({
|
|
127
|
+
alias: "evaluate",
|
|
128
|
+
input: { jobId: { type: String } },
|
|
129
|
+
service: async ({ jobId }, context) => {
|
|
130
|
+
context?.sendMessage?.({ content: `Processing ${jobId}` });
|
|
131
|
+
|
|
132
|
+
try {
|
|
133
|
+
await riskyOperation();
|
|
134
|
+
} catch (err) {
|
|
135
|
+
context?.onError?.(err); // Reports error but continues
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return { jobId, status: "complete" };
|
|
139
|
+
},
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
const { tool } = createLlmTool({
|
|
143
|
+
handler,
|
|
144
|
+
onComplete: (result) => console.log("Tool completed:", result),
|
|
145
|
+
onError: (error) => console.warn("Recoverable error:", error),
|
|
146
|
+
onFatal: (error) => console.error("Fatal error:", error),
|
|
147
|
+
onMessage: (msg) => console.log(`[${msg.level || "info"}] ${msg.content}`),
|
|
148
|
+
});
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
**Error handling**: Services receive `context.onError()` and `context.onFatal()` callbacks to report errors without throwing. Any error that escapes the service (is thrown) is treated as fatal and routes to `onFatal`. If `onFatal` is not provided, thrown errors fall back to `onError`. Callback errors are swallowed to ensure failures never halt service execution.
|
|
152
|
+
|
|
153
|
+
## inputToJsonSchema
|
|
154
|
+
|
|
155
|
+
Converts vocabulary input definitions to JSON Schema:
|
|
156
|
+
|
|
157
|
+
```typescript
|
|
158
|
+
import { inputToJsonSchema } from "@jaypie/vocabulary/llm";
|
|
159
|
+
|
|
160
|
+
const schema = inputToJsonSchema({
|
|
161
|
+
userName: { type: String, description: "User's name" },
|
|
162
|
+
age: { type: Number, required: false },
|
|
163
|
+
role: { type: ["admin", "user", "guest"], default: "user" },
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
// Returns:
|
|
167
|
+
{
|
|
168
|
+
type: "object",
|
|
169
|
+
properties: {
|
|
170
|
+
userName: { type: "string", description: "User's name" },
|
|
171
|
+
age: { type: "number" },
|
|
172
|
+
role: { type: "string", enum: ["admin", "user", "guest"] },
|
|
173
|
+
},
|
|
174
|
+
required: ["userName"],
|
|
175
|
+
}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### Type Mappings
|
|
179
|
+
|
|
180
|
+
| Vocabulary Type | JSON Schema |
|
|
181
|
+
|-----------------|-------------|
|
|
182
|
+
| `String` | `{ type: "string" }` |
|
|
183
|
+
| `Number` | `{ type: "number" }` |
|
|
184
|
+
| `Boolean` | `{ type: "boolean" }` |
|
|
185
|
+
| `Array` | `{ type: "array" }` |
|
|
186
|
+
| `Object` | `{ type: "object" }` |
|
|
187
|
+
| `[String]` | `{ type: "array", items: { type: "string" } }` |
|
|
188
|
+
| `[Number]` | `{ type: "array", items: { type: "number" } }` |
|
|
189
|
+
| `/regex/` | `{ type: "string", pattern: "..." }` |
|
|
190
|
+
| `["a", "b"]` | `{ type: "string", enum: ["a", "b"] }` |
|
|
191
|
+
| `[1, 2, 3]` | `{ type: "number", enum: [1, 2, 3] }` |
|
|
192
|
+
|
|
193
|
+
### Excluding Fields
|
|
194
|
+
|
|
195
|
+
```typescript
|
|
196
|
+
const schema = inputToJsonSchema(handler.input, {
|
|
197
|
+
exclude: ["internalField", "debugMode"],
|
|
198
|
+
});
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
## Complete Example
|
|
202
|
+
|
|
203
|
+
```typescript
|
|
204
|
+
import { serviceHandler } from "@jaypie/vocabulary";
|
|
205
|
+
import { createLlmTool } from "@jaypie/vocabulary/llm";
|
|
206
|
+
import { Llm, Toolkit } from "@jaypie/llm";
|
|
207
|
+
|
|
208
|
+
// Define service handlers
|
|
209
|
+
const weatherHandler = serviceHandler({
|
|
210
|
+
alias: "get_weather",
|
|
211
|
+
description: "Get current weather for a location",
|
|
212
|
+
input: {
|
|
213
|
+
location: { type: String, description: "City name or coordinates" },
|
|
214
|
+
units: { type: ["celsius", "fahrenheit"], default: "celsius" },
|
|
215
|
+
},
|
|
216
|
+
service: async ({ location, units }) => {
|
|
217
|
+
const weather = await fetchWeather(location);
|
|
218
|
+
return {
|
|
219
|
+
location,
|
|
220
|
+
temperature: units === "celsius" ? weather.tempC : weather.tempF,
|
|
221
|
+
units,
|
|
222
|
+
conditions: weather.conditions,
|
|
223
|
+
};
|
|
224
|
+
},
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
const searchHandler = serviceHandler({
|
|
228
|
+
alias: "search_web",
|
|
229
|
+
description: "Search the web for information",
|
|
230
|
+
input: {
|
|
231
|
+
query: { type: String, description: "Search query" },
|
|
232
|
+
maxResults: { type: Number, default: 5, description: "Maximum results" },
|
|
233
|
+
},
|
|
234
|
+
service: async ({ query, maxResults }) => {
|
|
235
|
+
return await performSearch(query, maxResults);
|
|
236
|
+
},
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
// Create tools
|
|
240
|
+
const { tool: weatherTool } = createLlmTool({ handler: weatherHandler });
|
|
241
|
+
const { tool: searchTool } = createLlmTool({ handler: searchHandler });
|
|
242
|
+
|
|
243
|
+
// Use with Toolkit
|
|
244
|
+
const toolkit = new Toolkit([weatherTool, searchTool]);
|
|
245
|
+
const llm = new Llm({ toolkit });
|
|
246
|
+
|
|
247
|
+
const response = await llm.ask("What's the weather in Tokyo?");
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
## TypeScript Types
|
|
251
|
+
|
|
252
|
+
```typescript
|
|
253
|
+
import type {
|
|
254
|
+
CreateLlmToolConfig,
|
|
255
|
+
CreateLlmToolResult,
|
|
256
|
+
LlmTool,
|
|
257
|
+
OnCompleteCallback,
|
|
258
|
+
OnErrorCallback,
|
|
259
|
+
OnFatalCallback,
|
|
260
|
+
OnMessageCallback,
|
|
261
|
+
} from "@jaypie/vocabulary/llm";
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
### Type Definitions
|
|
265
|
+
|
|
266
|
+
```typescript
|
|
267
|
+
interface LlmTool {
|
|
268
|
+
name: string;
|
|
269
|
+
description: string;
|
|
270
|
+
parameters: JsonSchema;
|
|
271
|
+
function: (params: Record<string, unknown>) => Promise<unknown>;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
interface CreateLlmToolConfig {
|
|
275
|
+
handler: ServiceHandlerFunction;
|
|
276
|
+
name?: string;
|
|
277
|
+
description?: string;
|
|
278
|
+
message?: string | ((params: Record<string, unknown>) => string);
|
|
279
|
+
exclude?: string[];
|
|
280
|
+
onComplete?: OnCompleteCallback;
|
|
281
|
+
onError?: OnErrorCallback;
|
|
282
|
+
onFatal?: OnFatalCallback;
|
|
283
|
+
onMessage?: OnMessageCallback;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
interface CreateLlmToolResult {
|
|
287
|
+
tool: LlmTool;
|
|
288
|
+
}
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
## Exports
|
|
292
|
+
|
|
293
|
+
```typescript
|
|
294
|
+
// @jaypie/vocabulary/llm
|
|
295
|
+
export { createLlmTool } from "./createLlmTool.js";
|
|
296
|
+
export { inputToJsonSchema } from "./inputToJsonSchema.js";
|
|
297
|
+
|
|
298
|
+
export type {
|
|
299
|
+
CreateLlmToolConfig,
|
|
300
|
+
CreateLlmToolResult,
|
|
301
|
+
LlmTool,
|
|
302
|
+
OnCompleteCallback,
|
|
303
|
+
OnErrorCallback,
|
|
304
|
+
OnFatalCallback,
|
|
305
|
+
OnMessageCallback,
|
|
306
|
+
} from "./types.js";
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
## Related
|
|
310
|
+
|
|
311
|
+
- [Jaypie_Vocabulary_Package.md](Jaypie_Vocabulary_Package.md) - Core serviceHandler and type coercion
|
|
312
|
+
- [Jaypie_Llm_Tools.md](Jaypie_Llm_Tools.md) - LLM tools and Toolkit usage
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: AWS Lambda integration with serviceHandler for event processing and callbacks
|
|
3
|
+
include: "**/lambda/**"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Jaypie Vocabulary Lambda Adapter
|
|
7
|
+
|
|
8
|
+
The Lambda adapter (`@jaypie/vocabulary/lambda`) wraps Jaypie service handlers for use as AWS Lambda handlers, providing automatic event parsing, secrets management, and lifecycle hooks.
|
|
9
|
+
|
|
10
|
+
**See also:** [Jaypie_Vocabulary_Package.md](Jaypie_Vocabulary_Package.md) for core serviceHandler documentation.
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm install @jaypie/vocabulary
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Quick Start
|
|
19
|
+
|
|
20
|
+
```typescript
|
|
21
|
+
import { serviceHandler } from "@jaypie/vocabulary";
|
|
22
|
+
import { lambdaServiceHandler } from "@jaypie/vocabulary/lambda";
|
|
23
|
+
|
|
24
|
+
const handler = serviceHandler({
|
|
25
|
+
alias: "processOrder",
|
|
26
|
+
input: { orderId: { type: String } },
|
|
27
|
+
service: async ({ orderId }) => {
|
|
28
|
+
return { orderId, status: "processed" };
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
export const lambdaHandler = lambdaServiceHandler({ handler });
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## lambdaServiceHandler
|
|
36
|
+
|
|
37
|
+
Wraps a serviceHandler for use as an AWS Lambda handler.
|
|
38
|
+
|
|
39
|
+
### Options
|
|
40
|
+
|
|
41
|
+
| Option | Type | Description |
|
|
42
|
+
|--------|------|-------------|
|
|
43
|
+
| `handler` | `ServiceHandlerFunction` | Required. The service handler to wrap |
|
|
44
|
+
| `chaos` | `string` | Chaos testing mode |
|
|
45
|
+
| `name` | `string` | Override handler name for logging (default: handler.alias) |
|
|
46
|
+
| `onComplete` | `OnCompleteCallback` | Called with handler's return value on success |
|
|
47
|
+
| `onError` | `OnErrorCallback` | Receives errors reported via `context.onError()` in service |
|
|
48
|
+
| `onFatal` | `OnFatalCallback` | Receives fatal errors (thrown or via `context.onFatal()`) |
|
|
49
|
+
| `onMessage` | `OnMessageCallback` | Receives messages from `context.sendMessage` |
|
|
50
|
+
| `secrets` | `string[]` | AWS secrets to load into process.env |
|
|
51
|
+
| `setup` | `LifecycleFunction[]` | Functions to run before handler |
|
|
52
|
+
| `teardown` | `LifecycleFunction[]` | Functions to run after handler (always runs) |
|
|
53
|
+
| `throw` | `boolean` | Re-throw errors instead of returning error response |
|
|
54
|
+
| `unavailable` | `boolean` | Return 503 Unavailable immediately |
|
|
55
|
+
| `validate` | `ValidatorFunction[]` | Validation functions to run before handler |
|
|
56
|
+
|
|
57
|
+
## Lifecycle Callbacks
|
|
58
|
+
|
|
59
|
+
Services can use context callbacks to report progress, errors, and completion:
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
import { serviceHandler } from "@jaypie/vocabulary";
|
|
63
|
+
import { lambdaServiceHandler } from "@jaypie/vocabulary/lambda";
|
|
64
|
+
|
|
65
|
+
const handler = serviceHandler({
|
|
66
|
+
alias: "evaluate",
|
|
67
|
+
input: { jobId: { type: String } },
|
|
68
|
+
service: async ({ jobId }, context) => {
|
|
69
|
+
context?.sendMessage?.({ content: `Starting job ${jobId}` });
|
|
70
|
+
|
|
71
|
+
// Handle recoverable errors without throwing
|
|
72
|
+
try {
|
|
73
|
+
await riskyOperation();
|
|
74
|
+
} catch (err) {
|
|
75
|
+
context?.onError?.(err); // Reports error but continues
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// For fatal errors, either throw or call context.onFatal()
|
|
79
|
+
if (criticalFailure) {
|
|
80
|
+
context?.onFatal?.(new Error("Cannot continue"));
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return { jobId, status: "complete" };
|
|
84
|
+
},
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
export const lambdaHandler = lambdaServiceHandler({
|
|
88
|
+
handler,
|
|
89
|
+
onComplete: (response) => {
|
|
90
|
+
console.log("Done:", JSON.stringify(response, null, 2));
|
|
91
|
+
},
|
|
92
|
+
onError: (error) => {
|
|
93
|
+
// Recoverable errors reported via context.onError()
|
|
94
|
+
console.error("Warning:", error);
|
|
95
|
+
},
|
|
96
|
+
onFatal: (error) => {
|
|
97
|
+
// Fatal errors (thrown or via context.onFatal())
|
|
98
|
+
console.error("Fatal:", error);
|
|
99
|
+
},
|
|
100
|
+
onMessage: (msg) => {
|
|
101
|
+
console.log(`[${msg.level || "info"}] ${msg.content}`);
|
|
102
|
+
},
|
|
103
|
+
});
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
**Error handling**: Services receive `context.onError()` and `context.onFatal()` callbacks to report errors without throwing. Any error that escapes the service (is thrown) is treated as fatal and routes to `onFatal`. If `onFatal` is not provided, thrown errors fall back to `onError`. Callback errors are swallowed to ensure failures never halt service execution.
|
|
107
|
+
|
|
108
|
+
## Secrets Management
|
|
109
|
+
|
|
110
|
+
Automatically loads AWS Secrets Manager values into `process.env`:
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
export const lambdaHandler = lambdaServiceHandler({
|
|
114
|
+
handler,
|
|
115
|
+
secrets: ["ANTHROPIC_API_KEY", "DATABASE_URL"],
|
|
116
|
+
});
|
|
117
|
+
// Before handler runs, secrets are fetched and available as:
|
|
118
|
+
// process.env.ANTHROPIC_API_KEY
|
|
119
|
+
// process.env.DATABASE_URL
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Lifecycle Hooks
|
|
123
|
+
|
|
124
|
+
### setup
|
|
125
|
+
|
|
126
|
+
Functions to run before the handler:
|
|
127
|
+
|
|
128
|
+
```typescript
|
|
129
|
+
export const lambdaHandler = lambdaServiceHandler({
|
|
130
|
+
handler,
|
|
131
|
+
setup: [
|
|
132
|
+
async () => {
|
|
133
|
+
await initializeDatabase();
|
|
134
|
+
},
|
|
135
|
+
async () => {
|
|
136
|
+
await warmCache();
|
|
137
|
+
},
|
|
138
|
+
],
|
|
139
|
+
});
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### teardown
|
|
143
|
+
|
|
144
|
+
Functions to run after the handler (always runs, even on error):
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
export const lambdaHandler = lambdaServiceHandler({
|
|
148
|
+
handler,
|
|
149
|
+
teardown: [
|
|
150
|
+
async () => {
|
|
151
|
+
await closeConnections();
|
|
152
|
+
},
|
|
153
|
+
],
|
|
154
|
+
});
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### validate
|
|
158
|
+
|
|
159
|
+
Validation functions to run before handler. If any returns falsy or throws, handler is skipped:
|
|
160
|
+
|
|
161
|
+
```typescript
|
|
162
|
+
export const lambdaHandler = lambdaServiceHandler({
|
|
163
|
+
handler,
|
|
164
|
+
validate: [
|
|
165
|
+
(event) => event.headers?.authorization !== undefined,
|
|
166
|
+
async (event) => {
|
|
167
|
+
const token = event.headers?.authorization;
|
|
168
|
+
return await verifyToken(token);
|
|
169
|
+
},
|
|
170
|
+
],
|
|
171
|
+
});
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## Event Handling
|
|
175
|
+
|
|
176
|
+
The adapter uses `getMessages()` from `@jaypie/aws` to extract messages from various event types:
|
|
177
|
+
|
|
178
|
+
- **SQS Events**: Extracts message body from each record
|
|
179
|
+
- **SNS Events**: Extracts message from SNS notification
|
|
180
|
+
- **Direct Invocation**: Uses event body directly
|
|
181
|
+
|
|
182
|
+
### Single vs Multiple Messages
|
|
183
|
+
|
|
184
|
+
```typescript
|
|
185
|
+
// Single message returns single response
|
|
186
|
+
const result = await lambdaHandler(singleMessageEvent);
|
|
187
|
+
// result: { orderId: "123", status: "processed" }
|
|
188
|
+
|
|
189
|
+
// Multiple messages return array of responses
|
|
190
|
+
const results = await lambdaHandler(sqsBatchEvent);
|
|
191
|
+
// results: [
|
|
192
|
+
// { orderId: "123", status: "processed" },
|
|
193
|
+
// { orderId: "456", status: "processed" },
|
|
194
|
+
// ]
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## Complete Example
|
|
198
|
+
|
|
199
|
+
```typescript
|
|
200
|
+
import { serviceHandler } from "@jaypie/vocabulary";
|
|
201
|
+
import { lambdaServiceHandler } from "@jaypie/vocabulary/lambda";
|
|
202
|
+
import log from "@jaypie/logger";
|
|
203
|
+
|
|
204
|
+
const processOrderHandler = serviceHandler({
|
|
205
|
+
alias: "processOrder",
|
|
206
|
+
description: "Process an incoming order",
|
|
207
|
+
input: {
|
|
208
|
+
orderId: { type: String, description: "Order ID to process" },
|
|
209
|
+
priority: { type: [1, 2, 3], default: 2 },
|
|
210
|
+
rush: { type: Boolean, default: false },
|
|
211
|
+
},
|
|
212
|
+
service: async ({ orderId, priority, rush }, context) => {
|
|
213
|
+
context?.sendMessage?.({ content: `Processing order ${orderId}` });
|
|
214
|
+
|
|
215
|
+
if (rush) {
|
|
216
|
+
context?.sendMessage?.({ content: "Rush order - expediting", level: "warn" });
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Process the order...
|
|
220
|
+
await processOrder(orderId, { priority, rush });
|
|
221
|
+
|
|
222
|
+
context?.sendMessage?.({ content: "Order processed successfully" });
|
|
223
|
+
return { orderId, status: "complete", priority, rush };
|
|
224
|
+
},
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
export const handler = lambdaServiceHandler({
|
|
228
|
+
handler: processOrderHandler,
|
|
229
|
+
name: "order-processor",
|
|
230
|
+
secrets: ["DATABASE_URL", "STRIPE_API_KEY"],
|
|
231
|
+
setup: [
|
|
232
|
+
async () => {
|
|
233
|
+
await connectToDatabase();
|
|
234
|
+
},
|
|
235
|
+
],
|
|
236
|
+
teardown: [
|
|
237
|
+
async () => {
|
|
238
|
+
await flushMetrics();
|
|
239
|
+
},
|
|
240
|
+
],
|
|
241
|
+
onMessage: (msg) => {
|
|
242
|
+
log[msg.level || "info"](msg.content);
|
|
243
|
+
},
|
|
244
|
+
});
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
## Error Handling
|
|
248
|
+
|
|
249
|
+
### Default Behavior
|
|
250
|
+
|
|
251
|
+
Errors are caught and returned as structured error responses:
|
|
252
|
+
|
|
253
|
+
```typescript
|
|
254
|
+
// On error, returns:
|
|
255
|
+
{
|
|
256
|
+
error: true,
|
|
257
|
+
message: "Error message",
|
|
258
|
+
statusCode: 500,
|
|
259
|
+
// ... additional error details
|
|
260
|
+
}
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### Re-throwing Errors
|
|
264
|
+
|
|
265
|
+
Set `throw: true` to re-throw errors (useful for SQS retry behavior):
|
|
266
|
+
|
|
267
|
+
```typescript
|
|
268
|
+
export const lambdaHandler = lambdaServiceHandler({
|
|
269
|
+
handler,
|
|
270
|
+
throw: true, // Errors will propagate, triggering SQS retry
|
|
271
|
+
});
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
## TypeScript Types
|
|
275
|
+
|
|
276
|
+
```typescript
|
|
277
|
+
import type {
|
|
278
|
+
LambdaContext,
|
|
279
|
+
LambdaServiceHandlerConfig,
|
|
280
|
+
LambdaServiceHandlerOptions,
|
|
281
|
+
LambdaServiceHandlerResult,
|
|
282
|
+
OnCompleteCallback,
|
|
283
|
+
OnErrorCallback,
|
|
284
|
+
OnFatalCallback,
|
|
285
|
+
OnMessageCallback,
|
|
286
|
+
} from "@jaypie/vocabulary/lambda";
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
## Exports
|
|
290
|
+
|
|
291
|
+
```typescript
|
|
292
|
+
// @jaypie/vocabulary/lambda
|
|
293
|
+
export { lambdaServiceHandler } from "./lambdaServiceHandler.js";
|
|
294
|
+
|
|
295
|
+
export type {
|
|
296
|
+
LambdaContext,
|
|
297
|
+
LambdaServiceHandlerConfig,
|
|
298
|
+
LambdaServiceHandlerOptions,
|
|
299
|
+
LambdaServiceHandlerResult,
|
|
300
|
+
OnCompleteCallback,
|
|
301
|
+
OnErrorCallback,
|
|
302
|
+
OnFatalCallback,
|
|
303
|
+
OnMessageCallback,
|
|
304
|
+
} from "./types.js";
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
## Related
|
|
308
|
+
|
|
309
|
+
- [Jaypie_Vocabulary_Package.md](Jaypie_Vocabulary_Package.md) - Core serviceHandler and type coercion
|
|
310
|
+
- [Jaypie_Init_Lambda_Package.md](Jaypie_Init_Lambda_Package.md) - Setting up Lambda projects
|