@jaypie/mcp 0.3.2 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/createMcpServer.d.ts +7 -1
- package/dist/index.js +26 -3135
- package/dist/index.js.map +1 -1
- package/dist/suite.d.ts +1 -0
- package/dist/suite.js +2442 -0
- package/dist/suite.js.map +1 -0
- package/package.json +8 -3
- package/release-notes/constructs/1.2.17.md +11 -0
- package/release-notes/fabric/0.1.2.md +11 -0
- package/release-notes/fabric/0.1.3.md +25 -0
- package/release-notes/fabric/0.1.4.md +42 -0
- package/release-notes/mcp/0.3.3.md +12 -0
- package/release-notes/mcp/0.3.4.md +36 -0
- package/release-notes/mcp/0.4.0.md +27 -0
- package/release-notes/testkit/1.2.15.md +23 -0
- package/skills/agents.md +25 -0
- package/skills/aws.md +107 -0
- package/skills/cdk.md +141 -0
- package/skills/cicd.md +152 -0
- package/skills/datadog.md +129 -0
- package/skills/debugging.md +148 -0
- package/skills/dns.md +134 -0
- package/skills/dynamodb.md +140 -0
- package/skills/errors.md +142 -0
- package/skills/fabric.md +191 -0
- package/skills/index.md +7 -0
- package/skills/jaypie.md +100 -0
- package/skills/legacy.md +97 -0
- package/skills/logs.md +160 -0
- package/skills/mocks.md +174 -0
- package/skills/models.md +195 -0
- package/skills/releasenotes.md +94 -0
- package/skills/secrets.md +155 -0
- package/skills/services.md +175 -0
- package/skills/style.md +190 -0
- package/skills/tests.md +209 -0
- package/skills/tools.md +127 -0
- package/skills/topics.md +116 -0
- package/skills/variables.md +146 -0
- package/skills/writing.md +153 -0
- package/prompts/Branch_Management.md +0 -34
- package/prompts/Development_Process.md +0 -89
- package/prompts/Jaypie_Agent_Rules.md +0 -110
- package/prompts/Jaypie_Auth0_Express_Mongoose.md +0 -736
- package/prompts/Jaypie_Browser_and_Frontend_Web_Packages.md +0 -18
- package/prompts/Jaypie_CDK_Constructs_and_Patterns.md +0 -430
- package/prompts/Jaypie_CICD_with_GitHub_Actions.md +0 -371
- package/prompts/Jaypie_Commander_CLI_Package.md +0 -166
- package/prompts/Jaypie_Core_Errors_and_Logging.md +0 -39
- package/prompts/Jaypie_DynamoDB_Package.md +0 -774
- package/prompts/Jaypie_Eslint_NPM_Package.md +0 -78
- package/prompts/Jaypie_Express_Package.md +0 -630
- package/prompts/Jaypie_Fabric_Commander.md +0 -411
- package/prompts/Jaypie_Fabric_LLM.md +0 -312
- package/prompts/Jaypie_Fabric_Lambda.md +0 -308
- package/prompts/Jaypie_Fabric_MCP.md +0 -316
- package/prompts/Jaypie_Fabric_Package.md +0 -513
- package/prompts/Jaypie_Fabricator.md +0 -617
- package/prompts/Jaypie_Ideal_Project_Structure.md +0 -78
- package/prompts/Jaypie_Init_CICD_with_GitHub_Actions.md +0 -1186
- package/prompts/Jaypie_Init_Express_on_Lambda.md +0 -115
- package/prompts/Jaypie_Init_Jaypie_CDK_Package.md +0 -35
- package/prompts/Jaypie_Init_Lambda_Package.md +0 -505
- package/prompts/Jaypie_Init_Monorepo_Project.md +0 -44
- package/prompts/Jaypie_Init_Project_Subpackage.md +0 -65
- package/prompts/Jaypie_Legacy_Patterns.md +0 -15
- package/prompts/Jaypie_Llm_Calls.md +0 -449
- package/prompts/Jaypie_Llm_Tools.md +0 -155
- package/prompts/Jaypie_MCP_Package.md +0 -281
- package/prompts/Jaypie_Mocks_and_Testkit.md +0 -137
- package/prompts/Jaypie_Repokit.md +0 -103
- package/prompts/Jaypie_Scrub.md +0 -177
- package/prompts/Jaypie_Streaming.md +0 -467
- package/prompts/Templates_CDK_Subpackage.md +0 -115
- package/prompts/Templates_Express_Subpackage.md +0 -187
- package/prompts/Templates_Project_Monorepo.md +0 -326
- package/prompts/Templates_Project_Subpackage.md +0 -93
- package/prompts/Write_Efficient_Prompt_Guides.md +0 -48
- package/prompts/Write_and_Maintain_Engaging_Readme.md +0 -67
|
@@ -1,467 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Complete guide to streaming in Jaypie - Lambda, Express, SSE, and NLJSON 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
|
-
## Stream Formats
|
|
11
|
-
|
|
12
|
-
Jaypie supports two stream output formats:
|
|
13
|
-
|
|
14
|
-
| Format | Content-Type | Use Case |
|
|
15
|
-
|--------|--------------|----------|
|
|
16
|
-
| SSE (default) | `text/event-stream` | Browser EventSource, real-time UI updates |
|
|
17
|
-
| NLJSON | `application/x-ndjson` | Machine-to-machine, log processing |
|
|
18
|
-
|
|
19
|
-
### Format Comparison
|
|
20
|
-
|
|
21
|
-
| Aspect | SSE | NLJSON |
|
|
22
|
-
|--------|-----|--------|
|
|
23
|
-
| Data format | `event: <type>\ndata: {...}\n\n` | `{...}\n` |
|
|
24
|
-
| Error format | `event: error\ndata: {...}\n\n` | `{"error":{...}}\n` |
|
|
25
|
-
| Browser support | Native EventSource API | Requires manual parsing |
|
|
26
|
-
|
|
27
|
-
## Quick Reference
|
|
28
|
-
|
|
29
|
-
| Handler | Package | Express Required | Use Case |
|
|
30
|
-
|---------|---------|------------------|----------|
|
|
31
|
-
| `lambdaStreamHandler` | `@jaypie/lambda` | No | Pure Lambda Function URL streaming |
|
|
32
|
-
| `expressStreamHandler` | `@jaypie/express` | Yes | Express routes with SSE |
|
|
33
|
-
| `createLambdaStreamHandler` | `@jaypie/express` | Yes | Express app deployed to Lambda with streaming |
|
|
34
|
-
|
|
35
|
-
### Decision Guide
|
|
36
|
-
|
|
37
|
-
- **Building a pure Lambda function?** Use `lambdaStreamHandler`
|
|
38
|
-
- **Building an Express app for non-Lambda deployment?** Use `expressStreamHandler`
|
|
39
|
-
- **Building an Express app that runs on Lambda?** Use `createLambdaStreamHandler`
|
|
40
|
-
|
|
41
|
-
## Streaming Utilities
|
|
42
|
-
|
|
43
|
-
All streaming utilities are exported from `@jaypie/aws` and re-exported through `jaypie`:
|
|
44
|
-
|
|
45
|
-
| Function | Purpose |
|
|
46
|
-
|----------|---------|
|
|
47
|
-
| `createLambdaStream(stream, writer)` | Pipe async iterable to Lambda response writer |
|
|
48
|
-
| `createExpressStream(stream, res)` | Pipe async iterable to Express response with SSE headers |
|
|
49
|
-
| `JaypieStream` | Wrapper class with `.toLambda()` and `.toExpress()` methods |
|
|
50
|
-
| `createJaypieStream(source)` | Factory function for JaypieStream |
|
|
51
|
-
| `formatSse(chunk)` | Format a chunk as SSE event string |
|
|
52
|
-
| `formatNljson(chunk)` | Format a chunk as NLJSON string |
|
|
53
|
-
| `formatStreamError(errorBody, format)` | Format error based on stream format |
|
|
54
|
-
| `getContentTypeForFormat(format)` | Get content type for stream format |
|
|
55
|
-
| `streamToSse(stream)` | Convert async iterable to SSE-formatted strings |
|
|
56
|
-
|
|
57
|
-
### Types
|
|
58
|
-
|
|
59
|
-
```typescript
|
|
60
|
-
import type {
|
|
61
|
-
ExpressStreamResponse,
|
|
62
|
-
LambdaStreamWriter,
|
|
63
|
-
SseEvent,
|
|
64
|
-
StreamChunk,
|
|
65
|
-
StreamFormat, // "sse" | "nljson"
|
|
66
|
-
} from "jaypie";
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
## Pattern 1: lambdaStreamHandler
|
|
70
|
-
|
|
71
|
-
Use for pure Lambda functions without Express. Requires AWS Lambda Response Streaming via Function URL.
|
|
72
|
-
|
|
73
|
-
**Note:** `lambdaStreamHandler` automatically wraps with `awslambda.streamifyResponse()` in the Lambda runtime. You no longer need to wrap manually.
|
|
74
|
-
|
|
75
|
-
### Basic Usage
|
|
76
|
-
|
|
77
|
-
```typescript
|
|
78
|
-
import { lambdaStreamHandler } from "jaypie";
|
|
79
|
-
import type { StreamHandlerContext } from "@jaypie/lambda";
|
|
80
|
-
|
|
81
|
-
// Auto-wrapped with awslambda.streamifyResponse() in Lambda runtime
|
|
82
|
-
export const handler = lambdaStreamHandler(
|
|
83
|
-
async (event: unknown, context: StreamHandlerContext) => {
|
|
84
|
-
const { responseStream } = context;
|
|
85
|
-
|
|
86
|
-
responseStream.write("event: start\ndata: {}\n\n");
|
|
87
|
-
|
|
88
|
-
for (let i = 0; i < 5; i++) {
|
|
89
|
-
responseStream.write(`event: data\ndata: {"count": ${i}}\n\n`);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
responseStream.write("event: done\ndata: {}\n\n");
|
|
93
|
-
// Handler automatically calls responseStream.end()
|
|
94
|
-
},
|
|
95
|
-
{
|
|
96
|
-
name: "streamWorker",
|
|
97
|
-
}
|
|
98
|
-
);
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
### With Format Option
|
|
102
|
-
|
|
103
|
-
```typescript
|
|
104
|
-
// SSE format (default)
|
|
105
|
-
export const sseHandler = lambdaStreamHandler(myHandler, { format: "sse" });
|
|
106
|
-
|
|
107
|
-
// NLJSON format
|
|
108
|
-
export const nljsonHandler = lambdaStreamHandler(myHandler, { format: "nljson" });
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
### With LLM Streaming
|
|
112
|
-
|
|
113
|
-
```typescript
|
|
114
|
-
import { lambdaStreamHandler, createLambdaStream, Llm } from "jaypie";
|
|
115
|
-
import type { StreamHandlerContext } from "@jaypie/lambda";
|
|
116
|
-
|
|
117
|
-
interface PromptEvent {
|
|
118
|
-
prompt?: string;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
// Auto-wrapped with awslambda.streamifyResponse() in Lambda runtime
|
|
122
|
-
export const handler = lambdaStreamHandler(
|
|
123
|
-
async (event: PromptEvent, context: StreamHandlerContext) => {
|
|
124
|
-
const llm = new Llm("anthropic");
|
|
125
|
-
const stream = llm.stream(event.prompt || "Hello");
|
|
126
|
-
|
|
127
|
-
// createLambdaStream pipes chunks as SSE events
|
|
128
|
-
await createLambdaStream(stream, context.responseStream);
|
|
129
|
-
},
|
|
130
|
-
{
|
|
131
|
-
name: "llmStream",
|
|
132
|
-
secrets: ["ANTHROPIC_API_KEY"],
|
|
133
|
-
}
|
|
134
|
-
);
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
### Handler Options
|
|
138
|
-
|
|
139
|
-
```typescript
|
|
140
|
-
import type { LambdaStreamHandlerOptions, StreamFormat } from "@jaypie/lambda";
|
|
141
|
-
|
|
142
|
-
const options: LambdaStreamHandlerOptions = {
|
|
143
|
-
name: "myStreamHandler", // Handler name for logging
|
|
144
|
-
format: "sse", // Stream format: "sse" (default) or "nljson"
|
|
145
|
-
contentType: "text/event-stream", // Response content type (auto-set from format)
|
|
146
|
-
chaos: "low", // Chaos testing level
|
|
147
|
-
secrets: ["API_KEY"], // AWS secrets to load into process.env
|
|
148
|
-
setup: [], // Setup function(s)
|
|
149
|
-
teardown: [], // Teardown function(s)
|
|
150
|
-
validate: [], // Validation function(s)
|
|
151
|
-
throw: false, // Re-throw errors instead of streaming error
|
|
152
|
-
unavailable: false, // Return 503 if true
|
|
153
|
-
};
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
### CDK Configuration
|
|
157
|
-
|
|
158
|
-
```typescript
|
|
159
|
-
import { JaypieLambda } from "@jaypie/constructs";
|
|
160
|
-
import { FunctionUrlAuthType, InvokeMode } from "aws-cdk-lib/aws-lambda";
|
|
161
|
-
|
|
162
|
-
const streamingLambda = new JaypieLambda(this, "StreamingFunction", {
|
|
163
|
-
code: "dist",
|
|
164
|
-
handler: "streamWorker.handler",
|
|
165
|
-
timeout: Duration.minutes(5),
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
// For direct Function URL access:
|
|
169
|
-
streamingLambda.addFunctionUrl({
|
|
170
|
-
authType: FunctionUrlAuthType.NONE,
|
|
171
|
-
invokeMode: InvokeMode.RESPONSE_STREAM,
|
|
172
|
-
});
|
|
173
|
-
|
|
174
|
-
// Or use JaypieDistribution with streaming: true
|
|
175
|
-
new JaypieDistribution(this, "Distribution", {
|
|
176
|
-
handler: streamingLambda,
|
|
177
|
-
streaming: true,
|
|
178
|
-
host: "api.example.com",
|
|
179
|
-
zone: "example.com",
|
|
180
|
-
});
|
|
181
|
-
```
|
|
182
|
-
|
|
183
|
-
## Pattern 2: expressStreamHandler
|
|
184
|
-
|
|
185
|
-
Use for Express applications not running on Lambda. Sets SSE headers automatically.
|
|
186
|
-
|
|
187
|
-
### Basic Usage
|
|
188
|
-
|
|
189
|
-
```typescript
|
|
190
|
-
import { expressStreamHandler } from "jaypie";
|
|
191
|
-
import type { Request, Response } from "express";
|
|
192
|
-
|
|
193
|
-
const streamRoute = expressStreamHandler(async (req: Request, res: Response) => {
|
|
194
|
-
// Write SSE events directly to response
|
|
195
|
-
res.write("event: message\ndata: {\"text\": \"Hello\"}\n\n");
|
|
196
|
-
res.write("event: message\ndata: {\"text\": \"World\"}\n\n");
|
|
197
|
-
// Handler automatically ends the stream
|
|
198
|
-
});
|
|
199
|
-
|
|
200
|
-
app.get("/stream", streamRoute);
|
|
201
|
-
```
|
|
202
|
-
|
|
203
|
-
### With LLM Streaming
|
|
204
|
-
|
|
205
|
-
```typescript
|
|
206
|
-
import { expressStreamHandler, createExpressStream, Llm } from "jaypie";
|
|
207
|
-
|
|
208
|
-
const llmStreamRoute = expressStreamHandler(async (req: Request, res: Response) => {
|
|
209
|
-
const llm = new Llm("anthropic");
|
|
210
|
-
const stream = llm.stream(req.body.prompt);
|
|
211
|
-
|
|
212
|
-
// createExpressStream pipes LLM chunks as SSE events
|
|
213
|
-
await createExpressStream(stream, res);
|
|
214
|
-
});
|
|
215
|
-
|
|
216
|
-
app.post("/chat", llmStreamRoute);
|
|
217
|
-
```
|
|
218
|
-
|
|
219
|
-
### With Format Option
|
|
220
|
-
|
|
221
|
-
```typescript
|
|
222
|
-
// SSE format (default)
|
|
223
|
-
app.get("/stream-sse", expressStreamHandler(myHandler, { format: "sse" }));
|
|
224
|
-
|
|
225
|
-
// NLJSON format
|
|
226
|
-
app.get("/stream-nljson", expressStreamHandler(myHandler, { format: "nljson" }));
|
|
227
|
-
```
|
|
228
|
-
|
|
229
|
-
### Handler Options
|
|
230
|
-
|
|
231
|
-
```typescript
|
|
232
|
-
import type { ExpressStreamHandlerOptions, StreamFormat } from "jaypie";
|
|
233
|
-
|
|
234
|
-
const options: ExpressStreamHandlerOptions = {
|
|
235
|
-
name: "myStreamHandler", // Handler name for logging
|
|
236
|
-
format: "sse", // Stream format: "sse" (default) or "nljson"
|
|
237
|
-
contentType: "text/event-stream", // Response content type (auto-set from format)
|
|
238
|
-
chaos: "low", // Chaos testing level
|
|
239
|
-
secrets: ["API_KEY"], // Secrets to load
|
|
240
|
-
setup: [], // Setup function(s)
|
|
241
|
-
teardown: [], // Teardown function(s)
|
|
242
|
-
validate: [], // Validation function(s)
|
|
243
|
-
locals: {}, // Values to set on req.locals
|
|
244
|
-
unavailable: false, // Return 503 if true
|
|
245
|
-
};
|
|
246
|
-
```
|
|
247
|
-
|
|
248
|
-
### SSE Headers
|
|
249
|
-
|
|
250
|
-
`expressStreamHandler` automatically sets these headers:
|
|
251
|
-
|
|
252
|
-
- `Content-Type: text/event-stream`
|
|
253
|
-
- `Cache-Control: no-cache`
|
|
254
|
-
- `Connection: keep-alive`
|
|
255
|
-
- `X-Accel-Buffering: no` (disables nginx buffering)
|
|
256
|
-
|
|
257
|
-
## Pattern 3: createLambdaStreamHandler
|
|
258
|
-
|
|
259
|
-
Use for Express applications deployed to AWS Lambda with streaming support.
|
|
260
|
-
|
|
261
|
-
### Basic Usage
|
|
262
|
-
|
|
263
|
-
```typescript
|
|
264
|
-
import express from "express";
|
|
265
|
-
import { createLambdaStreamHandler, expressStreamHandler } from "jaypie";
|
|
266
|
-
|
|
267
|
-
const app = express();
|
|
268
|
-
|
|
269
|
-
app.get("/stream", expressStreamHandler(async (req, res) => {
|
|
270
|
-
res.write("event: message\ndata: {\"text\": \"Hello\"}\n\n");
|
|
271
|
-
res.write("event: message\ndata: {\"text\": \"World\"}\n\n");
|
|
272
|
-
}));
|
|
273
|
-
|
|
274
|
-
// Export streaming Lambda handler for Express app
|
|
275
|
-
export const handler = createLambdaStreamHandler(app);
|
|
276
|
-
```
|
|
277
|
-
|
|
278
|
-
### Combined Buffered and Streaming
|
|
279
|
-
|
|
280
|
-
When you need both regular endpoints and streaming endpoints:
|
|
281
|
-
|
|
282
|
-
```typescript
|
|
283
|
-
import express from "express";
|
|
284
|
-
import {
|
|
285
|
-
createLambdaHandler,
|
|
286
|
-
createLambdaStreamHandler,
|
|
287
|
-
expressHandler,
|
|
288
|
-
expressStreamHandler,
|
|
289
|
-
cors,
|
|
290
|
-
} from "jaypie";
|
|
291
|
-
|
|
292
|
-
const app = express();
|
|
293
|
-
app.use(express.json());
|
|
294
|
-
app.use(cors());
|
|
295
|
-
|
|
296
|
-
// Standard buffered route
|
|
297
|
-
app.get("/api/data", expressHandler(async (req, res) => {
|
|
298
|
-
return { data: "buffered response" };
|
|
299
|
-
}));
|
|
300
|
-
|
|
301
|
-
// SSE streaming route
|
|
302
|
-
app.get("/api/stream", expressStreamHandler(async (req, res) => {
|
|
303
|
-
for (let i = 0; i < 5; i++) {
|
|
304
|
-
res.write(`event: update\ndata: {"count": ${i}}\n\n`);
|
|
305
|
-
}
|
|
306
|
-
}));
|
|
307
|
-
|
|
308
|
-
// Choose based on needs:
|
|
309
|
-
// - createLambdaHandler for buffered-only
|
|
310
|
-
// - createLambdaStreamHandler for streaming support
|
|
311
|
-
export const handler = createLambdaStreamHandler(app);
|
|
312
|
-
```
|
|
313
|
-
|
|
314
|
-
## Streaming Utilities Deep Dive
|
|
315
|
-
|
|
316
|
-
### JaypieStream Class
|
|
317
|
-
|
|
318
|
-
Wraps an async iterable for convenient streaming to different targets:
|
|
319
|
-
|
|
320
|
-
```typescript
|
|
321
|
-
import { JaypieStream, createJaypieStream, Llm } from "jaypie";
|
|
322
|
-
|
|
323
|
-
const llm = new Llm("anthropic");
|
|
324
|
-
const stream = createJaypieStream(llm.stream("Hello"));
|
|
325
|
-
|
|
326
|
-
// Pipe to Lambda
|
|
327
|
-
await stream.toLambda(context.responseStream);
|
|
328
|
-
|
|
329
|
-
// Or pipe to Express
|
|
330
|
-
await stream.toExpress(res);
|
|
331
|
-
|
|
332
|
-
// Or iterate directly
|
|
333
|
-
for await (const chunk of stream) {
|
|
334
|
-
console.log(chunk);
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
// Or convert to SSE strings
|
|
338
|
-
for await (const sseEvent of stream.toSSE()) {
|
|
339
|
-
console.log(sseEvent);
|
|
340
|
-
}
|
|
341
|
-
```
|
|
342
|
-
|
|
343
|
-
### Manual SSE Formatting
|
|
344
|
-
|
|
345
|
-
```typescript
|
|
346
|
-
import { formatSse } from "jaypie";
|
|
347
|
-
|
|
348
|
-
const chunk = { type: "message", content: "Hello" };
|
|
349
|
-
const sseString = formatSse(chunk);
|
|
350
|
-
// "event: message\ndata: {\"type\":\"message\",\"content\":\"Hello\"}\n\n"
|
|
351
|
-
```
|
|
352
|
-
|
|
353
|
-
### Converting Async Iterables
|
|
354
|
-
|
|
355
|
-
```typescript
|
|
356
|
-
import { streamToSse } from "jaypie";
|
|
357
|
-
|
|
358
|
-
async function* myGenerator() {
|
|
359
|
-
yield { type: "start", data: {} };
|
|
360
|
-
yield { type: "data", value: 42 };
|
|
361
|
-
yield { type: "end", data: {} };
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
for await (const sseEvent of streamToSse(myGenerator())) {
|
|
365
|
-
responseStream.write(sseEvent);
|
|
366
|
-
}
|
|
367
|
-
```
|
|
368
|
-
|
|
369
|
-
## Error Handling
|
|
370
|
-
|
|
371
|
-
Errors in streaming handlers are written to the stream in the configured format:
|
|
372
|
-
|
|
373
|
-
**SSE format (default):**
|
|
374
|
-
```
|
|
375
|
-
event: error
|
|
376
|
-
data: {"errors":[{"status":500,"title":"Internal Error"}]}
|
|
377
|
-
|
|
378
|
-
```
|
|
379
|
-
|
|
380
|
-
**NLJSON format:**
|
|
381
|
-
```
|
|
382
|
-
{"error":{"errors":[{"status":500,"title":"Internal Error"}]}}
|
|
383
|
-
```
|
|
384
|
-
|
|
385
|
-
For `lambdaStreamHandler`, set `throw: true` to re-throw errors instead of writing to stream:
|
|
386
|
-
|
|
387
|
-
```typescript
|
|
388
|
-
export const handler = lambdaStreamHandler(
|
|
389
|
-
async (event, context) => {
|
|
390
|
-
throw new InternalError("Something went wrong");
|
|
391
|
-
},
|
|
392
|
-
{
|
|
393
|
-
throw: true, // Re-throw instead of streaming error
|
|
394
|
-
}
|
|
395
|
-
);
|
|
396
|
-
```
|
|
397
|
-
|
|
398
|
-
## Testing Streaming Handlers
|
|
399
|
-
|
|
400
|
-
### Mocking for Unit Tests
|
|
401
|
-
|
|
402
|
-
```typescript
|
|
403
|
-
import { describe, expect, it, vi } from "vitest";
|
|
404
|
-
|
|
405
|
-
vi.mock("jaypie", async () => {
|
|
406
|
-
const testkit = await import("@jaypie/testkit/mock");
|
|
407
|
-
return testkit;
|
|
408
|
-
});
|
|
409
|
-
|
|
410
|
-
import { handler } from "./streamWorker.js";
|
|
411
|
-
|
|
412
|
-
describe("Stream Handler", () => {
|
|
413
|
-
it("writes expected events", async () => {
|
|
414
|
-
const writes: string[] = [];
|
|
415
|
-
const mockWriter = {
|
|
416
|
-
write: vi.fn((chunk) => writes.push(chunk)),
|
|
417
|
-
end: vi.fn(),
|
|
418
|
-
};
|
|
419
|
-
|
|
420
|
-
const event = { prompt: "test" };
|
|
421
|
-
const context = { responseStream: mockWriter };
|
|
422
|
-
|
|
423
|
-
await handler(event, context);
|
|
424
|
-
|
|
425
|
-
expect(mockWriter.write).toHaveBeenCalled();
|
|
426
|
-
expect(writes.some(w => w.includes("event:"))).toBe(true);
|
|
427
|
-
expect(mockWriter.end).toHaveBeenCalled();
|
|
428
|
-
});
|
|
429
|
-
});
|
|
430
|
-
```
|
|
431
|
-
|
|
432
|
-
### Integration Testing
|
|
433
|
-
|
|
434
|
-
Use the Docker setup in `packages/express/docker/` for local Lambda streaming tests.
|
|
435
|
-
|
|
436
|
-
## TypeScript Types
|
|
437
|
-
|
|
438
|
-
```typescript
|
|
439
|
-
// From @jaypie/lambda
|
|
440
|
-
import type {
|
|
441
|
-
AwsStreamingHandler,
|
|
442
|
-
LambdaHandler, // Wrapped handler type (after awslambda.streamifyResponse)
|
|
443
|
-
LambdaStreamHandlerOptions,
|
|
444
|
-
RawStreamingHandler, // Alias for AwsStreamingHandler (for testing)
|
|
445
|
-
ResponseStream,
|
|
446
|
-
StreamFormat, // "sse" | "nljson" (re-exported from @jaypie/aws)
|
|
447
|
-
StreamHandlerContext,
|
|
448
|
-
} from "@jaypie/lambda";
|
|
449
|
-
|
|
450
|
-
// From @jaypie/express (or jaypie)
|
|
451
|
-
import type {
|
|
452
|
-
ExpressStreamHandlerOptions,
|
|
453
|
-
ExpressStreamHandlerLocals,
|
|
454
|
-
JaypieStreamHandlerSetup,
|
|
455
|
-
JaypieStreamHandlerTeardown,
|
|
456
|
-
JaypieStreamHandlerValidate,
|
|
457
|
-
} from "jaypie";
|
|
458
|
-
|
|
459
|
-
// From @jaypie/aws (or jaypie)
|
|
460
|
-
import type {
|
|
461
|
-
ExpressStreamResponse,
|
|
462
|
-
LambdaStreamWriter,
|
|
463
|
-
SseEvent,
|
|
464
|
-
StreamChunk,
|
|
465
|
-
StreamFormat, // "sse" | "nljson"
|
|
466
|
-
} from "jaypie";
|
|
467
|
-
```
|
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Template files for creating a CDK subpackage in a Jaypie monorepo
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
# CDK Subpackage Templates
|
|
6
|
-
|
|
7
|
-
Templates for creating a CDK (AWS Cloud Development Kit) subpackage in a Jaypie monorepo.
|
|
8
|
-
|
|
9
|
-
## bin/cdk.ts
|
|
10
|
-
|
|
11
|
-
```typescript
|
|
12
|
-
#!/usr/bin/env node
|
|
13
|
-
|
|
14
|
-
import cdk from "aws-cdk-lib";
|
|
15
|
-
import { AppStack } from "../lib/cdk-app.ts";
|
|
16
|
-
import { InfrastructureStack } from "../lib/cdk-infrastructure.ts";
|
|
17
|
-
|
|
18
|
-
const app = new cdk.App();
|
|
19
|
-
|
|
20
|
-
new InfrastructureStack(app, "InfrastructureStack");
|
|
21
|
-
|
|
22
|
-
new AppStack(app, "AppStack");
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
> **Important:** The second argument to `new AppStack(app, "AppStack")` is the stack ID used by CloudFormation. This must exactly match the `stack-name` parameter in your GitHub Actions deploy workflows. If you customize this value (e.g., `"MyProjectAppStack"`), update `.github/workflows/deploy-*.yml` accordingly.
|
|
26
|
-
|
|
27
|
-
## lib/cdk-app.ts
|
|
28
|
-
|
|
29
|
-
```typescript
|
|
30
|
-
import {
|
|
31
|
-
JaypieAppStack,
|
|
32
|
-
JaypieApiGateway,
|
|
33
|
-
JaypieExpressLambda,
|
|
34
|
-
JaypieMongoDbSecret,
|
|
35
|
-
JaypieLambda,
|
|
36
|
-
} from "@jaypie/constructs";
|
|
37
|
-
|
|
38
|
-
import * as cdk from "aws-cdk-lib";
|
|
39
|
-
import { Construct } from "constructs";
|
|
40
|
-
import * as lambda from "aws-cdk-lib/aws-lambda";
|
|
41
|
-
|
|
42
|
-
export class AppStack extends JaypieAppStack {
|
|
43
|
-
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
|
|
44
|
-
super(scope, id, props);
|
|
45
|
-
|
|
46
|
-
const mongoConnectionString = new JaypieMongoDbSecret(this);
|
|
47
|
-
|
|
48
|
-
const expressLambda = new JaypieExpressLambda(this, "expressLambda", {
|
|
49
|
-
code: lambda.Code.fromAsset("../express"),
|
|
50
|
-
handler: "dist/index.expressLambda",
|
|
51
|
-
secrets: [mongoConnectionString],
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
new JaypieApiGateway(this, "apiGateway", {
|
|
55
|
-
handler: expressLambda,
|
|
56
|
-
host: "api.example.com",
|
|
57
|
-
zone: "example.com",
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
new JaypieLambda(
|
|
61
|
-
this,
|
|
62
|
-
"lambdaWorker",
|
|
63
|
-
{
|
|
64
|
-
code: lambda.Code.fromAsset("../lambda"),
|
|
65
|
-
handler: "dist/index.lambdaWorker",
|
|
66
|
-
secrets: [mongoConnectionString],
|
|
67
|
-
},
|
|
68
|
-
);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
## lib/cdk-infrastructure.ts
|
|
74
|
-
|
|
75
|
-
```typescript
|
|
76
|
-
import {
|
|
77
|
-
JaypieInfrastructureStack,
|
|
78
|
-
JaypieWebDeploymentBucket,
|
|
79
|
-
} from "@jaypie/constructs";
|
|
80
|
-
|
|
81
|
-
export class InfrastructureStack extends JaypieInfrastructureStack {
|
|
82
|
-
constructor(scope, id, props = {}) {
|
|
83
|
-
super(scope, id, props);
|
|
84
|
-
|
|
85
|
-
new JaypieWebDeploymentBucket(this, "DeploymentBucket", {
|
|
86
|
-
// * host is not needed if CDK_ENV_WEB_SUBDOMAIN and CDK_ENV_WEB_HOSTED_ZONE or CDK_ENV_HOSTED_ZONE
|
|
87
|
-
// * zone is not needed if CDK_ENV_WEB_HOSTED_ZONE or CDK_ENV_HOSTED_ZONE
|
|
88
|
-
});
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
## cdk.json
|
|
94
|
-
|
|
95
|
-
```json
|
|
96
|
-
{
|
|
97
|
-
"app": "npx ts-node --prefer-ts-exts bin/cdk.ts",
|
|
98
|
-
"watch": {
|
|
99
|
-
"include": [
|
|
100
|
-
"**"
|
|
101
|
-
],
|
|
102
|
-
"exclude": [
|
|
103
|
-
"README.md",
|
|
104
|
-
"cdk*.json",
|
|
105
|
-
"**/*.d.ts",
|
|
106
|
-
"**/*.js",
|
|
107
|
-
"tsconfig.json",
|
|
108
|
-
"package*.json",
|
|
109
|
-
"yarn.lock",
|
|
110
|
-
"node_modules",
|
|
111
|
-
"test"
|
|
112
|
-
]
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
```
|