@backstage/backend-app-api 0.2.4 → 0.3.0-next.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.
Potentially problematic release.
This version of @backstage/backend-app-api might be problematic. Click here for more details.
- package/CHANGELOG.md +36 -0
- package/alpha/package.json +1 -1
- package/dist/index.alpha.d.ts +270 -9
- package/dist/index.beta.d.ts +270 -9
- package/dist/index.cjs.js +844 -156
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +270 -9
- package/package.json +26 -6
package/dist/index.cjs.js
CHANGED
|
@@ -2,32 +2,575 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
-
var
|
|
5
|
+
var http = require('http');
|
|
6
|
+
var https = require('https');
|
|
7
|
+
var stoppableServer = require('stoppable');
|
|
8
|
+
var fs = require('fs-extra');
|
|
9
|
+
var path = require('path');
|
|
10
|
+
var forge = require('node-forge');
|
|
11
|
+
var cors = require('cors');
|
|
12
|
+
var helmet = require('helmet');
|
|
13
|
+
var morgan = require('morgan');
|
|
14
|
+
var compression = require('compression');
|
|
15
|
+
var minimatch = require('minimatch');
|
|
6
16
|
var errors = require('@backstage/errors');
|
|
17
|
+
var backendPluginApi = require('@backstage/backend-plugin-api');
|
|
18
|
+
var express = require('express');
|
|
7
19
|
var backendCommon = require('@backstage/backend-common');
|
|
8
20
|
var pluginPermissionNode = require('@backstage/plugin-permission-node');
|
|
9
21
|
var backendTasks = require('@backstage/backend-tasks');
|
|
10
|
-
var Router = require('express-promise-router');
|
|
11
22
|
|
|
12
23
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
13
24
|
|
|
14
|
-
|
|
25
|
+
function _interopNamespace(e) {
|
|
26
|
+
if (e && e.__esModule) return e;
|
|
27
|
+
var n = Object.create(null);
|
|
28
|
+
if (e) {
|
|
29
|
+
Object.keys(e).forEach(function (k) {
|
|
30
|
+
if (k !== 'default') {
|
|
31
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
32
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
33
|
+
enumerable: true,
|
|
34
|
+
get: function () { return e[k]; }
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
n["default"] = e;
|
|
40
|
+
return Object.freeze(n);
|
|
41
|
+
}
|
|
15
42
|
|
|
16
|
-
var
|
|
43
|
+
var http__namespace = /*#__PURE__*/_interopNamespace(http);
|
|
44
|
+
var https__namespace = /*#__PURE__*/_interopNamespace(https);
|
|
45
|
+
var stoppableServer__default = /*#__PURE__*/_interopDefaultLegacy(stoppableServer);
|
|
46
|
+
var fs__default = /*#__PURE__*/_interopDefaultLegacy(fs);
|
|
47
|
+
var forge__default = /*#__PURE__*/_interopDefaultLegacy(forge);
|
|
48
|
+
var cors__default = /*#__PURE__*/_interopDefaultLegacy(cors);
|
|
49
|
+
var helmet__default = /*#__PURE__*/_interopDefaultLegacy(helmet);
|
|
50
|
+
var morgan__default = /*#__PURE__*/_interopDefaultLegacy(morgan);
|
|
51
|
+
var compression__default = /*#__PURE__*/_interopDefaultLegacy(compression);
|
|
52
|
+
var express__default = /*#__PURE__*/_interopDefaultLegacy(express);
|
|
53
|
+
|
|
54
|
+
const DEFAULT_PORT = 7007;
|
|
55
|
+
const DEFAULT_HOST = "";
|
|
56
|
+
function readHttpServerOptions(config) {
|
|
57
|
+
return {
|
|
58
|
+
listen: readHttpListenOptions(config),
|
|
59
|
+
https: readHttpsOptions(config)
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
function readHttpListenOptions(config) {
|
|
63
|
+
var _a, _b;
|
|
64
|
+
const listen = config == null ? void 0 : config.getOptional("listen");
|
|
65
|
+
if (typeof listen === "string") {
|
|
66
|
+
const parts = String(listen).split(":");
|
|
67
|
+
const port = parseInt(parts[parts.length - 1], 10);
|
|
68
|
+
if (!isNaN(port)) {
|
|
69
|
+
if (parts.length === 1) {
|
|
70
|
+
return { port, host: DEFAULT_HOST };
|
|
71
|
+
}
|
|
72
|
+
if (parts.length === 2) {
|
|
73
|
+
return { host: parts[0], port };
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
throw new Error(
|
|
77
|
+
`Unable to parse listen address ${listen}, expected <port> or <host>:<port>`
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
const host = (_a = config == null ? void 0 : config.getOptional("listen.host")) != null ? _a : DEFAULT_HOST;
|
|
81
|
+
if (typeof host !== "string") {
|
|
82
|
+
config == null ? void 0 : config.getOptionalString("listen.host");
|
|
83
|
+
throw new Error("unreachable");
|
|
84
|
+
}
|
|
85
|
+
return {
|
|
86
|
+
port: (_b = config == null ? void 0 : config.getOptionalNumber("listen.port")) != null ? _b : DEFAULT_PORT,
|
|
87
|
+
host
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
function readHttpsOptions(config) {
|
|
91
|
+
const https = config == null ? void 0 : config.getOptional("https");
|
|
92
|
+
if (https === true) {
|
|
93
|
+
const baseUrl = config.getString("baseUrl");
|
|
94
|
+
let hostname;
|
|
95
|
+
try {
|
|
96
|
+
hostname = new URL(baseUrl).hostname;
|
|
97
|
+
} catch (error) {
|
|
98
|
+
throw new Error(`Invalid baseUrl "${baseUrl}"`);
|
|
99
|
+
}
|
|
100
|
+
return { certificate: { type: "generated", hostname } };
|
|
101
|
+
}
|
|
102
|
+
const cc = config == null ? void 0 : config.getOptionalConfig("https");
|
|
103
|
+
if (!cc) {
|
|
104
|
+
return void 0;
|
|
105
|
+
}
|
|
106
|
+
return {
|
|
107
|
+
certificate: {
|
|
108
|
+
type: "plain",
|
|
109
|
+
cert: cc.getString("certificate.cert"),
|
|
110
|
+
key: cc.getString("certificate.key")
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const FIVE_DAYS_IN_MS = 5 * 24 * 60 * 60 * 1e3;
|
|
116
|
+
const IP_HOSTNAME_REGEX = /:|^\d+\.\d+\.\d+\.\d+$/;
|
|
117
|
+
async function getGeneratedCertificate(hostname, logger) {
|
|
118
|
+
const hasModules = await fs__default["default"].pathExists("node_modules");
|
|
119
|
+
let certPath;
|
|
120
|
+
if (hasModules) {
|
|
121
|
+
certPath = path.resolve(
|
|
122
|
+
"node_modules/.cache/backstage-backend/dev-cert.pem"
|
|
123
|
+
);
|
|
124
|
+
await fs__default["default"].ensureDir(path.dirname(certPath));
|
|
125
|
+
} else {
|
|
126
|
+
certPath = path.resolve(".dev-cert.pem");
|
|
127
|
+
}
|
|
128
|
+
if (await fs__default["default"].pathExists(certPath)) {
|
|
129
|
+
try {
|
|
130
|
+
const cert = await fs__default["default"].readFile(certPath);
|
|
131
|
+
const crt = forge__default["default"].pki.certificateFromPem(cert.toString());
|
|
132
|
+
const remainingMs = crt.validity.notAfter.getTime() - Date.now();
|
|
133
|
+
if (remainingMs > FIVE_DAYS_IN_MS) {
|
|
134
|
+
logger.info("Using existing self-signed certificate");
|
|
135
|
+
return {
|
|
136
|
+
key: cert,
|
|
137
|
+
cert
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
} catch (error) {
|
|
141
|
+
logger.warn(`Unable to use existing self-signed certificate, ${error}`);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
logger.info("Generating new self-signed certificate");
|
|
145
|
+
const newCert = await generateCertificate(hostname);
|
|
146
|
+
await fs__default["default"].writeFile(certPath, newCert.cert + newCert.key, "utf8");
|
|
147
|
+
return newCert;
|
|
148
|
+
}
|
|
149
|
+
async function generateCertificate(hostname) {
|
|
150
|
+
const attributes = [
|
|
151
|
+
{
|
|
152
|
+
name: "commonName",
|
|
153
|
+
value: "dev-cert"
|
|
154
|
+
}
|
|
155
|
+
];
|
|
156
|
+
const sans = [
|
|
157
|
+
{
|
|
158
|
+
type: 2,
|
|
159
|
+
// DNS
|
|
160
|
+
value: "localhost"
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
type: 2,
|
|
164
|
+
value: "localhost.localdomain"
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
type: 2,
|
|
168
|
+
value: "[::1]"
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
type: 7,
|
|
172
|
+
// IP
|
|
173
|
+
ip: "127.0.0.1"
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
type: 7,
|
|
177
|
+
ip: "fe80::1"
|
|
178
|
+
}
|
|
179
|
+
];
|
|
180
|
+
if (!sans.find(({ value, ip }) => value === hostname || ip === hostname)) {
|
|
181
|
+
sans.push(
|
|
182
|
+
IP_HOSTNAME_REGEX.test(hostname) ? {
|
|
183
|
+
type: 7,
|
|
184
|
+
ip: hostname
|
|
185
|
+
} : {
|
|
186
|
+
type: 2,
|
|
187
|
+
value: hostname
|
|
188
|
+
}
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
const params = {
|
|
192
|
+
algorithm: "sha256",
|
|
193
|
+
keySize: 2048,
|
|
194
|
+
days: 30,
|
|
195
|
+
extensions: [
|
|
196
|
+
{
|
|
197
|
+
name: "keyUsage",
|
|
198
|
+
keyCertSign: true,
|
|
199
|
+
digitalSignature: true,
|
|
200
|
+
nonRepudiation: true,
|
|
201
|
+
keyEncipherment: true,
|
|
202
|
+
dataEncipherment: true
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
name: "extKeyUsage",
|
|
206
|
+
serverAuth: true,
|
|
207
|
+
clientAuth: true,
|
|
208
|
+
codeSigning: true,
|
|
209
|
+
timeStamping: true
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
name: "subjectAltName",
|
|
213
|
+
altNames: sans
|
|
214
|
+
}
|
|
215
|
+
]
|
|
216
|
+
};
|
|
217
|
+
return new Promise(
|
|
218
|
+
(resolve, reject) => require("selfsigned").generate(
|
|
219
|
+
attributes,
|
|
220
|
+
params,
|
|
221
|
+
(err, bundle) => {
|
|
222
|
+
if (err) {
|
|
223
|
+
reject(err);
|
|
224
|
+
} else {
|
|
225
|
+
resolve({ key: bundle.private, cert: bundle.cert });
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
)
|
|
229
|
+
);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
async function createHttpServer(listener, options, deps) {
|
|
233
|
+
const server = await createServer(listener, options, deps);
|
|
234
|
+
const stopper = stoppableServer__default["default"](server, 0);
|
|
235
|
+
const stopServer = stopper.stop.bind(stopper);
|
|
236
|
+
return Object.assign(server, {
|
|
237
|
+
start() {
|
|
238
|
+
return new Promise((resolve, reject) => {
|
|
239
|
+
const handleStartupError = (error) => {
|
|
240
|
+
server.close();
|
|
241
|
+
reject(error);
|
|
242
|
+
};
|
|
243
|
+
server.on("error", handleStartupError);
|
|
244
|
+
const { host, port } = options.listen;
|
|
245
|
+
server.listen(port, host, () => {
|
|
246
|
+
server.off("error", handleStartupError);
|
|
247
|
+
deps.logger.info(`Listening on ${host}:${port}`);
|
|
248
|
+
resolve();
|
|
249
|
+
});
|
|
250
|
+
});
|
|
251
|
+
},
|
|
252
|
+
stop() {
|
|
253
|
+
return new Promise((resolve, reject) => {
|
|
254
|
+
stopServer((error) => {
|
|
255
|
+
if (error) {
|
|
256
|
+
reject(error);
|
|
257
|
+
} else {
|
|
258
|
+
resolve();
|
|
259
|
+
}
|
|
260
|
+
});
|
|
261
|
+
});
|
|
262
|
+
},
|
|
263
|
+
port() {
|
|
264
|
+
const address = server.address();
|
|
265
|
+
if (typeof address === "string" || address === null) {
|
|
266
|
+
throw new Error(`Unexpected server address '${address}'`);
|
|
267
|
+
}
|
|
268
|
+
return address.port;
|
|
269
|
+
}
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
async function createServer(listener, options, deps) {
|
|
273
|
+
if (options.https) {
|
|
274
|
+
const { certificate } = options.https;
|
|
275
|
+
if (certificate.type === "generated") {
|
|
276
|
+
const credentials = await getGeneratedCertificate(
|
|
277
|
+
certificate.hostname,
|
|
278
|
+
deps.logger
|
|
279
|
+
);
|
|
280
|
+
return https__namespace.createServer(credentials, listener);
|
|
281
|
+
}
|
|
282
|
+
return https__namespace.createServer(certificate, listener);
|
|
283
|
+
}
|
|
284
|
+
return http__namespace.createServer(listener);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
function readHelmetOptions(config) {
|
|
288
|
+
const cspOptions = readCspDirectives(config);
|
|
289
|
+
return {
|
|
290
|
+
contentSecurityPolicy: {
|
|
291
|
+
useDefaults: false,
|
|
292
|
+
directives: applyCspDirectives(cspOptions)
|
|
293
|
+
},
|
|
294
|
+
// These are all disabled in order to maintain backwards compatibility
|
|
295
|
+
// when bumping helmet v5. We can't enable these by default because
|
|
296
|
+
// there is no way for users to configure them.
|
|
297
|
+
// TODO(Rugvip): We should give control of this setup to consumers
|
|
298
|
+
crossOriginEmbedderPolicy: false,
|
|
299
|
+
crossOriginOpenerPolicy: false,
|
|
300
|
+
crossOriginResourcePolicy: false,
|
|
301
|
+
originAgentCluster: false
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
function readCspDirectives(config) {
|
|
305
|
+
const cc = config == null ? void 0 : config.getOptionalConfig("csp");
|
|
306
|
+
if (!cc) {
|
|
307
|
+
return void 0;
|
|
308
|
+
}
|
|
309
|
+
const result = {};
|
|
310
|
+
for (const key of cc.keys()) {
|
|
311
|
+
if (cc.get(key) === false) {
|
|
312
|
+
result[key] = false;
|
|
313
|
+
} else {
|
|
314
|
+
result[key] = cc.getStringArray(key);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
return result;
|
|
318
|
+
}
|
|
319
|
+
function applyCspDirectives(directives) {
|
|
320
|
+
const result = helmet__default["default"].contentSecurityPolicy.getDefaultDirectives();
|
|
321
|
+
result["script-src"] = ["'self'", "'unsafe-eval'"];
|
|
322
|
+
delete result["form-action"];
|
|
323
|
+
if (directives) {
|
|
324
|
+
for (const [key, value] of Object.entries(directives)) {
|
|
325
|
+
if (value === false) {
|
|
326
|
+
delete result[key];
|
|
327
|
+
} else {
|
|
328
|
+
result[key] = value;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
return result;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
function readCorsOptions(config) {
|
|
336
|
+
const cc = config == null ? void 0 : config.getOptionalConfig("cors");
|
|
337
|
+
if (!cc) {
|
|
338
|
+
return { origin: false };
|
|
339
|
+
}
|
|
340
|
+
return {
|
|
341
|
+
origin: createCorsOriginMatcher(readStringArray(cc, "origin")),
|
|
342
|
+
methods: readStringArray(cc, "methods"),
|
|
343
|
+
allowedHeaders: readStringArray(cc, "allowedHeaders"),
|
|
344
|
+
exposedHeaders: readStringArray(cc, "exposedHeaders"),
|
|
345
|
+
credentials: cc.getOptionalBoolean("credentials"),
|
|
346
|
+
maxAge: cc.getOptionalNumber("maxAge"),
|
|
347
|
+
preflightContinue: cc.getOptionalBoolean("preflightContinue"),
|
|
348
|
+
optionsSuccessStatus: cc.getOptionalNumber("optionsSuccessStatus")
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
function readStringArray(config, key) {
|
|
352
|
+
const value = config.getOptional(key);
|
|
353
|
+
if (typeof value === "string") {
|
|
354
|
+
return [value];
|
|
355
|
+
} else if (!value) {
|
|
356
|
+
return void 0;
|
|
357
|
+
}
|
|
358
|
+
return config.getStringArray(key);
|
|
359
|
+
}
|
|
360
|
+
function createCorsOriginMatcher(allowedOriginPatterns) {
|
|
361
|
+
if (!allowedOriginPatterns) {
|
|
362
|
+
return void 0;
|
|
363
|
+
}
|
|
364
|
+
const allowedOriginMatchers = allowedOriginPatterns.map(
|
|
365
|
+
(pattern) => new minimatch.Minimatch(pattern, { nocase: true, noglobstar: true })
|
|
366
|
+
);
|
|
367
|
+
return (origin, callback) => {
|
|
368
|
+
return callback(
|
|
369
|
+
null,
|
|
370
|
+
allowedOriginMatchers.some((pattern) => pattern.match(origin != null ? origin : ""))
|
|
371
|
+
);
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
var __accessCheck$5 = (obj, member, msg) => {
|
|
17
376
|
if (!member.has(obj))
|
|
18
377
|
throw TypeError("Cannot " + msg);
|
|
19
378
|
};
|
|
20
|
-
var __privateGet$
|
|
21
|
-
__accessCheck$
|
|
379
|
+
var __privateGet$5 = (obj, member, getter) => {
|
|
380
|
+
__accessCheck$5(obj, member, "read from private field");
|
|
22
381
|
return getter ? getter.call(obj) : member.get(obj);
|
|
23
382
|
};
|
|
24
|
-
var __privateAdd$
|
|
383
|
+
var __privateAdd$5 = (obj, member, value) => {
|
|
25
384
|
if (member.has(obj))
|
|
26
385
|
throw TypeError("Cannot add the same private member more than once");
|
|
27
386
|
member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
28
387
|
};
|
|
29
|
-
var __privateSet$
|
|
30
|
-
__accessCheck$
|
|
388
|
+
var __privateSet$5 = (obj, member, value, setter) => {
|
|
389
|
+
__accessCheck$5(obj, member, "write to private field");
|
|
390
|
+
setter ? setter.call(obj, value) : member.set(obj, value);
|
|
391
|
+
return value;
|
|
392
|
+
};
|
|
393
|
+
var _config, _logger;
|
|
394
|
+
const _MiddlewareFactory = class {
|
|
395
|
+
constructor(options) {
|
|
396
|
+
__privateAdd$5(this, _config, void 0);
|
|
397
|
+
__privateAdd$5(this, _logger, void 0);
|
|
398
|
+
__privateSet$5(this, _config, options.config);
|
|
399
|
+
__privateSet$5(this, _logger, options.logger);
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* Creates a new {@link MiddlewareFactory}.
|
|
403
|
+
*/
|
|
404
|
+
static create(options) {
|
|
405
|
+
return new _MiddlewareFactory(options);
|
|
406
|
+
}
|
|
407
|
+
/**
|
|
408
|
+
* Returns a middleware that unconditionally produces a 404 error response.
|
|
409
|
+
*
|
|
410
|
+
* @remarks
|
|
411
|
+
*
|
|
412
|
+
* Typically you want to place this middleware at the end of the chain, such
|
|
413
|
+
* that it's the last one attempted after no other routes matched.
|
|
414
|
+
*
|
|
415
|
+
* @returns An Express request handler
|
|
416
|
+
*/
|
|
417
|
+
notFound() {
|
|
418
|
+
return (_req, res) => {
|
|
419
|
+
res.status(404).end();
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
/**
|
|
423
|
+
* Returns the compression middleware.
|
|
424
|
+
*
|
|
425
|
+
* @remarks
|
|
426
|
+
*
|
|
427
|
+
* The middleware will attempt to compress response bodies for all requests
|
|
428
|
+
* that traverse through the middleware.
|
|
429
|
+
*/
|
|
430
|
+
compression() {
|
|
431
|
+
return compression__default["default"]();
|
|
432
|
+
}
|
|
433
|
+
/**
|
|
434
|
+
* Returns a request logging middleware.
|
|
435
|
+
*
|
|
436
|
+
* @remarks
|
|
437
|
+
*
|
|
438
|
+
* Typically you want to place this middleware at the start of the chain, such
|
|
439
|
+
* that it always logs requests whether they are "caught" by handlers farther
|
|
440
|
+
* down or not.
|
|
441
|
+
*
|
|
442
|
+
* @returns An Express request handler
|
|
443
|
+
*/
|
|
444
|
+
logging() {
|
|
445
|
+
const logger = __privateGet$5(this, _logger).child({
|
|
446
|
+
type: "incomingRequest"
|
|
447
|
+
});
|
|
448
|
+
return morgan__default["default"]("combined", {
|
|
449
|
+
stream: {
|
|
450
|
+
write(message) {
|
|
451
|
+
logger.info(message.trimEnd());
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
/**
|
|
457
|
+
* Returns a middleware that implements the helmet library.
|
|
458
|
+
*
|
|
459
|
+
* @remarks
|
|
460
|
+
*
|
|
461
|
+
* This middleware applies security policies to incoming requests and outgoing
|
|
462
|
+
* responses. It is configured using config keys such as `backend.csp`.
|
|
463
|
+
*
|
|
464
|
+
* @see {@link https://helmetjs.github.io/}
|
|
465
|
+
*
|
|
466
|
+
* @returns An Express request handler
|
|
467
|
+
*/
|
|
468
|
+
helmet() {
|
|
469
|
+
return helmet__default["default"](readHelmetOptions(__privateGet$5(this, _config).getOptionalConfig("backend")));
|
|
470
|
+
}
|
|
471
|
+
/**
|
|
472
|
+
* Returns a middleware that implements the cors library.
|
|
473
|
+
*
|
|
474
|
+
* @remarks
|
|
475
|
+
*
|
|
476
|
+
* This middleware handles CORS. It is configured using the config key
|
|
477
|
+
* `backend.cors`.
|
|
478
|
+
*
|
|
479
|
+
* @see {@link https://github.com/expressjs/cors}
|
|
480
|
+
*
|
|
481
|
+
* @returns An Express request handler
|
|
482
|
+
*/
|
|
483
|
+
cors() {
|
|
484
|
+
return cors__default["default"](readCorsOptions(__privateGet$5(this, _config).getOptionalConfig("backend")));
|
|
485
|
+
}
|
|
486
|
+
/**
|
|
487
|
+
* Express middleware to handle errors during request processing.
|
|
488
|
+
*
|
|
489
|
+
* @remarks
|
|
490
|
+
*
|
|
491
|
+
* This is commonly the very last middleware in the chain.
|
|
492
|
+
*
|
|
493
|
+
* Its primary purpose is not to do translation of business logic exceptions,
|
|
494
|
+
* but rather to be a global catch-all for uncaught "fatal" errors that are
|
|
495
|
+
* expected to result in a 500 error. However, it also does handle some common
|
|
496
|
+
* error types (such as http-error exceptions, and the well-known error types
|
|
497
|
+
* in the `@backstage/errors` package) and returns the enclosed status code
|
|
498
|
+
* accordingly.
|
|
499
|
+
*
|
|
500
|
+
* It will also produce a response body with a serialized form of the error,
|
|
501
|
+
* unless a previous handler already did send a body. See
|
|
502
|
+
* {@link @backstage/errors#ErrorResponseBody} for the response shape used.
|
|
503
|
+
*
|
|
504
|
+
* @returns An Express error request handler
|
|
505
|
+
*/
|
|
506
|
+
error(options = {}) {
|
|
507
|
+
var _a;
|
|
508
|
+
const showStackTraces = (_a = options.showStackTraces) != null ? _a : process.env.NODE_ENV === "development";
|
|
509
|
+
const logger = __privateGet$5(this, _logger).child({
|
|
510
|
+
type: "errorHandler"
|
|
511
|
+
});
|
|
512
|
+
return (error, req, res, next) => {
|
|
513
|
+
const statusCode = getStatusCode(error);
|
|
514
|
+
if (options.logAllErrors || statusCode >= 500) {
|
|
515
|
+
logger.error(`Request failed with status ${statusCode}`, error);
|
|
516
|
+
}
|
|
517
|
+
if (res.headersSent) {
|
|
518
|
+
next(error);
|
|
519
|
+
return;
|
|
520
|
+
}
|
|
521
|
+
const body = {
|
|
522
|
+
error: errors.serializeError(error, { includeStack: showStackTraces }),
|
|
523
|
+
request: { method: req.method, url: req.url },
|
|
524
|
+
response: { statusCode }
|
|
525
|
+
};
|
|
526
|
+
res.status(statusCode).json(body);
|
|
527
|
+
};
|
|
528
|
+
}
|
|
529
|
+
};
|
|
530
|
+
let MiddlewareFactory = _MiddlewareFactory;
|
|
531
|
+
_config = new WeakMap();
|
|
532
|
+
_logger = new WeakMap();
|
|
533
|
+
function getStatusCode(error) {
|
|
534
|
+
const knownStatusCodeFields = ["statusCode", "status"];
|
|
535
|
+
for (const field of knownStatusCodeFields) {
|
|
536
|
+
const statusCode = error[field];
|
|
537
|
+
if (typeof statusCode === "number" && (statusCode | 0) === statusCode && // is whole integer
|
|
538
|
+
statusCode >= 100 && statusCode <= 599) {
|
|
539
|
+
return statusCode;
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
switch (error.name) {
|
|
543
|
+
case errors.NotModifiedError.name:
|
|
544
|
+
return 304;
|
|
545
|
+
case errors.InputError.name:
|
|
546
|
+
return 400;
|
|
547
|
+
case errors.AuthenticationError.name:
|
|
548
|
+
return 401;
|
|
549
|
+
case errors.NotAllowedError.name:
|
|
550
|
+
return 403;
|
|
551
|
+
case errors.NotFoundError.name:
|
|
552
|
+
return 404;
|
|
553
|
+
case errors.ConflictError.name:
|
|
554
|
+
return 409;
|
|
555
|
+
}
|
|
556
|
+
return 500;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
var __accessCheck$4 = (obj, member, msg) => {
|
|
560
|
+
if (!member.has(obj))
|
|
561
|
+
throw TypeError("Cannot " + msg);
|
|
562
|
+
};
|
|
563
|
+
var __privateGet$4 = (obj, member, getter) => {
|
|
564
|
+
__accessCheck$4(obj, member, "read from private field");
|
|
565
|
+
return getter ? getter.call(obj) : member.get(obj);
|
|
566
|
+
};
|
|
567
|
+
var __privateAdd$4 = (obj, member, value) => {
|
|
568
|
+
if (member.has(obj))
|
|
569
|
+
throw TypeError("Cannot add the same private member more than once");
|
|
570
|
+
member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
571
|
+
};
|
|
572
|
+
var __privateSet$4 = (obj, member, value, setter) => {
|
|
573
|
+
__accessCheck$4(obj, member, "write to private field");
|
|
31
574
|
setter ? setter.call(obj, value) : member.set(obj, value);
|
|
32
575
|
return value;
|
|
33
576
|
};
|
|
@@ -36,112 +579,95 @@ const CALLBACKS = ["SIGTERM", "SIGINT", "beforeExit"];
|
|
|
36
579
|
class BackendLifecycleImpl {
|
|
37
580
|
constructor(logger) {
|
|
38
581
|
this.logger = logger;
|
|
39
|
-
__privateAdd$
|
|
40
|
-
__privateAdd$
|
|
582
|
+
__privateAdd$4(this, _isCalled, false);
|
|
583
|
+
__privateAdd$4(this, _shutdownTasks, []);
|
|
41
584
|
CALLBACKS.map((signal) => process.on(signal, () => this.shutdown()));
|
|
42
585
|
}
|
|
43
586
|
addShutdownHook(options) {
|
|
44
|
-
__privateGet$
|
|
587
|
+
__privateGet$4(this, _shutdownTasks).push(options);
|
|
45
588
|
}
|
|
46
589
|
async shutdown() {
|
|
47
|
-
if (__privateGet$
|
|
590
|
+
if (__privateGet$4(this, _isCalled)) {
|
|
48
591
|
return;
|
|
49
592
|
}
|
|
50
|
-
__privateSet$
|
|
51
|
-
this.logger.info(`Running ${__privateGet$
|
|
593
|
+
__privateSet$4(this, _isCalled, true);
|
|
594
|
+
this.logger.info(`Running ${__privateGet$4(this, _shutdownTasks).length} shutdown tasks...`);
|
|
52
595
|
await Promise.all(
|
|
53
|
-
__privateGet$
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
);
|
|
58
|
-
})
|
|
59
|
-
(
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
)
|
|
63
|
-
)
|
|
596
|
+
__privateGet$4(this, _shutdownTasks).map(async (hook) => {
|
|
597
|
+
const { logger = this.logger } = hook;
|
|
598
|
+
try {
|
|
599
|
+
await hook.fn();
|
|
600
|
+
logger.info(`Shutdown hook succeeded`);
|
|
601
|
+
} catch (error) {
|
|
602
|
+
logger.error(`Shutdown hook failed, ${error}`);
|
|
603
|
+
}
|
|
604
|
+
})
|
|
64
605
|
);
|
|
65
606
|
}
|
|
66
607
|
}
|
|
67
608
|
_isCalled = new WeakMap();
|
|
68
609
|
_shutdownTasks = new WeakMap();
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
this.lifecycle = lifecycle;
|
|
72
|
-
this.pluginId = pluginId;
|
|
73
|
-
}
|
|
74
|
-
addShutdownHook(options) {
|
|
75
|
-
this.lifecycle.addShutdownHook({ ...options, pluginId: this.pluginId });
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
const lifecycleFactory = backendPluginApi.createServiceFactory({
|
|
79
|
-
service: backendPluginApi.coreServices.lifecycle,
|
|
610
|
+
const rootLifecycleFactory = backendPluginApi.createServiceFactory({
|
|
611
|
+
service: backendPluginApi.coreServices.rootLifecycle,
|
|
80
612
|
deps: {
|
|
81
|
-
logger: backendPluginApi.coreServices.rootLogger
|
|
82
|
-
plugin: backendPluginApi.coreServices.pluginMetadata
|
|
613
|
+
logger: backendPluginApi.coreServices.rootLogger
|
|
83
614
|
},
|
|
84
615
|
async factory({ logger }) {
|
|
85
|
-
|
|
86
|
-
backendPluginApi.loggerToWinstonLogger(logger)
|
|
87
|
-
);
|
|
88
|
-
return async ({ plugin }) => {
|
|
89
|
-
return new PluginScopedLifecycleImpl(rootLifecycle, plugin.getId());
|
|
90
|
-
};
|
|
616
|
+
return new BackendLifecycleImpl(logger);
|
|
91
617
|
}
|
|
92
618
|
});
|
|
93
619
|
|
|
94
|
-
var __accessCheck$
|
|
620
|
+
var __accessCheck$3 = (obj, member, msg) => {
|
|
95
621
|
if (!member.has(obj))
|
|
96
622
|
throw TypeError("Cannot " + msg);
|
|
97
623
|
};
|
|
98
|
-
var __privateGet$
|
|
99
|
-
__accessCheck$
|
|
624
|
+
var __privateGet$3 = (obj, member, getter) => {
|
|
625
|
+
__accessCheck$3(obj, member, "read from private field");
|
|
100
626
|
return getter ? getter.call(obj) : member.get(obj);
|
|
101
627
|
};
|
|
102
|
-
var __privateAdd$
|
|
628
|
+
var __privateAdd$3 = (obj, member, value) => {
|
|
103
629
|
if (member.has(obj))
|
|
104
630
|
throw TypeError("Cannot add the same private member more than once");
|
|
105
631
|
member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
106
632
|
};
|
|
107
|
-
var __privateSet$
|
|
108
|
-
__accessCheck$
|
|
633
|
+
var __privateSet$3 = (obj, member, value, setter) => {
|
|
634
|
+
__accessCheck$3(obj, member, "write to private field");
|
|
109
635
|
setter ? setter.call(obj, value) : member.set(obj, value);
|
|
110
636
|
return value;
|
|
111
637
|
};
|
|
112
|
-
var __privateMethod$
|
|
113
|
-
__accessCheck$
|
|
638
|
+
var __privateMethod$2 = (obj, member, method) => {
|
|
639
|
+
__accessCheck$3(obj, member, "access private method");
|
|
114
640
|
return method;
|
|
115
641
|
};
|
|
116
642
|
var _started, _features, _registerInits, _extensionPoints, _serviceHolder, _getInitDeps, getInitDeps_fn, _resolveInitOrder, resolveInitOrder_fn;
|
|
117
643
|
class BackendInitializer {
|
|
118
644
|
constructor(serviceHolder) {
|
|
119
|
-
__privateAdd$
|
|
120
|
-
__privateAdd$
|
|
121
|
-
__privateAdd$
|
|
122
|
-
__privateAdd$
|
|
123
|
-
__privateAdd$
|
|
124
|
-
__privateAdd$
|
|
125
|
-
__privateAdd$
|
|
126
|
-
__privateSet$
|
|
645
|
+
__privateAdd$3(this, _getInitDeps);
|
|
646
|
+
__privateAdd$3(this, _resolveInitOrder);
|
|
647
|
+
__privateAdd$3(this, _started, false);
|
|
648
|
+
__privateAdd$3(this, _features, /* @__PURE__ */ new Map());
|
|
649
|
+
__privateAdd$3(this, _registerInits, new Array());
|
|
650
|
+
__privateAdd$3(this, _extensionPoints, /* @__PURE__ */ new Map());
|
|
651
|
+
__privateAdd$3(this, _serviceHolder, void 0);
|
|
652
|
+
__privateSet$3(this, _serviceHolder, serviceHolder);
|
|
127
653
|
}
|
|
128
654
|
add(feature, options) {
|
|
129
|
-
if (__privateGet$
|
|
655
|
+
if (__privateGet$3(this, _started)) {
|
|
130
656
|
throw new Error("feature can not be added after the backend has started");
|
|
131
657
|
}
|
|
132
|
-
__privateGet$
|
|
658
|
+
__privateGet$3(this, _features).set(feature, options);
|
|
133
659
|
}
|
|
134
660
|
async start() {
|
|
135
|
-
if (__privateGet$
|
|
661
|
+
if (__privateGet$3(this, _started)) {
|
|
136
662
|
throw new Error("Backend has already started");
|
|
137
663
|
}
|
|
138
|
-
__privateSet$
|
|
139
|
-
for (const ref of __privateGet$
|
|
664
|
+
__privateSet$3(this, _started, true);
|
|
665
|
+
for (const ref of __privateGet$3(this, _serviceHolder).getServiceRefs()) {
|
|
140
666
|
if (ref.scope === "root") {
|
|
141
|
-
await __privateGet$
|
|
667
|
+
await __privateGet$3(this, _serviceHolder).get(ref, "root");
|
|
142
668
|
}
|
|
143
669
|
}
|
|
144
|
-
for (const [feature] of __privateGet$
|
|
670
|
+
for (const [feature] of __privateGet$3(this, _features)) {
|
|
145
671
|
const provides = /* @__PURE__ */ new Set();
|
|
146
672
|
let registerInit = void 0;
|
|
147
673
|
feature.register({
|
|
@@ -149,10 +675,10 @@ class BackendInitializer {
|
|
|
149
675
|
if (registerInit) {
|
|
150
676
|
throw new Error("registerExtensionPoint called after registerInit");
|
|
151
677
|
}
|
|
152
|
-
if (__privateGet$
|
|
678
|
+
if (__privateGet$3(this, _extensionPoints).has(extensionPointRef)) {
|
|
153
679
|
throw new Error(`API ${extensionPointRef.id} already registered`);
|
|
154
680
|
}
|
|
155
|
-
__privateGet$
|
|
681
|
+
__privateGet$3(this, _extensionPoints).set(extensionPointRef, impl);
|
|
156
682
|
provides.add(extensionPointRef);
|
|
157
683
|
},
|
|
158
684
|
registerInit: (registerOptions) => {
|
|
@@ -173,25 +699,24 @@ class BackendInitializer {
|
|
|
173
699
|
`registerInit was not called by register in ${feature.id}`
|
|
174
700
|
);
|
|
175
701
|
}
|
|
176
|
-
__privateGet$
|
|
702
|
+
__privateGet$3(this, _registerInits).push(registerInit);
|
|
177
703
|
}
|
|
178
|
-
const orderedRegisterResults = __privateMethod$
|
|
704
|
+
const orderedRegisterResults = __privateMethod$2(this, _resolveInitOrder, resolveInitOrder_fn).call(this, __privateGet$3(this, _registerInits));
|
|
179
705
|
for (const registerInit of orderedRegisterResults) {
|
|
180
|
-
const deps = await __privateMethod$
|
|
706
|
+
const deps = await __privateMethod$2(this, _getInitDeps, getInitDeps_fn).call(this, registerInit.deps, registerInit.id);
|
|
181
707
|
await registerInit.init(deps);
|
|
182
708
|
}
|
|
183
709
|
}
|
|
184
710
|
async stop() {
|
|
185
|
-
if (!__privateGet$
|
|
711
|
+
if (!__privateGet$3(this, _started)) {
|
|
186
712
|
return;
|
|
187
713
|
}
|
|
188
|
-
const lifecycleService = await __privateGet$
|
|
189
|
-
backendPluginApi.coreServices.
|
|
714
|
+
const lifecycleService = await __privateGet$3(this, _serviceHolder).get(
|
|
715
|
+
backendPluginApi.coreServices.rootLifecycle,
|
|
190
716
|
"root"
|
|
191
717
|
);
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
await lifecycle.shutdown();
|
|
718
|
+
if (lifecycleService instanceof BackendLifecycleImpl) {
|
|
719
|
+
await lifecycleService.shutdown();
|
|
195
720
|
} else {
|
|
196
721
|
throw new Error("Unexpected lifecycle service implementation");
|
|
197
722
|
}
|
|
@@ -207,13 +732,13 @@ getInitDeps_fn = async function(deps, pluginId) {
|
|
|
207
732
|
const result = /* @__PURE__ */ new Map();
|
|
208
733
|
const missingRefs = /* @__PURE__ */ new Set();
|
|
209
734
|
for (const [name, ref] of Object.entries(deps)) {
|
|
210
|
-
const extensionPoint = __privateGet$
|
|
735
|
+
const extensionPoint = __privateGet$3(this, _extensionPoints).get(
|
|
211
736
|
ref
|
|
212
737
|
);
|
|
213
738
|
if (extensionPoint) {
|
|
214
739
|
result.set(name, extensionPoint);
|
|
215
740
|
} else {
|
|
216
|
-
const impl = await __privateGet$
|
|
741
|
+
const impl = await __privateGet$3(this, _serviceHolder).get(
|
|
217
742
|
ref,
|
|
218
743
|
pluginId
|
|
219
744
|
);
|
|
@@ -257,59 +782,51 @@ resolveInitOrder_fn = function(registerInits) {
|
|
|
257
782
|
return orderedRegisterInits;
|
|
258
783
|
};
|
|
259
784
|
|
|
260
|
-
var __accessCheck$
|
|
785
|
+
var __accessCheck$2 = (obj, member, msg) => {
|
|
261
786
|
if (!member.has(obj))
|
|
262
787
|
throw TypeError("Cannot " + msg);
|
|
263
788
|
};
|
|
264
|
-
var __privateGet$
|
|
265
|
-
__accessCheck$
|
|
789
|
+
var __privateGet$2 = (obj, member, getter) => {
|
|
790
|
+
__accessCheck$2(obj, member, "read from private field");
|
|
266
791
|
return getter ? getter.call(obj) : member.get(obj);
|
|
267
792
|
};
|
|
268
|
-
var __privateAdd$
|
|
793
|
+
var __privateAdd$2 = (obj, member, value) => {
|
|
269
794
|
if (member.has(obj))
|
|
270
795
|
throw TypeError("Cannot add the same private member more than once");
|
|
271
796
|
member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
272
797
|
};
|
|
273
|
-
var __privateSet$
|
|
274
|
-
__accessCheck$
|
|
798
|
+
var __privateSet$2 = (obj, member, value, setter) => {
|
|
799
|
+
__accessCheck$2(obj, member, "write to private field");
|
|
275
800
|
setter ? setter.call(obj, value) : member.set(obj, value);
|
|
276
801
|
return value;
|
|
277
802
|
};
|
|
278
|
-
var __privateMethod = (obj, member, method) => {
|
|
279
|
-
__accessCheck$
|
|
803
|
+
var __privateMethod$1 = (obj, member, method) => {
|
|
804
|
+
__accessCheck$2(obj, member, "access private method");
|
|
280
805
|
return method;
|
|
281
806
|
};
|
|
282
807
|
var _providedFactories, _loadedDefaultFactories, _implementations, _resolveFactory, resolveFactory_fn, _separateMapForTheRootService, _checkForMissingDeps, checkForMissingDeps_fn;
|
|
283
808
|
class ServiceRegistry {
|
|
284
809
|
constructor(factories) {
|
|
285
|
-
__privateAdd$
|
|
286
|
-
__privateAdd$
|
|
287
|
-
__privateAdd$
|
|
288
|
-
__privateAdd$
|
|
289
|
-
__privateAdd$
|
|
290
|
-
__privateAdd$
|
|
291
|
-
__privateSet$
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
const cf = f();
|
|
295
|
-
return [cf.service.id, cf];
|
|
296
|
-
}
|
|
297
|
-
return [f.service.id, f];
|
|
298
|
-
})
|
|
299
|
-
));
|
|
300
|
-
__privateSet$1(this, _loadedDefaultFactories, /* @__PURE__ */ new Map());
|
|
301
|
-
__privateSet$1(this, _implementations, /* @__PURE__ */ new Map());
|
|
810
|
+
__privateAdd$2(this, _resolveFactory);
|
|
811
|
+
__privateAdd$2(this, _checkForMissingDeps);
|
|
812
|
+
__privateAdd$2(this, _providedFactories, void 0);
|
|
813
|
+
__privateAdd$2(this, _loadedDefaultFactories, void 0);
|
|
814
|
+
__privateAdd$2(this, _implementations, void 0);
|
|
815
|
+
__privateAdd$2(this, _separateMapForTheRootService, /* @__PURE__ */ new Map());
|
|
816
|
+
__privateSet$2(this, _providedFactories, new Map(factories.map((f) => [f.service.id, f])));
|
|
817
|
+
__privateSet$2(this, _loadedDefaultFactories, /* @__PURE__ */ new Map());
|
|
818
|
+
__privateSet$2(this, _implementations, /* @__PURE__ */ new Map());
|
|
302
819
|
}
|
|
303
820
|
getServiceRefs() {
|
|
304
|
-
return Array.from(__privateGet$
|
|
821
|
+
return Array.from(__privateGet$2(this, _providedFactories).values()).map((f) => f.service);
|
|
305
822
|
}
|
|
306
823
|
get(ref, pluginId) {
|
|
307
824
|
var _a;
|
|
308
|
-
return (_a = __privateMethod(this, _resolveFactory, resolveFactory_fn).call(this, ref, pluginId)) == null ? void 0 : _a.then((factory) => {
|
|
825
|
+
return (_a = __privateMethod$1(this, _resolveFactory, resolveFactory_fn).call(this, ref, pluginId)) == null ? void 0 : _a.then((factory) => {
|
|
309
826
|
if (factory.scope === "root") {
|
|
310
|
-
let existing = __privateGet$
|
|
827
|
+
let existing = __privateGet$2(this, _separateMapForTheRootService).get(factory);
|
|
311
828
|
if (!existing) {
|
|
312
|
-
__privateMethod(this, _checkForMissingDeps, checkForMissingDeps_fn).call(this, factory, pluginId);
|
|
829
|
+
__privateMethod$1(this, _checkForMissingDeps, checkForMissingDeps_fn).call(this, factory, pluginId);
|
|
313
830
|
const rootDeps = new Array();
|
|
314
831
|
for (const [name, serviceRef] of Object.entries(factory.deps)) {
|
|
315
832
|
if (serviceRef.scope !== "root") {
|
|
@@ -323,13 +840,13 @@ class ServiceRegistry {
|
|
|
323
840
|
existing = Promise.all(rootDeps).then(
|
|
324
841
|
(entries) => factory.factory(Object.fromEntries(entries))
|
|
325
842
|
);
|
|
326
|
-
__privateGet$
|
|
843
|
+
__privateGet$2(this, _separateMapForTheRootService).set(factory, existing);
|
|
327
844
|
}
|
|
328
845
|
return existing;
|
|
329
846
|
}
|
|
330
|
-
let implementation = __privateGet$
|
|
847
|
+
let implementation = __privateGet$2(this, _implementations).get(factory);
|
|
331
848
|
if (!implementation) {
|
|
332
|
-
__privateMethod(this, _checkForMissingDeps, checkForMissingDeps_fn).call(this, factory, pluginId);
|
|
849
|
+
__privateMethod$1(this, _checkForMissingDeps, checkForMissingDeps_fn).call(this, factory, pluginId);
|
|
333
850
|
const rootDeps = new Array();
|
|
334
851
|
for (const [name, serviceRef] of Object.entries(factory.deps)) {
|
|
335
852
|
if (serviceRef.scope === "root") {
|
|
@@ -346,7 +863,7 @@ class ServiceRegistry {
|
|
|
346
863
|
}),
|
|
347
864
|
byPlugin: /* @__PURE__ */ new Map()
|
|
348
865
|
};
|
|
349
|
-
__privateGet$
|
|
866
|
+
__privateGet$2(this, _implementations).set(factory, implementation);
|
|
350
867
|
}
|
|
351
868
|
let result = implementation.byPlugin.get(pluginId);
|
|
352
869
|
if (!result) {
|
|
@@ -388,18 +905,18 @@ resolveFactory_fn = function(ref, pluginId) {
|
|
|
388
905
|
})
|
|
389
906
|
});
|
|
390
907
|
}
|
|
391
|
-
let resolvedFactory = __privateGet$
|
|
908
|
+
let resolvedFactory = __privateGet$2(this, _providedFactories).get(ref.id);
|
|
392
909
|
const { __defaultFactory: defaultFactory } = ref;
|
|
393
910
|
if (!resolvedFactory && !defaultFactory) {
|
|
394
911
|
return void 0;
|
|
395
912
|
}
|
|
396
913
|
if (!resolvedFactory) {
|
|
397
|
-
let loadedFactory = __privateGet$
|
|
914
|
+
let loadedFactory = __privateGet$2(this, _loadedDefaultFactories).get(defaultFactory);
|
|
398
915
|
if (!loadedFactory) {
|
|
399
916
|
loadedFactory = Promise.resolve().then(() => defaultFactory(ref)).then(
|
|
400
917
|
(f) => typeof f === "function" ? f() : f
|
|
401
918
|
);
|
|
402
|
-
__privateGet$
|
|
919
|
+
__privateGet$2(this, _loadedDefaultFactories).set(defaultFactory, loadedFactory);
|
|
403
920
|
}
|
|
404
921
|
resolvedFactory = loadedFactory.catch((error) => {
|
|
405
922
|
throw new Error(
|
|
@@ -418,7 +935,7 @@ checkForMissingDeps_fn = function(factory, pluginId) {
|
|
|
418
935
|
if (ref.id === backendPluginApi.coreServices.pluginMetadata.id) {
|
|
419
936
|
return false;
|
|
420
937
|
}
|
|
421
|
-
if (__privateGet$
|
|
938
|
+
if (__privateGet$2(this, _providedFactories).get(ref.id)) {
|
|
422
939
|
return false;
|
|
423
940
|
}
|
|
424
941
|
return !ref.__defaultFactory;
|
|
@@ -431,51 +948,220 @@ checkForMissingDeps_fn = function(factory, pluginId) {
|
|
|
431
948
|
}
|
|
432
949
|
};
|
|
433
950
|
|
|
434
|
-
var __accessCheck = (obj, member, msg) => {
|
|
951
|
+
var __accessCheck$1 = (obj, member, msg) => {
|
|
435
952
|
if (!member.has(obj))
|
|
436
953
|
throw TypeError("Cannot " + msg);
|
|
437
954
|
};
|
|
438
|
-
var __privateGet = (obj, member, getter) => {
|
|
439
|
-
__accessCheck(obj, member, "read from private field");
|
|
955
|
+
var __privateGet$1 = (obj, member, getter) => {
|
|
956
|
+
__accessCheck$1(obj, member, "read from private field");
|
|
440
957
|
return getter ? getter.call(obj) : member.get(obj);
|
|
441
958
|
};
|
|
442
|
-
var __privateAdd = (obj, member, value) => {
|
|
959
|
+
var __privateAdd$1 = (obj, member, value) => {
|
|
443
960
|
if (member.has(obj))
|
|
444
961
|
throw TypeError("Cannot add the same private member more than once");
|
|
445
962
|
member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
446
963
|
};
|
|
447
|
-
var __privateSet = (obj, member, value, setter) => {
|
|
448
|
-
__accessCheck(obj, member, "write to private field");
|
|
964
|
+
var __privateSet$1 = (obj, member, value, setter) => {
|
|
965
|
+
__accessCheck$1(obj, member, "write to private field");
|
|
449
966
|
setter ? setter.call(obj, value) : member.set(obj, value);
|
|
450
967
|
return value;
|
|
451
968
|
};
|
|
452
969
|
var _services, _initializer;
|
|
453
970
|
class BackstageBackend {
|
|
454
971
|
constructor(apiFactories) {
|
|
455
|
-
__privateAdd(this, _services, void 0);
|
|
456
|
-
__privateAdd(this, _initializer, void 0);
|
|
457
|
-
__privateSet(this, _services, new ServiceRegistry(apiFactories));
|
|
458
|
-
__privateSet(this, _initializer, new BackendInitializer(__privateGet(this, _services)));
|
|
972
|
+
__privateAdd$1(this, _services, void 0);
|
|
973
|
+
__privateAdd$1(this, _initializer, void 0);
|
|
974
|
+
__privateSet$1(this, _services, new ServiceRegistry(apiFactories));
|
|
975
|
+
__privateSet$1(this, _initializer, new BackendInitializer(__privateGet$1(this, _services)));
|
|
459
976
|
}
|
|
460
977
|
add(feature) {
|
|
461
|
-
__privateGet(this, _initializer).add(feature);
|
|
978
|
+
__privateGet$1(this, _initializer).add(feature);
|
|
462
979
|
}
|
|
463
980
|
async start() {
|
|
464
|
-
await __privateGet(this, _initializer).start();
|
|
981
|
+
await __privateGet$1(this, _initializer).start();
|
|
465
982
|
}
|
|
466
983
|
async stop() {
|
|
467
|
-
await __privateGet(this, _initializer).stop();
|
|
984
|
+
await __privateGet$1(this, _initializer).stop();
|
|
468
985
|
}
|
|
469
986
|
}
|
|
470
987
|
_services = new WeakMap();
|
|
471
988
|
_initializer = new WeakMap();
|
|
472
989
|
|
|
473
990
|
function createSpecializedBackend(options) {
|
|
474
|
-
|
|
475
|
-
|
|
991
|
+
const services = options.services.map(
|
|
992
|
+
(sf) => typeof sf === "function" ? sf() : sf
|
|
476
993
|
);
|
|
994
|
+
const exists = /* @__PURE__ */ new Set();
|
|
995
|
+
const duplicates = /* @__PURE__ */ new Set();
|
|
996
|
+
for (const { service } of services) {
|
|
997
|
+
if (exists.has(service.id)) {
|
|
998
|
+
duplicates.add(service.id);
|
|
999
|
+
} else {
|
|
1000
|
+
exists.add(service.id);
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
if (duplicates.size > 0) {
|
|
1004
|
+
const ids = Array.from(duplicates).join(", ");
|
|
1005
|
+
throw new Error(`Duplicate service implementations provided for ${ids}`);
|
|
1006
|
+
}
|
|
1007
|
+
if (exists.has(backendPluginApi.coreServices.pluginMetadata.id)) {
|
|
1008
|
+
throw new Error(
|
|
1009
|
+
`The ${backendPluginApi.coreServices.pluginMetadata.id} service cannot be overridden`
|
|
1010
|
+
);
|
|
1011
|
+
}
|
|
1012
|
+
return new BackstageBackend(services);
|
|
477
1013
|
}
|
|
478
1014
|
|
|
1015
|
+
const httpRouterFactory = backendPluginApi.createServiceFactory({
|
|
1016
|
+
service: backendPluginApi.coreServices.httpRouter,
|
|
1017
|
+
deps: {
|
|
1018
|
+
plugin: backendPluginApi.coreServices.pluginMetadata,
|
|
1019
|
+
rootHttpRouter: backendPluginApi.coreServices.rootHttpRouter
|
|
1020
|
+
},
|
|
1021
|
+
async factory({ rootHttpRouter }, options) {
|
|
1022
|
+
var _a;
|
|
1023
|
+
const getPath = (_a = options == null ? void 0 : options.getPath) != null ? _a : (id) => `/api/${id}`;
|
|
1024
|
+
return async ({ plugin }) => {
|
|
1025
|
+
const path = getPath(plugin.getId());
|
|
1026
|
+
return {
|
|
1027
|
+
use(handler) {
|
|
1028
|
+
rootHttpRouter.use(path, handler);
|
|
1029
|
+
}
|
|
1030
|
+
};
|
|
1031
|
+
};
|
|
1032
|
+
}
|
|
1033
|
+
});
|
|
1034
|
+
|
|
1035
|
+
var __accessCheck = (obj, member, msg) => {
|
|
1036
|
+
if (!member.has(obj))
|
|
1037
|
+
throw TypeError("Cannot " + msg);
|
|
1038
|
+
};
|
|
1039
|
+
var __privateGet = (obj, member, getter) => {
|
|
1040
|
+
__accessCheck(obj, member, "read from private field");
|
|
1041
|
+
return getter ? getter.call(obj) : member.get(obj);
|
|
1042
|
+
};
|
|
1043
|
+
var __privateAdd = (obj, member, value) => {
|
|
1044
|
+
if (member.has(obj))
|
|
1045
|
+
throw TypeError("Cannot add the same private member more than once");
|
|
1046
|
+
member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
1047
|
+
};
|
|
1048
|
+
var __privateSet = (obj, member, value, setter) => {
|
|
1049
|
+
__accessCheck(obj, member, "write to private field");
|
|
1050
|
+
setter ? setter.call(obj, value) : member.set(obj, value);
|
|
1051
|
+
return value;
|
|
1052
|
+
};
|
|
1053
|
+
var __privateMethod = (obj, member, method) => {
|
|
1054
|
+
__accessCheck(obj, member, "access private method");
|
|
1055
|
+
return method;
|
|
1056
|
+
};
|
|
1057
|
+
var _indexPath, _router, _namedRoutes, _indexRouter, _existingPaths, _findConflictingPath, findConflictingPath_fn;
|
|
1058
|
+
function normalizePath(path) {
|
|
1059
|
+
return path.replace(/\/*$/, "/");
|
|
1060
|
+
}
|
|
1061
|
+
class RestrictedIndexedRouter {
|
|
1062
|
+
constructor(indexPath) {
|
|
1063
|
+
__privateAdd(this, _findConflictingPath);
|
|
1064
|
+
__privateAdd(this, _indexPath, void 0);
|
|
1065
|
+
__privateAdd(this, _router, express.Router());
|
|
1066
|
+
__privateAdd(this, _namedRoutes, express.Router());
|
|
1067
|
+
__privateAdd(this, _indexRouter, express.Router());
|
|
1068
|
+
__privateAdd(this, _existingPaths, new Array());
|
|
1069
|
+
__privateSet(this, _indexPath, indexPath);
|
|
1070
|
+
__privateGet(this, _router).use(__privateGet(this, _namedRoutes));
|
|
1071
|
+
__privateGet(this, _router).use(__privateGet(this, _indexRouter));
|
|
1072
|
+
}
|
|
1073
|
+
use(path, handler) {
|
|
1074
|
+
if (path.match(/^[/\s]*$/)) {
|
|
1075
|
+
throw new Error(`Root router path may not be empty`);
|
|
1076
|
+
}
|
|
1077
|
+
const conflictingPath = __privateMethod(this, _findConflictingPath, findConflictingPath_fn).call(this, path);
|
|
1078
|
+
if (conflictingPath) {
|
|
1079
|
+
throw new Error(
|
|
1080
|
+
`Path ${path} conflicts with the existing path ${conflictingPath}`
|
|
1081
|
+
);
|
|
1082
|
+
}
|
|
1083
|
+
__privateGet(this, _existingPaths).push(path);
|
|
1084
|
+
__privateGet(this, _namedRoutes).use(path, handler);
|
|
1085
|
+
if (__privateGet(this, _indexPath) === path) {
|
|
1086
|
+
__privateGet(this, _indexRouter).use(handler);
|
|
1087
|
+
}
|
|
1088
|
+
}
|
|
1089
|
+
handler() {
|
|
1090
|
+
return __privateGet(this, _router);
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
1093
|
+
_indexPath = new WeakMap();
|
|
1094
|
+
_router = new WeakMap();
|
|
1095
|
+
_namedRoutes = new WeakMap();
|
|
1096
|
+
_indexRouter = new WeakMap();
|
|
1097
|
+
_existingPaths = new WeakMap();
|
|
1098
|
+
_findConflictingPath = new WeakSet();
|
|
1099
|
+
findConflictingPath_fn = function(newPath) {
|
|
1100
|
+
const normalizedNewPath = normalizePath(newPath);
|
|
1101
|
+
for (const path of __privateGet(this, _existingPaths)) {
|
|
1102
|
+
const normalizedPath = normalizePath(path);
|
|
1103
|
+
if (normalizedPath.startsWith(normalizedNewPath)) {
|
|
1104
|
+
return path;
|
|
1105
|
+
}
|
|
1106
|
+
if (normalizedNewPath.startsWith(normalizedPath)) {
|
|
1107
|
+
return path;
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
return void 0;
|
|
1111
|
+
};
|
|
1112
|
+
|
|
1113
|
+
function defaultConfigure({
|
|
1114
|
+
app,
|
|
1115
|
+
routes,
|
|
1116
|
+
middleware
|
|
1117
|
+
}) {
|
|
1118
|
+
app.use(middleware.helmet());
|
|
1119
|
+
app.use(middleware.cors());
|
|
1120
|
+
app.use(middleware.compression());
|
|
1121
|
+
app.use(middleware.logging());
|
|
1122
|
+
app.use(routes);
|
|
1123
|
+
app.use(middleware.notFound());
|
|
1124
|
+
app.use(middleware.error());
|
|
1125
|
+
}
|
|
1126
|
+
const rootHttpRouterFactory = backendPluginApi.createServiceFactory({
|
|
1127
|
+
service: backendPluginApi.coreServices.rootHttpRouter,
|
|
1128
|
+
deps: {
|
|
1129
|
+
config: backendPluginApi.coreServices.config,
|
|
1130
|
+
rootLogger: backendPluginApi.coreServices.rootLogger,
|
|
1131
|
+
lifecycle: backendPluginApi.coreServices.rootLifecycle
|
|
1132
|
+
},
|
|
1133
|
+
async factory({ config, rootLogger, lifecycle }, {
|
|
1134
|
+
indexPath,
|
|
1135
|
+
configure = defaultConfigure
|
|
1136
|
+
} = {}) {
|
|
1137
|
+
const router = new RestrictedIndexedRouter(indexPath != null ? indexPath : "/api/app");
|
|
1138
|
+
const logger = rootLogger.child({ service: "rootHttpRouter" });
|
|
1139
|
+
const app = express__default["default"]();
|
|
1140
|
+
const middleware = MiddlewareFactory.create({ config, logger });
|
|
1141
|
+
configure({
|
|
1142
|
+
app,
|
|
1143
|
+
routes: router.handler(),
|
|
1144
|
+
middleware,
|
|
1145
|
+
config,
|
|
1146
|
+
logger,
|
|
1147
|
+
lifecycle
|
|
1148
|
+
});
|
|
1149
|
+
const server = await createHttpServer(
|
|
1150
|
+
app,
|
|
1151
|
+
readHttpServerOptions(config.getOptionalConfig("backend")),
|
|
1152
|
+
{ logger }
|
|
1153
|
+
);
|
|
1154
|
+
lifecycle.addShutdownHook({
|
|
1155
|
+
async fn() {
|
|
1156
|
+
await server.stop();
|
|
1157
|
+
},
|
|
1158
|
+
logger
|
|
1159
|
+
});
|
|
1160
|
+
await server.start();
|
|
1161
|
+
return router;
|
|
1162
|
+
}
|
|
1163
|
+
});
|
|
1164
|
+
|
|
479
1165
|
const cacheFactory = backendPluginApi.createServiceFactory({
|
|
480
1166
|
service: backendPluginApi.coreServices.cache,
|
|
481
1167
|
deps: {
|
|
@@ -498,7 +1184,7 @@ const configFactory = backendPluginApi.createServiceFactory({
|
|
|
498
1184
|
async factory({ logger }) {
|
|
499
1185
|
const config = await backendCommon.loadBackendConfig({
|
|
500
1186
|
argv: process.argv,
|
|
501
|
-
logger:
|
|
1187
|
+
logger: backendCommon.loggerToWinstonLogger(logger)
|
|
502
1188
|
});
|
|
503
1189
|
return config;
|
|
504
1190
|
}
|
|
@@ -539,7 +1225,7 @@ const loggerFactory = backendPluginApi.createServiceFactory({
|
|
|
539
1225
|
},
|
|
540
1226
|
async factory({ rootLogger }) {
|
|
541
1227
|
return async ({ plugin }) => {
|
|
542
|
-
return rootLogger.child({
|
|
1228
|
+
return rootLogger.child({ plugin: plugin.getId() });
|
|
543
1229
|
};
|
|
544
1230
|
}
|
|
545
1231
|
});
|
|
@@ -615,7 +1301,7 @@ const tokenManagerFactory = backendPluginApi.createServiceFactory({
|
|
|
615
1301
|
async factory() {
|
|
616
1302
|
return async ({ config, logger }) => {
|
|
617
1303
|
return backendCommon.ServerTokenManager.fromConfig(config, {
|
|
618
|
-
logger:
|
|
1304
|
+
logger: backendCommon.loggerToWinstonLogger(logger)
|
|
619
1305
|
});
|
|
620
1306
|
};
|
|
621
1307
|
}
|
|
@@ -631,42 +1317,39 @@ const urlReaderFactory = backendPluginApi.createServiceFactory({
|
|
|
631
1317
|
return async ({ config, logger }) => {
|
|
632
1318
|
return backendCommon.UrlReaders.default({
|
|
633
1319
|
config,
|
|
634
|
-
logger:
|
|
1320
|
+
logger: backendCommon.loggerToWinstonLogger(logger)
|
|
635
1321
|
});
|
|
636
1322
|
};
|
|
637
1323
|
}
|
|
638
1324
|
});
|
|
639
1325
|
|
|
640
|
-
const
|
|
641
|
-
service: backendPluginApi.coreServices.
|
|
1326
|
+
const lifecycleFactory = backendPluginApi.createServiceFactory({
|
|
1327
|
+
service: backendPluginApi.coreServices.lifecycle,
|
|
642
1328
|
deps: {
|
|
643
|
-
|
|
644
|
-
|
|
1329
|
+
logger: backendPluginApi.coreServices.logger,
|
|
1330
|
+
rootLifecycle: backendPluginApi.coreServices.rootLifecycle,
|
|
1331
|
+
pluginMetadata: backendPluginApi.coreServices.pluginMetadata
|
|
645
1332
|
},
|
|
646
|
-
async factory({
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
const apiRouter = Router__default["default"]();
|
|
650
|
-
const rootRouter = Router__default["default"]();
|
|
651
|
-
const service = backendCommon.createServiceBuilder(module).loadConfig(config).addRouter("/api", apiRouter).addRouter("", rootRouter);
|
|
652
|
-
await service.start();
|
|
653
|
-
return async ({ plugin }) => {
|
|
654
|
-
const pluginId = plugin.getId();
|
|
1333
|
+
async factory({ rootLifecycle }) {
|
|
1334
|
+
return async ({ logger, pluginMetadata }) => {
|
|
1335
|
+
const plugin = pluginMetadata.getId();
|
|
655
1336
|
return {
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
}
|
|
1337
|
+
addShutdownHook(options) {
|
|
1338
|
+
var _a, _b;
|
|
1339
|
+
rootLifecycle.addShutdownHook({
|
|
1340
|
+
...options,
|
|
1341
|
+
logger: (_b = (_a = options.logger) == null ? void 0 : _a.child({ plugin })) != null ? _b : logger
|
|
1342
|
+
});
|
|
662
1343
|
}
|
|
663
1344
|
};
|
|
664
1345
|
};
|
|
665
1346
|
}
|
|
666
1347
|
});
|
|
667
1348
|
|
|
1349
|
+
exports.MiddlewareFactory = MiddlewareFactory;
|
|
668
1350
|
exports.cacheFactory = cacheFactory;
|
|
669
1351
|
exports.configFactory = configFactory;
|
|
1352
|
+
exports.createHttpServer = createHttpServer;
|
|
670
1353
|
exports.createSpecializedBackend = createSpecializedBackend;
|
|
671
1354
|
exports.databaseFactory = databaseFactory;
|
|
672
1355
|
exports.discoveryFactory = discoveryFactory;
|
|
@@ -674,6 +1357,11 @@ exports.httpRouterFactory = httpRouterFactory;
|
|
|
674
1357
|
exports.lifecycleFactory = lifecycleFactory;
|
|
675
1358
|
exports.loggerFactory = loggerFactory;
|
|
676
1359
|
exports.permissionsFactory = permissionsFactory;
|
|
1360
|
+
exports.readCorsOptions = readCorsOptions;
|
|
1361
|
+
exports.readHelmetOptions = readHelmetOptions;
|
|
1362
|
+
exports.readHttpServerOptions = readHttpServerOptions;
|
|
1363
|
+
exports.rootHttpRouterFactory = rootHttpRouterFactory;
|
|
1364
|
+
exports.rootLifecycleFactory = rootLifecycleFactory;
|
|
677
1365
|
exports.rootLoggerFactory = rootLoggerFactory;
|
|
678
1366
|
exports.schedulerFactory = schedulerFactory;
|
|
679
1367
|
exports.tokenManagerFactory = tokenManagerFactory;
|