@stone-js/aws-lambda-http-adapter 0.2.0 → 0.3.1

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/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,13 +1,47 @@
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 { defaultLoggerResolver, IntegrationError, Adapter, AdapterEventBuilder, isNotEmpty, defaultKernelResolver, classDecoratorLegacyWrapper, addBlueprint } from '@stone-js/core';
3
2
  import mime from 'mime';
4
3
  import accepts from 'accepts';
5
4
  import statuses from 'statuses';
6
- import { getString } from '@stone-js/env';
5
+ import { HTTP_INTERNAL_SERVER_ERROR, IncomingHttpEvent, BinaryFileResponse, OutgoingHttpResponse, isMultipart, getFilesUploads, CookieCollection, isIpTrusted, getHostname, getProtocol, getCharset, httpCoreBlueprint } from '@stone-js/http-core';
7
6
  import { File } from '@stone-js/filesystem';
8
7
  import proxyAddr from 'proxy-addr';
9
8
  import bytes from 'bytes';
10
9
  import typeIs from 'type-is';
10
+ import { getString } from '@stone-js/env';
11
+
12
+ /**
13
+ * Class representing an AwsLambdaHttpErrorHandler.
14
+ */
15
+ class AwsLambdaHttpErrorHandler {
16
+ logger;
17
+ /**
18
+ * Create an NodeHttpErrorHandler.
19
+ *
20
+ * @param options - NodeHttpErrorHandler options.
21
+ */
22
+ constructor({ blueprint }) {
23
+ this.logger = blueprint.get('stone.logger.resolver', defaultLoggerResolver)(blueprint);
24
+ }
25
+ /**
26
+ * Handle an error.
27
+ *
28
+ * @param error - The error to handle.
29
+ * @param context - The context of the adapter.
30
+ * @returns The raw response builder.
31
+ */
32
+ handle(error, context) {
33
+ this.logger.error(error.message, { error });
34
+ const statusCode = error.cause?.status ?? HTTP_INTERNAL_SERVER_ERROR;
35
+ const type = accepts(context.rawEvent).type(['json', 'html']);
36
+ const contentType = mime.getType(type !== false ? type : 'txt') ?? context.rawEvent.headers['content-type'] ?? 'text/plain';
37
+ const headers = new Headers({ 'Content-Type': contentType });
38
+ return context
39
+ .rawResponseBuilder
40
+ .add('headers', headers)
41
+ .add('statusCode', statusCode)
42
+ .add('statusMessage', statuses.message[statusCode]);
43
+ }
44
+ }
11
45
 
12
46
  /**
13
47
  * Wrapper for HTTP raw responses in AWS Lambda.
@@ -73,9 +107,22 @@ class RawHttpResponseWrapper {
73
107
  respond() {
74
108
  return {
75
109
  ...this.options,
76
- statusCode: this.options.statusCode ?? 500
110
+ statusCode: this.options.statusCode ?? 500,
111
+ headers: this.normalizeHeaders(this.options.headers)
77
112
  };
78
113
  }
114
+ /**
115
+ * Normalizes the headers to a consistent format.
116
+ *
117
+ * Converts Headers or Record<string, string> to a normalized Record<string, string>
118
+ * with all keys in lowercase.
119
+ *
120
+ * @param headers - The headers to normalize.
121
+ * @returns A normalized record of headers.
122
+ */
123
+ normalizeHeaders(headers) {
124
+ return Object.fromEntries(new Headers(headers ?? {}));
125
+ }
79
126
  }
80
127
 
