@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 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.0#988a2bd8"
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jaypie/mcp",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "Jaypie MCP",
5
5
  "repository": {
6
6
  "type": "git",
@@ -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: Minimal agent instructions
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
- Add to CLAUDE.md or AGENTS.md:
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, topics
15
- Development: debugging, errors, logs, mocks, style, tests, writing
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, tools
18
- Meta: agents, jaypie, legacy
25
+ Patterns: fabric, models, services, vocabulary
26
+ Meta: issues, jaypie, skills, tools
19
27
  ```
20
28
 
21
- Or, for one line,
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(index)` describes Jaypie development skills for this repository.
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, CLI tools, and cloud services
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 SDK utilities and CLI tools available via the MCP.
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 AWS Tools
11
+ ## MCP Tools
11
12
 
12
- The Jaypie MCP provides AWS tools that use your local AWS credentials:
13
+ For interactive AWS tools (Lambda, S3, SQS, CloudWatch, Step Functions, CloudFormation), see **tools-aws**.
13
14
 
14
- ### Lambda Functions
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
- ### Step Functions
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
- ### CloudWatch Logs
27
- ```
28
- aws_logs_filter_log_events - Search logs with patterns and time ranges
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
- ### S3
32
- ```
33
- aws_s3_list_objects - List bucket objects with prefix filtering
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
- ### DynamoDB
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
- aws_dynamodb_describe_table - Get table metadata and indexes
39
- aws_dynamodb_scan - Scan table (use sparingly)
40
- aws_dynamodb_query - Query by partition key
41
- aws_dynamodb_get_item - Get single item by key
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
- ### SQS
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
- aws_sqs_list_queues - List queues with prefix filter
47
- aws_sqs_get_queue_attributes - Get queue attributes
48
- aws_sqs_receive_message - Peek at queue messages
49
- aws_sqs_purge_queue - Delete all messages (irreversible)
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
- ### CloudFormation
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
- aws_cloudformation_describe_stack - Get stack details and outputs
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
- ## Credential Management
149
+ ## S3 Operations
58
150
 
59
- Tools use the host's AWS credential chain:
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
- ```bash
65
- # List available profiles
66
- aws_list_profiles
153
+ Fetch a file from S3 as a Buffer:
154
+
155
+ ```typescript
156
+ import { getS3FileBuffer } from "@jaypie/aws";
67
157
 
68
- # Use a specific profile
69
- aws_lambda_list_functions --profile production
158
+ const buffer = await getS3FileBuffer({
159
+ bucket: process.env.CDK_ENV_BUCKET,
160
+ key: "documents/report.pdf",
161
+ });
70
162
  ```
71
163
 
72
- ## Jaypie AWS Package
164
+ ## Textract
73
165
 
74
- The `@jaypie/aws` package provides SDK utilities:
166
+ ### Document Processing
75
167
 
76
168
  ```typescript
77
- import { getSecret, sendMessage } from "@jaypie/aws";
169
+ import { sendTextractJob, getTextractJob } from "@jaypie/aws";
78
170
 
79
- // Get secret from Secrets Manager
80
- const apiKey = await getSecret("my-api-key");
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
- // Send SQS message
83
- await sendMessage(queueUrl, { action: "process", id: "123" });
177
+ // Later, retrieve results
178
+ const results = await getTextractJob(JobId);
84
179
  ```
85
180
 
86
- ## Environment-Based Configuration
87
-
88
- Use CDK environment variables in Lambda:
181
+ ## Environment Variables
89
182
 
90
183
  | Variable | Description |
91
184
  |----------|-------------|
92
- | `CDK_ENV_BUCKET` | S3 bucket name |
93
- | `CDK_ENV_QUEUE_URL` | SQS queue URL |
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
- ## Profile Selection
192
+ ## Credential Management
97
193
 
98
- When working with multiple AWS accounts:
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 specify per-command via MCP tools
105
- aws_lambda_list_functions --profile production --region us-west-2
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 Datadog Tools
10
+ ## MCP Tools
11
11
 
12
- The Jaypie MCP provides tools for querying Datadog:
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
- ## Query Syntax
53
+ ## @jaypie/datadog Package
93
54
 
94
- ### Log Search Syntax
55
+ The `@jaypie/datadog` package provides utilities:
95
56
 
96
- ```
97
- status:error # By status
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
- ### Time Ranges
60
+ // Send custom metric
61
+ await datadogMetric("checkout.completed", 1, {
62
+ tags: ["env:production", "service:checkout"],
63
+ });
104
64
 
105
- ```
106
- now-15m # Last 15 minutes
107
- now-1h # Last hour
108
- now-1d # Last day
109
- 2024-01-15T10:00:00Z # Specific time (ISO 8601)
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
+