@stone-js/aws-lambda-http-adapter 0.2.0 → 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.
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2025 Stone.js
3
+ Copyright © 2026 Stone Foundation
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  [![npm](https://img.shields.io/npm/l/@stone-js/aws-lambda-http-adapter)](https://opensource.org/licenses/MIT)
4
4
  [![npm](https://img.shields.io/npm/v/@stone-js/aws-lambda-http-adapter)](https://www.npmjs.com/package/@stone-js/aws-lambda-http-adapter)
5
5
  [![npm](https://img.shields.io/npm/dm/@stone-js/aws-lambda-http-adapter)](https://www.npmjs.com/package/@stone-js/aws-lambda-http-adapter)
6
- ![Maintenance](https://img.shields.io/maintenance/yes/2025)
6
+ ![Maintenance](https://img.shields.io/maintenance/yes/2026)
7
7
  [![Build Status](https://github.com/stone-foundation/stone-js-aws-lambda-http-adapter/actions/workflows/main.yml/badge.svg)](https://github.com/stone-foundation/stone-js-aws-lambda-http-adapter/actions/workflows/main.yml)
8
8
  [![Publish Package to npmjs](https://github.com/stone-foundation/stone-js-aws-lambda-http-adapter/actions/workflows/release.yml/badge.svg)](https://github.com/stone-foundation/stone-js-aws-lambda-http-adapter/actions/workflows/release.yml)
9
9
  [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=stone-foundation_stone-js-aws-lambda-http-adapter&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=stone-foundation_stone-js-aws-lambda-http-adapter)
package/dist/browser.js CHANGED
@@ -19,6 +19,19 @@ class AwsLambdaHttpAdapterError extends IntegrationError {
19
19
  }
20
20
  }
21
21
 
22
+ /**
23
+ * Default blueprint configuration for the AWS Lambda Http Adapter.
24
+ *
25
+ * This blueprint defines the initial configuration for the AWS Lambda Http adapter
26
+ * within the Stone.js framework. It includes:
27
+ * - An alias for the AWS Lambda platform (`AWS_LAMBDA_HTTP_PLATFORM`).
28
+ * - A default resolver function (currently a placeholder).
29
+ * - Middleware, hooks, and state flags (`current`, `default`, `preferred`).
30
+ *
31
+ * NB: This is a stub for browser environments and does not perform any actual functionality in the browser.
32
+ */
33
+ const awsLambdaHttpAdapterBlueprint = { stone: { http: {}, adapters: [] } };
34
+
22
35
  /**
23
36
  * A Stone.js decorator that integrates the AWS Lambda HTTP Adapter with a class.
24
37
  *
@@ -52,17 +65,4 @@ const AwsLambdaHttp = (_options = {}) => {
52
65
  return classDecoratorLegacyWrapper((_target, _context) => { });
53
66
  };
54
67
 
55
- /**
56
- * Default blueprint configuration for the AWS Lambda Http Adapter.
57
- *
58
- * This blueprint defines the initial configuration for the AWS Lambda Http adapter
59
- * within the Stone.js framework. It includes:
60
- * - An alias for the AWS Lambda platform (`AWS_LAMBDA_HTTP_PLATFORM`).
61
- * - A default resolver function (currently a placeholder).
62
- * - Middleware, hooks, and state flags (`current`, `default`, `preferred`).
63
- *
64
- * NB: This is a stub for browser environments and does not perform any actual functionality in the browser.
65
- */
66
- const awsLambdaHttpAdapterBlueprint = { stone: { http: {}, adapters: [] } };
67
-
68
68
  export { AWS_LAMBDA_HTTP_PLATFORM, AwsLambdaHttp, AwsLambdaHttpAdapterError, awsLambdaHttpAdapterBlueprint };
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { IRawResponseWrapper, RawResponseOptions, AdapterContext, IAdapterEventBuilder, Adapter, IBlueprint, IAdapterErrorHandler, AdapterErrorContext, AdapterEventBuilderType, AdapterResolver, AdapterConfig, AppConfig, StoneBlueprint, ClassType, IntegrationError, ErrorOptions, BlueprintContext, NextMiddleware, MetaMiddleware } from '@stone-js/core';
1
+ import { IRawResponseWrapper, RawResponseOptions, AdapterContext, IAdapterEventBuilder, Adapter, IBlueprint, IAdapterErrorHandler, AdapterErrorContext, AdapterEventBuilderType, AdapterResolver, AdapterConfig, StoneBlueprint, AppConfig, ClassType, IntegrationError, ErrorOptions, BlueprintContext, NextMiddleware, MetaMiddleware } from '@stone-js/core';
2
2
  import { IncomingHttpEvent, IncomingHttpEventOptions, OutgoingHttpResponse, HttpConfig } from '@stone-js/http-core';
3
3
 
4
4
  /**
@@ -59,6 +59,16 @@ declare class RawHttpResponseWrapper implements IRawResponseWrapper<RawHttpRespo
59
59
  * ```
60
60
  */
61
61
  respond(): RawHttpResponse;
62
+ /**
63
+ * Normalizes the headers to a consistent format.
64
+ *
65
+ * Converts Headers or Record<string, string> to a normalized Record<string, string>
66
+ * with all keys in lowercase.
67
+ *
68
+ * @param headers - The headers to normalize.
69
+ * @returns A normalized record of headers.
70
+ */
71
+ private normalizeHeaders;
62
72
  }
63
73
 
64
74
  /**
@@ -451,6 +461,24 @@ declare class BodyEventMiddleware {
451
461
  * @throws {AwsLambdaHttpAdapterError} If the body parsing fails or is invalid.
452
462
  */
453
463
  private getBody;
464
+ /**
465
+ * Get the normalized raw body from the event.
466
+ *
467
+ * @param rawEvent - The raw event containing the body.
468
+ * @param encoding - The encoding to use for the body.
469
+ * @returns The normalized body as a string.
470
+ */
471
+ private getNormalizedRawBody;
472
+ /**
473
+ * Parse the body content based on the specified type and encoding.
474
+ *
475
+ * @param type - The content type of the body.
476
+ * @param body - The raw body content as a string.
477
+ * @param encoding - The encoding of the body content.
478
+ * @returns The parsed body content as an object, string, or Buffer.
479
+ * @throws {AwsLambdaHttpAdapterError} If parsing fails.
480
+ */
481
+ private parseBodyContent;
454
482
  }
455
483
  /**
456
484
  * Meta Middleware for processing the request body.
@@ -460,6 +488,50 @@ declare const MetaBodyEventMiddleware: {
460
488
  isClass: boolean;
461
489
  };
462
490
 
491
+ /**
492
+ * Class representing a FilesEventMiddleware.
493
+ *
494
+ * @author Mr. Stone <evensstone@gmail.com>
495
+ */
496
+ declare class FilesEventMiddleware {
497
+ /**
498
+ * The blueprint for resolving configuration and dependencies.
499
+ */
500
+ private readonly blueprint;
501
+ /**
502
+ * Create a FilesEventMiddleware.
503
+ *
504
+ * @param {blueprint} options - Options for creating the FilesEventMiddleware.
505
+ */
506
+ constructor({ blueprint }: {
507
+ blueprint: IBlueprint;
508
+ });
509
+ /**
510
+ * Handles the incoming event, processes it, and invokes the next middleware in the pipeline.
511
+ *
512
+ * @param context - The adapter context containing the raw event, execution context, and other data.
513
+ * @param next - The next middleware to be invoked in the pipeline.
514
+ * @returns A promise that resolves to the destination type after processing.
515
+ *
516
+ * @throws {AwsLambdaHttpAdapterError} If required components such as the rawEvent or IncomingEventBuilder are not provided.
517
+ */
518
+ handle(context: AwsLambdaHttpAdapterContext, next: NextMiddleware<AwsLambdaHttpAdapterContext, AwsLambdaHttpAdapterResponseBuilder>): Promise<AwsLambdaHttpAdapterResponseBuilder>;
519
+ /**
520
+ * Normalize the incoming event to an IncomingMessage.
521
+ *
522
+ * @param rawEvent - The raw event to be normalized.
523
+ * @returns The normalized event.
524
+ */
525
+ private normalizeEvent;
526
+ }
527
+ /**
528
+ * Meta Middleware for processing files uploads.
529
+ */
530
+ declare const MetaFilesEventMiddleware: {
531
+ module: typeof FilesEventMiddleware;
532
+ isClass: boolean;
533
+ };
534
+
463
535
  /**
464
536
  * Middleware for handling incoming events and transforming them into Stone.js events.
465
537
  *
@@ -567,50 +639,6 @@ declare const MetaIncomingEventMiddleware: {
567
639
  isClass: boolean;
568
640
  };
569
641
 
570
- /**
571
- * Class representing a FilesEventMiddleware.
572
- *
573
- * @author Mr. Stone <evensstone@gmail.com>
574
- */
575
- declare class FilesEventMiddleware {
576
- /**
577
- * The blueprint for resolving configuration and dependencies.
578
- */
579
- private readonly blueprint;
580
- /**
581
- * Create a FilesEventMiddleware.
582
- *
583
- * @param {blueprint} options - Options for creating the FilesEventMiddleware.
584
- */
585
- constructor({ blueprint }: {
586
- blueprint: IBlueprint;
587
- });
588
- /**
589
- * Handles the incoming event, processes it, and invokes the next middleware in the pipeline.
590
- *
591
- * @param context - The adapter context containing the raw event, execution context, and other data.
592
- * @param next - The next middleware to be invoked in the pipeline.
593
- * @returns A promise that resolves to the destination type after processing.
594
- *
595
- * @throws {AwsLambdaHttpAdapterError} If required components such as the rawEvent or IncomingEventBuilder are not provided.
596
- */
597
- handle(context: AwsLambdaHttpAdapterContext, next: NextMiddleware<AwsLambdaHttpAdapterContext, AwsLambdaHttpAdapterResponseBuilder>): Promise<AwsLambdaHttpAdapterResponseBuilder>;
598
- /**
599
- * Normalize the incoming event to an IncomingMessage.
600
- *
601
- * @param rawEvent - The raw event to be normalized.
602
- * @returns The normalized event.
603
- */
604
- private normalizeEvent;
605
- }
606
- /**
607
- * Meta Middleware for processing files uploads.
608
- */
609
- declare const MetaFilesEventMiddleware: {
610
- module: typeof FilesEventMiddleware;
611
- isClass: boolean;
612
- };
613
-
614
642
  /**
615
643
  * Middleware for handling server responses and transforming them into the appropriate HTTP responses.
616
644
  *
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { IntegrationError, Adapter, AdapterEventBuilder, defaultLoggerResolver, isNotEmpty, defaultKernelResolver, classDecoratorLegacyWrapper, addBlueprint } from '@stone-js/core';
2
- import { IncomingHttpEvent, HTTP_INTERNAL_SERVER_ERROR, BinaryFileResponse, OutgoingHttpResponse, CookieCollection, isIpTrusted, getHostname, getProtocol, httpCoreBlueprint, isMultipart, getCharset, getType, getFilesUploads } from '@stone-js/http-core';
1
+ import { IntegrationError, Adapter, AdapterEventBuilder, defaultLoggerResolver, defaultKernelResolver, isNotEmpty, classDecoratorLegacyWrapper, addBlueprint } from '@stone-js/core';
2
+ import { IncomingHttpEvent, HTTP_INTERNAL_SERVER_ERROR, BinaryFileResponse, OutgoingHttpResponse, CookieCollection, isIpTrusted, getHostname, getProtocol, httpCoreBlueprint, isMultipart, getCharset, getFilesUploads } from '@stone-js/http-core';
3
3
  import mime from 'mime';
4
4
  import accepts from 'accepts';
5
5
  import statuses from 'statuses';
@@ -73,9 +73,22 @@ class RawHttpResponseWrapper {
73
73
  respond() {
74
74
  return {
75
75
  ...this.options,
76
- statusCode: this.options.statusCode ?? 500
76
+ statusCode: this.options.statusCode ?? 500,
77
+ headers: this.normalizeHeaders(this.options.headers)
77
78
  };
78
79
  }
80
+ /**
81
+ * Normalizes the headers to a consistent format.
82
+ *
83
+ * Converts Headers or Record<string, string> to a normalized Record<string, string>
84
+ * with all keys in lowercase.
85
+ *
86
+ * @param headers - The headers to normalize.
87
+ * @returns A normalized record of headers.
88
+ */
89
+ normalizeHeaders(headers) {
90
+ return Object.fromEntries(new Headers(headers ?? {}));
91
+ }
79
92
  }
80
93
 
81
94
  /**
@@ -800,19 +813,58 @@ class BodyEventMiddleware {
800
813
  const { defaultType, defaultCharset, limit: rawLimit } = this.blueprint.get('stone.http.body', defaultOptions);
801
814
  const limit = bytes.parse(rawLimit) ?? 100000;
802
815
  const encoding = getCharset(message, defaultCharset);
803
- const type = getType(message, defaultType);
804
- if (typeIs.is(type, ['urlencoded', 'json', 'text', 'bin']) === false) {
805
- return {};
816
+ const type = typeIs(message, ['urlencoded', 'json', 'text', 'bin']) ?? defaultType;
817
+ const rawBodyContent = this.getNormalizedRawBody(rawEvent, encoding);
818
+ if (Buffer.byteLength(rawBodyContent, encoding) > limit) {
819
+ throw new AwsLambdaHttpAdapterError('Body payload exceeds configured limit.');
806
820
  }
807
- const stringifiedBody = typeof rawEvent.body === 'string'
808
- ? rawEvent.body
809
- : (typeof rawEvent.body === 'object' && rawEvent.body !== null
810
- ? JSON.stringify(rawEvent.body)
811
- : '');
812
- if (Buffer.byteLength(stringifiedBody, encoding) > limit) {
813
- throw new AwsLambdaHttpAdapterError('The context is missing required components.');
821
+ return this.parseBodyContent(type, rawBodyContent, encoding);
822
+ }
823
+ /**
824
+ * Get the normalized raw body from the event.
825
+ *
826
+ * @param rawEvent - The raw event containing the body.
827
+ * @param encoding - The encoding to use for the body.
828
+ * @returns The normalized body as a string.
829
+ */
830
+ getNormalizedRawBody(rawEvent, encoding) {
831
+ if (typeof rawEvent.body === 'string') {
832
+ return rawEvent.isBase64Encoded === true
833
+ ? Buffer.from(rawEvent.body, 'base64').toString(encoding)
834
+ : rawEvent.body;
835
+ }
836
+ if (typeof rawEvent.body === 'object' && rawEvent.body !== null) {
837
+ return JSON.stringify(rawEvent.body);
838
+ }
839
+ return '';
840
+ }
841
+ /**
842
+ * Parse the body content based on the specified type and encoding.
843
+ *
844
+ * @param type - The content type of the body.
845
+ * @param body - The raw body content as a string.
846
+ * @param encoding - The encoding of the body content.
847
+ * @returns The parsed body content as an object, string, or Buffer.
848
+ * @throws {AwsLambdaHttpAdapterError} If parsing fails.
849
+ */
850
+ parseBodyContent(type, body, encoding) {
851
+ try {
852
+ switch (type) {
853
+ case 'json':
854
+ return isNotEmpty(body) ? JSON.parse(body) : {};
855
+ case 'text':
856
+ return body;
857
+ case 'urlencoded':
858
+ return new URLSearchParams(body);
859
+ case 'bin':
860
+ return Buffer.from(body, encoding);
861
+ default:
862
+ return {};
863
+ }
864
+ }
865
+ catch (error) {
866
+ throw new AwsLambdaHttpAdapterError('Failed to parse request body.', { cause: error });
814
867
  }
815
- return rawEvent.body;
816
868
  }
817
869
  }
818
870
  /**
@@ -871,8 +923,14 @@ class FilesEventMiddleware {
871
923
  * @returns The normalized event.
872
924
  */
873
925
  normalizeEvent(rawEvent) {
926
+ let body = rawEvent.body;
927
+ if (typeof rawEvent.body === 'string') {
928
+ body = rawEvent.isBase64Encoded === true
929
+ ? Buffer.from(rawEvent.body, 'base64')
930
+ : Buffer.from(rawEvent.body, 'utf-8');
931
+ }
874
932
  return {
875
- body: rawEvent.body,
933
+ body,
876
934
  headers: {
877
935
  'content-type': rawEvent.headers['content-type'] ?? rawEvent.headers['Content-Type'],
878
936
  'content-length': rawEvent.headers['content-length'] ?? rawEvent.headers['Content-Length'],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stone-js/aws-lambda-http-adapter",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Official AWS Lambda HTTP adapter for Stone.js. Run your Stone.js apps on AWS Lambda behind API Gateway with full Continuum lifecycle support.",
5
5
  "author": "Mr. Stone <evensstone@gmail.com>",
6
6
  "license": "MIT",
@@ -71,7 +71,7 @@
71
71
  "accepts": "^1.3.8",
72
72
  "bytes": "^3.1.2",
73
73
  "content-type": "^1.0.5",
74
- "mime": "^4.0.7",
74
+ "mime": "^4.1.0",
75
75
  "proxy-addr": "^2.0.7",
76
76
  "statuses": "^2.0.1",
77
77
  "type-is": "^2.0.1"
@@ -82,27 +82,27 @@
82
82
  "@rollup/plugin-commonjs": "^28.0.2",
83
83
  "@rollup/plugin-multi-entry": "^6.0.1",
84
84
  "@rollup/plugin-node-resolve": "^15.2.3",
85
- "@rollup/plugin-typescript": "^12.1.1",
85
+ "@rollup/plugin-typescript": "^12.3.0",
86
86
  "@types/accepts": "^1.3.7",
87
87
  "@types/bytes": "^3.1.5",
88
88
  "@types/content-type": "^1.1.8",
89
- "@types/node": "^24.0.1",
89
+ "@types/node": "^24.9.2",
90
90
  "@types/proxy-addr": "^2.0.3",
91
91
  "@types/statuses": "^2.0.5",
92
92
  "@types/type-is": "^1.6.7",
93
- "@vitest/coverage-v8": "^3.2.3",
93
+ "@vitest/coverage-v8": "^3.2.4",
94
94
  "husky": "^9.1.7",
95
- "rimraf": "^6.0.1",
96
- "rollup": "^4.43.0",
95
+ "rimraf": "^6.1.0",
96
+ "rollup": "^4.52.5",
97
97
  "rollup-plugin-delete": "^3.0.1",
98
- "rollup-plugin-dts": "^6.2.1",
99
- "rollup-plugin-node-externals": "^8.0.0",
98
+ "rollup-plugin-dts": "^6.2.3",
99
+ "rollup-plugin-node-externals": "^8.1.1",
100
100
  "ts-standard": "^12.0.2",
101
101
  "tslib": "^2.8.1",
102
- "typedoc": "^0.28.5",
103
- "typedoc-plugin-markdown": "^4.6.4",
104
- "typescript": "^5.6.3",
105
- "vitest": "^3.2.3"
102
+ "typedoc": "^0.28.14",
103
+ "typedoc-plugin-markdown": "^4.9.0",
104
+ "typescript": "^5.9.3",
105
+ "vitest": "^3.2.4"
106
106
  },
107
107
  "ts-standard": {
108
108
  "globals": [