81
128
  /**
@@ -208,40 +255,6 @@ class AwsLambdaHttpAdapter extends Adapter {
208
255
  }
209
256
  }
210
257
 
211
- /**
212
- * Class representing an AwsLambdaHttpErrorHandler.
213
- */
214
- class AwsLambdaHttpErrorHandler {
215
- logger;
216
- /**
217
- * Create an NodeHttpErrorHandler.
218
- *
219
- * @param options - NodeHttpErrorHandler options.
220
- */
221
- constructor({ blueprint }) {
222
- this.logger = blueprint.get('stone.logger.resolver', defaultLoggerResolver)(blueprint);
223
- }
224
- /**
225
- * Handle an error.
226
- *
227
- * @param error - The error to handle.
228
- * @param context - The context of the adapter.
229
- * @returns The raw response builder.
230
- */
231
- handle(error, context) {
232
- this.logger.error(error.message, { error });
233
- const statusCode = error.cause?.status ?? HTTP_INTERNAL_SERVER_ERROR;
234
- const type = accepts(context.rawEvent).type(['json', 'html']);
235
- const contentType = mime.getType(type !== false ? type : 'txt') ?? context.rawEvent.headers['content-type'] ?? 'text/plain';
236
- const headers = new Headers({ 'Content-Type': contentType });
237
- return context
238
- .rawResponseBuilder
239
- .add('headers', headers)
240
- .add('statusCode', statusCode)
241
- .add('statusMessage', statuses.message[statusCode]);
242
- }
243
- }
244
-
245
258
  /**
246
259
  * A constant representing the AWS Lambda HTTP platform identifier.
247
260
  *
@@ -263,154 +276,6 @@ const awsLambdaHttpAdapterResolver = (blueprint) => {
263
276
  return AwsLambdaHttpAdapter.create(blueprint);
264
277
  };
265
278
 
266
- function getDefaultExportFromCjs (x) {
267
- return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
268
- }
269
-
270
- var cjs;
271
- var hasRequiredCjs;
272
-
273
- function requireCjs () {
274
- if (hasRequiredCjs) return cjs;
275
- hasRequiredCjs = 1;
276
-
277
- var isMergeableObject = function isMergeableObject(value) {
278
- return isNonNullObject(value)
279
- && !isSpecial(value)
280
- };
281
-
282
- function isNonNullObject(value) {
283
- return !!value && typeof value === 'object'
284
- }
285
-
286
- function isSpecial(value) {
287
- var stringValue = Object.prototype.toString.call(value);
288
-
289
- return stringValue === '[object RegExp]'
290
- || stringValue === '[object Date]'
291
- || isReactElement(value)
292
- }
293
-
294
- // see https://github.com/facebook/react/blob/b5ac963fb791d1298e7f396236383bc955f916c1/src/isomorphic/classic/element/ReactElement.js#L21-L25
295
- var canUseSymbol = typeof Symbol === 'function' && Symbol.for;
296
- var REACT_ELEMENT_TYPE = canUseSymbol ? Symbol.for('react.element') : 0xeac7;
297
-
298
- function isReactElement(value) {
299
- return value.$$typeof === REACT_ELEMENT_TYPE
300
- }
301
-
302
- function emptyTarget(val) {
303
- return Array.isArray(val) ? [] : {}
304
- }
305
-
306
- function cloneUnlessOtherwiseSpecified(value, options) {
307
- return (options.clone !== false && options.isMergeableObject(value))
308
- ? deepmerge(emptyTarget(value), value, options)
309
- : value
310
- }
311
-
312
- function defaultArrayMerge(target, source, options) {
313
- return target.concat(source).map(function(element) {
314
- return cloneUnlessOtherwiseSpecified(element, options)
315
- })
316
- }
317
-
318
- function getMergeFunction(key, options) {
319
- if (!options.customMerge) {
320
- return deepmerge
321
- }
322
- var customMerge = options.customMerge(key);
323
- return typeof customMerge === 'function' ? customMerge : deepmerge
324
- }
325
-
326
- function getEnumerableOwnPropertySymbols(target) {
327
- return Object.getOwnPropertySymbols
328
- ? Object.getOwnPropertySymbols(target).filter(function(symbol) {
329
- return Object.propertyIsEnumerable.call(target, symbol)
330
- })
331
- : []
332
- }
333
-
334
- function getKeys(target) {
335
- return Object.keys(target).concat(getEnumerableOwnPropertySymbols(target))
336
- }
337
-
338
- function propertyIsOnObject(object, property) {
339
- try {
340
- return property in object
341
- } catch(_) {
342
- return false
343
- }
344
- }
345
-
346
- // Protects from prototype poisoning and unexpected merging up the prototype chain.
347
- function propertyIsUnsafe(target, key) {
348
- return propertyIsOnObject(target, key) // Properties are safe to merge if they don't exist in the target yet,
349
- && !(Object.hasOwnProperty.call(target, key) // unsafe if they exist up the prototype chain,
350
- && Object.propertyIsEnumerable.call(target, key)) // and also unsafe if they're nonenumerable.
351
- }
352
-
353
- function mergeObject(target, source, options) {
354
- var destination = {};
355
- if (options.isMergeableObject(target)) {
356
- getKeys(target).forEach(function(key) {
357
- destination[key] = cloneUnlessOtherwiseSpecified(target[key], options);
358
- });
359
- }
360
- getKeys(source).forEach(function(key) {
361
- if (propertyIsUnsafe(target, key)) {
362
- return
363
- }
364
-
365
- if (propertyIsOnObject(target, key) && options.isMergeableObject(source[key])) {
366
- destination[key] = getMergeFunction(key, options)(target[key], source[key], options);
367
- } else {
368
- destination[key] = cloneUnlessOtherwiseSpecified(source[key], options);
369
- }
370
- });
371
- return destination
372
- }
373
-
374
- function deepmerge(target, source, options) {
375
- options = options || {};
376
- options.arrayMerge = options.arrayMerge || defaultArrayMerge;
377
- options.isMergeableObject = options.isMergeableObject || isMergeableObject;
378
- // cloneUnlessOtherwiseSpecified is added to `options` so that custom arrayMerge()
379
- // implementations can use it. The caller may not replace it.
380
- options.cloneUnlessOtherwiseSpecified = cloneUnlessOtherwiseSpecified;
381
-
382
- var sourceIsArray = Array.isArray(source);
383
- var targetIsArray = Array.isArray(target);
384
- var sourceAndTargetTypesMatch = sourceIsArray === targetIsArray;
385
-
386
- if (!sourceAndTargetTypesMatch) {
387
- return cloneUnlessOtherwiseSpecified(source, options)
388
- } else if (sourceIsArray) {
389
- return options.arrayMerge(target, source, options)
390
- } else {
391
- return mergeObject(target, source, options)
392
- }
393
- }
394
-
395
- deepmerge.all = function deepmergeAll(array, options) {
396
- if (!Array.isArray(array)) {
397
- throw new Error('first argument should be an array')
398
- }
399
-
400
- return array.reduce(function(prev, next) {
401
- return deepmerge(prev, next, options)
402
- }, {})
403
- };
404
-
405
- var deepmerge_1 = deepmerge;
406
-
407
- cjs = deepmerge_1;
408
- return cjs;
409
- }
410
-
411
- var cjsExports = requireCjs();
412
- var deepmerge = /*@__PURE__*/getDefaultExportFromCjs(cjsExports);
413
-
414
279
  /**
415
280
  * Middleware to dynamically set response resolver for adapter.
416
281
  *
@@ -444,20 +309,19 @@ const metaAdapterBlueprintMiddleware = [
444
309
  ];
445
310
 
446
311
  /**
447
- * Middleware for handling incoming events and transforming them into Stone.js events.
312
+ * Class representing a FilesEventMiddleware.
448
313
  *
449
- * This class processes incoming HTTP requests, extracting relevant data such as URL, IP addresses,
450
- * headers, cookies, and more, and forwards them to the next middleware in the pipeline.
314
+ * @author Mr. Stone <evensstone@gmail.com>
451
315
  */
