@jaypie/mcp 0.2.9 → 0.2.12

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/index.js CHANGED
@@ -885,7 +885,7 @@ function listLlmProviders() {
885
885
  };
886
886
  }
887
887
 
888
- const BUILD_VERSION_STRING = "@jaypie/mcp@0.2.9#f022ac30"
888
+ const BUILD_VERSION_STRING = "@jaypie/mcp@0.2.12#512ddebf"
889
889
  ;
890
890
  const __filename$1 = fileURLToPath(import.meta.url);
891
891
  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.2.9",
3
+ "version": "0.2.12",
4
4
  "description": "Jaypie MCP",
5
5
  "repository": {
6
6
  "type": "git",
@@ -102,33 +102,27 @@ Preconfigured with API-optimized timeouts and role tags.
102
102
 
103
103
  ### Streaming Lambda Functions
104
104
 
105
- Use `JaypieStreamingLambda` for Express apps with AWS Lambda Web Adapter and streaming support:
105
+ For streaming responses (SSE, real-time updates), use `createLambdaStreamHandler` from `@jaypie/express` with `JaypieDistribution`:
106
106
 
107
107
  ```typescript
108
- import { JaypieStreamingLambda, JaypieDistribution } from "@jaypie/constructs";
108
+ import { JaypieExpressLambda, JaypieDistribution } from "@jaypie/constructs";
109
+ import * as lambda from "aws-cdk-lib/aws-lambda";
109
110
 
110
- // Create streaming Lambda with Web Adapter
111
- const streamingLambda = new JaypieStreamingLambda(this, "StreamingApi", {
111
+ // Create Lambda (handler uses createLambdaStreamHandler internally)
112
+ const streamingApi = new JaypieExpressLambda(this, "StreamingApi", {
112
113
  code: "dist/api",
113
- handler: "run.sh", // Shell script to start Express app
114
- streaming: true, // Enables RESPONSE_STREAM invoke mode
115
- port: 8000, // Port your app listens on (default: 8000)
114
+ handler: "index.handler",
116
115
  });
117
116
 
118
- // CloudFront auto-detects invokeMode from JaypieStreamingLambda
117
+ // Use with CloudFront and RESPONSE_STREAM invoke mode
119
118
  new JaypieDistribution(this, "Distribution", {
120
- handler: streamingLambda,
119
+ handler: streamingApi,
120
+ invokeMode: lambda.InvokeMode.RESPONSE_STREAM,
121
121
  host: "api.example.com",
122
122
  zone: "example.com",
123
123
  });
124
124
  ```
125
125
 
126
- Features:
127
- - Automatically adds AWS Lambda Web Adapter layer (supports ARM64 and x86_64)
128
- - Sets `AWS_LAMBDA_EXEC_WRAPPER` and `AWS_LWA_INVOKE_MODE` environment variables
129
- - Exposes `invokeMode` property for auto-detection by `JaypieDistribution`
130
- - Use `streaming: false` for buffered mode (traditional Lambda behavior)
131
-
132
126
  For direct Function URL access (bypass CloudFront):
133
127
  ```typescript
134
128
  import { FunctionUrlAuthType, InvokeMode } from "aws-cdk-lib/aws-lambda";
@@ -147,7 +141,7 @@ const functionUrl = streamingLambda.addFunctionUrl({
147
141
  new cdk.CfnOutput(this, "StreamingUrl", { value: functionUrl.url });
148
142
  ```
149
143
 
150
- Note: API Gateway has a 29-second timeout limit. For longer streaming operations, use Function URLs or CloudFront with Lambda Function URLs.
144
+ Note: Streaming requires Lambda Function URLs (not API Gateway). `JaypieDistribution` uses Function URLs by default.
151
145
 
152
146
  ### Stack Types
153
147
 
@@ -323,21 +317,22 @@ Common usage:
323
317
 
324
318
  ### DynamoDB Tables
325
319
 
326
- Use `JaypieDynamoDb` for single-table design with Jaypie GSI patterns:
320
+ Use `JaypieDynamoDb` for single-table design with Jaypie patterns:
327
321
  ```typescript
328
322
  // Shorthand: tableName becomes "myApp", construct id is "JaypieDynamoDb-myApp"
329
323
  const table = new JaypieDynamoDb(this, "myApp");
330
324
 
331
- // No GSIs
332
- const table = new JaypieDynamoDb(this, "MyTable", {
333
- globalSecondaryIndexes: false,
325
+ // With standard Jaypie GSIs (indexScope, indexAlias, indexClass, indexType, indexXid)
326
+ const tableWithIndexes = new JaypieDynamoDb(this, "myApp", {
327
+ indexes: JaypieDynamoDb.DEFAULT_INDEXES,
334
328
  });
335
329
 
336
- // Use only specific GSIs
337
- const table = new JaypieDynamoDb(this, "MyTable", {
338
- globalSecondaryIndexes: [
339
- JaypieDynamoDb.GlobalSecondaryIndex.Ou,
340
- JaypieDynamoDb.GlobalSecondaryIndex.Type,
330
+ // With custom indexes using IndexDefinition from @jaypie/fabric
331
+ const customTable = new JaypieDynamoDb(this, "myApp", {
332
+ indexes: [
333
+ { pk: ["scope", "model"], sk: ["sequence"] }, // indexScopeModel
334
+ { pk: ["scope", "model", "type"], sparse: true }, // indexScopeModelType
335
+ { name: "byAlias", pk: ["alias"], sk: ["createdAt"] }, // custom name
341
336
  ],
342
337
  });
343
338
 
@@ -352,9 +347,9 @@ Features:
352
347
  - Default partition key: `model` (string), sort key: `id` (string)
353
348
  - PAY_PER_REQUEST billing mode by default
354
349
  - RETAIN removal policy in production, DESTROY otherwise
355
- - GSI options: `true`/omit = all five, `false` = none, array = specific GSIs
356
- - Static constants: `JaypieDynamoDb.GlobalSecondaryIndex.*` and `JaypieDynamoDb.GlobalSecondaryIndexes`
357
- - All GSIs use partition key (string) + `sequence` (number) sort key
350
+ - No GSIs by default - use `indexes` prop to add them
351
+ - `JaypieDynamoDb.DEFAULT_INDEXES` provides standard Jaypie GSIs from `@jaypie/fabric`
352
+ - Uses `IndexDefinition` from `@jaypie/fabric` for GSI configuration
358
353
  - Implements `ITableV2` interface
359
354
 
360
355
  For single-table design patterns, key builders, and query utilities, see `Jaypie_DynamoDB_Package.md`.
@@ -21,21 +21,21 @@ All entities share a single DynamoDB table with:
21
21
  - **Primary Key**: `model` (partition) + `id` (sort)
22
22
  - **Five GSIs**: All use `sequence` as sort key for chronological ordering
23
23
 
24
- ### Organizational Unit (OU)
24
+ ### Scope
25
25
 
26
- The `ou` field creates hierarchical relationships:
27
- - Root entities: `ou = "@"` (APEX constant)
28
- - Child entities: `ou = "{parent.model}#{parent.id}"`
26
+ The `scope` field creates hierarchical relationships:
27
+ - Root entities: `scope = "@"` (APEX constant)
28
+ - Child entities: `scope = "{parent.model}#{parent.id}"`
29
29
 
30
30
  ### GSI Pattern
31
31
 
32
32
  | GSI Name | Partition Key | Use Case |
33
33
  |----------|---------------|----------|
34
- | `indexOu` | `{ou}#{model}` | List all entities under a parent |
35
- | `indexAlias` | `{ou}#{model}#{alias}` | Human-friendly slug lookup |
36
- | `indexClass` | `{ou}#{model}#{class}` | Category filtering |
37
- | `indexType` | `{ou}#{model}#{type}` | Type filtering |
38
- | `indexXid` | `{ou}#{model}#{xid}` | External system ID lookup |
34
+ | `indexScope` | `{scope}#{model}` | List all entities under a parent |
35
+ | `indexAlias` | `{scope}#{model}#{alias}` | Human-friendly slug lookup |
36
+ | `indexClass` | `{scope}#{model}#{class}` | Category filtering |
37
+ | `indexType` | `{scope}#{model}#{type}` | Type filtering |
38
+ | `indexXid` | `{scope}#{model}#{xid}` | External system ID lookup |
39
39
 
40
40
  ## Client Initialization
41
41
 
@@ -61,21 +61,21 @@ initClient({
61
61
  });
62
62
  ```
63
63
 
64
- ## FabricEntity Interface
64
+ ## StorableEntity Interface
65
65
 
66
- All entities must implement `FabricEntity`:
66
+ All entities must implement `StorableEntity`:
67
67
 
68
68
  ```typescript
69
- import type { FabricEntity } from "@jaypie/dynamodb";
69
+ import type { StorableEntity } from "@jaypie/dynamodb";
70
70
 
71
- interface MyRecord extends FabricEntity {
71
+ interface MyRecord extends StorableEntity {
72
72
  // Primary Key (required)
73
73
  model: string; // e.g., "record"
74
74
  id: string; // UUID
75
75
 
76
76
  // Required fields
77
77
  name: string;
78
- ou: string; // APEX or hierarchical
78
+ scope: string; // APEX or hierarchical
79
79
  sequence: number; // Date.now()
80
80
 
81
81
  // Timestamps (ISO 8601)
@@ -108,7 +108,7 @@ const record = await putEntity({
108
108
  model: "record",
109
109
  id: crypto.randomUUID(),
110
110
  name: "Daily Log",
111
- ou: APEX,
111
+ scope: APEX,
112
112
  sequence: Date.now(),
113
113
  alias: "2026-01-07", // Optional
114
114
  class: "memory", // Optional
@@ -118,7 +118,7 @@ const record = await putEntity({
118
118
  });
119
119
 
120
120
  // Result includes auto-populated indexes:
121
- // indexOu: "@#record"
121
+ // indexScope: "@#record"
122
122
  // indexAlias: "@#record#2026-01-07"
123
123
  // indexClass: "@#record#memory"
124
124
  ```
@@ -187,16 +187,16 @@ await destroyEntity({ id: "123", model: "record" });
187
187
 
188
188
  ### Hierarchical Entities
189
189
 
190
- Use `calculateOu` to derive OU from parent:
190
+ Use `calculateScope` to derive scope from parent:
191
191
 
192
192
  ```typescript
193
- import { calculateOu, putEntity, queryByOu } from "@jaypie/dynamodb";
193
+ import { calculateScope, putEntity, queryByScope } from "@jaypie/dynamodb";
194
194
 
195
195
  // Parent reference
196
196
  const chat = { model: "chat", id: "abc-123" };
197
197
 
198
- // Calculate child OU
199
- const messageOu = calculateOu(chat); // "chat#abc-123"
198
+ // Calculate child scope
199
+ const messageScope = calculateScope(chat); // "chat#abc-123"
200
200
 
201
201
  // Create child entity
202
202
  const message = await putEntity({
@@ -204,39 +204,39 @@ const message = await putEntity({
204
204
  model: "message",
205
205
  id: crypto.randomUUID(),
206
206
  name: "First message",
207
- ou: messageOu,
207
+ scope: messageScope,
208
208
  sequence: Date.now(),
209
209
  createdAt: now,
210
210
  updatedAt: now,
211
211
  },
212
212
  });
213
- // indexOu: "chat#abc-123#message"
213
+ // indexScope: "chat#abc-123#message"
214
214
 
215
215
  // Query all messages in chat
216
- const { items } = await queryByOu({ model: "message", ou: messageOu });
216
+ const { items } = await queryByScope({ model: "message", scope: messageScope });
217
217
  ```
218
218
 
219
219
  ## Query Functions
220
220
 
221
221
  All queries use object parameters and filter soft-deleted and archived records by default.
222
222
 
223
- ### queryByOu - List by Parent
223
+ ### queryByScope - List by Parent
224
224
 
225
225
  List all entities of a model under a parent:
226
226
 
227
227
  ```typescript
228
- import { APEX, queryByOu } from "@jaypie/dynamodb";
228
+ import { APEX, queryByScope } from "@jaypie/dynamodb";
229
229
 
230
230
  // Root-level records
231
- const { items, lastEvaluatedKey } = await queryByOu({
231
+ const { items, lastEvaluatedKey } = await queryByScope({
232
232
  model: "record",
233
- ou: APEX,
233
+ scope: APEX,
234
234
  });
235
235
 
236
236
  // Messages under a chat
237
- const { items: messages } = await queryByOu({
237
+ const { items: messages } = await queryByScope({
238
238
  model: "message",
239
- ou: "chat#abc-123",
239
+ scope: "chat#abc-123",
240
240
  });
241
241
  ```
242
242
 
@@ -250,7 +250,7 @@ import { APEX, queryByAlias } from "@jaypie/dynamodb";
250
250
  const record = await queryByAlias({
251
251
  alias: "2026-01-07",
252
252
  model: "record",
253
- ou: APEX,
253
+ scope: APEX,
254
254
  });
255
255
  // Returns entity or null
256
256
  ```
@@ -263,14 +263,14 @@ import { APEX, queryByClass, queryByType } from "@jaypie/dynamodb";
263
263
  // All memory records
264
264
  const { items } = await queryByClass({
265
265
  model: "record",
266
- ou: APEX,
266
+ scope: APEX,
267
267
  recordClass: "memory",
268
268
  });
269
269
 
270
270
  // All note-type records
271
271
  const { items: notes } = await queryByType({
272
272
  model: "record",
273
- ou: APEX,
273
+ scope: APEX,
274
274
  type: "note",
275
275
  });
276
276
  ```
@@ -284,7 +284,7 @@ import { APEX, queryByXid } from "@jaypie/dynamodb";
284
284
 
285
285
  const record = await queryByXid({
286
286
  model: "record",
287
- ou: APEX,
287
+ scope: APEX,
288
288
  xid: "ext-12345",
289
289
  });
290
290
  // Returns entity or null
@@ -295,9 +295,9 @@ const record = await queryByXid({
295
295
  ```typescript
296
296
  import type { BaseQueryOptions } from "@jaypie/dynamodb";
297
297
 
298
- const result = await queryByOu({
298
+ const result = await queryByScope({
299
299
  model: "record",
300
- ou: APEX,
300
+ scope: APEX,
301
301
  // BaseQueryOptions:
302
302
  limit: 25, // Max items to return
303
303
  ascending: true, // Oldest first (default: false = newest first)
@@ -310,15 +310,15 @@ const result = await queryByOu({
310
310
  ### Pagination
311
311
 
312
312
  ```typescript
313
- import { APEX, queryByOu } from "@jaypie/dynamodb";
313
+ import { APEX, queryByScope } from "@jaypie/dynamodb";
314
314
 
315
315
  let startKey: Record<string, unknown> | undefined;
316
- const allItems: FabricEntity[] = [];
316
+ const allItems: StorableEntity[] = [];
317
317
 
318
318
  do {
319
- const { items, lastEvaluatedKey } = await queryByOu({
319
+ const { items, lastEvaluatedKey } = await queryByScope({
320
320
  model: "record",
321
- ou: APEX,
321
+ scope: APEX,
322
322
  limit: 100,
323
323
  startKey,
324
324
  });
@@ -337,11 +337,11 @@ import { indexEntity } from "@jaypie/dynamodb";
337
337
  const indexed = indexEntity({
338
338
  model: "record",
339
339
  id: "123",
340
- ou: "@",
340
+ scope: "@",
341
341
  alias: "my-alias",
342
342
  // ...
343
343
  });
344
- // indexOu: "@#record"
344
+ // indexScope: "@#record"
345
345
  // indexAlias: "@#record#my-alias"
346
346
  ```
347
347
 
@@ -349,14 +349,14 @@ Use individual key builders for manual key construction:
349
349
 
350
350
  ```typescript
351
351
  import {
352
- buildIndexOu,
352
+ buildIndexScope,
353
353
  buildIndexAlias,
354
354
  buildIndexClass,
355
355
  buildIndexType,
356
356
  buildIndexXid,
357
357
  } from "@jaypie/dynamodb";
358
358
 
359
- buildIndexOu("@", "record"); // "@#record"
359
+ buildIndexScope("@", "record"); // "@#record"
360
360
  buildIndexAlias("@", "record", "my-alias"); // "@#record#my-alias"
361
361
  buildIndexClass("@", "record", "memory"); // "@#record#memory"
362
362
  buildIndexType("@", "record", "note"); // "@#record#note"
@@ -369,7 +369,7 @@ buildIndexXid("@", "record", "ext-123"); // "@#record#ext-123"
369
369
  import {
370
370
  APEX, // "@" - Root-level marker
371
371
  SEPARATOR, // "#" - Composite key separator
372
- INDEX_OU, // "indexOu"
372
+ INDEX_SCOPE, // "indexScope"
373
373
  INDEX_ALIAS, // "indexAlias"
374
374
  INDEX_CLASS, // "indexClass"
375
375
  INDEX_TYPE, // "indexType"
@@ -385,7 +385,7 @@ AttributeDefinitions:
385
385
  AttributeType: S
386
386
  - AttributeName: id
387
387
  AttributeType: S
388
- - AttributeName: indexOu
388
+ - AttributeName: indexScope
389
389
  AttributeType: S
390
390
  - AttributeName: indexAlias
391
391
  AttributeType: S
@@ -405,9 +405,9 @@ KeySchema:
405
405
  KeyType: RANGE
406
406
 
407
407
  GlobalSecondaryIndexes:
408
- - IndexName: indexOu
408
+ - IndexName: indexScope
409
409
  KeySchema:
410
- - AttributeName: indexOu
410
+ - AttributeName: indexScope
411
411
  KeyType: HASH
412
412
  - AttributeName: sequence
413
413
  KeyType: RANGE
@@ -445,7 +445,7 @@ const created = await seedEntityIfNotExists({
445
445
  alias: "config-main",
446
446
  model: "config",
447
447
  name: "Main Configuration",
448
- ou: APEX,
448
+ scope: APEX,
449
449
  });
450
450
  // Returns true if created, false if already exists
451
451
  ```
@@ -458,8 +458,8 @@ Seed multiple entities with idempotency:
458
458
  import { APEX, seedEntities } from "@jaypie/dynamodb";
459
459
 
460
460
  const result = await seedEntities([
461
- { alias: "vocab-en", model: "vocabulary", name: "English", ou: APEX },
462
- { alias: "vocab-es", model: "vocabulary", name: "Spanish", ou: APEX },
461
+ { alias: "vocab-en", model: "vocabulary", name: "English", scope: APEX },
462
+ { alias: "vocab-es", model: "vocabulary", name: "Spanish", scope: APEX },
463
463
  ]);
464
464
  // result.created: aliases of created entities
465
465
  // result.skipped: aliases of entities that already existed
@@ -476,13 +476,13 @@ Auto-generates `id` (UUID), `createdAt`, `updatedAt`, and `sequence` if missing.
476
476
 
477
477
  ### exportEntities
478
478
 
479
- Export entities by model and organizational unit:
479
+ Export entities by model and scope:
480
480
 
481
481
  ```typescript
482
482
  import { APEX, exportEntities } from "@jaypie/dynamodb";
483
483
 
484
484
  const { entities, count } = await exportEntities("vocabulary", APEX);
485
- // entities: FabricEntity[] sorted by sequence ascending
485
+ // entities: StorableEntity[] sorted by sequence ascending
486
486
  // count: number of entities
487
487
 
488
488
  // With limit
@@ -517,7 +517,7 @@ interface SeedOptions {
517
517
  dryRun?: boolean; // Preview without writing (default: false)
518
518
  }
519
519
 
520
- interface ExportResult<T extends FabricEntity = FabricEntity> {
520
+ interface ExportResult<T extends StorableEntity = StorableEntity> {
521
521
  entities: T[]; // Exported entities
522
522
  count: number; // Number of entities
523
523
  }
@@ -546,11 +546,11 @@ import {
546
546
  exportEntities,
547
547
  getEntity,
548
548
  putEntity,
549
- queryByOu,
549
+ queryByScope,
550
550
  seedEntities,
551
551
  } from "@jaypie/testkit/mock";
552
552
 
553
- queryByOu.mockResolvedValue({
553
+ queryByScope.mockResolvedValue({
554
554
  items: [{ id: "123", name: "Test" }],
555
555
  lastEvaluatedKey: undefined,
556
556
  });
@@ -644,12 +644,12 @@ await deleteEntity({ id: "123", model: "record" });
644
644
  await archiveEntity({ id: "123", model: "record" });
645
645
 
646
646
  // Queries exclude both by default
647
- const { items } = await queryByOu({ model: "record", ou: APEX });
647
+ const { items } = await queryByScope({ model: "record", scope: APEX });
648
648
 
649
649
  // Include if needed
650
- const { items: all } = await queryByOu({
650
+ const { items: all } = await queryByScope({
651
651
  model: "record",
652
- ou: APEX,
652
+ scope: APEX,
653
653
  includeDeleted: true,
654
654
  includeArchived: true,
655
655
  });
@@ -704,7 +704,7 @@ const { tools } = registerDynamoDbTools({ server });
704
704
  #### Query Operations
705
705
  | Tool | Description |
706
706
  |------|-------------|
707
- | `dynamodb_query_ou` | Query by organizational unit |
707
+ | `dynamodb_query_scope` | Query by scope |
708
708
  | `dynamodb_query_alias` | Query by human-friendly alias |
709
709
  | `dynamodb_query_class` | Query by category classification |
710
710
  | `dynamodb_query_type` | Query by type classification |
@@ -753,15 +753,15 @@ Generate docker-compose and create table:
753
753
  "id": "abc-123",
754
754
  "model": "record",
755
755
  "name": "My Record",
756
- "ou": "@",
756
+ "scope": "@",
757
757
  "alias": "my-record",
758
758
  "class": "memory"
759
759
  }
760
760
 
761
- // dynamodb_query_ou
761
+ // dynamodb_query_scope
762
762
  {
763
763
  "model": "record",
764
- "ou": "@",
764
+ "scope": "@",
765
765
  "limit": 10
766
766
  }
767
767
 
@@ -407,50 +407,6 @@ expressHandler automatically sets these headers:
407
407
 
408
408
  When Datadog environment variables are configured, expressHandler automatically submits metrics for each request including status code and path.
409
409
 
410
- ## Server Creation
411
-
412
- Use `createServer` to quickly set up an Express server with standard Jaypie middleware.
413
-
414
- ### Basic Server Usage
415
-
416
- ```typescript
417
- import express from "express";
418
- import { createServer, expressHandler } from "jaypie";
419
-
420
- const app = express();
421
-
422
- app.get("/", expressHandler(async (req, res) => {
423
- return { message: "Hello World" };
424
- }));
425
-
426
- const { server, port } = await createServer(app);
427
- console.log(`Server running on port ${port}`);
428
- ```
429
-
430
- ### Server Options
431
-
432
- ```typescript
433
- import { createServer } from "jaypie";
434
- import type { CreateServerOptions } from "jaypie";
435
-
436
- const options: CreateServerOptions = {
437
- port: 3000, // Port to listen on (default: PORT env var or 8080)
438
- cors: { origin: "*" }, // CORS config (false to disable)
439
- jsonLimit: "10mb", // JSON body parser limit (default: "1mb")
440
- middleware: [myMiddleware], // Additional middleware to apply
441
- };
442
-
443
- const { server, port } = await createServer(app, options);
444
- ```
445
-
446
- ### Server Result
447
-
448
- ```typescript
449
- import type { ServerResult } from "jaypie";
450
-
451
- // { server: Server, port: number }
452
- ```
453
-
454
410
  ## Streaming Responses
455
411
 
456
412
  Use `expressStreamHandler` for Server-Sent Events (SSE) streaming responses. Ideal for real-time updates, LLM streaming, and long-running operations.
@@ -542,6 +498,107 @@ import type {
542
498
  } from "jaypie";
543
499
  ```
544
500
 
501
+ ## Lambda Handlers
502
+
503
+ Create Lambda handlers from Express apps using `createLambdaHandler` and `createLambdaStreamHandler`. These functions wrap Express applications to run directly on AWS Lambda Function URLs without requiring a separate Lambda adapter library.
504
+
505
+ ### Buffered Handler
506
+
507
+ Use `createLambdaHandler` for standard Lambda responses where the entire response is buffered before sending.
508
+
509
+ ```typescript
510
+ import express from "express";
511
+ import { createLambdaHandler, expressHandler } from "jaypie";
512
+
513
+ const app = express();
514
+
515
+ app.get("/", expressHandler(async (req, res) => {
516
+ return { message: "Hello from Lambda!" };
517
+ }));
518
+
519
+ // Export for Lambda Function URL
520
+ export const handler = createLambdaHandler(app);
521
+ ```
522
+
523
+ ### Streaming Handler
524
+
525
+ Use `createLambdaStreamHandler` for Lambda response streaming, ideal for Server-Sent Events (SSE) and real-time updates.
526
+
527
+ ```typescript
528
+ import express from "express";
529
+ import { createLambdaStreamHandler, expressStreamHandler } from "jaypie";
530
+
531
+ const app = express();
532
+
533
+ app.get("/stream", expressStreamHandler(async (req, res) => {
534
+ res.write("event: message\ndata: {\"text\": \"Hello\"}\n\n");
535
+ res.write("event: message\ndata: {\"text\": \"World\"}\n\n");
536
+ }));
537
+
538
+ // Export for Lambda Function URL with streaming
539
+ export const handler = createLambdaStreamHandler(app);
540
+ ```
541
+
542
+ ### Combined Usage
543
+
544
+ A typical Lambda Express application with both buffered and streaming endpoints:
545
+
546
+ ```typescript
547
+ import express from "express";
548
+ import {
549
+ createLambdaHandler,
550
+ createLambdaStreamHandler,
551
+ expressHandler,
552
+ expressStreamHandler,
553
+ cors,
554
+ } from "jaypie";
555
+
556
+ const app = express();
557
+ app.use(express.json());
558
+ app.use(cors());
559
+
560
+ // Standard buffered route
561
+ app.get("/api/data", expressHandler(async (req, res) => {
562
+ return { data: "buffered response" };
563
+ }));
564
+
565
+ // SSE streaming route
566
+ app.get("/api/stream", expressStreamHandler(async (req, res) => {
567
+ for (let i = 0; i < 5; i++) {
568
+ res.write(`event: update\ndata: {"count": ${i}}\n\n`);
569
+ }
570
+ }));
571
+
572
+ // Choose handler based on your needs
573
+ // For buffered: export const handler = createLambdaHandler(app);
574
+ // For streaming: export const handler = createLambdaStreamHandler(app);
575
+ export const handler = createLambdaHandler(app);
576
+ ```
577
+
578
+ ### Lambda Context Access
579
+
580
+ Both handlers expose Lambda context on the request object:
581
+
582
+ ```typescript
583
+ app.get("/", expressHandler(async (req, res) => {
584
+ // Access Lambda context directly on request
585
+ const awsRequestId = (req as any)._lambdaContext?.awsRequestId;
586
+ return { requestId: awsRequestId };
587
+ }));
588
+ ```
589
+
590
+ ### TypeScript Types
591
+
592
+ ```typescript
593
+ import type {
594
+ LambdaHandler,
595
+ LambdaStreamHandler,
596
+ LambdaContext,
597
+ FunctionUrlEvent,
598
+ LambdaResponse,
599
+ } from "jaypie";
600
+ ```
601
+
545
602
  ## Invoke UUID Detection
546
603
 
547
604
  Use `getCurrentInvokeUuid` to get the current request ID. Automatically detects the environment (Lambda, Lambda Web Adapter, or local development).