@h4ad/serverless-adapter 2.1.0 → 2.2.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/README.md +33 -3
- package/lib/@types/huawei/huawei-api-gateway-event.d.ts +19 -0
- package/lib/@types/huawei/huawei-api-gateway-event.js +2 -0
- package/lib/@types/huawei/huawei-api-gateway-response.d.ts +7 -0
- package/lib/@types/huawei/huawei-api-gateway-response.js +2 -0
- package/lib/@types/huawei/huawei-context.d.ts +31 -0
- package/lib/@types/huawei/huawei-context.js +2 -0
- package/lib/@types/huawei/index.d.ts +3 -0
- package/lib/@types/huawei/index.js +15 -0
- package/lib/adapters/aws/api-gateway-v2.adapter.js +2 -2
- package/lib/adapters/huawei/huawei-api-gateway.adapter.d.ts +59 -0
- package/lib/adapters/huawei/huawei-api-gateway.adapter.js +113 -0
- package/lib/adapters/huawei/index.d.ts +1 -0
- package/lib/adapters/huawei/index.js +13 -0
- package/lib/resolvers/dummy/index.d.ts +1 -0
- package/lib/resolvers/dummy/index.js +13 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
<a href="#install">Install</a> |
|
|
7
7
|
<a href="#usage">Usage</a> |
|
|
8
8
|
<a href="#support">Support</a> |
|
|
9
|
+
<a href="#examples">Examples</a> |
|
|
9
10
|
<a href="#architecture">Architecture</a> |
|
|
10
11
|
<a href="#credits">Credits</a>
|
|
11
12
|
</p>
|
|
@@ -140,7 +141,8 @@ We support these event sources:
|
|
|
140
141
|
using ([SQSAdapter](./src/adapters/aws/sqs.adapter.ts))
|
|
141
142
|
- Huawei
|
|
142
143
|
- [Http Function](https://support.huaweicloud.com/intl/en-us/usermanual-functiongraph/functiongraph_01_1442.html): Look [this section](#huawei-http-function) about Huawei support for Http Function.
|
|
143
|
-
- [Event Function](https://support.huaweicloud.com/intl/en-us/usermanual-functiongraph/functiongraph_01_1441.html):
|
|
144
|
+
- [Event Function](https://support.huaweicloud.com/intl/en-us/usermanual-functiongraph/functiongraph_01_1441.html):
|
|
145
|
+
- [Api Gateway](https://support.huaweicloud.com/intl/en-us/devg-functiongraph/functiongraph_02_0102.html#functiongraph_02_0102__li5178638110137) by using ([HuaweiApiGatewayAdapter](src/adapters/huawei/huawei-api-gateway.adapter.ts)).
|
|
144
146
|
- Azure
|
|
145
147
|
- [The support is coming soon.](https://github.com/H4ad/serverless-adapter/issues/3)
|
|
146
148
|
- Firebase
|
|
@@ -161,7 +163,7 @@ We support these handlers:
|
|
|
161
163
|
|
|
162
164
|
## Huawei
|
|
163
165
|
|
|
164
|
-
In Huawei,
|
|
166
|
+
In Huawei, we added support to FunctionGraphV2 with Http Function and Event Function.
|
|
165
167
|
|
|
166
168
|
The difference between Http Function and Event Function is that in Http Function you must expose port 8000 and Huawei will proxy Api Gateway requests to your application.
|
|
167
169
|
So, on implementation, this library will create an http server to listen on port 8000 and forward the request to your framework.
|
|
@@ -216,7 +218,35 @@ In the end, the structure of the zip file you upload looks like this:
|
|
|
216
218
|
|
|
217
219
|
### Huawei Event Function
|
|
218
220
|
|
|
219
|
-
|
|
221
|
+
With Http Function you need to use [HttpHuaweiHandler](src/handlers/huawei/http-huawei.handler.ts),
|
|
222
|
+
but with Event Function you should use [DefaultHandler](src/handlers/default/default.handler.ts).
|
|
223
|
+
|
|
224
|
+
So, to add support to Api Gateway you do the following:
|
|
225
|
+
|
|
226
|
+
```ts
|
|
227
|
+
import { ServerlessAdapter } from '@h4ad/serverless-adapter';
|
|
228
|
+
import { HuaweiApiGatewayAdapter } from '@h4ad/serverless-adapter/lib/adapters/huawei';
|
|
229
|
+
import { ExpressFramework } from '@h4ad/serverless-adapter/lib/frameworks/express';
|
|
230
|
+
import { DefaultHandler } from '@h4ad/serverless-adapter/lib/handlers/default';
|
|
231
|
+
import { CallbackResolver } from '@h4ad/serverless-adapter/lib/resolvers/callback';
|
|
232
|
+
import app from './app';
|
|
233
|
+
|
|
234
|
+
export const handler = ServerlessAdapter.new(app)
|
|
235
|
+
.setFramework(new ExpressFramework())
|
|
236
|
+
.setHandler(new DefaultHandler())
|
|
237
|
+
.setResolver(new CallbackResolver())
|
|
238
|
+
.addAdapter(new HuaweiApiGatewayAdapter())
|
|
239
|
+
.build();
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
#### One important thing
|
|
243
|
+
|
|
244
|
+
You must use the callback resolver because I couldn't get it to work with the PromiseResolver.
|
|
245
|
+
Maybe it's a bug in the library or something specific in Huawei, if you have a tip please create an issue.
|
|
246
|
+
|
|
247
|
+
# Examples
|
|
248
|
+
|
|
249
|
+
You can see some examples of how to use this library [here](https://github.com/H4ad/serverless-adapter-examples).
|
|
220
250
|
|
|
221
251
|
# Architecture
|
|
222
252
|
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { BothValueHeaders } from '../index';
|
|
2
|
+
export interface HuaweiApiGatewayEvent {
|
|
3
|
+
body: string;
|
|
4
|
+
headers: BothValueHeaders;
|
|
5
|
+
httpMethod: string;
|
|
6
|
+
isBase64Encoded: boolean;
|
|
7
|
+
path: string;
|
|
8
|
+
pathParameters: HuaweiRequestPathParameters;
|
|
9
|
+
queryStringParameters: HuaweiRequestQueryStringParameters;
|
|
10
|
+
requestContext: HuaweiRequestContext;
|
|
11
|
+
[key: string]: any;
|
|
12
|
+
}
|
|
13
|
+
export declare type HuaweiRequestPathParameters = Record<string, string>;
|
|
14
|
+
export declare type HuaweiRequestQueryStringParameters = Record<string, string | string[]>;
|
|
15
|
+
export interface HuaweiRequestContext {
|
|
16
|
+
apiId: string;
|
|
17
|
+
requestId: string;
|
|
18
|
+
stage: string;
|
|
19
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export declare type GetRequestIDSecondsReturn = string;
|
|
2
|
+
export declare type GetRemainingTimeInMilliSecondsReturn = number;
|
|
3
|
+
export declare type GetAccessKeyReturn = string;
|
|
4
|
+
export declare type GetSecretKeyReturn = string;
|
|
5
|
+
export declare type GetUserDataKeyParameter = string;
|
|
6
|
+
export declare type GetUserDataReturn = any;
|
|
7
|
+
export declare type GetFunctionNameReturn = string;
|
|
8
|
+
export declare type GetRunningTimeInSecondsReturn = number;
|
|
9
|
+
export declare type GetVersionReturn = string;
|
|
10
|
+
export declare type GetMemorySizeReturn = number;
|
|
11
|
+
export declare type GetCPUNumberReturn = number;
|
|
12
|
+
export declare type GetProjectIdReturn = number;
|
|
13
|
+
export declare type GetPackageReturn = string;
|
|
14
|
+
export declare type GetLoggerReturn = {
|
|
15
|
+
info(message: string): void;
|
|
16
|
+
};
|
|
17
|
+
export interface HuaweiContext {
|
|
18
|
+
getRequestID(): GetRequestIDSecondsReturn;
|
|
19
|
+
getRemainingTimeInMilliSeconds(): GetRemainingTimeInMilliSecondsReturn;
|
|
20
|
+
getAccessKey(): GetAccessKeyReturn;
|
|
21
|
+
getSecretKey(): GetSecretKeyReturn;
|
|
22
|
+
getUserData(key: GetUserDataKeyParameter): GetUserDataReturn;
|
|
23
|
+
getFunctionName(): GetFunctionNameReturn;
|
|
24
|
+
getRunningTimeInSeconds(): GetRunningTimeInSecondsReturn;
|
|
25
|
+
getVersion(): GetVersionReturn;
|
|
26
|
+
getMemorySize(): GetMemorySizeReturn;
|
|
27
|
+
getCPUNumber(): GetCPUNumberReturn;
|
|
28
|
+
getProjectID(): GetProjectIdReturn;
|
|
29
|
+
getPackage(): GetPackageReturn;
|
|
30
|
+
getLogger(): GetLoggerReturn;
|
|
31
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
|
5
|
+
}) : (function(o, m, k, k2) {
|
|
6
|
+
if (k2 === undefined) k2 = k;
|
|
7
|
+
o[k2] = m[k];
|
|
8
|
+
}));
|
|
9
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
10
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
11
|
+
};
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
__exportStar(require("./huawei-context"), exports);
|
|
14
|
+
__exportStar(require("./huawei-api-gateway-event"), exports);
|
|
15
|
+
__exportStar(require("./huawei-api-gateway-response"), exports);
|
|
@@ -73,10 +73,10 @@ class ApiGatewayV2Adapter {
|
|
|
73
73
|
const transferEncodingHeader = headers['transfer-encoding'];
|
|
74
74
|
const hasTransferEncodingChunked = transferEncodingHeader && transferEncodingHeader.includes('chunked');
|
|
75
75
|
if (hasTransferEncodingChunked) {
|
|
76
|
-
throw new Error('chunked encoding in headers is not supported by API Gateway
|
|
76
|
+
throw new Error('chunked encoding in headers is not supported by API Gateway V2');
|
|
77
77
|
}
|
|
78
78
|
if (response === null || response === void 0 ? void 0 : response.chunkedEncoding) {
|
|
79
|
-
throw new Error('chunked encoding in response is not supported by API Gateway
|
|
79
|
+
throw new Error('chunked encoding in response is not supported by API Gateway V2');
|
|
80
80
|
}
|
|
81
81
|
const cookies = multiValueHeaders['set-cookie'];
|
|
82
82
|
if (headers)
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { HuaweiApiGatewayEvent, HuaweiContext } from '../../@types/huawei';
|
|
2
|
+
import { HuaweiApiGatewayResponse } from '../../@types/huawei/huawei-api-gateway-response';
|
|
3
|
+
import { AdapterContract, AdapterRequest, GetResponseAdapterProps, OnErrorProps } from '../../contracts';
|
|
4
|
+
/**
|
|
5
|
+
* The options to customize the {@link HuaweiApiGatewayAdapter}
|
|
6
|
+
*/
|
|
7
|
+
export interface HuaweiApiGatewayOptions {
|
|
8
|
+
/**
|
|
9
|
+
* Strip base path for custom domains
|
|
10
|
+
*
|
|
11
|
+
* @default ''
|
|
12
|
+
*/
|
|
13
|
+
stripBasePath?: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* The adapter to handle requests from Huawei Api Gateway
|
|
17
|
+
*
|
|
18
|
+
* @example```typescript
|
|
19
|
+
* const stripBasePath = '/any/custom/base/path'; // default ''
|
|
20
|
+
* const adapter = new ApiGatewayAdapter({ stripBasePath });
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* {@link https://support.huaweicloud.com/intl/en-us/devg-functiongraph/functiongraph_02_0102.html#functiongraph_02_0102__li5178638110137 Event Reference}
|
|
24
|
+
*/
|
|
25
|
+
export declare class HuaweiApiGatewayAdapter implements AdapterContract<HuaweiApiGatewayEvent, HuaweiContext, HuaweiApiGatewayResponse> {
|
|
26
|
+
protected readonly options?: HuaweiApiGatewayOptions | undefined;
|
|
27
|
+
/**
|
|
28
|
+
* Default constructor
|
|
29
|
+
*
|
|
30
|
+
* @param options The options to customize the {@link HuaweiApiGatewayAdapter}
|
|
31
|
+
*/
|
|
32
|
+
constructor(options?: HuaweiApiGatewayOptions | undefined);
|
|
33
|
+
/**
|
|
34
|
+
* @inheritDoc
|
|
35
|
+
*/
|
|
36
|
+
getAdapterName(): string;
|
|
37
|
+
/**
|
|
38
|
+
* @inheritDoc
|
|
39
|
+
*/
|
|
40
|
+
canHandle(event: unknown): event is HuaweiApiGatewayEvent;
|
|
41
|
+
/**
|
|
42
|
+
* @inheritDoc
|
|
43
|
+
*/
|
|
44
|
+
getRequest(event: HuaweiApiGatewayEvent): AdapterRequest;
|
|
45
|
+
/**
|
|
46
|
+
* @inheritDoc
|
|
47
|
+
*/
|
|
48
|
+
getResponse({ headers: responseHeaders, body, isBase64Encoded, statusCode, }: GetResponseAdapterProps<HuaweiApiGatewayEvent>): HuaweiApiGatewayResponse;
|
|
49
|
+
/**
|
|
50
|
+
* @inheritDoc
|
|
51
|
+
*/
|
|
52
|
+
onErrorWhileForwarding({ error, delegatedResolver, respondWithErrors, event, log, }: OnErrorProps<HuaweiApiGatewayEvent, HuaweiApiGatewayResponse>): void;
|
|
53
|
+
/**
|
|
54
|
+
* Get path from event with query strings
|
|
55
|
+
*
|
|
56
|
+
* @param event The event sent by serverless
|
|
57
|
+
*/
|
|
58
|
+
protected getPathFromEvent(event: HuaweiApiGatewayEvent): string;
|
|
59
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
//#region Imports
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.HuaweiApiGatewayAdapter = void 0;
|
|
5
|
+
const core_1 = require("../../core");
|
|
6
|
+
/**
|
|
7
|
+
* The adapter to handle requests from Huawei Api Gateway
|
|
8
|
+
*
|
|
9
|
+
* @example```typescript
|
|
10
|
+
* const stripBasePath = '/any/custom/base/path'; // default ''
|
|
11
|
+
* const adapter = new ApiGatewayAdapter({ stripBasePath });
|
|
12
|
+
* ```
|
|
13
|
+
*
|
|
14
|
+
* {@link https://support.huaweicloud.com/intl/en-us/devg-functiongraph/functiongraph_02_0102.html#functiongraph_02_0102__li5178638110137 Event Reference}
|
|
15
|
+
*/
|
|
16
|
+
class HuaweiApiGatewayAdapter {
|
|
17
|
+
//#region Constructor
|
|
18
|
+
/**
|
|
19
|
+
* Default constructor
|
|
20
|
+
*
|
|
21
|
+
* @param options The options to customize the {@link HuaweiApiGatewayAdapter}
|
|
22
|
+
*/
|
|
23
|
+
constructor(options) {
|
|
24
|
+
this.options = options;
|
|
25
|
+
}
|
|
26
|
+
//#endregion
|
|
27
|
+
//#region Public Methods
|
|
28
|
+
/**
|
|
29
|
+
* @inheritDoc
|
|
30
|
+
*/
|
|
31
|
+
getAdapterName() {
|
|
32
|
+
return HuaweiApiGatewayAdapter.name;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* @inheritDoc
|
|
36
|
+
*/
|
|
37
|
+
canHandle(event) {
|
|
38
|
+
const apiGatewayEvent = event;
|
|
39
|
+
return !!(apiGatewayEvent &&
|
|
40
|
+
apiGatewayEvent.httpMethod &&
|
|
41
|
+
apiGatewayEvent.requestContext &&
|
|
42
|
+
apiGatewayEvent.requestContext.apiId &&
|
|
43
|
+
apiGatewayEvent.requestContext.stage &&
|
|
44
|
+
apiGatewayEvent.requestContext.requestId &&
|
|
45
|
+
// to avoid conflict with api gateway v1 of aws
|
|
46
|
+
!('multiValueQueryStringParameters' in apiGatewayEvent));
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* @inheritDoc
|
|
50
|
+
*/
|
|
51
|
+
getRequest(event) {
|
|
52
|
+
const method = event.httpMethod;
|
|
53
|
+
const path = this.getPathFromEvent(event);
|
|
54
|
+
const headers = (0, core_1.getFlattenedHeadersMap)(event.headers, ',', true);
|
|
55
|
+
let body;
|
|
56
|
+
if (event.body) {
|
|
57
|
+
const [bufferBody, contentLength] = (0, core_1.getEventBodyAsBuffer)(event.body, event.isBase64Encoded);
|
|
58
|
+
body = bufferBody;
|
|
59
|
+
headers['content-length'] = String(contentLength);
|
|
60
|
+
}
|
|
61
|
+
const remoteAddress = headers['x-real-ip'];
|
|
62
|
+
return {
|
|
63
|
+
method,
|
|
64
|
+
headers,
|
|
65
|
+
body,
|
|
66
|
+
remoteAddress,
|
|
67
|
+
path,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* @inheritDoc
|
|
72
|
+
*/
|
|
73
|
+
getResponse({ headers: responseHeaders, body, isBase64Encoded, statusCode, }) {
|
|
74
|
+
const headers = (0, core_1.getMultiValueHeadersMap)(responseHeaders);
|
|
75
|
+
return {
|
|
76
|
+
statusCode,
|
|
77
|
+
body,
|
|
78
|
+
headers,
|
|
79
|
+
isBase64Encoded,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* @inheritDoc
|
|
84
|
+
*/
|
|
85
|
+
onErrorWhileForwarding({ error, delegatedResolver, respondWithErrors, event, log, }) {
|
|
86
|
+
const body = respondWithErrors ? error.stack : '';
|
|
87
|
+
const errorResponse = this.getResponse({
|
|
88
|
+
event,
|
|
89
|
+
statusCode: 500,
|
|
90
|
+
body: body || '',
|
|
91
|
+
headers: {},
|
|
92
|
+
isBase64Encoded: false,
|
|
93
|
+
log,
|
|
94
|
+
});
|
|
95
|
+
delegatedResolver.succeed(errorResponse);
|
|
96
|
+
}
|
|
97
|
+
//#endregion
|
|
98
|
+
//#region Protected Methods
|
|
99
|
+
/**
|
|
100
|
+
* Get path from event with query strings
|
|
101
|
+
*
|
|
102
|
+
* @param event The event sent by serverless
|
|
103
|
+
*/
|
|
104
|
+
getPathFromEvent(event) {
|
|
105
|
+
var _a;
|
|
106
|
+
const stripBasePath = (0, core_1.getDefaultIfUndefined)((_a = this.options) === null || _a === void 0 ? void 0 : _a.stripBasePath, '');
|
|
107
|
+
const replaceRegex = new RegExp(`^${stripBasePath}`);
|
|
108
|
+
const path = event.path.replace(replaceRegex, '');
|
|
109
|
+
const queryParams = event.queryStringParameters;
|
|
110
|
+
return (0, core_1.getPathWithQueryStringParams)(path, queryParams);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
exports.HuaweiApiGatewayAdapter = HuaweiApiGatewayAdapter;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './huawei-api-gateway.adapter';
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
|
5
|
+
}) : (function(o, m, k, k2) {
|
|
6
|
+
if (k2 === undefined) k2 = k;
|
|
7
|
+
o[k2] = m[k];
|
|
8
|
+
}));
|
|
9
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
10
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
11
|
+
};
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
__exportStar(require("./huawei-api-gateway.adapter"), exports);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './dummy.resolver';
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
|
5
|
+
}) : (function(o, m, k, k2) {
|
|
6
|
+
if (k2 === undefined) k2 = k;
|
|
7
|
+
o[k2] = m[k];
|
|
8
|
+
}));
|
|
9
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
10
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
11
|
+
};
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
__exportStar(require("./dummy.resolver"), exports);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@h4ad/serverless-adapter",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"description": "This library enables you to utilize any Cloud or Event Source to respond to web and API requests using your existing Node.js application framework.",
|
|
5
5
|
"main": "./lib/index.js",
|
|
6
6
|
"files": [
|