@jaypie/mcp 0.2.10 → 0.3.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.
@@ -0,0 +1,249 @@
1
+ ---
2
+ description: MCP server package with documentation, AWS, Datadog, and LLM tools
3
+ include: "packages/mcp/**"
4
+ ---
5
+
6
+ # @jaypie/mcp Package
7
+
8
+ The `@jaypie/mcp` package provides a Model Context Protocol (MCP) server for AI agents working with Jaypie projects. It includes tools for accessing documentation, AWS CLI operations, Datadog observability, and LLM debugging.
9
+
10
+ ## Package Structure
11
+
12
+ ```
13
+ packages/mcp/
14
+ ├── src/
15
+ │ ├── index.ts # CLI entrypoint, exports createMcpServer and mcpExpressHandler
16
+ │ ├── createMcpServer.ts # Core MCP server factory with tool definitions
17
+ │ ├── mcpExpressHandler.ts # Express middleware for HTTP transport
18
+ │ ├── aws.ts # AWS CLI integration (spawn-based)
19
+ │ ├── datadog.ts # Datadog API integration (https-based)
20
+ │ └── llm.ts # LLM debug utilities
21
+ ├── prompts/ # Markdown guides served via list_prompts/read_prompt tools
22
+ └── dist/ # Built output
23
+ ```
24
+
25
+ ## Usage
26
+
27
+ ### CLI (stdio transport)
28
+
29
+ ```bash
30
+ npx jaypie-mcp # Run MCP server via stdio
31
+ npx jaypie-mcp --verbose # Run with debug logging
32
+ ```
33
+
34
+ ### Express Integration (HTTP transport)
35
+
36
+ ```typescript
37
+ import express from "express";
38
+ import { mcpExpressHandler } from "@jaypie/mcp";
39
+
40
+ const app = express();
41
+ app.use(express.json());
42
+ app.use("/mcp", await mcpExpressHandler({ version: "1.0.0" }));
43
+ ```
44
+
45
+ ### Direct Server Creation
46
+
47
+ ```typescript
48
+ import { createMcpServer } from "@jaypie/mcp";
49
+
50
+ const server = createMcpServer({ version: "1.0.0", verbose: true });
51
+ ```
52
+
53
+ ## MCP Tools (27 total)
54
+
55
+ ### Documentation Tools (3)
56
+
57
+ | Tool | Description |
58
+ |------|-------------|
59
+ | `list_prompts` | Lists all `.md` files in `prompts/` with descriptions and required file patterns |
60
+ | `read_prompt` | Returns content of a specific prompt file |
61
+ | `version` | Returns package version string |
62
+
63
+ ### AWS CLI Tools (16)
64
+
65
+ Requires AWS CLI installed and configured. All tools accept optional `profile` and `region` parameters.
66
+
67
+ | Tool | Description |
68
+ |------|-------------|
69
+ | `aws_list_profiles` | List available AWS profiles from ~/.aws/config and credentials |
70
+ | `aws_stepfunctions_list_executions` | List Step Function executions for a state machine |
71
+ | `aws_stepfunctions_stop_execution` | Stop a running Step Function execution |
72
+ | `aws_lambda_list_functions` | List Lambda functions with optional prefix filtering |
73
+ | `aws_lambda_get_function` | Get configuration and details for a specific Lambda function |
74
+ | `aws_logs_filter_log_events` | Search CloudWatch Logs with pattern and time range filtering |
75
+ | `aws_s3_list_objects` | List objects in an S3 bucket with optional prefix filtering |
76
+ | `aws_cloudformation_describe_stack` | Get details and status of a CloudFormation stack |
77
+ | `aws_dynamodb_describe_table` | Get metadata about a DynamoDB table |
78
+ | `aws_dynamodb_scan` | Scan a DynamoDB table (use sparingly on large tables) |
79
+ | `aws_dynamodb_query` | Query a DynamoDB table by partition key |
80
+ | `aws_dynamodb_get_item` | Get a single item from a DynamoDB table by primary key |
81
+ | `aws_sqs_list_queues` | List SQS queues with optional prefix filtering |
82
+ | `aws_sqs_get_queue_attributes` | Get queue attributes including message counts |
83
+ | `aws_sqs_receive_message` | Peek at messages in an SQS queue (does not delete) |
84
+ | `aws_sqs_purge_queue` | Delete all messages from an SQS queue (irreversible) |
85
+
86
+ ### Datadog Tools (6)
87
+
88
+ Requires `DATADOG_API_KEY` and `DATADOG_APP_KEY` environment variables.
89
+
90
+ | Tool | Description |
91
+ |------|-------------|
92
+ | `datadog_logs` | Search individual log entries |
93
+ | `datadog_log_analytics` | Aggregate logs with groupBy operations |
94
+ | `datadog_monitors` | List and filter monitors by status/tags |
95
+ | `datadog_synthetics` | List synthetic tests or get results for a specific test |
96
+ | `datadog_metrics` | Query timeseries metrics |
97
+ | `datadog_rum` | Search Real User Monitoring events |
98
+
99
+ ### LLM Tools (2)
100
+
101
+ | Tool | Description |
102
+ |------|-------------|
103
+ | `llm_debug_call` | Debug LLM API calls and inspect raw responses |
104
+ | `llm_list_providers` | List available LLM providers with their models |
105
+
106
+ ## Environment Variables
107
+
108
+ ### AWS CLI Integration
109
+
110
+ | Variable | Description |
111
+ |----------|-------------|
112
+ | `AWS_PROFILE` | Default profile if not specified per-call |
113
+ | `AWS_REGION` or `AWS_DEFAULT_REGION` | Default region if not specified |
114
+
115
+ AWS tools use the host's existing credential chain:
116
+ - `~/.aws/credentials` and `~/.aws/config` files
117
+ - Environment variables (`AWS_ACCESS_KEY_ID`, etc.)
118
+ - SSO sessions established via `aws sso login`
119
+
120
+ ### Datadog Integration
121
+
122
+ | Variable | Description |
123
+ |----------|-------------|
124
+ | `DATADOG_API_KEY` or `DD_API_KEY` | Datadog API key |
125
+ | `DATADOG_APP_KEY` or `DD_APP_KEY` | Datadog Application key |
126
+ | `DD_ENV` | Default environment filter |
127
+ | `DD_SERVICE` | Default service filter |
128
+ | `DD_SOURCE` | Default log source (defaults to "lambda") |
129
+ | `DD_QUERY` | Default query terms appended to searches |
130
+
131
+ ## Adding New Tools
132
+
133
+ Tools are registered in `createMcpServer.ts` using the MCP SDK pattern:
134
+
135
+ ```typescript
136
+ server.tool(
137
+ "tool_name",
138
+ "Description shown to AI agents",
139
+ {
140
+ // Zod schema for parameters
141
+ param1: z.string().describe("Parameter description"),
142
+ param2: z.number().optional().describe("Optional parameter"),
143
+ },
144
+ async ({ param1, param2 }) => {
145
+ // Implementation
146
+ return {
147
+ content: [{ type: "text" as const, text: "Result text" }],
148
+ };
149
+ },
150
+ );
151
+ ```
152
+
153
+ ### AWS Tool Pattern
154
+
155
+ AWS tools use `child_process.spawn` to call the AWS CLI:
156
+
157
+ ```typescript
158
+ // In aws.ts
159
+ export async function myAwsOperation(
160
+ options: MyOperationOptions,
161
+ logger: Logger = nullLogger,
162
+ ): Promise<AwsCommandResult<MyResultType>> {
163
+ const args = ["--required-arg", options.requiredArg];
164
+ if (options.optionalArg) {
165
+ args.push("--optional-arg", options.optionalArg);
166
+ }
167
+
168
+ return executeAwsCommand(
169
+ "service-name", // e.g., "stepfunctions", "lambda", "s3api"
170
+ "command-name", // e.g., "list-executions", "get-function"
171
+ args,
172
+ { profile: options.profile, region: options.region },
173
+ logger,
174
+ );
175
+ }
176
+ ```
177
+
178
+ ### Datadog Tool Pattern
179
+
180
+ Datadog tools use Node.js `https` module directly:
181
+
182
+ ```typescript
183
+ // In datadog.ts
184
+ export async function myDatadogOperation(
185
+ credentials: DatadogCredentials,
186
+ options: MyOptions,
187
+ logger: Logger = nullLogger,
188
+ ): Promise<MyResult> {
189
+ const requestOptions = {
190
+ hostname: "api.datadoghq.com",
191
+ port: 443,
192
+ path: "/api/v2/endpoint",
193
+ method: "POST",
194
+ headers: {
195
+ "DD-API-KEY": credentials.apiKey,
196
+ "DD-APPLICATION-KEY": credentials.appKey,
197
+ "Content-Type": "application/json",
198
+ },
199
+ };
200
+
201
+ return new Promise((resolve) => {
202
+ const req = https.request(requestOptions, (res) => {
203
+ // Handle response
204
+ });
205
+ req.write(JSON.stringify(body));
206
+ req.end();
207
+ });
208
+ }
209
+ ```
210
+
211
+ ## Adding New Prompts
212
+
213
+ Prompts are markdown files in `prompts/` with optional YAML frontmatter:
214
+
215
+ ```yaml
216
+ ---
217
+ description: Brief description shown in list_prompts
218
+ include: "packages/express/**" # File patterns this guide applies to
219
+ ---
220
+
221
+ # Prompt Title
222
+
223
+ Markdown content here...
224
+ ```
225
+
226
+ Prompts are automatically available via `list_prompts` and `read_prompt` tools.
227
+
228
+ ## Exports
229
+
230
+ ```typescript
231
+ import { createMcpServer, mcpExpressHandler } from "@jaypie/mcp";
232
+ import type { CreateMcpServerOptions, McpExpressHandlerOptions } from "@jaypie/mcp";
233
+ ```
234
+
235
+ ## Commands
236
+
237
+ ```bash
238
+ npm run build -w packages/mcp # Build with rollup
239
+ npm run test -w packages/mcp # Run tests (vitest run)
240
+ npm run typecheck -w packages/mcp # Type check (tsc --noEmit)
241
+ npm run format packages/mcp # Format with eslint --fix
242
+ ```
243
+
244
+ ## Security Considerations
245
+
246
+ 1. **Allowlisted operations only** - No arbitrary command execution
247
+ 2. **Read-heavy design** - Most tools are read-only; mutating operations have explicit warnings
248
+ 3. **No credential exposure** - Credentials never passed through MCP; uses host's credential chain
249
+ 4. **Profile isolation** - Each call can specify a different profile for multi-account work
@@ -0,0 +1,408 @@
1
+ ---
2
+ description: Complete guide to streaming in Jaypie - Lambda, Express, and SSE patterns
3
+ globs: packages/express/**, packages/lambda/**, packages/aws/**
4
+ ---
5
+
6
+ # Jaypie Streaming Guide
7
+
8
+ Jaypie provides three distinct streaming patterns for different deployment scenarios. This guide explains when to use each approach and how to implement streaming correctly.
9
+
10
+ ## Quick Reference
11
+
12
+ | Handler | Package | Express Required | Use Case |
13
+ |---------|---------|------------------|----------|
14
+ | `lambdaStreamHandler` | `@jaypie/lambda` | No | Pure Lambda Function URL streaming |
15
+ | `expressStreamHandler` | `@jaypie/express` | Yes | Express routes with SSE |
16
+ | `createLambdaStreamHandler` | `@jaypie/express` | Yes | Express app deployed to Lambda with streaming |
17
+
18
+ ### Decision Guide
19
+
20
+ - **Building a pure Lambda function?** Use `lambdaStreamHandler`
21
+ - **Building an Express app for non-Lambda deployment?** Use `expressStreamHandler`
22
+ - **Building an Express app that runs on Lambda?** Use `createLambdaStreamHandler`
23
+
24
+ ## Streaming Utilities
25
+
26
+ All streaming utilities are exported from `@jaypie/aws` and re-exported through `jaypie`:
27
+
28
+ | Function | Purpose |
29
+ |----------|---------|
30
+ | `createLambdaStream(stream, writer)` | Pipe async iterable to Lambda response writer |
31
+ | `createExpressStream(stream, res)` | Pipe async iterable to Express response with SSE headers |
32
+ | `JaypieStream` | Wrapper class with `.toLambda()` and `.toExpress()` methods |
33
+ | `createJaypieStream(source)` | Factory function for JaypieStream |
34
+ | `formatSSE(chunk)` | Format a chunk as SSE event string |
35
+ | `streamToSSE(stream)` | Convert async iterable to SSE-formatted strings |
36
+
37
+ ### Types
38
+
39
+ ```typescript
40
+ import type {
41
+ ExpressStreamResponse,
42
+ LambdaStreamWriter,
43
+ SSEEvent,
44
+ StreamChunk,
45
+ } from "jaypie";
46
+ ```
47
+
48
+ ## Pattern 1: lambdaStreamHandler
49
+
50
+ Use for pure Lambda functions without Express. Requires AWS Lambda Response Streaming via Function URL.
51
+
52
+ ### Basic Usage
53
+
54
+ ```typescript
55
+ import { lambdaStreamHandler } from "jaypie";
56
+ import type { StreamHandlerContext } from "@jaypie/lambda";
57
+
58
+ const streamWorker = lambdaStreamHandler(
59
+ async (event: unknown, context: StreamHandlerContext) => {
60
+ const { responseStream } = context;
61
+
62
+ responseStream.write("event: start\ndata: {}\n\n");
63
+
64
+ for (let i = 0; i < 5; i++) {
65
+ responseStream.write(`event: data\ndata: {"count": ${i}}\n\n`);
66
+ }
67
+
68
+ responseStream.write("event: done\ndata: {}\n\n");
69
+ // Handler automatically calls responseStream.end()
70
+ },
71
+ {
72
+ name: "streamWorker",
73
+ contentType: "text/event-stream",
74
+ }
75
+ );
76
+
77
+ // Wrap with AWS streamifyResponse for Lambda
78
+ declare const awslambda: { streamifyResponse: <T>(handler: T) => T };
79
+ export const handler = awslambda.streamifyResponse(streamWorker);
80
+ ```
81
+
82
+ ### With LLM Streaming
83
+
84
+ ```typescript
85
+ import { lambdaStreamHandler, createLambdaStream, Llm } from "jaypie";
86
+ import type { StreamHandlerContext } from "@jaypie/lambda";
87
+
88
+ interface PromptEvent {
89
+ prompt?: string;
90
+ }
91
+
92
+ const llmStreamHandler = lambdaStreamHandler(
93
+ async (event: PromptEvent, context: StreamHandlerContext) => {
94
+ const llm = new Llm("anthropic");
95
+ const stream = llm.stream(event.prompt || "Hello");
96
+
97
+ // createLambdaStream pipes chunks as SSE events
98
+ await createLambdaStream(stream, context.responseStream);
99
+ },
100
+ {
101
+ name: "llmStream",
102
+ secrets: ["ANTHROPIC_API_KEY"],
103
+ }
104
+ );
105
+
106
+ declare const awslambda: { streamifyResponse: <T>(handler: T) => T };
107
+ export const handler = awslambda.streamifyResponse(llmStreamHandler);
108
+ ```
109
+
110
+ ### Handler Options
111
+
112
+ ```typescript
113
+ import type { LambdaStreamHandlerOptions } from "@jaypie/lambda";
114
+
115
+ const options: LambdaStreamHandlerOptions = {
116
+ name: "myStreamHandler", // Handler name for logging
117
+ contentType: "text/event-stream", // Response content type (default)
118
+ chaos: "low", // Chaos testing level
119
+ secrets: ["API_KEY"], // AWS secrets to load into process.env
120
+ setup: [], // Setup function(s)
121
+ teardown: [], // Teardown function(s)
122
+ validate: [], // Validation function(s)
123
+ throw: false, // Re-throw errors instead of SSE error
124
+ unavailable: false, // Return 503 if true
125
+ };
126
+ ```
127
+
128
+ ### CDK Configuration
129
+
130
+ ```typescript
131
+ import { JaypieLambda } from "@jaypie/constructs";
132
+ import { FunctionUrlAuthType, InvokeMode } from "aws-cdk-lib/aws-lambda";
133
+
134
+ const streamingLambda = new JaypieLambda(this, "StreamingFunction", {
135
+ code: "dist",
136
+ handler: "streamWorker.handler",
137
+ timeout: Duration.minutes(5),
138
+ });
139
+
140
+ // Enable Lambda Response Streaming
141
+ streamingLambda.addFunctionUrl({
142
+ authType: FunctionUrlAuthType.NONE,
143
+ invokeMode: InvokeMode.RESPONSE_STREAM,
144
+ });
145
+ ```
146
+
147
+ ## Pattern 2: expressStreamHandler
148
+
149
+ Use for Express applications not running on Lambda. Sets SSE headers automatically.
150
+
151
+ ### Basic Usage
152
+
153
+ ```typescript
154
+ import { expressStreamHandler } from "jaypie";
155
+ import type { Request, Response } from "express";
156
+
157
+ const streamRoute = expressStreamHandler(async (req: Request, res: Response) => {
158
+ // Write SSE events directly to response
159
+ res.write("event: message\ndata: {\"text\": \"Hello\"}\n\n");
160
+ res.write("event: message\ndata: {\"text\": \"World\"}\n\n");
161
+ // Handler automatically ends the stream
162
+ });
163
+
164
+ app.get("/stream", streamRoute);
165
+ ```
166
+
167
+ ### With LLM Streaming
168
+
169
+ ```typescript
170
+ import { expressStreamHandler, createExpressStream, Llm } from "jaypie";
171
+
172
+ const llmStreamRoute = expressStreamHandler(async (req: Request, res: Response) => {
173
+ const llm = new Llm("anthropic");
174
+ const stream = llm.stream(req.body.prompt);
175
+
176
+ // createExpressStream pipes LLM chunks as SSE events
177
+ await createExpressStream(stream, res);
178
+ });
179
+
180
+ app.post("/chat", llmStreamRoute);
181
+ ```
182
+
183
+ ### Handler Options
184
+
185
+ ```typescript
186
+ import type { ExpressStreamHandlerOptions } from "jaypie";
187
+
188
+ const options: ExpressStreamHandlerOptions = {
189
+ name: "myStreamHandler", // Handler name for logging
190
+ contentType: "text/event-stream", // Default SSE content type
191
+ chaos: "low", // Chaos testing level
192
+ secrets: ["API_KEY"], // Secrets to load
193
+ setup: [], // Setup function(s)
194
+ teardown: [], // Teardown function(s)
195
+ validate: [], // Validation function(s)
196
+ locals: {}, // Values to set on req.locals
197
+ unavailable: false, // Return 503 if true
198
+ };
199
+ ```
200
+
201
+ ### SSE Headers
202
+
203
+ `expressStreamHandler` automatically sets these headers:
204
+
205
+ - `Content-Type: text/event-stream`
206
+ - `Cache-Control: no-cache`
207
+ - `Connection: keep-alive`
208
+ - `X-Accel-Buffering: no` (disables nginx buffering)
209
+
210
+ ## Pattern 3: createLambdaStreamHandler
211
+
212
+ Use for Express applications deployed to AWS Lambda with streaming support.
213
+
214
+ ### Basic Usage
215
+
216
+ ```typescript
217
+ import express from "express";
218
+ import { createLambdaStreamHandler, expressStreamHandler } from "jaypie";
219
+
220
+ const app = express();
221
+
222
+ app.get("/stream", expressStreamHandler(async (req, res) => {
223
+ res.write("event: message\ndata: {\"text\": \"Hello\"}\n\n");
224
+ res.write("event: message\ndata: {\"text\": \"World\"}\n\n");
225
+ }));
226
+
227
+ // Export streaming Lambda handler for Express app
228
+ export const handler = createLambdaStreamHandler(app);
229
+ ```
230
+
231
+ ### Combined Buffered and Streaming
232
+
233
+ When you need both regular endpoints and streaming endpoints:
234
+
235
+ ```typescript
236
+ import express from "express";
237
+ import {
238
+ createLambdaHandler,
239
+ createLambdaStreamHandler,
240
+ expressHandler,
241
+ expressStreamHandler,
242
+ cors,
243
+ } from "jaypie";
244
+
245
+ const app = express();
246
+ app.use(express.json());
247
+ app.use(cors());
248
+
249
+ // Standard buffered route
250
+ app.get("/api/data", expressHandler(async (req, res) => {
251
+ return { data: "buffered response" };
252
+ }));
253
+
254
+ // SSE streaming route
255
+ app.get("/api/stream", expressStreamHandler(async (req, res) => {
256
+ for (let i = 0; i < 5; i++) {
257
+ res.write(`event: update\ndata: {"count": ${i}}\n\n`);
258
+ }
259
+ }));
260
+
261
+ // Choose based on needs:
262
+ // - createLambdaHandler for buffered-only
263
+ // - createLambdaStreamHandler for streaming support
264
+ export const handler = createLambdaStreamHandler(app);
265
+ ```
266
+
267
+ ## Streaming Utilities Deep Dive
268
+
269
+ ### JaypieStream Class
270
+
271
+ Wraps an async iterable for convenient streaming to different targets:
272
+
273
+ ```typescript
274
+ import { JaypieStream, createJaypieStream, Llm } from "jaypie";
275
+
276
+ const llm = new Llm("anthropic");
277
+ const stream = createJaypieStream(llm.stream("Hello"));
278
+
279
+ // Pipe to Lambda
280
+ await stream.toLambda(context.responseStream);
281
+
282
+ // Or pipe to Express
283
+ await stream.toExpress(res);
284
+
285
+ // Or iterate directly
286
+ for await (const chunk of stream) {
287
+ console.log(chunk);
288
+ }
289
+
290
+ // Or convert to SSE strings
291
+ for await (const sseEvent of stream.toSSE()) {
292
+ console.log(sseEvent);
293
+ }
294
+ ```
295
+
296
+ ### Manual SSE Formatting
297
+
298
+ ```typescript
299
+ import { formatSSE } from "jaypie";
300
+
301
+ const chunk = { type: "message", content: "Hello" };
302
+ const sseString = formatSSE(chunk);
303
+ // "event: message\ndata: {\"type\":\"message\",\"content\":\"Hello\"}\n\n"
304
+ ```
305
+
306
+ ### Converting Async Iterables
307
+
308
+ ```typescript
309
+ import { streamToSSE } from "jaypie";
310
+
311
+ async function* myGenerator() {
312
+ yield { type: "start", data: {} };
313
+ yield { type: "data", value: 42 };
314
+ yield { type: "end", data: {} };
315
+ }
316
+
317
+ for await (const sseEvent of streamToSSE(myGenerator())) {
318
+ responseStream.write(sseEvent);
319
+ }
320
+ ```
321
+
322
+ ## Error Handling
323
+
324
+ Errors in streaming handlers are written as SSE error events:
325
+
326
+ ```typescript
327
+ // Format: event: error\ndata: {"errors":[{"status":500,"title":"Internal Error"}]}\n\n
328
+ ```
329
+
330
+ For `lambdaStreamHandler`, set `throw: true` to re-throw errors instead of writing to stream:
331
+
332
+ ```typescript
333
+ const handler = lambdaStreamHandler(
334
+ async (event, context) => {
335
+ throw new InternalError("Something went wrong");
336
+ },
337
+ {
338
+ throw: true, // Re-throw instead of SSE error
339
+ }
340
+ );
341
+ ```
342
+
343
+ ## Testing Streaming Handlers
344
+
345
+ ### Mocking for Unit Tests
346
+
347
+ ```typescript
348
+ import { describe, expect, it, vi } from "vitest";
349
+
350
+ vi.mock("jaypie", async () => {
351
+ const testkit = await import("@jaypie/testkit/mock");
352
+ return testkit;
353
+ });
354
+
355
+ import { handler } from "./streamWorker.js";
356
+
357
+ describe("Stream Handler", () => {
358
+ it("writes expected events", async () => {
359
+ const writes: string[] = [];
360
+ const mockWriter = {
361
+ write: vi.fn((chunk) => writes.push(chunk)),
362
+ end: vi.fn(),
363
+ };
364
+
365
+ const event = { prompt: "test" };
366
+ const context = { responseStream: mockWriter };
367
+
368
+ await handler(event, context);
369
+
370
+ expect(mockWriter.write).toHaveBeenCalled();
371
+ expect(writes.some(w => w.includes("event:"))).toBe(true);
372
+ expect(mockWriter.end).toHaveBeenCalled();
373
+ });
374
+ });
375
+ ```
376
+
377
+ ### Integration Testing
378
+
379
+ Use the Docker setup in `packages/express/docker/` for local Lambda streaming tests.
380
+
381
+ ## TypeScript Types
382
+
383
+ ```typescript
384
+ // From @jaypie/lambda
385
+ import type {
386
+ LambdaStreamHandlerOptions,
387
+ StreamHandlerContext,
388
+ ResponseStream,
389
+ AwsStreamingHandler,
390
+ } from "@jaypie/lambda";
391
+
392
+ // From @jaypie/express (or jaypie)
393
+ import type {
394
+ ExpressStreamHandlerOptions,
395
+ ExpressStreamHandlerLocals,
396
+ JaypieStreamHandlerSetup,
397
+ JaypieStreamHandlerTeardown,
398
+ JaypieStreamHandlerValidate,
399
+ } from "jaypie";
400
+
401
+ // From @jaypie/aws (or jaypie)
402
+ import type {
403
+ ExpressStreamResponse,
404
+ LambdaStreamWriter,
405
+ SSEEvent,
406
+ StreamChunk,
407
+ } from "jaypie";
408
+ ```