@redmix/api-server 0.0.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 +21 -0
- package/README.md +64 -0
- package/dist/apiCLIConfig.d.ts +6 -0
- package/dist/apiCLIConfig.d.ts.map +1 -0
- package/dist/apiCLIConfig.js +71 -0
- package/dist/apiCLIConfigHandler.d.ts +3 -0
- package/dist/apiCLIConfigHandler.d.ts.map +1 -0
- package/dist/apiCLIConfigHandler.js +68 -0
- package/dist/bin.d.ts +2 -0
- package/dist/bin.d.ts.map +1 -0
- package/dist/bin.js +850 -0
- package/dist/bothCLIConfig.d.ts +6 -0
- package/dist/bothCLIConfig.d.ts.map +1 -0
- package/dist/bothCLIConfig.js +76 -0
- package/dist/bothCLIConfigHandler.d.ts +3 -0
- package/dist/bothCLIConfigHandler.d.ts.map +1 -0
- package/dist/bothCLIConfigHandler.js +107 -0
- package/dist/buildManager.d.ts +15 -0
- package/dist/buildManager.d.ts.map +1 -0
- package/dist/buildManager.js +74 -0
- package/dist/cliHelpers.d.ts +5 -0
- package/dist/cliHelpers.d.ts.map +1 -0
- package/dist/cliHelpers.js +52 -0
- package/dist/createServer.d.ts +30 -0
- package/dist/createServer.d.ts.map +1 -0
- package/dist/createServer.js +142 -0
- package/dist/createServerHelpers.d.ts +39 -0
- package/dist/createServerHelpers.d.ts.map +1 -0
- package/dist/createServerHelpers.js +101 -0
- package/dist/fastify.d.ts +14 -0
- package/dist/fastify.d.ts.map +1 -0
- package/dist/fastify.js +88 -0
- package/dist/logFormatter/ambient.d.js +1 -0
- package/dist/logFormatter/bin.d.ts +2 -0
- package/dist/logFormatter/bin.d.ts.map +1 -0
- package/dist/logFormatter/bin.js +369 -0
- package/dist/logFormatter/formatters.d.ts +30 -0
- package/dist/logFormatter/formatters.d.ts.map +1 -0
- package/dist/logFormatter/formatters.js +275 -0
- package/dist/logFormatter/index.d.ts +2 -0
- package/dist/logFormatter/index.d.ts.map +1 -0
- package/dist/logFormatter/index.js +184 -0
- package/dist/plugins/api.d.ts +13 -0
- package/dist/plugins/api.d.ts.map +1 -0
- package/dist/plugins/api.js +77 -0
- package/dist/plugins/graphql.d.ts +10 -0
- package/dist/plugins/graphql.d.ts.map +1 -0
- package/dist/plugins/graphql.js +115 -0
- package/dist/plugins/lambdaLoader.d.ts +23 -0
- package/dist/plugins/lambdaLoader.d.ts.map +1 -0
- package/dist/plugins/lambdaLoader.js +116 -0
- package/dist/requestHandlers/awsLambdaFastify.d.ts +5 -0
- package/dist/requestHandlers/awsLambdaFastify.d.ts.map +1 -0
- package/dist/requestHandlers/awsLambdaFastify.js +103 -0
- package/dist/requestHandlers/utils.d.ts +26 -0
- package/dist/requestHandlers/utils.d.ts.map +1 -0
- package/dist/requestHandlers/utils.js +55 -0
- package/dist/serverManager.d.ts +8 -0
- package/dist/serverManager.d.ts.map +1 -0
- package/dist/serverManager.js +138 -0
- package/dist/types.d.ts +19 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/watch.d.ts +2 -0
- package/dist/watch.d.ts.map +1 -0
- package/dist/watch.js +274 -0
- package/package.json +77 -0
package/dist/bin.js
ADDED
@@ -0,0 +1,850 @@
|
|
1
|
+
#!/usr/bin/env node
|
2
|
+
"use strict";
|
3
|
+
var __create = Object.create;
|
4
|
+
var __defProp = Object.defineProperty;
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
9
|
+
var __esm = (fn, res) => function __init() {
|
10
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
11
|
+
};
|
12
|
+
var __export = (target, all) => {
|
13
|
+
for (var name in all)
|
14
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
15
|
+
};
|
16
|
+
var __copyProps = (to, from, except, desc) => {
|
17
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
18
|
+
for (let key of __getOwnPropNames(from))
|
19
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
20
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
21
|
+
}
|
22
|
+
return to;
|
23
|
+
};
|
24
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
25
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
26
|
+
// file that has been converted to a CommonJS file using a Babel-
|
27
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
28
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
29
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
30
|
+
mod
|
31
|
+
));
|
32
|
+
|
33
|
+
// src/cliHelpers.ts
|
34
|
+
function getAPIHost() {
|
35
|
+
let host = process.env.REDWOOD_API_HOST;
|
36
|
+
host ??= (0, import_project_config.getConfig)().api.host;
|
37
|
+
host ??= process.env.NODE_ENV === "production" ? "0.0.0.0" : "::";
|
38
|
+
return host;
|
39
|
+
}
|
40
|
+
function getAPIPort() {
|
41
|
+
return process.env.REDWOOD_API_PORT ? parseInt(process.env.REDWOOD_API_PORT) : (0, import_project_config.getConfig)().api.port;
|
42
|
+
}
|
43
|
+
function getWebHost() {
|
44
|
+
let host = process.env.REDWOOD_WEB_HOST;
|
45
|
+
host ??= (0, import_project_config.getConfig)().web.host;
|
46
|
+
host ??= process.env.NODE_ENV === "production" ? "0.0.0.0" : "::";
|
47
|
+
return host;
|
48
|
+
}
|
49
|
+
function getWebPort() {
|
50
|
+
return process.env.REDWOOD_WEB_PORT ? parseInt(process.env.REDWOOD_WEB_PORT) : (0, import_project_config.getConfig)().web.port;
|
51
|
+
}
|
52
|
+
var import_project_config;
|
53
|
+
var init_cliHelpers = __esm({
|
54
|
+
"src/cliHelpers.ts"() {
|
55
|
+
"use strict";
|
56
|
+
import_project_config = require("@redmix/project-config");
|
57
|
+
}
|
58
|
+
});
|
59
|
+
|
60
|
+
// src/createServerHelpers.ts
|
61
|
+
function resolveOptions(options = {}, args) {
|
62
|
+
options.parseArgs ??= true;
|
63
|
+
options.logger ??= DEFAULT_CREATE_SERVER_OPTIONS.logger;
|
64
|
+
const resolvedOptions = {
|
65
|
+
apiRootPath: options.apiRootPath ?? DEFAULT_CREATE_SERVER_OPTIONS.apiRootPath,
|
66
|
+
fastifyServerOptions: options.fastifyServerOptions ?? {
|
67
|
+
requestTimeout: DEFAULT_CREATE_SERVER_OPTIONS.fastifyServerOptions.requestTimeout,
|
68
|
+
logger: options.logger ?? DEFAULT_CREATE_SERVER_OPTIONS.logger,
|
69
|
+
bodyLimit: DEFAULT_CREATE_SERVER_OPTIONS.fastifyServerOptions.bodyLimit
|
70
|
+
},
|
71
|
+
configureApiServer: options.configureApiServer ?? DEFAULT_CREATE_SERVER_OPTIONS.configureApiServer,
|
72
|
+
apiHost: getAPIHost(),
|
73
|
+
apiPort: getAPIPort()
|
74
|
+
};
|
75
|
+
resolvedOptions.fastifyServerOptions.requestTimeout ??= DEFAULT_CREATE_SERVER_OPTIONS.fastifyServerOptions.requestTimeout;
|
76
|
+
resolvedOptions.fastifyServerOptions.logger = options.logger;
|
77
|
+
if (options.parseArgs) {
|
78
|
+
const { values } = (0, import_util.parseArgs)({
|
79
|
+
options: {
|
80
|
+
apiHost: {
|
81
|
+
type: "string"
|
82
|
+
},
|
83
|
+
apiPort: {
|
84
|
+
type: "string",
|
85
|
+
short: "p"
|
86
|
+
},
|
87
|
+
apiRootPath: {
|
88
|
+
type: "string"
|
89
|
+
}
|
90
|
+
},
|
91
|
+
strict: false,
|
92
|
+
...args && { args }
|
93
|
+
});
|
94
|
+
if (values.apiHost && typeof values.apiHost !== "string") {
|
95
|
+
throw new Error("`apiHost` must be a string");
|
96
|
+
}
|
97
|
+
if (values.apiHost) {
|
98
|
+
resolvedOptions.apiHost = values.apiHost;
|
99
|
+
}
|
100
|
+
if (values.apiPort) {
|
101
|
+
resolvedOptions.apiPort = +values.apiPort;
|
102
|
+
if (isNaN(resolvedOptions.apiPort)) {
|
103
|
+
throw new Error("`apiPort` must be an integer");
|
104
|
+
}
|
105
|
+
}
|
106
|
+
if (values.apiRootPath && typeof values.apiRootPath !== "string") {
|
107
|
+
throw new Error("`apiRootPath` must be a string");
|
108
|
+
}
|
109
|
+
if (values.apiRootPath) {
|
110
|
+
resolvedOptions.apiRootPath = values.apiRootPath;
|
111
|
+
}
|
112
|
+
}
|
113
|
+
resolvedOptions.apiRootPath = (0, import_helpers.coerceRootPath)(resolvedOptions.apiRootPath);
|
114
|
+
return resolvedOptions;
|
115
|
+
}
|
116
|
+
var import_util, import_helpers, DEFAULT_CREATE_SERVER_OPTIONS;
|
117
|
+
var init_createServerHelpers = __esm({
|
118
|
+
"src/createServerHelpers.ts"() {
|
119
|
+
"use strict";
|
120
|
+
import_util = require("util");
|
121
|
+
import_helpers = require("@redmix/fastify-web/dist/helpers");
|
122
|
+
init_cliHelpers();
|
123
|
+
DEFAULT_CREATE_SERVER_OPTIONS = {
|
124
|
+
apiRootPath: "/",
|
125
|
+
logger: {
|
126
|
+
level: process.env.LOG_LEVEL ?? (process.env.NODE_ENV === "development" ? "debug" : "warn")
|
127
|
+
},
|
128
|
+
fastifyServerOptions: {
|
129
|
+
requestTimeout: 15e3,
|
130
|
+
bodyLimit: 1024 * 1024 * 100
|
131
|
+
// 100MB
|
132
|
+
},
|
133
|
+
configureApiServer: () => {
|
134
|
+
},
|
135
|
+
parseArgs: true
|
136
|
+
};
|
137
|
+
}
|
138
|
+
});
|
139
|
+
|
140
|
+
// src/fastify.ts
|
141
|
+
async function loadFastifyConfig() {
|
142
|
+
const serverConfigPath = import_path.default.join(
|
143
|
+
(0, import_project_config2.getPaths)().base,
|
144
|
+
(0, import_project_config2.getConfig)().api.serverConfig
|
145
|
+
);
|
146
|
+
if (!import_fs.default.existsSync(serverConfigPath)) {
|
147
|
+
return serverConfigFile;
|
148
|
+
}
|
149
|
+
if (!isServerConfigLoaded) {
|
150
|
+
console.log(`Loading server config from ${serverConfigPath}`);
|
151
|
+
const config3 = await import(`file://${serverConfigPath}`);
|
152
|
+
serverConfigFile = { ...config3.default };
|
153
|
+
isServerConfigLoaded = true;
|
154
|
+
}
|
155
|
+
return serverConfigFile;
|
156
|
+
}
|
157
|
+
var import_fs, import_path, import_fastify, import_store, import_project_config2, DEFAULT_OPTIONS, isServerConfigLoaded, serverConfigFile, createFastifyInstance, fastify_default;
|
158
|
+
var init_fastify = __esm({
|
159
|
+
"src/fastify.ts"() {
|
160
|
+
"use strict";
|
161
|
+
import_fs = __toESM(require("fs"));
|
162
|
+
import_path = __toESM(require("path"));
|
163
|
+
import_fastify = __toESM(require("fastify"));
|
164
|
+
import_store = require("@redmix/context/dist/store");
|
165
|
+
import_project_config2 = require("@redmix/project-config");
|
166
|
+
DEFAULT_OPTIONS = {
|
167
|
+
logger: {
|
168
|
+
level: process.env.NODE_ENV === "development" ? "debug" : "info"
|
169
|
+
}
|
170
|
+
};
|
171
|
+
isServerConfigLoaded = false;
|
172
|
+
serverConfigFile = {
|
173
|
+
config: DEFAULT_OPTIONS,
|
174
|
+
configureFastify: async (fastify2, options) => {
|
175
|
+
fastify2.log.trace(
|
176
|
+
options,
|
177
|
+
`In configureFastify hook for side: ${options?.side}`
|
178
|
+
);
|
179
|
+
return fastify2;
|
180
|
+
}
|
181
|
+
};
|
182
|
+
createFastifyInstance = async (options) => {
|
183
|
+
const { config: config3 } = await loadFastifyConfig();
|
184
|
+
const fastify2 = (0, import_fastify.default)(options || config3 || DEFAULT_OPTIONS);
|
185
|
+
fastify2.addHook("onRequest", (_req, _reply, done) => {
|
186
|
+
(0, import_store.getAsyncStoreInstance)().run(/* @__PURE__ */ new Map(), done);
|
187
|
+
});
|
188
|
+
return fastify2;
|
189
|
+
};
|
190
|
+
fastify_default = createFastifyInstance;
|
191
|
+
}
|
192
|
+
});
|
193
|
+
|
194
|
+
// src/requestHandlers/utils.ts
|
195
|
+
var parseBody, mergeMultiValueHeaders;
|
196
|
+
var init_utils = __esm({
|
197
|
+
"src/requestHandlers/utils.ts"() {
|
198
|
+
"use strict";
|
199
|
+
parseBody = (rawBody) => {
|
200
|
+
if (typeof rawBody === "string") {
|
201
|
+
return { body: rawBody, isBase64Encoded: false };
|
202
|
+
}
|
203
|
+
if (rawBody instanceof Buffer) {
|
204
|
+
return { body: rawBody.toString("base64"), isBase64Encoded: true };
|
205
|
+
}
|
206
|
+
return { body: "", isBase64Encoded: false };
|
207
|
+
};
|
208
|
+
mergeMultiValueHeaders = (headers, multiValueHeaders) => {
|
209
|
+
const mergedHeaders = Object.entries(
|
210
|
+
headers || {}
|
211
|
+
).reduce((acc, [name, value]) => {
|
212
|
+
acc[name.toLowerCase()] = [value];
|
213
|
+
return acc;
|
214
|
+
}, {});
|
215
|
+
Object.entries(multiValueHeaders || {}).forEach(([headerName, values]) => {
|
216
|
+
const name = headerName.toLowerCase();
|
217
|
+
if (name.toLowerCase() === "set-cookie") {
|
218
|
+
mergedHeaders["set-cookie"] = values;
|
219
|
+
} else {
|
220
|
+
mergedHeaders[name] = [values.join("; ")];
|
221
|
+
}
|
222
|
+
});
|
223
|
+
return mergedHeaders;
|
224
|
+
};
|
225
|
+
}
|
226
|
+
});
|
227
|
+
|
228
|
+
// src/requestHandlers/awsLambdaFastify.ts
|
229
|
+
var import_qs, lambdaEventForFastifyRequest, fastifyResponseForLambdaResult, fastifyResponseForLambdaError, requestHandler;
|
230
|
+
var init_awsLambdaFastify = __esm({
|
231
|
+
"src/requestHandlers/awsLambdaFastify.ts"() {
|
232
|
+
"use strict";
|
233
|
+
import_qs = __toESM(require("qs"));
|
234
|
+
init_utils();
|
235
|
+
lambdaEventForFastifyRequest = (request) => {
|
236
|
+
return {
|
237
|
+
httpMethod: request.method,
|
238
|
+
headers: request.headers,
|
239
|
+
path: request.urlData("path"),
|
240
|
+
queryStringParameters: import_qs.default.parse(request.url.split(/\?(.+)/)[1]),
|
241
|
+
requestContext: {
|
242
|
+
requestId: request.id,
|
243
|
+
identity: {
|
244
|
+
sourceIp: request.ip
|
245
|
+
}
|
246
|
+
},
|
247
|
+
...parseBody(request.rawBody || "")
|
248
|
+
// adds `body` and `isBase64Encoded`
|
249
|
+
};
|
250
|
+
};
|
251
|
+
fastifyResponseForLambdaResult = (reply, lambdaResult) => {
|
252
|
+
const {
|
253
|
+
statusCode = 200,
|
254
|
+
headers,
|
255
|
+
body = "",
|
256
|
+
multiValueHeaders
|
257
|
+
} = lambdaResult;
|
258
|
+
const mergedHeaders = mergeMultiValueHeaders(headers, multiValueHeaders);
|
259
|
+
Object.entries(mergedHeaders).forEach(
|
260
|
+
([name, values]) => values.forEach((value) => reply.header(name, value))
|
261
|
+
);
|
262
|
+
reply.status(statusCode);
|
263
|
+
if (lambdaResult.isBase64Encoded) {
|
264
|
+
return reply.send(Buffer.from(body, "base64"));
|
265
|
+
} else {
|
266
|
+
return reply.send(body);
|
267
|
+
}
|
268
|
+
};
|
269
|
+
fastifyResponseForLambdaError = (req, reply, error) => {
|
270
|
+
req.log.error(error);
|
271
|
+
reply.status(500).send();
|
272
|
+
};
|
273
|
+
requestHandler = async (req, reply, handler3) => {
|
274
|
+
const event = lambdaEventForFastifyRequest(req);
|
275
|
+
const handlerCallback = (reply2) => (error, lambdaResult) => {
|
276
|
+
if (error) {
|
277
|
+
fastifyResponseForLambdaError(req, reply2, error);
|
278
|
+
return;
|
279
|
+
}
|
280
|
+
fastifyResponseForLambdaResult(reply2, lambdaResult);
|
281
|
+
};
|
282
|
+
const handlerPromise = handler3(
|
283
|
+
event,
|
284
|
+
// @ts-expect-error - Add support for context: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/0bb210867d16170c4a08d9ce5d132817651a0f80/types/aws-lambda/index.d.ts#L443-L467
|
285
|
+
{},
|
286
|
+
handlerCallback(reply)
|
287
|
+
);
|
288
|
+
if (handlerPromise && typeof handlerPromise.then === "function") {
|
289
|
+
try {
|
290
|
+
const lambdaResponse = await handlerPromise;
|
291
|
+
return fastifyResponseForLambdaResult(reply, lambdaResponse);
|
292
|
+
} catch (error) {
|
293
|
+
return fastifyResponseForLambdaError(req, reply, error);
|
294
|
+
}
|
295
|
+
}
|
296
|
+
};
|
297
|
+
}
|
298
|
+
});
|
299
|
+
|
300
|
+
// src/plugins/lambdaLoader.ts
|
301
|
+
function findApiDistFunctions(cwd = (0, import_project_config3.getPaths)().api.base, options = {}) {
|
302
|
+
return import_fast_glob.default.sync("dist/functions/**/*.{ts,js}", {
|
303
|
+
cwd,
|
304
|
+
deep: 2,
|
305
|
+
// We don't support deeply nested api functions, to maximise compatibility with deployment providers
|
306
|
+
absolute: true,
|
307
|
+
...options
|
308
|
+
});
|
309
|
+
}
|
310
|
+
var import_path2, import_chalk, import_fast_glob, import_lodash, import_project_config3, LAMBDA_FUNCTIONS, setLambdaFunctions, loadFunctionsFromDist, lambdaRequestHandler;
|
311
|
+
var init_lambdaLoader = __esm({
|
312
|
+
"src/plugins/lambdaLoader.ts"() {
|
313
|
+
"use strict";
|
314
|
+
import_path2 = __toESM(require("path"));
|
315
|
+
import_chalk = __toESM(require("chalk"));
|
316
|
+
import_fast_glob = __toESM(require("fast-glob"));
|
317
|
+
import_lodash = require("lodash");
|
318
|
+
import_project_config3 = require("@redmix/project-config");
|
319
|
+
init_awsLambdaFastify();
|
320
|
+
LAMBDA_FUNCTIONS = {};
|
321
|
+
setLambdaFunctions = async (foundFunctions) => {
|
322
|
+
const tsImport = Date.now();
|
323
|
+
console.log(import_chalk.default.dim.italic("Importing Server Functions... "));
|
324
|
+
const imports = foundFunctions.map(async (fnPath) => {
|
325
|
+
const ts = Date.now();
|
326
|
+
const routeName = import_path2.default.basename(fnPath).replace(".js", "");
|
327
|
+
const { handler: handler3 } = await import(`file://${fnPath}`);
|
328
|
+
LAMBDA_FUNCTIONS[routeName] = handler3;
|
329
|
+
if (!handler3) {
|
330
|
+
console.warn(
|
331
|
+
routeName,
|
332
|
+
"at",
|
333
|
+
fnPath,
|
334
|
+
"does not have a function called handler defined."
|
335
|
+
);
|
336
|
+
}
|
337
|
+
console.log(
|
338
|
+
import_chalk.default.magenta("/" + routeName),
|
339
|
+
import_chalk.default.dim.italic(Date.now() - ts + " ms")
|
340
|
+
);
|
341
|
+
});
|
342
|
+
await Promise.all(imports);
|
343
|
+
console.log(
|
344
|
+
import_chalk.default.dim.italic("...Done importing in " + (Date.now() - tsImport) + " ms")
|
345
|
+
);
|
346
|
+
};
|
347
|
+
loadFunctionsFromDist = async (options = {}) => {
|
348
|
+
const serverFunctions = findApiDistFunctions(
|
349
|
+
(0, import_project_config3.getPaths)().api.base,
|
350
|
+
options?.fastGlobOptions
|
351
|
+
);
|
352
|
+
const i = serverFunctions.findIndex((x) => x.includes("graphql"));
|
353
|
+
if (i >= 0) {
|
354
|
+
const graphQLFn = serverFunctions.splice(i, 1)[0];
|
355
|
+
serverFunctions.unshift(graphQLFn);
|
356
|
+
}
|
357
|
+
await setLambdaFunctions(serverFunctions);
|
358
|
+
};
|
359
|
+
lambdaRequestHandler = async (req, reply) => {
|
360
|
+
const { routeName } = req.params;
|
361
|
+
if (!LAMBDA_FUNCTIONS[routeName]) {
|
362
|
+
const errorMessage = `Function "${routeName}" was not found.`;
|
363
|
+
req.log.error(errorMessage);
|
364
|
+
reply.status(404);
|
365
|
+
if (process.env.NODE_ENV === "development") {
|
366
|
+
const devError = {
|
367
|
+
error: errorMessage,
|
368
|
+
availableFunctions: Object.keys(LAMBDA_FUNCTIONS)
|
369
|
+
};
|
370
|
+
reply.send(devError);
|
371
|
+
} else {
|
372
|
+
reply.send((0, import_lodash.escape)(errorMessage));
|
373
|
+
}
|
374
|
+
return;
|
375
|
+
}
|
376
|
+
return requestHandler(req, reply, LAMBDA_FUNCTIONS[routeName]);
|
377
|
+
};
|
378
|
+
}
|
379
|
+
});
|
380
|
+
|
381
|
+
// src/plugins/api.ts
|
382
|
+
async function redwoodFastifyAPI(fastify2, opts) {
|
383
|
+
const redwoodOptions = opts.redwood ?? {};
|
384
|
+
redwoodOptions.apiRootPath ??= "/";
|
385
|
+
redwoodOptions.apiRootPath = (0, import_helpers2.coerceRootPath)(redwoodOptions.apiRootPath);
|
386
|
+
redwoodOptions.fastGlobOptions ??= {};
|
387
|
+
redwoodOptions.loadUserConfig ??= false;
|
388
|
+
fastify2.register(import_url_data.default);
|
389
|
+
await fastify2.register(import_fastify_raw_body.default);
|
390
|
+
fastify2.addHook("onRequest", (_req, _reply, done) => {
|
391
|
+
(0, import_store2.getAsyncStoreInstance)().run(/* @__PURE__ */ new Map(), done);
|
392
|
+
});
|
393
|
+
fastify2.addContentTypeParser(
|
394
|
+
["application/x-www-form-urlencoded", "multipart/form-data"],
|
395
|
+
{ parseAs: "string" },
|
396
|
+
fastify2.defaultTextParser
|
397
|
+
);
|
398
|
+
if (redwoodOptions.loadUserConfig) {
|
399
|
+
const { configureFastify } = await loadFastifyConfig();
|
400
|
+
if (configureFastify) {
|
401
|
+
await configureFastify(fastify2, {
|
402
|
+
side: "api",
|
403
|
+
apiRootPath: redwoodOptions.apiRootPath
|
404
|
+
});
|
405
|
+
}
|
406
|
+
}
|
407
|
+
if (redwoodOptions.configureServer) {
|
408
|
+
await redwoodOptions.configureServer(fastify2);
|
409
|
+
}
|
410
|
+
fastify2.all(`${redwoodOptions.apiRootPath}:routeName`, lambdaRequestHandler);
|
411
|
+
fastify2.all(`${redwoodOptions.apiRootPath}:routeName/*`, lambdaRequestHandler);
|
412
|
+
await loadFunctionsFromDist({
|
413
|
+
fastGlobOptions: redwoodOptions.fastGlobOptions
|
414
|
+
});
|
415
|
+
}
|
416
|
+
var import_url_data, import_fastify_raw_body, import_store2, import_helpers2;
|
417
|
+
var init_api = __esm({
|
418
|
+
"src/plugins/api.ts"() {
|
419
|
+
"use strict";
|
420
|
+
import_url_data = __toESM(require("@fastify/url-data"));
|
421
|
+
import_fastify_raw_body = __toESM(require("fastify-raw-body"));
|
422
|
+
import_store2 = require("@redmix/context/dist/store");
|
423
|
+
import_helpers2 = require("@redmix/fastify-web/dist/helpers");
|
424
|
+
init_fastify();
|
425
|
+
init_lambdaLoader();
|
426
|
+
}
|
427
|
+
});
|
428
|
+
|
429
|
+
// src/plugins/graphql.ts
|
430
|
+
var graphql_exports = {};
|
431
|
+
__export(graphql_exports, {
|
432
|
+
redwoodFastifyGraphQLServer: () => redwoodFastifyGraphQLServer
|
433
|
+
});
|
434
|
+
async function redwoodFastifyGraphQLServer(fastify2, options) {
|
435
|
+
const redwoodOptions = options.redwood ?? {};
|
436
|
+
redwoodOptions.apiRootPath ??= "/";
|
437
|
+
redwoodOptions.apiRootPath = (0, import_helpers3.coerceRootPath)(redwoodOptions.apiRootPath);
|
438
|
+
fastify2.register(import_url_data2.default);
|
439
|
+
fastify2.register(import_multipart.default);
|
440
|
+
const method = ["GET", "POST", "OPTIONS"];
|
441
|
+
fastify2.addHook("onRequest", (_req, _reply, done) => {
|
442
|
+
(0, import_store3.getAsyncStoreInstance)().run(/* @__PURE__ */ new Map(), done);
|
443
|
+
});
|
444
|
+
try {
|
445
|
+
if (!redwoodOptions.graphql) {
|
446
|
+
const [graphqlFunctionPath] = await (0, import_fast_glob2.default)("dist/functions/graphql.{ts,js}", {
|
447
|
+
cwd: (0, import_project_config4.getPaths)().api.base,
|
448
|
+
absolute: true
|
449
|
+
});
|
450
|
+
const { __rw_graphqlOptions } = await import(`file://${graphqlFunctionPath}`);
|
451
|
+
redwoodOptions.graphql = __rw_graphqlOptions;
|
452
|
+
}
|
453
|
+
const graphqlOptions = redwoodOptions.graphql;
|
454
|
+
if (graphqlOptions?.realtime) {
|
455
|
+
const { useRedwoodRealtime } = await import("@redmix/realtime");
|
456
|
+
const originalExtraPlugins = graphqlOptions.extraPlugins ?? [];
|
457
|
+
originalExtraPlugins.push(useRedwoodRealtime(graphqlOptions.realtime));
|
458
|
+
graphqlOptions.extraPlugins = originalExtraPlugins;
|
459
|
+
if (graphqlOptions.realtime.subscriptions) {
|
460
|
+
method.push("PUT");
|
461
|
+
}
|
462
|
+
}
|
463
|
+
const { yoga } = (0, import_graphql_server.createGraphQLYoga)(graphqlOptions);
|
464
|
+
const graphQLYogaHandler = async (req, reply) => {
|
465
|
+
const response = await yoga.handleNodeRequest(req, {
|
466
|
+
req,
|
467
|
+
reply,
|
468
|
+
event: lambdaEventForFastifyRequest(req),
|
469
|
+
requestContext: {}
|
470
|
+
});
|
471
|
+
for (const [name, value] of response.headers) {
|
472
|
+
reply.header(name, value);
|
473
|
+
}
|
474
|
+
reply.status(response.status);
|
475
|
+
reply.send(response.body);
|
476
|
+
return reply;
|
477
|
+
};
|
478
|
+
const graphqlEndpoint = trimSlashes(yoga.graphqlEndpoint);
|
479
|
+
const routePaths = ["", "/health", "/readiness", "/stream"];
|
480
|
+
for (const routePath of routePaths) {
|
481
|
+
fastify2.route({
|
482
|
+
url: `${redwoodOptions.apiRootPath}${graphqlEndpoint}${routePath}`,
|
483
|
+
method,
|
484
|
+
handler: (req, reply) => graphQLYogaHandler(req, reply)
|
485
|
+
});
|
486
|
+
}
|
487
|
+
fastify2.addHook("onReady", (done) => {
|
488
|
+
console.info(`GraphQL Yoga Server endpoint at ${graphqlEndpoint}`);
|
489
|
+
console.info(
|
490
|
+
`GraphQL Yoga Server Health Check endpoint at ${graphqlEndpoint}/health`
|
491
|
+
);
|
492
|
+
console.info(
|
493
|
+
`GraphQL Yoga Server Readiness endpoint at ${graphqlEndpoint}/readiness`
|
494
|
+
);
|
495
|
+
done();
|
496
|
+
});
|
497
|
+
} catch (e) {
|
498
|
+
console.log(e);
|
499
|
+
}
|
500
|
+
}
|
501
|
+
function trimSlashes(path5) {
|
502
|
+
return path5.replace(/^\/|\/$/g, "");
|
503
|
+
}
|
504
|
+
var import_multipart, import_url_data2, import_fast_glob2, import_store3, import_helpers3, import_graphql_server, import_project_config4;
|
505
|
+
var init_graphql = __esm({
|
506
|
+
"src/plugins/graphql.ts"() {
|
507
|
+
"use strict";
|
508
|
+
import_multipart = __toESM(require("@fastify/multipart"));
|
509
|
+
import_url_data2 = __toESM(require("@fastify/url-data"));
|
510
|
+
import_fast_glob2 = __toESM(require("fast-glob"));
|
511
|
+
import_store3 = require("@redmix/context/dist/store");
|
512
|
+
import_helpers3 = require("@redmix/fastify-web/dist/helpers");
|
513
|
+
import_graphql_server = require("@redmix/graphql-server");
|
514
|
+
import_project_config4 = require("@redmix/project-config");
|
515
|
+
init_awsLambdaFastify();
|
516
|
+
}
|
517
|
+
});
|
518
|
+
|
519
|
+
// src/createServer.ts
|
520
|
+
async function createServer(options = {}) {
|
521
|
+
const {
|
522
|
+
apiRootPath,
|
523
|
+
fastifyServerOptions,
|
524
|
+
configureApiServer,
|
525
|
+
apiPort,
|
526
|
+
apiHost
|
527
|
+
} = resolveOptions(options);
|
528
|
+
const serverConfigPath = import_path3.default.join(
|
529
|
+
(0, import_project_config5.getPaths)().base,
|
530
|
+
(0, import_project_config5.getConfig)().api.serverConfig
|
531
|
+
);
|
532
|
+
if (import_fs2.default.existsSync(serverConfigPath)) {
|
533
|
+
console.warn(
|
534
|
+
import_chalk2.default.yellow(
|
535
|
+
[
|
536
|
+
"",
|
537
|
+
`Ignoring \`config\` and \`configureServer\` in api/server.config.js.`,
|
538
|
+
`Migrate them to api/src/server.{ts,js}:`,
|
539
|
+
"",
|
540
|
+
`\`\`\`js title="api/src/server.{ts,js}"`,
|
541
|
+
"// Pass your config to `createServer`",
|
542
|
+
"const server = createServer({",
|
543
|
+
" fastifyServerOptions: myFastifyConfig",
|
544
|
+
"})",
|
545
|
+
"",
|
546
|
+
"// Then inline your `configureFastify` logic:",
|
547
|
+
"server.register(myFastifyPlugin)",
|
548
|
+
"```",
|
549
|
+
""
|
550
|
+
].join("\n")
|
551
|
+
)
|
552
|
+
);
|
553
|
+
}
|
554
|
+
const server = Object.assign((0, import_fastify3.default)(fastifyServerOptions), {
|
555
|
+
// `start` will get replaced further down in this file
|
556
|
+
start: async () => {
|
557
|
+
throw new Error("Not implemented yet");
|
558
|
+
}
|
559
|
+
});
|
560
|
+
server.addHook("onRequest", (_req, _reply, done) => {
|
561
|
+
(0, import_store4.getAsyncStoreInstance)().run(/* @__PURE__ */ new Map(), done);
|
562
|
+
});
|
563
|
+
await server.register(redwoodFastifyAPI, {
|
564
|
+
redwood: {
|
565
|
+
apiRootPath,
|
566
|
+
fastGlobOptions: {
|
567
|
+
ignore: ["**/dist/functions/graphql.js"]
|
568
|
+
},
|
569
|
+
configureServer: configureApiServer
|
570
|
+
}
|
571
|
+
});
|
572
|
+
const [graphqlFunctionPath] = await (0, import_fast_glob3.default)("dist/functions/graphql.{ts,js}", {
|
573
|
+
cwd: (0, import_project_config5.getPaths)().api.base,
|
574
|
+
absolute: true
|
575
|
+
});
|
576
|
+
if (graphqlFunctionPath) {
|
577
|
+
const { redwoodFastifyGraphQLServer: redwoodFastifyGraphQLServer2 } = await Promise.resolve().then(() => (init_graphql(), graphql_exports));
|
578
|
+
const { __rw_graphqlOptions } = await import(`file://${graphqlFunctionPath}`);
|
579
|
+
await server.register(redwoodFastifyGraphQLServer2, {
|
580
|
+
redwood: {
|
581
|
+
apiRootPath,
|
582
|
+
graphql: __rw_graphqlOptions
|
583
|
+
}
|
584
|
+
});
|
585
|
+
}
|
586
|
+
server.addHook("onReady", (done) => {
|
587
|
+
process.send?.("ready");
|
588
|
+
done();
|
589
|
+
});
|
590
|
+
server.addHook("onListen", (done) => {
|
591
|
+
console.log(
|
592
|
+
`Server listening at ${import_chalk2.default.magenta(
|
593
|
+
`${server.listeningOrigin}${apiRootPath}`
|
594
|
+
)}`
|
595
|
+
);
|
596
|
+
done();
|
597
|
+
});
|
598
|
+
server.start = (options2 = {}) => {
|
599
|
+
return server.listen({
|
600
|
+
...options2,
|
601
|
+
port: apiPort,
|
602
|
+
host: apiHost
|
603
|
+
});
|
604
|
+
};
|
605
|
+
return server;
|
606
|
+
}
|
607
|
+
var import_fs2, import_path3, import_chalk2, import_dotenv_defaults, import_fast_glob3, import_fastify3, import_store4, import_project_config5;
|
608
|
+
var init_createServer = __esm({
|
609
|
+
"src/createServer.ts"() {
|
610
|
+
"use strict";
|
611
|
+
import_fs2 = __toESM(require("fs"));
|
612
|
+
import_path3 = __toESM(require("path"));
|
613
|
+
import_chalk2 = __toESM(require("chalk"));
|
614
|
+
import_dotenv_defaults = require("dotenv-defaults");
|
615
|
+
import_fast_glob3 = __toESM(require("fast-glob"));
|
616
|
+
import_fastify3 = __toESM(require("fastify"));
|
617
|
+
import_store4 = require("@redmix/context/dist/store");
|
618
|
+
import_project_config5 = require("@redmix/project-config");
|
619
|
+
init_createServerHelpers();
|
620
|
+
init_api();
|
621
|
+
if (!process.env.REDWOOD_ENV_FILES_LOADED) {
|
622
|
+
(0, import_dotenv_defaults.config)({
|
623
|
+
path: import_path3.default.join((0, import_project_config5.getPaths)().base, ".env"),
|
624
|
+
defaults: import_path3.default.join((0, import_project_config5.getPaths)().base, ".env.defaults"),
|
625
|
+
multiline: true
|
626
|
+
});
|
627
|
+
process.env.REDWOOD_ENV_FILES_LOADED = "true";
|
628
|
+
}
|
629
|
+
}
|
630
|
+
});
|
631
|
+
|
632
|
+
// src/apiCLIConfigHandler.ts
|
633
|
+
async function handler(options = {}) {
|
634
|
+
const timeStart = Date.now();
|
635
|
+
console.log(import_chalk3.default.dim.italic("Starting API Server..."));
|
636
|
+
options.apiRootPath = (0, import_fastify_web.coerceRootPath)(options.apiRootPath ?? "/");
|
637
|
+
const fastify2 = await createServer({
|
638
|
+
apiRootPath: options.apiRootPath
|
639
|
+
});
|
640
|
+
options.host ??= getAPIHost();
|
641
|
+
options.port ??= getAPIPort();
|
642
|
+
await fastify2.start();
|
643
|
+
fastify2.log.trace(
|
644
|
+
{ custom: { ...fastify2.initialConfig } },
|
645
|
+
"Fastify server configuration"
|
646
|
+
);
|
647
|
+
fastify2.log.trace(`Registered plugins
|
648
|
+
${fastify2.printPlugins()}`);
|
649
|
+
console.log(import_chalk3.default.dim.italic("Took " + (Date.now() - timeStart) + " ms"));
|
650
|
+
let address = fastify2.listeningOrigin;
|
651
|
+
if (process.env.NODE_ENV !== "production") {
|
652
|
+
address = address.replace(/http:\/\/\[::\]/, "http://localhost");
|
653
|
+
}
|
654
|
+
const apiServer = import_chalk3.default.magenta(`${address}${options.apiRootPath}`);
|
655
|
+
const graphqlEndpoint = import_chalk3.default.magenta(`${apiServer}graphql`);
|
656
|
+
console.log(`API server listening at ${apiServer}`);
|
657
|
+
console.log(`GraphQL endpoint at ${graphqlEndpoint}`);
|
658
|
+
process?.send?.("ready");
|
659
|
+
}
|
660
|
+
var import_chalk3, import_fastify_web;
|
661
|
+
var init_apiCLIConfigHandler = __esm({
|
662
|
+
"src/apiCLIConfigHandler.ts"() {
|
663
|
+
"use strict";
|
664
|
+
import_chalk3 = __toESM(require("chalk"));
|
665
|
+
import_fastify_web = require("@redmix/fastify-web");
|
666
|
+
init_cliHelpers();
|
667
|
+
init_createServer();
|
668
|
+
}
|
669
|
+
});
|
670
|
+
|
671
|
+
// src/bothCLIConfigHandler.ts
|
672
|
+
async function handler2(options) {
|
673
|
+
const timeStart = Date.now();
|
674
|
+
console.log(import_chalk4.default.dim.italic("Starting API and Web Servers..."));
|
675
|
+
options.webHost ??= getWebHost();
|
676
|
+
options.webPort ??= getWebPort();
|
677
|
+
options.apiHost ??= getAPIHost();
|
678
|
+
options.apiPort ??= getAPIPort();
|
679
|
+
options.apiRootPath = (0, import_fastify_web2.coerceRootPath)(options.apiRootPath ?? "/");
|
680
|
+
const apiProxyTarget = [
|
681
|
+
"http://",
|
682
|
+
options.apiHost.includes(":") ? `[${options.apiHost}]` : options.apiHost,
|
683
|
+
":",
|
684
|
+
options.apiPort,
|
685
|
+
options.apiRootPath
|
686
|
+
].join("");
|
687
|
+
const webFastify = await fastify_default();
|
688
|
+
webFastify.register(import_fastify_web2.redwoodFastifyWeb, {
|
689
|
+
redwood: {
|
690
|
+
apiProxyTarget
|
691
|
+
}
|
692
|
+
});
|
693
|
+
const apiFastify = await createServer({
|
694
|
+
apiRootPath: options.apiRootPath
|
695
|
+
});
|
696
|
+
await webFastify.listen({
|
697
|
+
port: options.webPort,
|
698
|
+
host: options.webHost,
|
699
|
+
listenTextResolver: getListenTextResolver("Web")
|
700
|
+
});
|
701
|
+
webFastify.log.trace(
|
702
|
+
{ custom: { ...webFastify.initialConfig } },
|
703
|
+
"Fastify server configuration"
|
704
|
+
);
|
705
|
+
webFastify.log.trace(`Registered plugins
|
706
|
+
${webFastify.printPlugins()}`);
|
707
|
+
await apiFastify.listen({
|
708
|
+
port: options.apiPort,
|
709
|
+
host: options.apiHost,
|
710
|
+
listenTextResolver: getListenTextResolver("API")
|
711
|
+
});
|
712
|
+
apiFastify.log.trace(
|
713
|
+
{ custom: { ...apiFastify.initialConfig } },
|
714
|
+
"Fastify server configuration"
|
715
|
+
);
|
716
|
+
apiFastify.log.trace(`Registered plugins
|
717
|
+
${apiFastify.printPlugins()}`);
|
718
|
+
console.log(import_chalk4.default.dim.italic("Took " + (Date.now() - timeStart) + " ms"));
|
719
|
+
const webServer = import_chalk4.default.green(webFastify.listeningOrigin);
|
720
|
+
const apiServer = import_chalk4.default.magenta(
|
721
|
+
`${apiFastify.listeningOrigin}${options.apiRootPath}`
|
722
|
+
);
|
723
|
+
const graphqlEndpoint = import_chalk4.default.magenta(`${apiServer}graphql`);
|
724
|
+
console.log(`Web server listening at ${webServer}`);
|
725
|
+
console.log(`API server listening at ${apiServer}`);
|
726
|
+
console.log(`GraphQL endpoint at ${graphqlEndpoint}`);
|
727
|
+
process?.send?.("ready");
|
728
|
+
}
|
729
|
+
function getListenTextResolver(side) {
|
730
|
+
return (address) => {
|
731
|
+
if (process.env.NODE_ENV !== "production") {
|
732
|
+
address = address.replace(/http:\/\/\[::\]/, "http://localhost");
|
733
|
+
}
|
734
|
+
return `${side} server listening at ${address}`;
|
735
|
+
};
|
736
|
+
}
|
737
|
+
var import_chalk4, import_fastify_web2;
|
738
|
+
var init_bothCLIConfigHandler = __esm({
|
739
|
+
"src/bothCLIConfigHandler.ts"() {
|
740
|
+
"use strict";
|
741
|
+
import_chalk4 = __toESM(require("chalk"));
|
742
|
+
import_fastify_web2 = require("@redmix/fastify-web");
|
743
|
+
init_cliHelpers();
|
744
|
+
init_createServer();
|
745
|
+
init_fastify();
|
746
|
+
}
|
747
|
+
});
|
748
|
+
|
749
|
+
// src/bin.ts
|
750
|
+
var import_path4 = __toESM(require("path"));
|
751
|
+
var import_dotenv_defaults2 = require("dotenv-defaults");
|
752
|
+
var import_helpers4 = require("yargs/helpers");
|
753
|
+
var import_yargs = __toESM(require("yargs/yargs"));
|
754
|
+
var import_project_config6 = require("@redmix/project-config");
|
755
|
+
var import_web_server = require("@redmix/web-server");
|
756
|
+
|
757
|
+
// src/apiCLIConfig.ts
|
758
|
+
var description = "Start a server for serving the api side";
|
759
|
+
function builder(yargs2) {
|
760
|
+
yargs2.options({
|
761
|
+
port: {
|
762
|
+
description: "The port to listen at",
|
763
|
+
type: "number",
|
764
|
+
alias: "p"
|
765
|
+
},
|
766
|
+
host: {
|
767
|
+
description: "The host to listen at. Note that you most likely want this to be '0.0.0.0' in production",
|
768
|
+
type: "string"
|
769
|
+
},
|
770
|
+
apiRootPath: {
|
771
|
+
description: "Root path where your api functions are served",
|
772
|
+
type: "string",
|
773
|
+
alias: ["api-root-path", "rootPath", "root-path"],
|
774
|
+
default: "/"
|
775
|
+
},
|
776
|
+
// This became a no-op in v7 because env files weren't loaded by default
|
777
|
+
// but removing it would break yargs parsing for older projects,
|
778
|
+
// so leaving it here so that yargs doesn't throw an error
|
779
|
+
loadEnvFiles: {
|
780
|
+
hidden: true
|
781
|
+
}
|
782
|
+
});
|
783
|
+
}
|
784
|
+
|
785
|
+
// src/bin.ts
|
786
|
+
init_apiCLIConfigHandler();
|
787
|
+
|
788
|
+
// src/bothCLIConfig.ts
|
789
|
+
var description2 = "Start a server for serving the api and web sides";
|
790
|
+
function builder2(yargs2) {
|
791
|
+
yargs2.options({
|
792
|
+
webPort: {
|
793
|
+
description: "The port for the web server to listen on",
|
794
|
+
type: "number",
|
795
|
+
alias: ["web-port"]
|
796
|
+
},
|
797
|
+
webHost: {
|
798
|
+
description: "The host for the web server to listen on. Note that you most likely want this to be '0.0.0.0' in production",
|
799
|
+
type: "string",
|
800
|
+
alias: ["web-host"]
|
801
|
+
},
|
802
|
+
apiPort: {
|
803
|
+
description: "The port for the api server to listen on",
|
804
|
+
type: "number",
|
805
|
+
alias: ["api-port"]
|
806
|
+
},
|
807
|
+
apiHost: {
|
808
|
+
description: "The host for the api server to listen on. Note that you most likely want this to be '0.0.0.0' in production",
|
809
|
+
type: "string",
|
810
|
+
alias: ["api-host"]
|
811
|
+
},
|
812
|
+
apiRootPath: {
|
813
|
+
description: "Root path where your api functions are served",
|
814
|
+
type: "string",
|
815
|
+
alias: ["api-root-path", "rootPath", "root-path"],
|
816
|
+
default: "/"
|
817
|
+
}
|
818
|
+
});
|
819
|
+
}
|
820
|
+
|
821
|
+
// src/bin.ts
|
822
|
+
init_bothCLIConfigHandler();
|
823
|
+
if (!process.env.REDWOOD_ENV_FILES_LOADED) {
|
824
|
+
(0, import_dotenv_defaults2.config)({
|
825
|
+
path: import_path4.default.join((0, import_project_config6.getPaths)().base, ".env"),
|
826
|
+
defaults: import_path4.default.join((0, import_project_config6.getPaths)().base, ".env.defaults"),
|
827
|
+
multiline: true
|
828
|
+
});
|
829
|
+
process.env.REDWOOD_ENV_FILES_LOADED = "true";
|
830
|
+
}
|
831
|
+
process.env.NODE_ENV ??= "production";
|
832
|
+
(0, import_yargs.default)((0, import_helpers4.hideBin)(process.argv)).scriptName("rw-server").strict().alias("h", "help").alias("v", "version").command(
|
833
|
+
"$0",
|
834
|
+
description2,
|
835
|
+
// @ts-expect-error The yargs types seem wrong; it's ok for builder to be a function
|
836
|
+
builder2,
|
837
|
+
handler2
|
838
|
+
).command(
|
839
|
+
"api",
|
840
|
+
description,
|
841
|
+
// @ts-expect-error The yargs types seem wrong; it's ok for builder to be a function
|
842
|
+
builder,
|
843
|
+
handler
|
844
|
+
).command(
|
845
|
+
"web",
|
846
|
+
import_web_server.description,
|
847
|
+
// @ts-expect-error The yargs types seem wrong; it's ok for builder to be a function
|
848
|
+
import_web_server.builder,
|
849
|
+
import_web_server.handler
|
850
|
+
).parse();
|