@jaypie/mcp 0.7.1 → 0.7.3
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/suites/docs/index.js +1 -1
- package/package.json +1 -1
- package/release-notes/constructs/1.2.26.md +11 -0
- package/release-notes/express/1.2.6.md +17 -0
- package/release-notes/mcp/0.7.2.md +18 -0
- package/release-notes/mcp/0.7.3.md +14 -0
- package/skills/cdk.md +18 -1
- package/skills/cors.md +324 -0
- package/skills/express.md +1 -1
- package/skills/streaming.md +36 -0
|
@@ -9,7 +9,7 @@ import { gt } from 'semver';
|
|
|
9
9
|
/**
|
|
10
10
|
* Docs Suite - Documentation services (skill, version, release_notes)
|
|
11
11
|
*/
|
|
12
|
-
const BUILD_VERSION_STRING = "@jaypie/mcp@0.7.
|
|
12
|
+
const BUILD_VERSION_STRING = "@jaypie/mcp@0.7.3#f9c2b3fe"
|
|
13
13
|
;
|
|
14
14
|
const __filename$1 = fileURLToPath(import.meta.url);
|
|
15
15
|
const __dirname$1 = path.dirname(__filename$1);
|
package/package.json
CHANGED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
---
|
|
2
|
+
version: 1.2.26
|
|
3
|
+
date: 2025-01-30
|
|
4
|
+
summary: Auto-set PROJECT_BASE_URL on Lambda handlers
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Changes
|
|
8
|
+
|
|
9
|
+
- JaypieDistribution now automatically sets `PROJECT_BASE_URL` environment variable on Lambda handlers when host is resolved
|
|
10
|
+
- JaypieApiGateway now automatically sets `PROJECT_BASE_URL` environment variable on Lambda handlers when host is resolved
|
|
11
|
+
- This enables automatic CORS configuration when using the cors helper from `@jaypie/express`
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
---
|
|
2
|
+
version: 1.2.6
|
|
3
|
+
date: 2025-01-30
|
|
4
|
+
summary: Improve CORS origin matching security with subdomain support
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Changes
|
|
8
|
+
|
|
9
|
+
- Fixed CORS security issue: origin matching now uses proper hostname extraction instead of `.includes()`
|
|
10
|
+
- Added subdomain matching: when `example.com` is allowed, subdomains like `app.example.com` are automatically allowed
|
|
11
|
+
- Added `extractHostname()` and `isOriginAllowed()` helpers for secure origin validation
|
|
12
|
+
- Origins in config can now be specified without protocol prefix (defaults to `https://`)
|
|
13
|
+
|
|
14
|
+
## Security
|
|
15
|
+
|
|
16
|
+
- Previously, allowing `example.com` would incorrectly allow `notexample.com` or `fakeexample.com` due to `.includes()` matching
|
|
17
|
+
- Now uses proper hostname extraction and suffix matching with dot separator to prevent this issue
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
version: 0.7.2
|
|
3
|
+
date: 2026-01-30
|
|
4
|
+
summary: Document JaypieNextJs streaming configuration requirements
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Documentation
|
|
8
|
+
|
|
9
|
+
- Added JaypieNextJs streaming documentation to `streaming.md` skill
|
|
10
|
+
- Added JaypieNextJs construct to `cdk.md` skill
|
|
11
|
+
- Clarified that `streaming: true` requires `open-next.config.ts` with `aws-lambda-streaming` wrapper
|
|
12
|
+
|
|
13
|
+
## Context
|
|
14
|
+
|
|
15
|
+
Issue #171 reported that `JaypieNextJs` with `streaming: true` returns a JSON envelope instead of streamed HTML. This is expected behavior - Lambda response streaming requires both:
|
|
16
|
+
|
|
17
|
+
1. CDK: `streaming: true` (configures `InvokeMode: RESPONSE_STREAM`)
|
|
18
|
+
2. Next.js: `open-next.config.ts` with `wrapper: "aws-lambda-streaming"`
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
---
|
|
2
|
+
version: 0.7.3
|
|
3
|
+
date: 2025-01-30
|
|
4
|
+
summary: Add CORS skill documentation comparing Jaypie cors helper with standard Express cors
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Changes
|
|
8
|
+
|
|
9
|
+
- Add `skill("cors")` documentation covering:
|
|
10
|
+
- Jaypie `cors` helper from `@jaypie/express`
|
|
11
|
+
- Comparison with standard `express/cors` middleware
|
|
12
|
+
- Environment variable integration (`BASE_URL`, `PROJECT_BASE_URL`)
|
|
13
|
+
- Sandbox mode automatic localhost handling
|
|
14
|
+
- Configuration options and usage patterns
|
package/skills/cdk.md
CHANGED
|
@@ -139,7 +139,24 @@ const handler = new JaypieLambda(this, "Handler", {
|
|
|
139
139
|
});
|
|
140
140
|
```
|
|
141
141
|
|
|
142
|
+
## JaypieNextJs
|
|
143
|
+
|
|
144
|
+
Deploy Next.js applications:
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
import { JaypieNextJs } from "@jaypie/constructs";
|
|
148
|
+
|
|
149
|
+
new JaypieNextJs(this, "App", {
|
|
150
|
+
nextjsPath: "../nextjs",
|
|
151
|
+
domainName: "app.example.com",
|
|
152
|
+
hostedZone: "example.com",
|
|
153
|
+
streaming: true, // Optional: enables response streaming
|
|
154
|
+
});
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
**Streaming Note:** When `streaming: true`, also create `open-next.config.ts` in your Next.js app with `wrapper: "aws-lambda-streaming"`. See `skill("streaming")` for details.
|
|
158
|
+
|
|
142
159
|
## See Also
|
|
143
160
|
|
|
144
|
-
- **`skill("streaming")`** - JaypieDistribution
|
|
161
|
+
- **`skill("streaming")`** - JaypieDistribution and JaypieNextJs streaming configuration
|
|
145
162
|
- **`skill("websockets")`** - JaypieWebSocket and JaypieWebSocketTable constructs
|
package/skills/cors.md
ADDED
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: CORS configuration for Express.js using Jaypie's cors helper
|
|
3
|
+
related: express, handlers, lambda
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# CORS Configuration
|
|
7
|
+
|
|
8
|
+
Jaypie's `@jaypie/express` package provides a `cors` helper that wraps the standard [express/cors](https://github.com/expressjs/cors) middleware with Jaypie-specific defaults and environment awareness.
|
|
9
|
+
|
|
10
|
+
## Quick Start
|
|
11
|
+
|
|
12
|
+
```typescript
|
|
13
|
+
import express from "express";
|
|
14
|
+
import { cors } from "jaypie";
|
|
15
|
+
|
|
16
|
+
const app = express();
|
|
17
|
+
|
|
18
|
+
// Basic usage - environment-aware defaults
|
|
19
|
+
app.use(cors());
|
|
20
|
+
|
|
21
|
+
// With specific origin
|
|
22
|
+
app.use(cors({ origin: "https://example.com" }));
|
|
23
|
+
|
|
24
|
+
// Multiple origins
|
|
25
|
+
app.use(cors({ origin: ["https://a.com", "https://b.com"] }));
|
|
26
|
+
|
|
27
|
+
// Allow all origins
|
|
28
|
+
app.use(cors({ origin: "*" }));
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Default Behavior: `cors()`
|
|
32
|
+
|
|
33
|
+
When called with no arguments, `cors()` allows origins based on environment variables only:
|
|
34
|
+
|
|
35
|
+
| Condition | Allowed |
|
|
36
|
+
|-----------|---------|
|
|
37
|
+
| No `Origin` header (curl, mobile, server-to-server) | ✅ Always |
|
|
38
|
+
| Origin matches `BASE_URL` env var | ✅ Yes |
|
|
39
|
+
| Origin matches `PROJECT_BASE_URL` env var | ✅ Yes |
|
|
40
|
+
| Origin is subdomain of allowed origin | ✅ Yes |
|
|
41
|
+
| `PROJECT_ENV=sandbox` and origin is `localhost[:port]` | ✅ Yes |
|
|
42
|
+
| Any other cross-origin request | ❌ Rejected |
|
|
43
|
+
|
|
44
|
+
### Subdomain Matching
|
|
45
|
+
|
|
46
|
+
When you allow a domain, all subdomains of that domain are also automatically allowed:
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
// Allow example.com and all its subdomains
|
|
50
|
+
app.use(cors({ origin: "example.com" }));
|
|
51
|
+
// Allows: https://example.com, https://app.example.com, https://sub.app.example.com
|
|
52
|
+
// Rejects: https://notexample.com, https://fakeexample.com
|
|
53
|
+
|
|
54
|
+
// Protocol prefix is optional in config
|
|
55
|
+
app.use(cors({ origin: "example.com" })); // Same as https://example.com
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
This is secure because it uses proper hostname extraction and suffix matching with a dot separator—domains like `notexample.com` or `fakeexample.com` are correctly rejected.
|
|
59
|
+
|
|
60
|
+
**Important:** With no environment variables set and not in sandbox mode, `cors()` rejects all cross-origin browser requests. This is secure by default—you must explicitly configure allowed origins.
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
// Example: Production environment
|
|
64
|
+
// BASE_URL=https://api.example.com
|
|
65
|
+
// PROJECT_BASE_URL=https://example.com
|
|
66
|
+
|
|
67
|
+
app.use(cors());
|
|
68
|
+
// Allows: https://api.example.com, https://example.com
|
|
69
|
+
// Rejects: all other origins
|
|
70
|
+
|
|
71
|
+
// Example: Sandbox/development
|
|
72
|
+
// PROJECT_ENV=sandbox
|
|
73
|
+
|
|
74
|
+
app.use(cors());
|
|
75
|
+
// Allows: http://localhost, http://localhost:3000, http://localhost:5173, etc.
|
|
76
|
+
// Rejects: all other origins (unless BASE_URL/PROJECT_BASE_URL set)
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Jaypie vs Standard Express CORS
|
|
80
|
+
|
|
81
|
+
### Key Differences
|
|
82
|
+
|
|
83
|
+
| Feature | Standard `cors` | Jaypie `cors` |
|
|
84
|
+
|---------|-----------------|---------------|
|
|
85
|
+
| **Origin Validation** | Static or manual callback | Dynamic environment-aware callback |
|
|
86
|
+
| **Subdomain Matching** | Manual implementation | Automatic (subdomains of allowed origins permitted) |
|
|
87
|
+
| **Environment URLs** | Not supported | Reads `BASE_URL`, `PROJECT_BASE_URL` |
|
|
88
|
+
| **Sandbox Mode** | Manual localhost config | Auto-allows localhost in sandbox |
|
|
89
|
+
| **Error Response** | Generic CORS error | Returns `CorsError` with JSON body |
|
|
90
|
+
| **No-Origin Requests** | Configurable | Always allowed (mobile apps, curl) |
|
|
91
|
+
| **Protocol Prefix** | Required in config | Optional (defaults to `https://`) |
|
|
92
|
+
|
|
93
|
+
### Jaypie-Specific Behavior
|
|
94
|
+
|
|
95
|
+
1. **Environment Variable Integration**
|
|
96
|
+
- `BASE_URL` - Automatically added to allowed origins
|
|
97
|
+
- `PROJECT_BASE_URL` - Automatically added to allowed origins
|
|
98
|
+
- Protocol auto-added if missing (defaults to `https://`)
|
|
99
|
+
|
|
100
|
+
2. **Sandbox Mode** (when `PROJECT_ENV=sandbox` or `PROJECT_SANDBOX_MODE=true`)
|
|
101
|
+
- `http://localhost` is automatically allowed
|
|
102
|
+
- `http://localhost:*` (any port) is automatically allowed
|
|
103
|
+
|
|
104
|
+
3. **No-Origin Requests**
|
|
105
|
+
- Requests without an `Origin` header are always allowed
|
|
106
|
+
- Enables mobile apps, server-to-server calls, and curl testing
|
|
107
|
+
|
|
108
|
+
4. **Error Handling**
|
|
109
|
+
- Invalid origins return a `CorsError` from `@jaypie/errors`
|
|
110
|
+
- Response includes JSON body with error details
|
|
111
|
+
|
|
112
|
+
## Configuration Options
|
|
113
|
+
|
|
114
|
+
### Jaypie `cors` Options
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
interface CorsConfig {
|
|
118
|
+
origin?: string | string[]; // Additional allowed origins
|
|
119
|
+
overrides?: Record<string, unknown>; // Pass-through to express/cors
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Standard `cors` Options (via `overrides`)
|
|
124
|
+
|
|
125
|
+
All standard `cors` options can be passed through the `overrides` parameter:
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
import { cors } from "jaypie";
|
|
129
|
+
|
|
130
|
+
app.use(cors({
|
|
131
|
+
origin: "https://example.com",
|
|
132
|
+
overrides: {
|
|
133
|
+
methods: ["GET", "POST", "PUT"],
|
|
134
|
+
allowedHeaders: ["Content-Type", "Authorization"],
|
|
135
|
+
exposedHeaders: ["X-Request-Id"],
|
|
136
|
+
credentials: true,
|
|
137
|
+
maxAge: 86400,
|
|
138
|
+
optionsSuccessStatus: 200,
|
|
139
|
+
preflightContinue: false,
|
|
140
|
+
},
|
|
141
|
+
}));
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Full Standard Options Reference
|
|
145
|
+
|
|
146
|
+
| Option | Type | Default | Description |
|
|
147
|
+
|--------|------|---------|-------------|
|
|
148
|
+
| `methods` | `string \| string[]` | All methods | Allowed HTTP methods |
|
|
149
|
+
| `allowedHeaders` | `string \| string[]` | Reflect request | Allowed request headers |
|
|
150
|
+
| `exposedHeaders` | `string \| string[]` | None | Headers exposed to browser |
|
|
151
|
+
| `credentials` | `boolean` | `false` | Allow credentials (cookies) |
|
|
152
|
+
| `maxAge` | `number` | None | Preflight cache duration (seconds) |
|
|
153
|
+
| `preflightContinue` | `boolean` | `false` | Pass OPTIONS to next handler |
|
|
154
|
+
| `optionsSuccessStatus` | `number` | `204` | Status for successful OPTIONS |
|
|
155
|
+
|
|
156
|
+
## Usage Patterns
|
|
157
|
+
|
|
158
|
+
### API with Multiple Allowed Origins
|
|
159
|
+
|
|
160
|
+
```typescript
|
|
161
|
+
import { cors } from "jaypie";
|
|
162
|
+
|
|
163
|
+
// Production + staging + local origins
|
|
164
|
+
app.use(cors({
|
|
165
|
+
origin: [
|
|
166
|
+
"https://app.example.com",
|
|
167
|
+
"https://staging.example.com",
|
|
168
|
+
],
|
|
169
|
+
}));
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### API with Credentials
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
import { cors } from "jaypie";
|
|
176
|
+
|
|
177
|
+
// Enable cookies for cross-origin requests
|
|
178
|
+
app.use(cors({
|
|
179
|
+
origin: "https://app.example.com",
|
|
180
|
+
overrides: {
|
|
181
|
+
credentials: true,
|
|
182
|
+
},
|
|
183
|
+
}));
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### Public API (Allow All Origins)
|
|
187
|
+
|
|
188
|
+
```typescript
|
|
189
|
+
import { cors } from "jaypie";
|
|
190
|
+
|
|
191
|
+
// Allow any origin
|
|
192
|
+
app.use(cors({ origin: "*" }));
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### Per-Route CORS
|
|
196
|
+
|
|
197
|
+
```typescript
|
|
198
|
+
import express from "express";
|
|
199
|
+
import { cors } from "jaypie";
|
|
200
|
+
|
|
201
|
+
const app = express();
|
|
202
|
+
|
|
203
|
+
// Public endpoints - wide open
|
|
204
|
+
app.use("/api/public", cors({ origin: "*" }));
|
|
205
|
+
|
|
206
|
+
// Protected endpoints - restricted origins
|
|
207
|
+
app.use("/api/admin", cors({
|
|
208
|
+
origin: "https://admin.example.com",
|
|
209
|
+
overrides: { credentials: true },
|
|
210
|
+
}));
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
## How Origin Validation Works
|
|
214
|
+
|
|
215
|
+
Jaypie's `cors` uses a dynamic origin callback that checks origins in this order:
|
|
216
|
+
|
|
217
|
+
1. **Wildcard** - If `origin: "*"`, allow all origins
|
|
218
|
+
2. **No Origin** - Allow requests without Origin header (mobile, curl, etc.)
|
|
219
|
+
3. **Environment URLs** - Check `BASE_URL` and `PROJECT_BASE_URL`
|
|
220
|
+
4. **Configured Origins** - Check origins passed to `cors({ origin: [...] })`
|
|
221
|
+
5. **Sandbox Localhost** - In sandbox mode, allow localhost with any port
|
|
222
|
+
|
|
223
|
+
For each allowed origin, the validation checks:
|
|
224
|
+
- **Exact hostname match** - `example.com` matches `https://example.com`
|
|
225
|
+
- **Subdomain match** - `example.com` matches `https://app.example.com`
|
|
226
|
+
|
|
227
|
+
```typescript
|
|
228
|
+
// Simplified origin validation logic
|
|
229
|
+
const isAllowed =
|
|
230
|
+
origin === "*" ||
|
|
231
|
+
!requestOrigin ||
|
|
232
|
+
isOriginAllowed(requestOrigin, process.env.BASE_URL) ||
|
|
233
|
+
isOriginAllowed(requestOrigin, process.env.PROJECT_BASE_URL) ||
|
|
234
|
+
configuredOrigins.some(o => isOriginAllowed(requestOrigin, o)) ||
|
|
235
|
+
(isSandbox && requestOrigin.match(/^http:\/\/localhost(:\d+)?$/));
|
|
236
|
+
|
|
237
|
+
// Where isOriginAllowed checks for exact match OR subdomain match
|
|
238
|
+
// e.g., "app.example.com".endsWith(".example.com") → true
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
## Error Responses
|
|
242
|
+
|
|
243
|
+
When an origin is not allowed, Jaypie returns a structured error response:
|
|
244
|
+
|
|
245
|
+
```json
|
|
246
|
+
{
|
|
247
|
+
"errors": [{
|
|
248
|
+
"title": "CorsError",
|
|
249
|
+
"status": 403,
|
|
250
|
+
"detail": "Cross-Origin Request Blocked"
|
|
251
|
+
}]
|
|
252
|
+
}
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
## Comparison: Standard vs Jaypie CORS Setup
|
|
256
|
+
|
|
257
|
+
### Standard Express CORS
|
|
258
|
+
|
|
259
|
+
```typescript
|
|
260
|
+
import express from "express";
|
|
261
|
+
import cors from "cors";
|
|
262
|
+
|
|
263
|
+
const app = express();
|
|
264
|
+
|
|
265
|
+
// Manual origin validation
|
|
266
|
+
app.use(cors({
|
|
267
|
+
origin: (origin, callback) => {
|
|
268
|
+
const allowedOrigins = [
|
|
269
|
+
process.env.BASE_URL,
|
|
270
|
+
process.env.PROJECT_BASE_URL,
|
|
271
|
+
"https://app.example.com",
|
|
272
|
+
];
|
|
273
|
+
|
|
274
|
+
// Allow no-origin requests
|
|
275
|
+
if (!origin) {
|
|
276
|
+
return callback(null, true);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// Check allowed list
|
|
280
|
+
if (allowedOrigins.some(o => origin.includes(o))) {
|
|
281
|
+
return callback(null, true);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// Sandbox localhost
|
|
285
|
+
if (process.env.PROJECT_ENV === "sandbox" &&
|
|
286
|
+
origin.match(/^http:\/\/localhost(:\d+)?$/)) {
|
|
287
|
+
return callback(null, true);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
callback(new Error("Not allowed by CORS"));
|
|
291
|
+
},
|
|
292
|
+
credentials: true,
|
|
293
|
+
}));
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
### Jaypie CORS (Equivalent)
|
|
297
|
+
|
|
298
|
+
```typescript
|
|
299
|
+
import express from "express";
|
|
300
|
+
import { cors } from "jaypie";
|
|
301
|
+
|
|
302
|
+
const app = express();
|
|
303
|
+
|
|
304
|
+
// Same behavior, less code
|
|
305
|
+
app.use(cors({
|
|
306
|
+
origin: "https://app.example.com",
|
|
307
|
+
overrides: { credentials: true },
|
|
308
|
+
}));
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
## Environment Variables
|
|
312
|
+
|
|
313
|
+
| Variable | Description |
|
|
314
|
+
|----------|-------------|
|
|
315
|
+
| `BASE_URL` | Automatically added to allowed origins |
|
|
316
|
+
| `PROJECT_BASE_URL` | Automatically added to allowed origins |
|
|
317
|
+
| `PROJECT_ENV` | Set to `sandbox` to enable localhost access |
|
|
318
|
+
| `PROJECT_SANDBOX_MODE` | Set to `true` to enable localhost access |
|
|
319
|
+
|
|
320
|
+
## See Also
|
|
321
|
+
|
|
322
|
+
- **`skill("express")`** - Express handler and Lambda adapter documentation
|
|
323
|
+
- **`skill("handlers")`** - Jaypie handler lifecycle documentation
|
|
324
|
+
- **`skill("lambda")`** - AWS Lambda deployment patterns
|
package/skills/express.md
CHANGED
package/skills/streaming.md
CHANGED
|
@@ -76,6 +76,8 @@ export const handler = lambdaStreamHandler(async (event, context) => {
|
|
|
76
76
|
|
|
77
77
|
## CDK Configuration
|
|
78
78
|
|
|
79
|
+
### JaypieDistribution
|
|
80
|
+
|
|
79
81
|
```typescript
|
|
80
82
|
import { JaypieLambda, JaypieDistribution } from "@jaypie/constructs";
|
|
81
83
|
|
|
@@ -90,6 +92,40 @@ new JaypieDistribution(this, "Api", {
|
|
|
90
92
|
});
|
|
91
93
|
```
|
|
92
94
|
|
|
95
|
+
### JaypieNextJs Streaming
|
|
96
|
+
|
|
97
|
+
For Next.js applications with `JaypieNextJs`, streaming requires **two** configurations:
|
|
98
|
+
|
|
99
|
+
1. **CDK** - Set `streaming: true` in the construct
|
|
100
|
+
2. **Next.js App** - Create `open-next.config.ts` with the streaming wrapper
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
// CDK Stack
|
|
104
|
+
import { JaypieNextJs } from "@jaypie/constructs";
|
|
105
|
+
|
|
106
|
+
new JaypieNextJs(this, "App", {
|
|
107
|
+
nextjsPath: "../nextjs",
|
|
108
|
+
streaming: true,
|
|
109
|
+
});
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
// nextjs/open-next.config.ts (required for streaming)
|
|
114
|
+
import type { OpenNextConfig } from "@opennextjs/aws/types/open-next.js";
|
|
115
|
+
|
|
116
|
+
const config = {
|
|
117
|
+
default: {
|
|
118
|
+
override: {
|
|
119
|
+
wrapper: "aws-lambda-streaming",
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
} satisfies OpenNextConfig;
|
|
123
|
+
|
|
124
|
+
export default config;
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
**Important:** Without `open-next.config.ts`, the Lambda returns a JSON envelope `{ statusCode, headers, body }` instead of streaming HTML. This is because `cdk-nextjs-standalone` configures the Lambda Function URL with `RESPONSE_STREAM` invoke mode, but OpenNext also needs to be configured to use the streaming wrapper.
|
|
128
|
+
|
|
93
129
|
## Error Handling
|
|
94
130
|
|
|
95
131
|
Errors are written to the stream in the configured format:
|