@stone-js/aws-lambda-http-adapter 0.3.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/dist/browser.js +13 -13
- package/dist/index.js +341 -341
- package/package.json +5 -5
package/dist/browser.js
CHANGED
|
@@ -19,19 +19,6 @@ 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
|
-
|
|
35
22
|
/**
|
|
36
23
|
* A Stone.js decorator that integrates the AWS Lambda HTTP Adapter with a class.
|
|
37
24
|
*
|
|
@@ -65,4 +52,17 @@ const AwsLambdaHttp = (_options = {}) => {
|
|
|
65
52
|
return classDecoratorLegacyWrapper((_target, _context) => { });
|
|
66
53
|
};
|
|
67
54
|
|
|
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.js
CHANGED
|
@@ -1,13 +1,47 @@
|
|
|
1
|
-
import { IntegrationError, Adapter, AdapterEventBuilder,
|
|
2
|
-
import { IncomingHttpEvent, HTTP_INTERNAL_SERVER_ERROR, BinaryFileResponse, OutgoingHttpResponse, CookieCollection, isIpTrusted, getHostname, getProtocol, httpCoreBlueprint, isMultipart, getCharset, 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 {
|
|
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.
|
|
@@ -221,40 +255,6 @@ class AwsLambdaHttpAdapter extends Adapter {
|
|
|
221
255
|
}
|
|
222
256
|
}
|
|
223
257
|
|
|
224
|
-
/**
|
|
225
|
-
* Class representing an AwsLambdaHttpErrorHandler.
|
|
226
|
-
*/
|
|
227
|
-
class AwsLambdaHttpErrorHandler {
|
|
228
|
-
logger;
|
|
229
|
-
/**
|
|
230
|
-
* Create an NodeHttpErrorHandler.
|
|
231
|
-
*
|
|
232
|
-
* @param options - NodeHttpErrorHandler options.
|
|
233
|
-
*/
|
|
234
|
-
constructor({ blueprint }) {
|
|
235
|
-
this.logger = blueprint.get('stone.logger.resolver', defaultLoggerResolver)(blueprint);
|
|
236
|
-
}
|
|
237
|
-
/**
|
|
238
|
-
* Handle an error.
|
|
239
|
-
*
|
|
240
|
-
* @param error - The error to handle.
|
|
241
|
-
* @param context - The context of the adapter.
|
|
242
|
-
* @returns The raw response builder.
|
|
243
|
-
*/
|
|
244
|
-
handle(error, context) {
|
|
245
|
-
this.logger.error(error.message, { error });
|
|
246
|
-
const statusCode = error.cause?.status ?? HTTP_INTERNAL_SERVER_ERROR;
|
|
247
|
-
const type = accepts(context.rawEvent).type(['json', 'html']);
|
|
248
|
-
const contentType = mime.getType(type !== false ? type : 'txt') ?? context.rawEvent.headers['content-type'] ?? 'text/plain';
|
|
249
|
-
const headers = new Headers({ 'Content-Type': contentType });
|
|
250
|
-
return context
|
|
251
|
-
.rawResponseBuilder
|
|
252
|
-
.add('headers', headers)
|
|
253
|
-
.add('statusCode', statusCode)
|
|
254
|
-
.add('statusMessage', statuses.message[statusCode]);
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
|
|
258
258
|
/**
|
|
259
259
|
* A constant representing the AWS Lambda HTTP platform identifier.
|
|
260
260
|
*
|
|
@@ -276,154 +276,6 @@ const awsLambdaHttpAdapterResolver = (blueprint) => {
|
|
|
276
276
|
return AwsLambdaHttpAdapter.create(blueprint);
|
|
277
277
|
};
|
|
278
278
|
|
|
279
|
-
function getDefaultExportFromCjs (x) {
|
|
280
|
-
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
var cjs;
|
|
284
|
-
var hasRequiredCjs;
|
|
285
|
-
|
|
286
|
-
function requireCjs () {
|
|
287
|
-
if (hasRequiredCjs) return cjs;
|
|
288
|
-
hasRequiredCjs = 1;
|
|
289
|
-
|
|
290
|
-
var isMergeableObject = function isMergeableObject(value) {
|
|
291
|
-
return isNonNullObject(value)
|
|
292
|
-
&& !isSpecial(value)
|
|
293
|
-
};
|
|
294
|
-
|
|
295
|
-
function isNonNullObject(value) {
|
|
296
|
-
return !!value && typeof value === 'object'
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
function isSpecial(value) {
|
|
300
|
-
var stringValue = Object.prototype.toString.call(value);
|
|
301
|
-
|
|
302
|
-
return stringValue === '[object RegExp]'
|
|
303
|
-
|| stringValue === '[object Date]'
|
|
304
|
-
|| isReactElement(value)
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
// see https://github.com/facebook/react/blob/b5ac963fb791d1298e7f396236383bc955f916c1/src/isomorphic/classic/element/ReactElement.js#L21-L25
|
|
308
|
-
var canUseSymbol = typeof Symbol === 'function' && Symbol.for;
|
|
309
|
-
var REACT_ELEMENT_TYPE = canUseSymbol ? Symbol.for('react.element') : 0xeac7;
|
|
310
|
-
|
|
311
|
-
function isReactElement(value) {
|
|
312
|
-
return value.$$typeof === REACT_ELEMENT_TYPE
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
function emptyTarget(val) {
|
|
316
|
-
return Array.isArray(val) ? [] : {}
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
function cloneUnlessOtherwiseSpecified(value, options) {
|
|
320
|
-
return (options.clone !== false && options.isMergeableObject(value))
|
|
321
|
-
? deepmerge(emptyTarget(value), value, options)
|
|
322
|
-
: value
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
function defaultArrayMerge(target, source, options) {
|
|
326
|
-
return target.concat(source).map(function(element) {
|
|
327
|
-
return cloneUnlessOtherwiseSpecified(element, options)
|
|
328
|
-
})
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
function getMergeFunction(key, options) {
|
|
332
|
-
if (!options.customMerge) {
|
|
333
|
-
return deepmerge
|
|
334
|
-
}
|
|
335
|
-
var customMerge = options.customMerge(key);
|
|
336
|
-
return typeof customMerge === 'function' ? customMerge : deepmerge
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
function getEnumerableOwnPropertySymbols(target) {
|
|
340
|
-
return Object.getOwnPropertySymbols
|
|
341
|
-
? Object.getOwnPropertySymbols(target).filter(function(symbol) {
|
|
342
|
-
return Object.propertyIsEnumerable.call(target, symbol)
|
|
343
|
-
})
|
|
344
|
-
: []
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
function getKeys(target) {
|
|
348
|
-
return Object.keys(target).concat(getEnumerableOwnPropertySymbols(target))
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
function propertyIsOnObject(object, property) {
|
|
352
|
-
try {
|
|
353
|
-
return property in object
|
|
354
|
-
} catch(_) {
|
|
355
|
-
return false
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
// Protects from prototype poisoning and unexpected merging up the prototype chain.
|
|
360
|
-
function propertyIsUnsafe(target, key) {
|
|
361
|
-
return propertyIsOnObject(target, key) // Properties are safe to merge if they don't exist in the target yet,
|
|
362
|
-
&& !(Object.hasOwnProperty.call(target, key) // unsafe if they exist up the prototype chain,
|
|
363
|
-
&& Object.propertyIsEnumerable.call(target, key)) // and also unsafe if they're nonenumerable.
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
function mergeObject(target, source, options) {
|
|
367
|
-
var destination = {};
|
|
368
|
-
if (options.isMergeableObject(target)) {
|
|
369
|
-
getKeys(target).forEach(function(key) {
|
|
370
|
-
destination[key] = cloneUnlessOtherwiseSpecified(target[key], options);
|
|
371
|
-
});
|
|
372
|
-
}
|
|
373
|
-
getKeys(source).forEach(function(key) {
|
|
374
|
-
if (propertyIsUnsafe(target, key)) {
|
|
375
|
-
return
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
if (propertyIsOnObject(target, key) && options.isMergeableObject(source[key])) {
|
|
379
|
-
destination[key] = getMergeFunction(key, options)(target[key], source[key], options);
|
|
380
|
-
} else {
|
|
381
|
-
destination[key] = cloneUnlessOtherwiseSpecified(source[key], options);
|
|
382
|
-
}
|
|
383
|
-
});
|
|
384
|
-
return destination
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
function deepmerge(target, source, options) {
|
|
388
|
-
options = options || {};
|
|
389
|
-
options.arrayMerge = options.arrayMerge || defaultArrayMerge;
|
|
390
|
-
options.isMergeableObject = options.isMergeableObject || isMergeableObject;
|
|
391
|
-
// cloneUnlessOtherwiseSpecified is added to `options` so that custom arrayMerge()
|
|
392
|
-
// implementations can use it. The caller may not replace it.
|
|
393
|
-
options.cloneUnlessOtherwiseSpecified = cloneUnlessOtherwiseSpecified;
|
|
394
|
-
|
|
395
|
-
var sourceIsArray = Array.isArray(source);
|
|
396
|
-
var targetIsArray = Array.isArray(target);
|
|
397
|
-
var sourceAndTargetTypesMatch = sourceIsArray === targetIsArray;
|
|
398
|
-
|
|
399
|
-
if (!sourceAndTargetTypesMatch) {
|
|
400
|
-
return cloneUnlessOtherwiseSpecified(source, options)
|
|
401
|
-
} else if (sourceIsArray) {
|
|
402
|
-
return options.arrayMerge(target, source, options)
|
|
403
|
-
} else {
|
|
404
|
-
return mergeObject(target, source, options)
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
deepmerge.all = function deepmergeAll(array, options) {
|
|
409
|
-
if (!Array.isArray(array)) {
|
|
410
|
-
throw new Error('first argument should be an array')
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
return array.reduce(function(prev, next) {
|
|
414
|
-
return deepmerge(prev, next, options)
|
|
415
|
-
}, {})
|
|
416
|
-
};
|
|
417
|
-
|
|
418
|
-
var deepmerge_1 = deepmerge;
|
|
419
|
-
|
|
420
|
-
cjs = deepmerge_1;
|
|
421
|
-
return cjs;
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
var cjsExports = requireCjs();
|
|
425
|
-
var deepmerge = /*@__PURE__*/getDefaultExportFromCjs(cjsExports);
|
|
426
|
-
|
|
427
279
|
/**
|
|
428
280
|
* Middleware to dynamically set response resolver for adapter.
|
|
429
281
|
*
|
|
@@ -457,20 +309,19 @@ const metaAdapterBlueprintMiddleware = [
|
|
|
457
309
|
];
|
|
458
310
|
|
|
459
311
|
/**
|
|
460
|
-
*
|
|
312
|
+
* Class representing a FilesEventMiddleware.
|
|
461
313
|
*
|
|
462
|
-
*
|
|
463
|
-
* headers, cookies, and more, and forwards them to the next middleware in the pipeline.
|
|
314
|
+
* @author Mr. Stone <evensstone@gmail.com>
|
|
464
315
|
*/
|
|
465
|
-
class
|
|
316
|
+
class FilesEventMiddleware {
|
|
466
317
|
/**
|
|
467
318
|
* The blueprint for resolving configuration and dependencies.
|
|
468
319
|
*/
|
|
469
320
|
blueprint;
|
|
470
321
|
/**
|
|
471
|
-
* Create
|
|
322
|
+
* Create a FilesEventMiddleware.
|
|
472
323
|
*
|
|
473
|
-
* @param {blueprint} options - Options
|
|
324
|
+
* @param {blueprint} options - Options for creating the FilesEventMiddleware.
|
|
474
325
|
*/
|
|
475
326
|
constructor({ blueprint }) {
|
|
476
327
|
this.blueprint = blueprint;
|
|
@@ -480,26 +331,99 @@ class IncomingEventMiddleware {
|
|
|
480
331
|
*
|
|
481
332
|
* @param context - The adapter context containing the raw event, execution context, and other data.
|
|
482
333
|
* @param next - The next middleware to be invoked in the pipeline.
|
|
483
|
-
* @returns A promise that resolves to the
|
|
484
|
-
*
|
|
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.
|
|
485
337
|
*/
|
|
486
338
|
async handle(context, next) {
|
|
487
|
-
if (
|
|
339
|
+
if (context.rawEvent === undefined || context.incomingEventBuilder?.add === undefined) {
|
|
488
340
|
throw new AwsLambdaHttpAdapterError('The context is missing required components.');
|
|
489
341
|
}
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
.add('source', this.getSource(context))
|
|
499
|
-
.add('headers', context.rawEvent.headers)
|
|
500
|
-
// If not defined by other middleware
|
|
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);
|
|
501
350
|
// In fullstack forms, the method is spoofed and sent as a hidden field
|
|
502
|
-
.
|
|
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))
|
|
503
427
|
.add('queryString', context.rawEvent.queryStringParameters)
|
|
504
428
|
.add('protocol', this.getProtocol(context.rawEvent, proxyOptions))
|
|
505
429
|
.add('cookies', CookieCollection.create(context.rawEvent.headers.cookie, cookieOptions, this.getCookieSecret()))
|
|
@@ -667,77 +591,6 @@ class ServerResponseMiddleware {
|
|
|
667
591
|
*/
|
|
668
592
|
const MetaServerResponseMiddleware = { module: ServerResponseMiddleware, isClass: true };
|
|
669
593
|
|
|
670
|
-
/**
|
|
671
|
-
* Default blueprint configuration for the AWS Lambda Http Adapter.
|
|
672
|
-
*
|
|
673
|
-
* This blueprint defines the initial configuration for the AWS Lambda Http adapter
|
|
674
|
-
* within the Stone.js framework. It includes:
|
|
675
|
-
* - An alias for the AWS Lambda platform (`AWS_LAMBDA_HTTP_PLATFORM`).
|
|
676
|
-
* - A default resolver function (currently a placeholder).
|
|
677
|
-
* - Middleware, hooks, and state flags (`current`, `default`, `preferred`).
|
|
678
|
-
*/
|
|
679
|
-
const awsLambdaHttpAdapterBlueprint = {
|
|
680
|
-
stone: {
|
|
681
|
-
...httpCoreBlueprint.stone,
|
|
682
|
-
blueprint: {
|
|
683
|
-
middleware: metaAdapterBlueprintMiddleware
|
|
684
|
-
},
|
|
685
|
-
adapters: [
|
|
686
|
-
{
|
|
687
|
-
current: false,
|
|
688
|
-
variant: 'server',
|
|
689
|
-
platform: AWS_LAMBDA_HTTP_PLATFORM,
|
|
690
|
-
middleware: [
|
|
691
|
-
MetaIncomingEventMiddleware,
|
|
692
|
-
MetaServerResponseMiddleware
|
|
693
|
-
],
|
|
694
|
-
resolver: awsLambdaHttpAdapterResolver,
|
|
695
|
-
eventHandlerResolver: defaultKernelResolver,
|
|
696
|
-
errorHandlers: {
|
|
697
|
-
default: { module: AwsLambdaHttpErrorHandler, isClass: true }
|
|
698
|
-
},
|
|
699
|
-
default: isNotEmpty(getString('AWS_LAMBDA_FUNCTION_NAME', ''))
|
|
700
|
-
}
|
|
701
|
-
]
|
|
702
|
-
}
|
|
703
|
-
};
|
|
704
|
-
|
|
705
|
-
/**
|
|
706
|
-
* A Stone.js decorator that integrates the AWS Lambda HTTP Adapter with a class.
|
|
707
|
-
*
|
|
708
|
-
* This decorator modifies the class to seamlessly enable AWS Lambda HTTP as the
|
|
709
|
-
* execution environment for a Stone.js application. By applying this decorator,
|
|
710
|
-
* the class is automatically configured with the necessary blueprint for AWS Lambda HTTP.
|
|
711
|
-
*
|
|
712
|
-
* @template T - The type of the class being decorated. Defaults to `ClassType`.
|
|
713
|
-
* @param options - Optional configuration to customize the AWS Lambda HTTP Adapter.
|
|
714
|
-
*
|
|
715
|
-
* @returns A class decorator that applies the AWS Lambda HTTP adapter configuration.
|
|
716
|
-
*
|
|
717
|
-
* @example
|
|
718
|
-
* ```typescript
|
|
719
|
-
* import { AwsLambdaHttp } from '@stone-js/aws-lambda-http-adapter';
|
|
720
|
-
*
|
|
721
|
-
* @AwsLambdaHttp({
|
|
722
|
-
* alias: 'MyAwsLambdaHttpAdapter',
|
|
723
|
-
* current: true,
|
|
724
|
-
* })
|
|
725
|
-
* class App {
|
|
726
|
-
* // Your application logic here
|
|
727
|
-
* }
|
|
728
|
-
* ```
|
|
729
|
-
*/
|
|
730
|
-
const AwsLambdaHttp = (options = {}) => {
|
|
731
|
-
return classDecoratorLegacyWrapper((target, context) => {
|
|
732
|
-
if (awsLambdaHttpAdapterBlueprint.stone?.adapters?.[0] !== undefined) {
|
|
733
|
-
// Merge provided options with the default AWS Lambda HTTP adapter blueprint.
|
|
734
|
-
awsLambdaHttpAdapterBlueprint.stone.adapters[0] = deepmerge(awsLambdaHttpAdapterBlueprint.stone.adapters[0], options);
|
|
735
|
-
}
|
|
736
|
-
// Add the modified blueprint to the target class.
|
|
737
|
-
addBlueprint(target, context, awsLambdaHttpAdapterBlueprint);
|
|
738
|
-
});
|
|
739
|
-
};
|
|
740
|
-
|
|
741
594
|
/**
|
|
742
595
|
* Class representing a BodyEventMiddleware.
|
|
743
596
|
*
|
|
@@ -872,76 +725,223 @@ class BodyEventMiddleware {
|
|
|
872
725
|
*/
|
|
873
726
|
const MetaBodyEventMiddleware = { module: BodyEventMiddleware, isClass: true };
|
|
874
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
|
+
|
|
875
876
|
/**
|
|
876
|
-
*
|
|
877
|
+
* Default blueprint configuration for the AWS Lambda Http Adapter.
|
|
877
878
|
*
|
|
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`).
|
|
879
884
|
*/
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
*/
|
|
902
|
-
async handle(context, next) {
|
|
903
|
-
if (context.rawEvent === undefined || context.incomingEventBuilder?.add === undefined) {
|
|
904
|
-
throw new AwsLambdaHttpAdapterError('The context is missing required components.');
|
|
905
|
-
}
|
|
906
|
-
if (isMultipart(this.normalizeEvent(context.rawEvent))) {
|
|
907
|
-
const options = this.blueprint.get('stone.http.files.upload', {});
|
|
908
|
-
const response = await getFilesUploads(this.normalizeEvent(context.rawEvent), options);
|
|
909
|
-
const method = response.fields.$method$;
|
|
910
|
-
context
|
|
911
|
-
.incomingEventBuilder
|
|
912
|
-
.add('files', response.files)
|
|
913
|
-
.add('body', response.fields);
|
|
914
|
-
// In fullstack forms, the method is spoofed and sent as a hidden field
|
|
915
|
-
isNotEmpty(method) && context.incomingEventBuilder.add('method', method);
|
|
916
|
-
}
|
|
917
|
-
return await next(context);
|
|
918
|
-
}
|
|
919
|
-
/**
|
|
920
|
-
* Normalize the incoming event to an IncomingMessage.
|
|
921
|
-
*
|
|
922
|
-
* @param rawEvent - The raw event to be normalized.
|
|
923
|
-
* @returns The normalized event.
|
|
924
|
-
*/
|
|
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
|
-
}
|
|
932
|
-
return {
|
|
933
|
-
body,
|
|
934
|
-
headers: {
|
|
935
|
-
'content-type': rawEvent.headers['content-type'] ?? rawEvent.headers['Content-Type'],
|
|
936
|
-
'content-length': rawEvent.headers['content-length'] ?? rawEvent.headers['Content-Length'],
|
|
937
|
-
'transfer-encoding': rawEvent.headers['transfer-encoding'] ?? rawEvent.headers['Transfer-Encoding']
|
|
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', ''))
|
|
938
906
|
}
|
|
939
|
-
|
|
907
|
+
]
|
|
940
908
|
}
|
|
941
|
-
}
|
|
909
|
+
};
|
|
910
|
+
|
|
942
911
|
/**
|
|
943
|
-
*
|
|
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
|
+
* ```
|
|
944
935
|
*/
|
|
945
|
-
const
|
|
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
|
+
};
|
|
946
946
|
|
|
947
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.3.
|
|
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,10 +62,10 @@
|
|
|
62
62
|
"prepare": "husky"
|
|
63
63
|
},
|
|
64
64
|
"peerDependencies": {
|
|
65
|
-
"@stone-js/core": "^0.
|
|
66
|
-
"@stone-js/env": "^0.1.
|
|
67
|
-
"@stone-js/filesystem": "^0.1.
|
|
68
|
-
"@stone-js/http-core": "^0.1.
|
|
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",
|