@jaypie/mcp 0.4.0 → 0.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/dist/suite.js +1 -1
- package/package.json +1 -1
- package/release-notes/constructs/1.2.18.md +12 -0
- package/release-notes/llm/1.2.5.md +25 -0
- package/release-notes/llm/1.2.6.md +55 -0
- package/skills/agents.md +18 -8
- package/skills/aws.md +232 -60
- package/skills/datadog.md +98 -64
- package/skills/dynamodb.md +37 -28
- package/skills/issues.md +55 -0
- package/skills/llm.md +381 -0
- package/skills/secrets.md +74 -18
- package/skills/skills.md +23 -0
- package/skills/tools-aws.md +148 -0
- package/skills/tools-datadog.md +190 -0
- package/skills/tools-dynamodb.md +140 -0
- package/skills/tools.md +19 -54
- package/skills/vocabulary.md +25 -0
- package/skills/topics.md +0 -116
- /package/skills/{writing.md → documentation.md} +0 -0
package/dist/suite.js
CHANGED
|
@@ -1202,7 +1202,7 @@ async function purgeSQSQueue(options, logger = nullLogger) {
|
|
|
1202
1202
|
|
|
1203
1203
|
// ServiceSuite for @jaypie/mcp
|
|
1204
1204
|
// Provides metadata and direct execution for Jaypie MCP services
|
|
1205
|
-
const BUILD_VERSION_STRING = "@jaypie/mcp@0.4.
|
|
1205
|
+
const BUILD_VERSION_STRING = "@jaypie/mcp@0.4.1#c7b5feb2"
|
|
1206
1206
|
;
|
|
1207
1207
|
const __filename$1 = fileURLToPath(import.meta.url);
|
|
1208
1208
|
const __dirname$1 = path.dirname(__filename$1);
|
package/package.json
CHANGED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
---
|
|
2
|
+
version: 1.2.18
|
|
3
|
+
date: 2025-01-21
|
|
4
|
+
summary: JaypieNextJs supports domain-less CloudFront-only deployment
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Changes
|
|
8
|
+
|
|
9
|
+
- Added `domainProps: false` option to `JaypieNextJs` to deploy without a custom domain
|
|
10
|
+
- When `domainProps: false`, the application is accessible only via CloudFront URL
|
|
11
|
+
- `NEXT_PUBLIC_SITE_URL` is automatically set to the CloudFront distribution URL when no domain is configured
|
|
12
|
+
- Cache policy names use construct ID instead of domain name for domain-less deployments
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
---
|
|
2
|
+
version: 1.2.5
|
|
3
|
+
date: 2025-01-21
|
|
4
|
+
summary: Preserve original error details in BadGatewayError thrown by RetryExecutor
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Changes
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
- **Preserve original error message in BadGatewayError**: When `RetryExecutor` encounters a non-retryable error or exhausts retries, it now preserves the original error message in the thrown `BadGatewayError`. Previously, the original error details (e.g., "Quota exceeded for metric X, limit: 0") were lost, making debugging difficult.
|
|
12
|
+
|
|
13
|
+
### Before
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
JaypieError: An unexpected error occurred on an upstream resource
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### After
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
JaypieError: You exceeded your current quota... limit: 0
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
This fix improves debugging by preserving context from LLM provider errors (like Gemini's 429 quota exceeded responses).
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
---
|
|
2
|
+
version: 1.2.6
|
|
3
|
+
date: 2025-01-21
|
|
4
|
+
summary: Add configurable fallback provider chain for automatic retry with alternative providers
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Changes
|
|
8
|
+
|
|
9
|
+
### New Features
|
|
10
|
+
|
|
11
|
+
- **Fallback Provider Support**: Configure a chain of fallback providers that automatically retry failed `operate()` calls when the primary provider fails with an unrecoverable error.
|
|
12
|
+
|
|
13
|
+
### Usage
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
// Instance-level configuration
|
|
17
|
+
const llm = new Llm("anthropic", {
|
|
18
|
+
model: "claude-sonnet-4",
|
|
19
|
+
fallback: [
|
|
20
|
+
{ provider: "openai", model: "gpt-4o" },
|
|
21
|
+
{ provider: "gemini", model: "gemini-2.0-flash" },
|
|
22
|
+
],
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
// Per-call override
|
|
26
|
+
const response = await llm.operate(input, {
|
|
27
|
+
fallback: [{ provider: "openai", model: "gpt-4o" }],
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
// Disable fallback for specific call
|
|
31
|
+
const response = await llm.operate(input, { fallback: false });
|
|
32
|
+
|
|
33
|
+
// Static method with fallback
|
|
34
|
+
const response = await Llm.operate(input, {
|
|
35
|
+
model: "claude-sonnet-4",
|
|
36
|
+
fallback: [{ provider: "openai", model: "gpt-4o" }],
|
|
37
|
+
});
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Response Metadata
|
|
41
|
+
|
|
42
|
+
The `LlmOperateResponse` now includes:
|
|
43
|
+
- `provider`: Which provider actually handled the request
|
|
44
|
+
- `fallbackUsed`: `true` if a fallback provider was used
|
|
45
|
+
- `fallbackAttempts`: Number of providers tried (1 = primary only)
|
|
46
|
+
|
|
47
|
+
### New Type
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
interface LlmFallbackConfig {
|
|
51
|
+
provider: string;
|
|
52
|
+
model?: string;
|
|
53
|
+
apiKey?: string;
|
|
54
|
+
}
|
|
55
|
+
```
|
package/skills/agents.md
CHANGED
|
@@ -1,25 +1,35 @@
|
|
|
1
1
|
---
|
|
2
|
-
description:
|
|
2
|
+
description: Recommended prompts to help agents use Jaypie; to put in AGENTS.md, CLAUDE.md, etc.
|
|
3
|
+
related: jaypie
|
|
3
4
|
---
|
|
4
5
|
|
|
5
6
|
# Agent Instructions
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
The goal is concise introduction to Jaypie capabilities that invite agent exploration.
|
|
9
|
+
|
|
10
|
+
Add one of the following to AGENTS.md, CLAUDE.md, or similar files.
|
|
11
|
+
|
|
12
|
+
## Complete Version
|
|
13
|
+
|
|
14
|
+
The complete version references as many daily tasks as possible without listing everything.
|
|
15
|
+
Some tasks should not be listed to avoid suboptimal pathing.
|
|
8
16
|
|
|
9
17
|
```markdown
|
|
10
18
|
## Jaypie
|
|
11
19
|
|
|
12
20
|
Query `mcp__jaypie__skill(alias: String)` for development guidance:
|
|
13
21
|
|
|
14
|
-
Contents: index, releasenotes
|
|
15
|
-
Development:
|
|
22
|
+
Contents: index, releasenotes
|
|
23
|
+
Development: documentation, errors, logs, mocks, style, tests
|
|
16
24
|
Infrastructure: aws, cdk, cicd, datadog, dns, dynamodb, secrets, variables
|
|
17
|
-
Patterns: fabric, models, services,
|
|
18
|
-
Meta:
|
|
25
|
+
Patterns: fabric, models, services, vocabulary
|
|
26
|
+
Meta: issues, jaypie, skills, tools
|
|
19
27
|
```
|
|
20
28
|
|
|
21
|
-
|
|
29
|
+
## Short Version
|
|
30
|
+
|
|
31
|
+
The one-line version tells the agent how to find out more about Jaypie skills.
|
|
22
32
|
|
|
23
33
|
```markdown
|
|
24
|
-
`mcp__jaypie__skill(
|
|
34
|
+
`mcp__jaypie__skill(skills)`: Discover Jaypie development skills and tools available in this repository.
|
|
25
35
|
```
|
package/skills/aws.md
CHANGED
|
@@ -1,107 +1,279 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: AWS integration
|
|
3
|
-
related: cdk, dynamodb, secrets, logs
|
|
2
|
+
description: AWS integration and cloud services code patterns
|
|
3
|
+
related: cdk, dynamodb, secrets, logs, tools-aws
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# AWS Integration
|
|
7
7
|
|
|
8
|
-
Jaypie integrates with AWS services through
|
|
8
|
+
Jaypie integrates with AWS services through the `@jaypie/aws` package and CDK constructs.
|
|
9
|
+
Access `@jaypie/aws` through the main `jaypie` package.
|
|
9
10
|
|
|
10
|
-
## MCP
|
|
11
|
+
## MCP Tools
|
|
11
12
|
|
|
12
|
-
|
|
13
|
+
For interactive AWS tools (Lambda, S3, SQS, CloudWatch, Step Functions, CloudFormation), see **tools-aws**.
|
|
13
14
|
|
|
14
|
-
|
|
15
|
-
```
|
|
16
|
-
aws_lambda_list_functions - List functions with optional prefix filter
|
|
17
|
-
aws_lambda_get_function - Get function configuration and details
|
|
18
|
-
```
|
|
15
|
+
## @jaypie/aws Package
|
|
19
16
|
|
|
20
|
-
|
|
21
|
-
```
|
|
22
|
-
aws_stepfunctions_list_executions - List executions for a state machine
|
|
23
|
-
aws_stepfunctions_stop_execution - Stop a running execution
|
|
24
|
-
```
|
|
17
|
+
The `@jaypie/aws` package provides SDK utilities for Secrets Manager, SQS, S3, Textract, and streaming.
|
|
25
18
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
19
|
+
```typescript
|
|
20
|
+
import {
|
|
21
|
+
getEnvSecret,
|
|
22
|
+
getMessages,
|
|
23
|
+
getS3FileBuffer,
|
|
24
|
+
loadEnvSecrets,
|
|
25
|
+
sendBatchMessages,
|
|
26
|
+
sendMessage,
|
|
27
|
+
} from "@jaypie/aws";
|
|
29
28
|
```
|
|
30
29
|
|
|
31
|
-
###
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
30
|
+
### Available Functions
|
|
31
|
+
|
|
32
|
+
| Function | Description |
|
|
33
|
+
|----------|-------------|
|
|
34
|
+
| **Secrets** | |
|
|
35
|
+
| `getEnvSecret(name, { env? })` | Preferred: Fetch secret using env var patterns |
|
|
36
|
+
| `loadEnvSecrets(...names)` | Load multiple secrets into `process.env` |
|
|
37
|
+
| `getSecret(name)` | Internal: Direct fetch by AWS secret name |
|
|
38
|
+
| **SQS Messaging** | |
|
|
39
|
+
| `sendMessage(body, { queueUrl?, ... })` | Send single message to SQS |
|
|
40
|
+
| `sendBatchMessages({ messages, queueUrl?, ... })` | Send multiple messages (batched in groups of 10) |
|
|
41
|
+
| `getMessages(event)` | Parse SQS/SNS event into array of message bodies |
|
|
42
|
+
| `getSingletonMessage(event)` | Get exactly one message or throw `BadGatewayError` |
|
|
43
|
+
| **S3** | |
|
|
44
|
+
| `getS3FileBuffer({ bucket, key })` | Fetch S3 file as Buffer |
|
|
45
|
+
| **Textract** | |
|
|
46
|
+
| `sendTextractJob({ bucket, key, ... })` | Start async Textract job |
|
|
47
|
+
| `getTextractJob(jobId)` | Get results of completed Textract job |
|
|
48
|
+
| **Streaming** | |
|
|
49
|
+
| `JaypieStream` | Class wrapping async iterable with streaming methods |
|
|
50
|
+
| `createJaypieStream(source)` | Factory for JaypieStream |
|
|
51
|
+
| `createLambdaStream(stream, writer)` | Stream to Lambda response writer |
|
|
52
|
+
| `createExpressStream(stream, res)` | Stream to Express response |
|
|
53
|
+
|
|
54
|
+
## Secrets Management
|
|
35
55
|
|
|
36
|
-
###
|
|
56
|
+
### getEnvSecret (Preferred)
|
|
57
|
+
|
|
58
|
+
Use `getEnvSecret` for environment-aware secret resolution. It checks environment variables in order:
|
|
59
|
+
|
|
60
|
+
1. `SECRET_{name}` - Explicit secret reference (fetches from Secrets Manager)
|
|
61
|
+
2. `{name}_SECRET` - Alternative secret reference (fetches from Secrets Manager)
|
|
62
|
+
3. `{name}` - Returns direct value without AWS call
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
import { getEnvSecret } from "@jaypie/aws";
|
|
66
|
+
|
|
67
|
+
// If SECRET_ANTHROPIC_API_KEY="arn:aws:secretsmanager:..." exists, fetches from AWS
|
|
68
|
+
// Otherwise returns process.env.ANTHROPIC_API_KEY directly
|
|
69
|
+
const apiKey = await getEnvSecret("ANTHROPIC_API_KEY");
|
|
37
70
|
```
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
71
|
+
|
|
72
|
+
This pattern allows the same code to work locally (with direct env values) and in Lambda (with secret references).
|
|
73
|
+
|
|
74
|
+
### loadEnvSecrets
|
|
75
|
+
|
|
76
|
+
Load multiple secrets at once during handler initialization:
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
import { loadEnvSecrets } from "@jaypie/aws";
|
|
80
|
+
|
|
81
|
+
// Load secrets and set in process.env
|
|
82
|
+
await loadEnvSecrets("ANTHROPIC_API_KEY", "OPENAI_API_KEY");
|
|
83
|
+
|
|
84
|
+
// Now available as process.env.ANTHROPIC_API_KEY, etc.
|
|
42
85
|
```
|
|
43
86
|
|
|
44
|
-
###
|
|
87
|
+
### getSecret (Internal Use)
|
|
88
|
+
|
|
89
|
+
Direct fetch by AWS secret name. Requires `AWS_SESSION_TOKEN`. Prefer `getEnvSecret` unless you need to fetch a secret by its exact AWS name:
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
import { getSecret } from "@jaypie/aws";
|
|
93
|
+
|
|
94
|
+
// Fetch by exact AWS secret name
|
|
95
|
+
const secret = await getSecret("my-project/production/api-key");
|
|
45
96
|
```
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
97
|
+
|
|
98
|
+
## SQS Messaging
|
|
99
|
+
|
|
100
|
+
### sendMessage
|
|
101
|
+
|
|
102
|
+
Send a single message to SQS. Uses `CDK_ENV_QUEUE_URL` by default:
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
import { sendMessage } from "@jaypie/aws";
|
|
106
|
+
|
|
107
|
+
// Simple usage with default queue
|
|
108
|
+
await sendMessage({ action: "process", documentId: "doc-123" });
|
|
109
|
+
|
|
110
|
+
// With explicit queue URL
|
|
111
|
+
await sendMessage({ action: "process" }, { queueUrl: "https://sqs..." });
|
|
112
|
+
|
|
113
|
+
// With options
|
|
114
|
+
await sendMessage(
|
|
115
|
+
{ action: "process" },
|
|
116
|
+
{
|
|
117
|
+
delaySeconds: 30,
|
|
118
|
+
messageAttributes: { Priority: { DataType: "String", StringValue: "high" } },
|
|
119
|
+
queueUrl: process.env.CDK_ENV_QUEUE_URL,
|
|
120
|
+
}
|
|
121
|
+
);
|
|
50
122
|
```
|
|
51
123
|
|
|
52
|
-
###
|
|
124
|
+
### sendBatchMessages
|
|
125
|
+
|
|
126
|
+
Send multiple messages, automatically batched in groups of 10:
|
|
127
|
+
|
|
128
|
+
```typescript
|
|
129
|
+
import { sendBatchMessages } from "@jaypie/aws";
|
|
130
|
+
|
|
131
|
+
const messages = items.map((item) => ({ action: "process", id: item.id }));
|
|
132
|
+
await sendBatchMessages({ messages });
|
|
53
133
|
```
|
|
54
|
-
|
|
134
|
+
|
|
135
|
+
### getMessages and getSingletonMessage
|
|
136
|
+
|
|
137
|
+
Parse incoming SQS/SNS events:
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
import { getMessages, getSingletonMessage } from "@jaypie/aws";
|
|
141
|
+
|
|
142
|
+
// Get all messages from event
|
|
143
|
+
const messages = getMessages(event); // Returns array
|
|
144
|
+
|
|
145
|
+
// Get exactly one message or throw BadGatewayError
|
|
146
|
+
const message = getSingletonMessage(event);
|
|
55
147
|
```
|
|
56
148
|
|
|
57
|
-
##
|
|
149
|
+
## S3 Operations
|
|
58
150
|
|
|
59
|
-
|
|
60
|
-
1. Environment variables (`AWS_ACCESS_KEY_ID`, etc.)
|
|
61
|
-
2. `~/.aws/credentials` and `~/.aws/config`
|
|
62
|
-
3. SSO sessions via `aws sso login`
|
|
151
|
+
### getS3FileBuffer
|
|
63
152
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
153
|
+
Fetch a file from S3 as a Buffer:
|
|
154
|
+
|
|
155
|
+
```typescript
|
|
156
|
+
import { getS3FileBuffer } from "@jaypie/aws";
|
|
67
157
|
|
|
68
|
-
|
|
69
|
-
|
|
158
|
+
const buffer = await getS3FileBuffer({
|
|
159
|
+
bucket: process.env.CDK_ENV_BUCKET,
|
|
160
|
+
key: "documents/report.pdf",
|
|
161
|
+
});
|
|
70
162
|
```
|
|
71
163
|
|
|
72
|
-
##
|
|
164
|
+
## Textract
|
|
73
165
|
|
|
74
|
-
|
|
166
|
+
### Document Processing
|
|
75
167
|
|
|
76
168
|
```typescript
|
|
77
|
-
import {
|
|
169
|
+
import { sendTextractJob, getTextractJob } from "@jaypie/aws";
|
|
78
170
|
|
|
79
|
-
//
|
|
80
|
-
const
|
|
171
|
+
// Start async job
|
|
172
|
+
const { JobId } = await sendTextractJob({
|
|
173
|
+
bucket: process.env.CDK_ENV_BUCKET,
|
|
174
|
+
key: "documents/scan.pdf",
|
|
175
|
+
});
|
|
81
176
|
|
|
82
|
-
//
|
|
83
|
-
|
|
177
|
+
// Later, retrieve results
|
|
178
|
+
const results = await getTextractJob(JobId);
|
|
84
179
|
```
|
|
85
180
|
|
|
86
|
-
## Environment
|
|
87
|
-
|
|
88
|
-
Use CDK environment variables in Lambda:
|
|
181
|
+
## Environment Variables
|
|
89
182
|
|
|
90
183
|
| Variable | Description |
|
|
91
184
|
|----------|-------------|
|
|
92
|
-
| `
|
|
93
|
-
| `
|
|
185
|
+
| `AWS_SESSION_TOKEN` | Required for secrets access in Lambda |
|
|
186
|
+
| `CDK_ENV_BUCKET` | Default S3 bucket name |
|
|
187
|
+
| `CDK_ENV_QUEUE_URL` | Default SQS queue URL |
|
|
94
188
|
| `CDK_ENV_SNS_TOPIC_ARN` | SNS topic ARN |
|
|
189
|
+
| `CDK_ENV_SNS_ROLE_ARN` | SNS role ARN |
|
|
190
|
+
| `PROJECT_KEY` | Used for FIFO queue message group ID |
|
|
95
191
|
|
|
96
|
-
##
|
|
192
|
+
## Credential Management
|
|
97
193
|
|
|
98
|
-
|
|
194
|
+
### Local Development
|
|
195
|
+
|
|
196
|
+
Configure credentials via environment or files:
|
|
99
197
|
|
|
100
198
|
```bash
|
|
101
199
|
# Set default profile
|
|
102
200
|
export AWS_PROFILE=development
|
|
103
201
|
|
|
104
|
-
# Or
|
|
105
|
-
|
|
202
|
+
# Or use named profiles
|
|
203
|
+
export AWS_PROFILE=production
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
Credential chain priority:
|
|
207
|
+
1. Environment variables (`AWS_ACCESS_KEY_ID`, etc.)
|
|
208
|
+
2. `~/.aws/credentials` and `~/.aws/config`
|
|
209
|
+
3. SSO sessions via `aws sso login`
|
|
210
|
+
|
|
211
|
+
### Lambda Runtime
|
|
212
|
+
|
|
213
|
+
Lambda functions automatically receive credentials via IAM role. Use CDK to grant permissions:
|
|
214
|
+
|
|
215
|
+
```typescript
|
|
216
|
+
import { JaypieLambda } from "@jaypie/constructs";
|
|
217
|
+
|
|
218
|
+
const handler = new JaypieLambda(this, "Handler", {
|
|
219
|
+
entry: "src/handler.ts",
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
// Grant S3 access
|
|
223
|
+
bucket.grantReadWrite(handler);
|
|
224
|
+
|
|
225
|
+
// Grant SQS access
|
|
226
|
+
queue.grantSendMessages(handler);
|
|
227
|
+
|
|
228
|
+
// Grant Secrets Manager access
|
|
229
|
+
secret.grantRead(handler);
|
|
106
230
|
```
|
|
107
231
|
|
|
232
|
+
## Error Handling
|
|
233
|
+
|
|
234
|
+
Handle AWS errors with Jaypie patterns:
|
|
235
|
+
|
|
236
|
+
```typescript
|
|
237
|
+
import { getEnvSecret } from "@jaypie/aws";
|
|
238
|
+
import { ConfigurationError, log } from "jaypie";
|
|
239
|
+
|
|
240
|
+
async function getApiKey() {
|
|
241
|
+
try {
|
|
242
|
+
return await getEnvSecret("API_KEY");
|
|
243
|
+
} catch (error) {
|
|
244
|
+
log.error("Failed to retrieve API key", { error });
|
|
245
|
+
throw new ConfigurationError("API key not configured");
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
## Testing
|
|
251
|
+
|
|
252
|
+
Mock AWS functions in tests:
|
|
253
|
+
|
|
254
|
+
```typescript
|
|
255
|
+
import { getEnvSecret, sendMessage } from "@jaypie/testkit/mock";
|
|
256
|
+
import { vi } from "vitest";
|
|
257
|
+
|
|
258
|
+
vi.mock("@jaypie/aws");
|
|
259
|
+
|
|
260
|
+
describe("Handler", () => {
|
|
261
|
+
it("sends message to queue", async () => {
|
|
262
|
+
vi.mocked(sendMessage).mockResolvedValue({ MessageId: "123" });
|
|
263
|
+
|
|
264
|
+
await handler({ documentId: "doc-123" });
|
|
265
|
+
|
|
266
|
+
expect(sendMessage).toHaveBeenCalledWith(
|
|
267
|
+
expect.objectContaining({ documentId: "doc-123" })
|
|
268
|
+
);
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
it("fetches secret from environment", async () => {
|
|
272
|
+
vi.mocked(getEnvSecret).mockResolvedValue("test-api-key");
|
|
273
|
+
|
|
274
|
+
const key = await getApiKey();
|
|
275
|
+
|
|
276
|
+
expect(key).toBe("test-api-key");
|
|
277
|
+
});
|
|
278
|
+
});
|
|
279
|
+
```
|
package/skills/datadog.md
CHANGED
|
@@ -1,61 +1,15 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: Datadog integration and observability
|
|
3
|
-
related: logs, debugging, aws
|
|
2
|
+
description: Datadog integration, logging, and observability code patterns
|
|
3
|
+
related: logs, debugging, aws, tools-datadog
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Datadog Integration
|
|
7
7
|
|
|
8
8
|
Jaypie integrates with Datadog for logging, monitoring, and APM.
|
|
9
9
|
|
|
10
|
-
## MCP
|
|
10
|
+
## MCP Tools
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
### Log Search
|
|
15
|
-
```
|
|
16
|
-
datadog_logs - Search individual log entries
|
|
17
|
-
datadog_log_analytics - Aggregate logs with groupBy
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
### Monitoring
|
|
21
|
-
```
|
|
22
|
-
datadog_monitors - List and check monitor status
|
|
23
|
-
datadog_synthetics - List synthetic tests and results
|
|
24
|
-
datadog_metrics - Query timeseries metrics
|
|
25
|
-
datadog_rum - Search Real User Monitoring events
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
## Environment Variables
|
|
29
|
-
|
|
30
|
-
Configure Datadog tools via environment:
|
|
31
|
-
|
|
32
|
-
| Variable | Description |
|
|
33
|
-
|----------|-------------|
|
|
34
|
-
| `DATADOG_API_KEY` or `DD_API_KEY` | API key |
|
|
35
|
-
| `DATADOG_APP_KEY` or `DD_APP_KEY` | Application key |
|
|
36
|
-
| `DD_ENV` | Default environment filter |
|
|
37
|
-
| `DD_SERVICE` | Default service filter |
|
|
38
|
-
| `DD_SOURCE` | Default log source (default: lambda) |
|
|
39
|
-
|
|
40
|
-
## Common Queries
|
|
41
|
-
|
|
42
|
-
### Search Error Logs
|
|
43
|
-
|
|
44
|
-
```
|
|
45
|
-
datadog_logs --query "status:error" --from "now-1h"
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
### Count Errors by Service
|
|
49
|
-
|
|
50
|
-
```
|
|
51
|
-
datadog_log_analytics --groupBy '["service"]' --query "status:error"
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
### Check Alerting Monitors
|
|
55
|
-
|
|
56
|
-
```
|
|
57
|
-
datadog_monitors --status '["Alert", "Warn"]'
|
|
58
|
-
```
|
|
12
|
+
For interactive Datadog tools (logs, monitors, metrics, synthetics, RUM), see **tools-datadog**.
|
|
59
13
|
|
|
60
14
|
## Lambda Integration
|
|
61
15
|
|
|
@@ -65,6 +19,7 @@ Enable Datadog tracing in CDK:
|
|
|
65
19
|
import { JaypieLambda } from "@jaypie/constructs";
|
|
66
20
|
|
|
67
21
|
const handler = new JaypieLambda(this, "Handler", {
|
|
22
|
+
entry: "src/handler.ts",
|
|
68
23
|
datadogApiKeyArn: process.env.CDK_ENV_DATADOG_API_KEY_ARN,
|
|
69
24
|
environment: {
|
|
70
25
|
DD_ENV: "production",
|
|
@@ -87,26 +42,32 @@ log.info("Request processed", {
|
|
|
87
42
|
action: "checkout",
|
|
88
43
|
duration: 150,
|
|
89
44
|
});
|
|
45
|
+
|
|
46
|
+
// Error logs include stack traces
|
|
47
|
+
log.error("Payment failed", {
|
|
48
|
+
error,
|
|
49
|
+
orderId: "order-456",
|
|
50
|
+
});
|
|
90
51
|
```
|
|
91
52
|
|
|
92
|
-
##
|
|
53
|
+
## @jaypie/datadog Package
|
|
93
54
|
|
|
94
|
-
|
|
55
|
+
The `@jaypie/datadog` package provides utilities:
|
|
95
56
|
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
@http.status_code:500 # By attribute
|
|
99
|
-
service:my-api # By service
|
|
100
|
-
*timeout* # Wildcard
|
|
101
|
-
```
|
|
57
|
+
```typescript
|
|
58
|
+
import { datadogMetric, datadogEvent } from "@jaypie/datadog";
|
|
102
59
|
|
|
103
|
-
|
|
60
|
+
// Send custom metric
|
|
61
|
+
await datadogMetric("checkout.completed", 1, {
|
|
62
|
+
tags: ["env:production", "service:checkout"],
|
|
63
|
+
});
|
|
104
64
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
65
|
+
// Send event
|
|
66
|
+
await datadogEvent({
|
|
67
|
+
title: "Deployment completed",
|
|
68
|
+
text: "Version 1.2.3 deployed to production",
|
|
69
|
+
tags: ["env:production"],
|
|
70
|
+
});
|
|
110
71
|
```
|
|
111
72
|
|
|
112
73
|
## Unified Service Tagging
|
|
@@ -127,3 +88,76 @@ environment: {
|
|
|
127
88
|
}
|
|
128
89
|
```
|
|
129
90
|
|
|
91
|
+
## Environment Variables
|
|
92
|
+
|
|
93
|
+
### CDK Configuration
|
|
94
|
+
|
|
95
|
+
| Variable | Description |
|
|
96
|
+
|----------|-------------|
|
|
97
|
+
| `CDK_ENV_DATADOG_API_KEY_ARN` | Datadog API key ARN in Secrets Manager |
|
|
98
|
+
|
|
99
|
+
### Lambda Environment
|
|
100
|
+
|
|
101
|
+
| Variable | Description |
|
|
102
|
+
|----------|-------------|
|
|
103
|
+
| `DD_ENV` | Environment tag |
|
|
104
|
+
| `DD_SERVICE` | Service tag |
|
|
105
|
+
| `DD_VERSION` | Version tag |
|
|
106
|
+
| `DD_TRACE_ENABLED` | Enable APM tracing |
|
|
107
|
+
| `DD_LOGS_INJECTION` | Inject trace IDs in logs |
|
|
108
|
+
|
|
109
|
+
## Trace Correlation
|
|
110
|
+
|
|
111
|
+
Correlate logs with traces:
|
|
112
|
+
|
|
113
|
+
```typescript
|
|
114
|
+
import { log, getTraceContext } from "jaypie";
|
|
115
|
+
|
|
116
|
+
function processRequest() {
|
|
117
|
+
const traceContext = getTraceContext();
|
|
118
|
+
|
|
119
|
+
log.info("Processing request", {
|
|
120
|
+
...traceContext,
|
|
121
|
+
requestId: "req-123",
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Custom Metrics
|
|
127
|
+
|
|
128
|
+
Send custom metrics from Lambda:
|
|
129
|
+
|
|
130
|
+
```typescript
|
|
131
|
+
import { log } from "jaypie";
|
|
132
|
+
|
|
133
|
+
// Use log for metrics that Datadog indexes
|
|
134
|
+
log.info("MONITORING", {
|
|
135
|
+
metric: "orders.processed",
|
|
136
|
+
value: 1,
|
|
137
|
+
tags: { env: "production", region: "us-east-1" },
|
|
138
|
+
});
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## Testing
|
|
142
|
+
|
|
143
|
+
Mock Datadog in tests:
|
|
144
|
+
|
|
145
|
+
```typescript
|
|
146
|
+
import { datadogMetric } from "@jaypie/datadog";
|
|
147
|
+
import { vi } from "vitest";
|
|
148
|
+
|
|
149
|
+
vi.mock("@jaypie/datadog");
|
|
150
|
+
|
|
151
|
+
describe("CheckoutService", () => {
|
|
152
|
+
it("sends metric on completion", async () => {
|
|
153
|
+
await processCheckout();
|
|
154
|
+
|
|
155
|
+
expect(datadogMetric).toHaveBeenCalledWith(
|
|
156
|
+
"checkout.completed",
|
|
157
|
+
1,
|
|
158
|
+
expect.objectContaining({ tags: expect.any(Array) })
|
|
159
|
+
);
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
```
|
|
163
|
+
|