452
- class IncomingEventMiddleware {
316
+ class FilesEventMiddleware {
453
317
  /**
454
318
  * The blueprint for resolving configuration and dependencies.
455
319
  */
456
320
  blueprint;
457
321
  /**
458
- * Create an IncomingEventMiddleware instance.
322
+ * Create a FilesEventMiddleware.
459
323
  *
460
- * @param {blueprint} options - Options containing the blueprint for resolving configuration and dependencies.
324
+ * @param {blueprint} options - Options for creating the FilesEventMiddleware.
461
325
  */
462
326
  constructor({ blueprint }) {
463
327
  this.blueprint = blueprint;
@@ -467,28 +331,101 @@ class IncomingEventMiddleware {
467
331
  *
468
332
  * @param context - The adapter context containing the raw event, execution context, and other data.
469
333
  * @param next - The next middleware to be invoked in the pipeline.
470
- * @returns A promise that resolves to the processed context.
471
- * @throws {AwsLambdaHttpAdapterError} If required components are missing in the context.
334
+ * @returns A promise that resolves to the destination type after processing.
335
+ *
336
+ * @throws {AwsLambdaHttpAdapterError} If required components such as the rawEvent or IncomingEventBuilder are not provided.
472
337
  */
473
338
  async handle(context, next) {
474
- if ((context.rawEvent === undefined) || ((context.incomingEventBuilder?.add) === undefined)) {
339
+ if (context.rawEvent === undefined || context.incomingEventBuilder?.add === undefined) {
475
340
  throw new AwsLambdaHttpAdapterError('The context is missing required components.');
476
341
  }
477
- const proxyOptions = this.getProxyOptions();
478
- const cookieOptions = this.getCookieOptions();
479
- const url = this.extractUrl(context.rawEvent, proxyOptions);
480
- const ipAddresses = this.extractIpAddresses(context.rawEvent, proxyOptions);
481
- context
482
- .incomingEventBuilder
483
- .add('url', url)
484
- .add('ips', ipAddresses)
485
- .add('source', this.getSource(context))
486
- .add('headers', context.rawEvent.headers)
487
- // If not defined by other middleware
488
- // In fullstack forms, the method is spoofed and sent as a hidden field
489
- .addIf('method', this.getMethod(context.rawEvent))
490
- .add('queryString', context.rawEvent.queryStringParameters)
491
- .add('protocol', this.getProtocol(context.rawEvent, proxyOptions))
342
+ if (isMultipart(this.normalizeEvent(context.rawEvent))) {
343
+ const options = this.blueprint.get('stone.http.files.upload', {});
344
+ const response = await getFilesUploads(this.normalizeEvent(context.rawEvent), options);
345
+ const method = response.fields.$method$;
346
+ context
347
+ .incomingEventBuilder
348
+ .add('files', response.files)
349
+ .add('body', response.fields);
350
+ // In fullstack forms, the method is spoofed and sent as a hidden field
351
+ isNotEmpty(method) && context.incomingEventBuilder.add('method', method);
352
+ }
353
+ return await next(context);
354
+ }
355
+ /**
356
+ * Normalize the incoming event to an IncomingMessage.
357
+ *
358
+ * @param rawEvent - The raw event to be normalized.
359
+ * @returns The normalized event.
360
+ */
361
+ normalizeEvent(rawEvent) {
362
+ let body = rawEvent.body;
363
+ if (typeof rawEvent.body === 'string') {
364
+ body = rawEvent.isBase64Encoded === true
365
+ ? Buffer.from(rawEvent.body, 'base64')
366
+ : Buffer.from(rawEvent.body, 'utf-8');
367
+ }
368
+ return {
369
+ body,
370
+ headers: {
371
+ 'content-type': rawEvent.headers['content-type'] ?? rawEvent.headers['Content-Type'],
372
+ 'content-length': rawEvent.headers['content-length'] ?? rawEvent.headers['Content-Length'],
373
+ 'transfer-encoding': rawEvent.headers['transfer-encoding'] ?? rawEvent.headers['Transfer-Encoding']
374
+ }
375
+ };
376
+ }
377
+ }
378
+ /**
379
+ * Meta Middleware for processing files uploads.
380
+ */
381
+ const MetaFilesEventMiddleware = { module: FilesEventMiddleware, isClass: true };
382
+
383
+ /**
384
+ * Middleware for handling incoming events and transforming them into Stone.js events.
385
+ *
386
+ * This class processes incoming HTTP requests, extracting relevant data such as URL, IP addresses,
387
+ * headers, cookies, and more, and forwards them to the next middleware in the pipeline.
388
+ */
389
+ class IncomingEventMiddleware {
390
+ /**
391
+ * The blueprint for resolving configuration and dependencies.
392
+ */
393
+ blueprint;
394
+ /**
395
+ * Create an IncomingEventMiddleware instance.
396
+ *
397
+ * @param {blueprint} options - Options containing the blueprint for resolving configuration and dependencies.
398
+ */
399
+ constructor({ blueprint }) {
400
+ this.blueprint = blueprint;
401
+ }
402
+ /**
403
+ * Handles the incoming event, processes it, and invokes the next middleware in the pipeline.
404
+ *
405
+ * @param context - The adapter context containing the raw event, execution context, and other data.
406
+ * @param next - The next middleware to be invoked in the pipeline.
407
+ * @returns A promise that resolves to the processed context.
408
+ * @throws {AwsLambdaHttpAdapterError} If required components are missing in the context.
409
+ */
410
+ async handle(context, next) {
411
+ if ((context.rawEvent === undefined) || ((context.incomingEventBuilder?.add) === undefined)) {
412
+ throw new AwsLambdaHttpAdapterError('The context is missing required components.');
413
+ }
414
+ const proxyOptions = this.getProxyOptions();
415
+ const cookieOptions = this.getCookieOptions();
416
+ const url = this.extractUrl(context.rawEvent, proxyOptions);
417
+ const ipAddresses = this.extractIpAddresses(context.rawEvent, proxyOptions);
418
+ context
419
+ .incomingEventBuilder
420
+ .add('url', url)
421
+ .add('ips', ipAddresses)
422
+ .add('source', this.getSource(context))
423
+ .add('headers', context.rawEvent.headers)
424
+ // If not defined by other middleware
425
+ // In fullstack forms, the method is spoofed and sent as a hidden field
426
+ .addIf('method', this.getMethod(context.rawEvent))
427
+ .add('queryString', context.rawEvent.queryStringParameters)
428
+ .add('protocol', this.getProtocol(context.rawEvent, proxyOptions))
492
429
  .add('cookies', CookieCollection.create(context.rawEvent.headers.cookie, cookieOptions, this.getCookieSecret()))
493
430
  .add('ip', proxyAddr(this.toNodeMessage(context.rawEvent), isIpTrusted(proxyOptions.trustedIp, proxyOptions.untrustedIp)));
494
431
  return await next(context);
@@ -654,77 +591,6 @@ class ServerResponseMiddleware {
654
591
  */
655
592
  const MetaServerResponseMiddleware = { module: ServerResponseMiddleware, isClass: true };
656
593
 
657
- /**
658
- * Default blueprint configuration for the AWS Lambda Http Adapter.
659
- *
660
- * This blueprint defines the initial configuration for the AWS Lambda Http adapter
661
- * within the Stone.js framework. It includes:
662
- * - An alias for the AWS Lambda platform (`AWS_LAMBDA_HTTP_PLATFORM`).
663
- * - A default resolver function (currently a placeholder).
664
- * - Middleware, hooks, and state flags (`current`, `default`, `preferred`).
665
- */
666
- const awsLambdaHttpAdapterBlueprint = {
667
- stone: {
668
- ...httpCoreBlueprint.stone,
669
- blueprint: {
670
- middleware: metaAdapterBlueprintMiddleware
671
- },
672
- adapters: [
673
- {
674
- current: false,
675
- variant: 'server',
676
- platform: AWS_LAMBDA_HTTP_PLATFORM,
677
- middleware: [
678
- MetaIncomingEventMiddleware,
679
- MetaServerResponseMiddleware
680
- ],
681
- resolver: awsLambdaHttpAdapterResolver,
682
- eventHandlerResolver: defaultKernelResolver,
683
- errorHandlers: {
684
- default: { module: AwsLambdaHttpErrorHandler, isClass: true }
685
- },
686
- default: isNotEmpty(getString('AWS_LAMBDA_FUNCTION_NAME', ''))
687
- }
688
- ]
689
- }
690
- };
691
-
692
- /**
693
- * A Stone.js decorator that integrates the AWS Lambda HTTP Adapter with a class.
694
- *
695
- * This decorator modifies the class to seamlessly enable AWS Lambda HTTP as the
696
- * execution environment for a Stone.js application. By applying this decorator,
697
- * the class is automatically configured with the necessary blueprint for AWS Lambda HTTP.
698
- *
699
- * @template T - The type of the class being decorated. Defaults to `ClassType`.
700
- * @param options - Optional configuration to customize the AWS Lambda HTTP Adapter.
701
- *
702
- * @returns A class decorator that applies the AWS Lambda HTTP adapter configuration.
703
- *
704
- * @example
705
- * ```typescript
706
- * import { AwsLambdaHttp } from '@stone-js/aws-lambda-http-adapter';
707
- *
708
- * @AwsLambdaHttp({
709
- * alias: 'MyAwsLambdaHttpAdapter',
710
- * current: true,
711
- * })
712
- * class App {
713
- * // Your application logic here
714
- * }
715
- * ```
716
- */
717
- const AwsLambdaHttp = (options = {}) => {
718
- return classDecoratorLegacyWrapper((target, context) => {
719
- if (awsLambdaHttpAdapterBlueprint.stone?.adapters?.[0] !== undefined) {
720
- // Merge provided options with the default AWS Lambda HTTP adapter blueprint.
721
- awsLambdaHttpAdapterBlueprint.stone.adapters[0] = deepmerge(awsLambdaHttpAdapterBlueprint.stone.adapters[0], options);
722
- }
723
- // Add the modified blueprint to the target class.
724
- addBlueprint(target, context, awsLambdaHttpAdapterBlueprint);
725
- });
726
- };
727
-
728
594
  /**
729
595
  * Class representing a BodyEventMiddleware.
730
596
  *
@@ -800,90 +666,282 @@ class BodyEventMiddleware {
800
666
  const { defaultType, defaultCharset, limit: rawLimit } = this.blueprint.get('stone.http.body', defaultOptions);
801
667
  const limit = bytes.parse(rawLimit) ?? 100000;
802
668
  const encoding = getCharset(message, defaultCharset);
803
- const type = getType(message, defaultType);
804
- if (typeIs.is(type, ['urlencoded', 'json', 'text', 'bin']) === false) {
805
- return {};
806
- }
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.');
669
+ const type = typeIs(message, ['urlencoded', 'json', 'text', 'bin']) ?? defaultType;
670
+ const rawBodyContent = this.getNormalizedRawBody(rawEvent, encoding);
671
+ if (Buffer.byteLength(rawBodyContent, encoding) > limit) {
672
+ throw new AwsLambdaHttpAdapterError('Body payload exceeds configured limit.');
814
673
  }
815
- return rawEvent.body;
674
+ return this.parseBodyContent(type, rawBodyContent, encoding);
816
675
  }
817
- }
818
- /**
819
- * Meta Middleware for processing the request body.
820
- */
821
- const MetaBodyEventMiddleware = { module: BodyEventMiddleware, isClass: true };
822
-
823
- /**
824
- * Class representing a FilesEventMiddleware.
825
- *
826
- * @author Mr. Stone <evensstone@gmail.com>
827
- */
828
- class FilesEventMiddleware {
829
- /**
830
- * The blueprint for resolving configuration and dependencies.
831
- */
832
- blueprint;
833
676
  /**
834
- * Create a FilesEventMiddleware.
677
+ * Get the normalized raw body from the event.
835
678
  *
836
- * @param {blueprint} options - Options for creating the FilesEventMiddleware.
679
+ * @param rawEvent - The raw event containing the body.
680
+ * @param encoding - The encoding to use for the body.
681
+ * @returns The normalized body as a string.
837
682
  */
838
- constructor({ blueprint }) {
839
- this.blueprint = blueprint;
840
- }
841
- /**
842
- * Handles the incoming event, processes it, and invokes the next middleware in the pipeline.
843
- *
844
- * @param context - The adapter context containing the raw event, execution context, and other data.
845
- * @param next - The next middleware to be invoked in the pipeline.
846
- * @returns A promise that resolves to the destination type after processing.
847
- *
848
- * @throws {AwsLambdaHttpAdapterError} If required components such as the rawEvent or IncomingEventBuilder are not provided.
849
- */
850
- async handle(context, next) {
851
- if (context.rawEvent === undefined || context.incomingEventBuilder?.add === undefined) {
852
- throw new AwsLambdaHttpAdapterError('The context is missing required components.');
683
+ getNormalizedRawBody(rawEvent, encoding) {
684
+ if (typeof rawEvent.body === 'string') {
685
+ return rawEvent.isBase64Encoded === true
686
+ ? Buffer.from(rawEvent.body, 'base64').toString(encoding)
687
+ : rawEvent.body;
853
688
  }
854
- if (isMultipart(this.normalizeEvent(context.rawEvent))) {
855
- const options = this.blueprint.get('stone.http.files.upload', {});
856
- const response = await getFilesUploads(this.normalizeEvent(context.rawEvent), options);
857
- const method = response.fields.$method$;
858
- context
859
- .incomingEventBuilder
860
- .add('files', response.files)
861
- .add('body', response.fields);
862
- // In fullstack forms, the method is spoofed and sent as a hidden field
863
- isNotEmpty(method) && context.incomingEventBuilder.add('method', method);
689
+ if (typeof rawEvent.body === 'object' && rawEvent.body !== null) {
690
+ return JSON.stringify(rawEvent.body);
864
691
  }
865
- return await next(context);
692
+ return '';
866
693
  }
867
694
  /**
868
- * Normalize the incoming event to an IncomingMessage.
695
+ * Parse the body content based on the specified type and encoding.
869
696
  *
870
- * @param rawEvent - The raw event to be normalized.
871
- * @returns The normalized event.
697
+ * @param type - The content type of the body.
698
+ * @param body - The raw body content as a string.
699
+ * @param encoding - The encoding of the body content.
700
+ * @returns The parsed body content as an object, string, or Buffer.
701
+ * @throws {AwsLambdaHttpAdapterError} If parsing fails.
872
702
  */
873
- normalizeEvent(rawEvent) {
874
- return {
875
- body: rawEvent.body,
876
- headers: {
877
- 'content-type': rawEvent.headers['content-type'] ?? rawEvent.headers['Content-Type'],
878
- 'content-length': rawEvent.headers['content-length'] ?? rawEvent.headers['Content-Length'],
879
- 'transfer-encoding': rawEvent.headers['transfer-encoding'] ?? rawEvent.headers['Transfer-Encoding']
703
+ parseBodyContent(type, body, encoding) {
704
+ try {
705
+ switch (type) {
706
+ case 'json':
707
+ return isNotEmpty(body) ? JSON.parse(body) : {};
708
+ case 'text':
709
+ return body;
710
+ case 'urlencoded':
711
+ return new URLSearchParams(body);
712
+ case 'bin':
713
+ return Buffer.from(body, encoding);
714
+ default:
715
+ return {};
880
716
  }
881
- };
717
+ }
718
+ catch (error) {
719
+ throw new AwsLambdaHttpAdapterError('Failed to parse request body.', { cause: error });
720
+ }
882
721
  }
883
722
  }
884
723
  /**
885
- * Meta Middleware for processing files uploads.
724
+ * Meta Middleware for processing the request body.
886
725
  */
887
- const MetaFilesEventMiddleware = { module: FilesEventMiddleware, isClass: true };
726
+ const MetaBodyEventMiddleware = { module: BodyEventMiddleware, isClass: true };
727
+
728
+ function getDefaultExportFromCjs (x) {
729
+ return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
730
+ }
731
+
732
+ var cjs;
733
+ var hasRequiredCjs;
734
+
735
+ function requireCjs () {
736
+ if (hasRequiredCjs) return cjs;
737
+ hasRequiredCjs = 1;
738
+
739
+ var isMergeableObject = function isMergeableObject(value) {
740
+ return isNonNullObject(value)
741
+ && !isSpecial(value)
742
+ };
743
+
744
+ function isNonNullObject(value) {
745
+ return !!value && typeof value === 'object'
746
+ }
747
+
748
+ function isSpecial(value) {
749
+ var stringValue = Object.prototype.toString.call(value);
750
+
751
+ return stringValue === '[object RegExp]'
752
+ || stringValue === '[object Date]'
753
+ || isReactElement(value)
754
+ }
755
+
756
+ // see https://github.com/facebook/react/blob/b5ac963fb791d1298e7f396236383bc955f916c1/src/isomorphic/classic/element/ReactElement.js#L21-L25
757
+ var canUseSymbol = typeof Symbol === 'function' && Symbol.for;
758
+ var REACT_ELEMENT_TYPE = canUseSymbol ? Symbol.for('react.element') : 0xeac7;
759
+
760
+ function isReactElement(value) {
761
+ return value.$$typeof === REACT_ELEMENT_TYPE
762
+ }
763
+
764
+ function emptyTarget(val) {
765
+ return Array.isArray(val) ? [] : {}
766
+ }
767
+
768
+ function cloneUnlessOtherwiseSpecified(value, options) {
769
+ return (options.clone !== false && options.isMergeableObject(value))
770
+ ? deepmerge(emptyTarget(value), value, options)
771
+ : value
772
+ }
773
+
774
+ function defaultArrayMerge(target, source, options) {
775
+ return target.concat(source).map(function(element) {
776
+ return cloneUnlessOtherwiseSpecified(element, options)
777
+ })
778
+ }
779
+
780
+ function getMergeFunction(key, options) {
781
+ if (!options.customMerge) {
782
+ return deepmerge
783
+ }
784
+ var customMerge = options.customMerge(key);
785
+ return typeof customMerge === 'function' ? customMerge : deepmerge
786
+ }
787
+
788
+ function getEnumerableOwnPropertySymbols(target) {
789
+ return Object.getOwnPropertySymbols
790
+ ? Object.getOwnPropertySymbols(target).filter(function(symbol) {
791
+ return Object.propertyIsEnumerable.call(target, symbol)
792
+ })
793
+ : []
794
+ }
795
+
796
+ function getKeys(target) {
797
+ return Object.keys(target).concat(getEnumerableOwnPropertySymbols(target))
798
+ }
799
+
800
+ function propertyIsOnObject(object, property) {
801
+ try {
802
+ return property in object
803
+ } catch(_) {
804
+ return false
805
+ }
806
+ }
807
+
808
+ // Protects from prototype poisoning and unexpected merging up the prototype chain.
809
+ function propertyIsUnsafe(target, key) {
810
+ return propertyIsOnObject(target, key) // Properties are safe to merge if they don't exist in the target yet,
811
+ && !(Object.hasOwnProperty.call(target, key) // unsafe if they exist up the prototype chain,
812
+ && Object.propertyIsEnumerable.call(target, key)) // and also unsafe if they're nonenumerable.
813
+ }
814
+
815
+ function mergeObject(target, source, options) {
816
+ var destination = {};
817
+ if (options.isMergeableObject(target)) {
818
+ getKeys(target).forEach(function(key) {
819
+ destination[key] = cloneUnlessOtherwiseSpecified(target[key], options);
820
+ });
821
+ }
822
+ getKeys(source).forEach(function(key) {
823
+ if (propertyIsUnsafe(target, key)) {
824
+ return
825
+ }
826
+
827
+ if (propertyIsOnObject(target, key) && options.isMergeableObject(source[key])) {
828
+ destination[key] = getMergeFunction(key, options)(target[key], source[key], options);
829
+ } else {
830
+ destination[key] = cloneUnlessOtherwiseSpecified(source[key], options);
831
+ }
832
+ });
833
+ return destination
834
+ }
835
+
836
+ function deepmerge(target, source, options) {
837
+ options = options || {};
838
+ options.arrayMerge = options.arrayMerge || defaultArrayMerge;
839
+ options.isMergeableObject = options.isMergeableObject || isMergeableObject;
840
+ // cloneUnlessOtherwiseSpecified is added to `options` so that custom arrayMerge()
841
+ // implementations can use it. The caller may not replace it.
842
+ options.cloneUnlessOtherwiseSpecified = cloneUnlessOtherwiseSpecified;
843
+
844
+ var sourceIsArray = Array.isArray(source);
845
+ var targetIsArray = Array.isArray(target);
846
+ var sourceAndTargetTypesMatch = sourceIsArray === targetIsArray;
847
+
848
+ if (!sourceAndTargetTypesMatch) {
849
+ return cloneUnlessOtherwiseSpecified(source, options)
850
+ } else if (sourceIsArray) {
851
+ return options.arrayMerge(target, source, options)
852
+ } else {
853
+ return mergeObject(target, source, options)
854
+ }
855
+ }
856
+
857
+ deepmerge.all = function deepmergeAll(array, options) {
858
+ if (!Array.isArray(array)) {
859
+ throw new Error('first argument should be an array')
860
+ }
861
+
862
+ return array.reduce(function(prev, next) {
863
+ return deepmerge(prev, next, options)
864
+ }, {})
865
+ };
866
+
867
+ var deepmerge_1 = deepmerge;
868
+
869
+ cjs = deepmerge_1;
870
+ return cjs;
871
+ }
872
+
873
+ var cjsExports = requireCjs();
874
+ var deepmerge = /*@__PURE__*/getDefaultExportFromCjs(cjsExports);
875
+
876
+ /**
877
+ * Default blueprint configuration for the AWS Lambda Http Adapter.
878
+ *
879
+ * This blueprint defines the initial configuration for the AWS Lambda Http adapter
880
+ * within the Stone.js framework. It includes:
881
+ * - An alias for the AWS Lambda platform (`AWS_LAMBDA_HTTP_PLATFORM`).
882
+ * - A default resolver function (currently a placeholder).
883
+ * - Middleware, hooks, and state flags (`current`, `default`, `preferred`).
884
+ */
885
+ const awsLambdaHttpAdapterBlueprint = {
886
+ stone: {
887
+ ...httpCoreBlueprint.stone,
888
+ blueprint: {
889
+ middleware: metaAdapterBlueprintMiddleware
890
+ },
891
+ adapters: [
892
+ {
893
+ current: false,
894
+ variant: 'server',
895
+ platform: AWS_LAMBDA_HTTP_PLATFORM,
896
+ middleware: [
897
+ MetaIncomingEventMiddleware,
898
+ MetaServerResponseMiddleware
899
+ ],
900
+ resolver: awsLambdaHttpAdapterResolver,
901
+ eventHandlerResolver: defaultKernelResolver,
902
+ errorHandlers: {
903
+ default: { module: AwsLambdaHttpErrorHandler, isClass: true }
904
+ },
905
+ default: isNotEmpty(getString('AWS_LAMBDA_FUNCTION_NAME', ''))
906
+ }
907
+ ]
908
+ }
909
+ };
910
+
911
+ /**
912
+ * A Stone.js decorator that integrates the AWS Lambda HTTP Adapter with a class.
913
+ *
914
+ * This decorator modifies the class to seamlessly enable AWS Lambda HTTP as the
915
+ * execution environment for a Stone.js application. By applying this decorator,
916
+ * the class is automatically configured with the necessary blueprint for AWS Lambda HTTP.
917
+ *
918
+ * @template T - The type of the class being decorated. Defaults to `ClassType`.
919
+ * @param options - Optional configuration to customize the AWS Lambda HTTP Adapter.
920
+ *
921
+ * @returns A class decorator that applies the AWS Lambda HTTP adapter configuration.
922
+ *
923
+ * @example
924
+ * ```typescript
925
+ * import { AwsLambdaHttp } from '@stone-js/aws-lambda-http-adapter';
926
+ *
927
+ * @AwsLambdaHttp({
928
+ * alias: 'MyAwsLambdaHttpAdapter',
929
+ * current: true,
930
+ * })
931
+ * class App {
932
+ * // Your application logic here
933
+ * }
934
+ * ```
935
+ */
936
+ const AwsLambdaHttp = (options = {}) => {
937
+ return classDecoratorLegacyWrapper((target, context) => {
938
+ if (awsLambdaHttpAdapterBlueprint.stone?.adapters?.[0] !== undefined) {
939
+ // Merge provided options with the default AWS Lambda HTTP adapter blueprint.
940
+ awsLambdaHttpAdapterBlueprint.stone.adapters[0] = deepmerge(awsLambdaHttpAdapterBlueprint.stone.adapters[0], options);
941
+ }
942
+ // Add the modified blueprint to the target class.
943
+ addBlueprint(target, context, awsLambdaHttpAdapterBlueprint);
944
+ });
945
+ };
888
946
 
889
947
  export { AWS_LAMBDA_HTTP_PLATFORM, AwsLambdaHttp, AwsLambdaHttpAdapter, AwsLambdaHttpAdapterError, AwsLambdaHttpErrorHandler, BodyEventMiddleware, FilesEventMiddleware, IncomingEventMiddleware, MetaBodyEventMiddleware, MetaFilesEventMiddleware, MetaIncomingEventMiddleware, MetaServerResponseMiddleware, RawHttpResponseWrapper, ServerResponseMiddleware, SetAwsLambdaHttpResponseResolverMiddleware, awsLambdaHttpAdapterBlueprint, awsLambdaHttpAdapterResolver, metaAdapterBlueprintMiddleware };
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.1",
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",
@@ -62,16 +62,16 @@
62
62
  "prepare": "husky"
63
63
  },
64
64
  "peerDependencies": {
65
- "@stone-js/core": "^0.1.1",
66
- "@stone-js/env": "^0.1.1",
67
- "@stone-js/filesystem": "^0.1.1",
68
- "@stone-js/http-core": "^0.1.2"
65
+ "@stone-js/core": "^0.2.1",
66
+ "@stone-js/env": "^0.1.2",
67
+ "@stone-js/filesystem": "^0.1.2",
68
+ "@stone-js/http-core": "^0.1.4"
69
69
  },
70
70
  "dependencies": {
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": [