@midwayjs/fc-starter 3.4.0-beta.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/README.md +29 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +199 -0
- package/package.json +34 -0
package/README.md
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# serverless fc starter
|
|
2
|
+
|
|
3
|
+
本模块用于包裹无法定制运行时的 FaaS 平台,比如阿里云 FC。
|
|
4
|
+
|
|
5
|
+
## 阿里云 FC
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { asyncWrapper, start } from '@midwayjs/serverless-fc-starter';
|
|
9
|
+
|
|
10
|
+
let runtime;
|
|
11
|
+
exports.init = asyncWrapper(async () => {
|
|
12
|
+
runtime = await start();
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
// for web request
|
|
16
|
+
exports.handler = asyncWrapper(async (...args) => {
|
|
17
|
+
return runtime.asyncEvent(async function(ctx) {
|
|
18
|
+
return 'hello world'; // ctx.body = 'hello world';
|
|
19
|
+
})(...args);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
// for event
|
|
23
|
+
exports.handler = asyncWrapper(async (...args) => {
|
|
24
|
+
return runtime.asyncEvent(async function(ctx, event) {
|
|
25
|
+
return {data: 1};
|
|
26
|
+
})(...args);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
```
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BootstrapStarter = void 0;
|
|
4
|
+
const core_1 = require("@midwayjs/core");
|
|
5
|
+
const getRawBody = require("raw-body");
|
|
6
|
+
function isOutputError() {
|
|
7
|
+
return (process.env.SERVERLESS_OUTPUT_ERROR_STACK === 'true' ||
|
|
8
|
+
['local', 'development'].includes(process.env.MIDWAY_SERVER_ENV) ||
|
|
9
|
+
['local', 'development'].includes(process.env.NODE_ENV));
|
|
10
|
+
}
|
|
11
|
+
class BootstrapStarter {
|
|
12
|
+
start(options = {}) {
|
|
13
|
+
if (!process.env.NODE_ENV) {
|
|
14
|
+
process.env.NODE_ENV = 'production';
|
|
15
|
+
}
|
|
16
|
+
if (process.env['FC_FUNC_CODE_PATH']) {
|
|
17
|
+
// 用于替换默认的上下文日志
|
|
18
|
+
process.env['MIDWAY_SERVERLESS_REPLACE_LOGGER'] = 'true';
|
|
19
|
+
// 移除控制台颜色,fc 控制台无法探测是否支持,日志采集也必须把颜色禁用掉
|
|
20
|
+
process.env['MIDWAY_LOGGER_DISABLE_COLORS'] = 'true';
|
|
21
|
+
}
|
|
22
|
+
const exports = {};
|
|
23
|
+
let framework;
|
|
24
|
+
exports[options.initializeMethodName || 'initializer'] = (0, core_1.wrapAsync)(async (context) => {
|
|
25
|
+
var _a, _b, _c;
|
|
26
|
+
const applicationAdapter = {
|
|
27
|
+
getFunctionName() {
|
|
28
|
+
return context.function.name;
|
|
29
|
+
},
|
|
30
|
+
getFunctionServiceName() {
|
|
31
|
+
return context.service.name;
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
(_a = options.performance) === null || _a === void 0 ? void 0 : _a.mark('starterRuntimeStartTime');
|
|
35
|
+
// init midway
|
|
36
|
+
const applicationContext = (this.applicationContext =
|
|
37
|
+
await (0, core_1.initializeGlobalApplicationContext)(Object.assign(options, {
|
|
38
|
+
globalConfig: {
|
|
39
|
+
faas: {
|
|
40
|
+
applicationAdapter,
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
})));
|
|
44
|
+
(_b = options.performance) === null || _b === void 0 ? void 0 : _b.mark('frameworkStartTime');
|
|
45
|
+
const midwayFrameworkService = applicationContext.get(core_1.MidwayFrameworkService);
|
|
46
|
+
framework = midwayFrameworkService.getMainFramework();
|
|
47
|
+
const handlerWrapper = (0, core_1.wrapAsync)(async (event, context, oldContext) => {
|
|
48
|
+
var _a, _b, _c, _d;
|
|
49
|
+
const isHTTPMode = event.constructor.name === 'IncomingMessage' ||
|
|
50
|
+
event.constructor.name === 'EventEmitter';
|
|
51
|
+
const isApiGateway = event &&
|
|
52
|
+
event.headers &&
|
|
53
|
+
'queryParameters' in event &&
|
|
54
|
+
'httpMethod' in event;
|
|
55
|
+
if (isHTTPMode) {
|
|
56
|
+
if (!((_a = oldContext.logger) === null || _a === void 0 ? void 0 : _a.info)) {
|
|
57
|
+
oldContext.logger = console;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
if (!((_b = context.logger) === null || _b === void 0 ? void 0 : _b.info)) {
|
|
62
|
+
context.logger = console;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
const triggerFunction = framework.getTriggerFunction((oldContext === null || oldContext === void 0 ? void 0 : oldContext.function.handler) || context.function.handler);
|
|
66
|
+
let ctx;
|
|
67
|
+
if (isHTTPMode) {
|
|
68
|
+
event.getOriginContext = () => {
|
|
69
|
+
return oldContext;
|
|
70
|
+
};
|
|
71
|
+
// 如果需要解析body并且body是个stream
|
|
72
|
+
if (['post', 'put', 'delete'].indexOf(event.method.toLowerCase()) !==
|
|
73
|
+
-1 &&
|
|
74
|
+
!event.body &&
|
|
75
|
+
typeof event.on === 'function') {
|
|
76
|
+
event.body = await getRawBody(event, {
|
|
77
|
+
limit: '10mb',
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
ctx = await framework.wrapHttpRequest(event);
|
|
81
|
+
}
|
|
82
|
+
else if (isApiGateway) {
|
|
83
|
+
ctx = await framework.wrapHttpRequest(event, context);
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
// 阿里云事件触发器,入参是 buffer
|
|
87
|
+
if (Buffer.isBuffer(event)) {
|
|
88
|
+
event = event.toString('utf8');
|
|
89
|
+
try {
|
|
90
|
+
event = JSON.parse(event);
|
|
91
|
+
}
|
|
92
|
+
catch (_err) {
|
|
93
|
+
/** ignore */
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
// format context
|
|
97
|
+
ctx = {
|
|
98
|
+
originEvent: event,
|
|
99
|
+
originContext: context,
|
|
100
|
+
logger: context.logger,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
try {
|
|
104
|
+
const result = await triggerFunction(ctx, {
|
|
105
|
+
isHttpFunction: isHTTPMode || isApiGateway,
|
|
106
|
+
originEvent: event,
|
|
107
|
+
originContext: context,
|
|
108
|
+
});
|
|
109
|
+
if (isHTTPMode || isApiGateway) {
|
|
110
|
+
const { isBase64Encoded, statusCode, headers, body } = result;
|
|
111
|
+
if (isApiGateway) {
|
|
112
|
+
const newHeader = {};
|
|
113
|
+
for (const key in headers) {
|
|
114
|
+
// The length after base64 is wrong.
|
|
115
|
+
if (!['content-length'].includes(key)) {
|
|
116
|
+
if ('set-cookie' === key && !isHTTPMode) {
|
|
117
|
+
// unsupport multiple cookie when use apiGateway
|
|
118
|
+
newHeader[key] = headers[key][0];
|
|
119
|
+
if (headers[key].length > 1) {
|
|
120
|
+
ctx.logger.warn('[fc-starter]: unsupport multiple cookie when use apiGateway');
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
newHeader[key] = headers[key];
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return {
|
|
129
|
+
isBase64Encoded,
|
|
130
|
+
statusCode,
|
|
131
|
+
headers: newHeader,
|
|
132
|
+
body,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
const res = context;
|
|
137
|
+
if (res.headersSent) {
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
if (res.setHeader) {
|
|
141
|
+
for (const key in headers) {
|
|
142
|
+
res.setHeader(key, headers[key]);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
if (res.statusCode !== statusCode) {
|
|
146
|
+
if (res.setStatusCode) {
|
|
147
|
+
res.setStatusCode(statusCode);
|
|
148
|
+
}
|
|
149
|
+
if (res.statusCode) {
|
|
150
|
+
res.statusCode = statusCode;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
if (res.send) {
|
|
154
|
+
// http trigger only support `Buffer` or a `string` or a `stream.Readable`
|
|
155
|
+
res.send(body);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
return result;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
catch (err) {
|
|
164
|
+
ctx.logger.error(err);
|
|
165
|
+
const res = context;
|
|
166
|
+
if (res.setHeader) {
|
|
167
|
+
res.setHeader('content-type', 'text/plain');
|
|
168
|
+
}
|
|
169
|
+
if (res.send) {
|
|
170
|
+
res.setStatusCode((_c = err.status) !== null && _c !== void 0 ? _c : 500);
|
|
171
|
+
res.send(isOutputError() ? err.stack : 'Internal Server Error');
|
|
172
|
+
}
|
|
173
|
+
return {
|
|
174
|
+
isBase64Encoded: false,
|
|
175
|
+
statusCode: (_d = err.status) !== null && _d !== void 0 ? _d : 500,
|
|
176
|
+
headers: {},
|
|
177
|
+
body: isOutputError() ? err.stack : 'Internal Server Error',
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
if (options.exportAllHandler) {
|
|
182
|
+
for (const handlerName of framework.getAllHandlerNames()) {
|
|
183
|
+
exports[handlerName.split('.')[1]] = handlerWrapper;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
else {
|
|
187
|
+
const handlerMethodName = context.function.handler.split('.')[1];
|
|
188
|
+
exports[handlerMethodName] = handlerWrapper;
|
|
189
|
+
}
|
|
190
|
+
(_c = options.performance) === null || _c === void 0 ? void 0 : _c.end();
|
|
191
|
+
});
|
|
192
|
+
return exports;
|
|
193
|
+
}
|
|
194
|
+
getApplicationContext() {
|
|
195
|
+
return this.applicationContext;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
exports.BootstrapStarter = BootstrapStarter;
|
|
199
|
+
//# sourceMappingURL=index.js.map
|
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@midwayjs/fc-starter",
|
|
3
|
+
"version": "3.4.0-beta.1",
|
|
4
|
+
"main": "dist/index",
|
|
5
|
+
"typings": "dist/index.d.ts",
|
|
6
|
+
"dependencies": {
|
|
7
|
+
"@midwayjs/faas": "^3.4.0-beta.1",
|
|
8
|
+
"raw-body": "2.5.1"
|
|
9
|
+
},
|
|
10
|
+
"devDependencies": {
|
|
11
|
+
"@midwayjs/core": "^3.4.0-beta.1",
|
|
12
|
+
"@midwayjs/decorator": "^3.4.0-beta.1",
|
|
13
|
+
"@midwayjs/runtime-mock": "^3.0.4",
|
|
14
|
+
"@midwayjs/serverless-http-parser": "^3.3.5"
|
|
15
|
+
},
|
|
16
|
+
"engines": {
|
|
17
|
+
"node": ">=12"
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"dist/**/*.js",
|
|
21
|
+
"dist/**/*.d.ts"
|
|
22
|
+
],
|
|
23
|
+
"scripts": {
|
|
24
|
+
"build": "tsc",
|
|
25
|
+
"test": "node --require=ts-node/register ../../node_modules/.bin/jest --runInBand",
|
|
26
|
+
"cov": "node --require=ts-node/register ../../node_modules/.bin/jest --runInBand --coverage --forceExit"
|
|
27
|
+
},
|
|
28
|
+
"repository": {
|
|
29
|
+
"type": "git",
|
|
30
|
+
"url": "git@github.com:midwayjs/midway.git"
|
|
31
|
+
},
|
|
32
|
+
"license": "MIT",
|
|
33
|
+
"gitHead": "14d8440f20978426184c988808343cc24bcf6e20"
|
|
34
|
+
}
|