@backstage/backend-defaults 0.10.1-next.1 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +71 -0
- package/config.d.ts +86 -0
- package/dist/CreateBackend.cjs.js +5 -5
- package/dist/CreateBackend.cjs.js.map +1 -1
- package/dist/alpha/entrypoints/actions/DefaultActionsService.cjs.js.map +1 -0
- package/dist/{entrypoints → alpha/entrypoints}/actions/actionsServiceFactory.cjs.js +2 -1
- package/dist/alpha/entrypoints/actions/actionsServiceFactory.cjs.js.map +1 -0
- package/dist/{entrypoints → alpha/entrypoints}/actionsRegistry/DefaultActionsRegistryService.cjs.js +9 -2
- package/dist/alpha/entrypoints/actionsRegistry/DefaultActionsRegistryService.cjs.js.map +1 -0
- package/dist/{entrypoints → alpha/entrypoints}/actionsRegistry/actionsRegistryServiceFactory.cjs.js +2 -1
- package/dist/alpha/entrypoints/actionsRegistry/actionsRegistryServiceFactory.cjs.js.map +1 -0
- package/dist/alpha.cjs.js +10 -0
- package/dist/alpha.cjs.js.map +1 -0
- package/dist/alpha.d.ts +14 -0
- package/dist/auditor.d.ts +3 -1
- package/dist/entrypoints/auditor/DefaultAuditorService.cjs.js +1 -1
- package/dist/entrypoints/auditor/DefaultAuditorService.cjs.js.map +1 -1
- package/dist/entrypoints/auditor/WinstonRootAuditorService.cjs.js +17 -4
- package/dist/entrypoints/auditor/WinstonRootAuditorService.cjs.js.map +1 -1
- package/dist/entrypoints/auditor/auditorServiceFactory.cjs.js +15 -31
- package/dist/entrypoints/auditor/auditorServiceFactory.cjs.js.map +1 -1
- package/dist/entrypoints/auditor/types.cjs.js +13 -0
- package/dist/entrypoints/auditor/types.cjs.js.map +1 -0
- package/dist/entrypoints/auditor/utils.cjs.js +31 -0
- package/dist/entrypoints/auditor/utils.cjs.js.map +1 -0
- package/dist/entrypoints/httpRouter/http/createRateLimitMiddleware.cjs.js +23 -0
- package/dist/entrypoints/httpRouter/http/createRateLimitMiddleware.cjs.js.map +1 -0
- package/dist/entrypoints/httpRouter/httpRouterServiceFactory.cjs.js +2 -0
- package/dist/entrypoints/httpRouter/httpRouterServiceFactory.cjs.js.map +1 -1
- package/dist/entrypoints/rootHttpRouter/http/MiddlewareFactory.cjs.js +31 -0
- package/dist/entrypoints/rootHttpRouter/http/MiddlewareFactory.cjs.js.map +1 -1
- package/dist/entrypoints/rootHttpRouter/rootHttpRouterServiceFactory.cjs.js +1 -0
- package/dist/entrypoints/rootHttpRouter/rootHttpRouterServiceFactory.cjs.js.map +1 -1
- package/dist/lib/RateLimitStoreFactory.cjs.js +37 -0
- package/dist/lib/RateLimitStoreFactory.cjs.js.map +1 -0
- package/dist/lib/rateLimitMiddleware.cjs.js +62 -0
- package/dist/lib/rateLimitMiddleware.cjs.js.map +1 -0
- package/dist/package.json.cjs.js +7 -9
- package/dist/package.json.cjs.js.map +1 -1
- package/dist/rootHttpRouter.d.ts +11 -0
- package/package.json +27 -33
- package/dist/actions.cjs.js +0 -8
- package/dist/actions.cjs.js.map +0 -1
- package/dist/actions.d.ts +0 -8
- package/dist/actionsRegistry.cjs.js +0 -8
- package/dist/actionsRegistry.cjs.js.map +0 -1
- package/dist/actionsRegistry.d.ts +0 -8
- package/dist/entrypoints/actions/DefaultActionsService.cjs.js.map +0 -1
- package/dist/entrypoints/actions/actionsServiceFactory.cjs.js.map +0 -1
- package/dist/entrypoints/actionsRegistry/DefaultActionsRegistryService.cjs.js.map +0 -1
- package/dist/entrypoints/actionsRegistry/actionsRegistryServiceFactory.cjs.js.map +0 -1
- /package/dist/{entrypoints → alpha/entrypoints}/actions/DefaultActionsService.cjs.js +0 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var errors = require('@backstage/errors');
|
|
4
|
+
var types = require('./types.cjs.js');
|
|
5
|
+
|
|
6
|
+
function getSeverityLogLevelMappings(config) {
|
|
7
|
+
const auditorConfig = config.getOptionalConfig(types.CONFIG_ROOT_KEY);
|
|
8
|
+
const severityLogLevelMappings = {
|
|
9
|
+
low: auditorConfig?.getOptionalString("severityLogLevelMappings.low") ?? "debug",
|
|
10
|
+
medium: auditorConfig?.getOptionalString("severityLogLevelMappings.medium") ?? "info",
|
|
11
|
+
high: auditorConfig?.getOptionalString("severityLogLevelMappings.high") ?? "info",
|
|
12
|
+
critical: auditorConfig?.getOptionalString("severityLogLevelMappings.critical") ?? "info"
|
|
13
|
+
};
|
|
14
|
+
const res = types.severityLogLevelMappingsSchema.safeParse(
|
|
15
|
+
severityLogLevelMappings
|
|
16
|
+
);
|
|
17
|
+
if (!res.success) {
|
|
18
|
+
const key = res.error.issues.at(0)?.path.at(0);
|
|
19
|
+
const value = res.error.issues.at(0).received;
|
|
20
|
+
const validKeys = res.error.issues.at(0).options;
|
|
21
|
+
throw new errors.InputError(
|
|
22
|
+
`The configuration value for 'backend.auditor.severityLogLevelMappings.${key}' was given an invalid value: '${value}'. Expected one of the following valid values: '${validKeys.join(
|
|
23
|
+
", "
|
|
24
|
+
)}'.`
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
return severityLogLevelMappings;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
exports.getSeverityLogLevelMappings = getSeverityLogLevelMappings;
|
|
31
|
+
//# sourceMappingURL=utils.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.cjs.js","sources":["../../../src/entrypoints/auditor/utils.ts"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { Config } from '@backstage/config';\nimport { InputError } from '@backstage/errors';\nimport { z } from 'zod';\nimport { CONFIG_ROOT_KEY, severityLogLevelMappingsSchema } from './types';\n\n/**\n * Gets the `backend.auditor.severityLogLevelMappings` configuration.\n *\n * @param config - The root Backstage {@link @backstage/config#Config} object.\n * @returns The validated severity-to-log-level mappings.\n * @throws error - {@link @backstage/errors#InputError} if the mapping configuration is invalid.\n */\nexport function getSeverityLogLevelMappings(config: Config) {\n const auditorConfig = config.getOptionalConfig(CONFIG_ROOT_KEY);\n\n const severityLogLevelMappings = {\n low:\n auditorConfig?.getOptionalString('severityLogLevelMappings.low') ??\n 'debug',\n medium:\n auditorConfig?.getOptionalString('severityLogLevelMappings.medium') ??\n 'info',\n high:\n auditorConfig?.getOptionalString('severityLogLevelMappings.high') ??\n 'info',\n critical:\n auditorConfig?.getOptionalString('severityLogLevelMappings.critical') ??\n 'info',\n } as Required<z.infer<typeof severityLogLevelMappingsSchema>>;\n\n const res = severityLogLevelMappingsSchema.safeParse(\n severityLogLevelMappings,\n );\n if (!res.success) {\n const key = res.error.issues.at(0)?.path.at(0) as string;\n const value = (\n res.error.issues.at(0) as unknown as Record<PropertyKey, unknown>\n ).received as string;\n const validKeys = (\n res.error.issues.at(0) as unknown as Record<PropertyKey, unknown>\n ).options as string[];\n throw new InputError(\n `The configuration value for 'backend.auditor.severityLogLevelMappings.${key}' was given an invalid value: '${value}'. Expected one of the following valid values: '${validKeys.join(\n ', ',\n )}'.`,\n );\n }\n\n return severityLogLevelMappings;\n}\n"],"names":["CONFIG_ROOT_KEY","severityLogLevelMappingsSchema","InputError"],"mappings":";;;;;AA4BO,SAAS,4BAA4B,MAAgB,EAAA;AAC1D,EAAM,MAAA,aAAA,GAAgB,MAAO,CAAA,iBAAA,CAAkBA,qBAAe,CAAA;AAE9D,EAAA,MAAM,wBAA2B,GAAA;AAAA,IAC/B,GACE,EAAA,aAAA,EAAe,iBAAkB,CAAA,8BAA8B,CAC/D,IAAA,OAAA;AAAA,IACF,MACE,EAAA,aAAA,EAAe,iBAAkB,CAAA,iCAAiC,CAClE,IAAA,MAAA;AAAA,IACF,IACE,EAAA,aAAA,EAAe,iBAAkB,CAAA,+BAA+B,CAChE,IAAA,MAAA;AAAA,IACF,QACE,EAAA,aAAA,EAAe,iBAAkB,CAAA,mCAAmC,CACpE,IAAA;AAAA,GACJ;AAEA,EAAA,MAAM,MAAMC,oCAA+B,CAAA,SAAA;AAAA,IACzC;AAAA,GACF;AACA,EAAI,IAAA,CAAC,IAAI,OAAS,EAAA;AAChB,IAAM,MAAA,GAAA,GAAM,IAAI,KAAM,CAAA,MAAA,CAAO,GAAG,CAAC,CAAA,EAAG,IAAK,CAAA,EAAA,CAAG,CAAC,CAAA;AAC7C,IAAA,MAAM,QACJ,GAAI,CAAA,KAAA,CAAM,MAAO,CAAA,EAAA,CAAG,CAAC,CACrB,CAAA,QAAA;AACF,IAAA,MAAM,YACJ,GAAI,CAAA,KAAA,CAAM,MAAO,CAAA,EAAA,CAAG,CAAC,CACrB,CAAA,OAAA;AACF,IAAA,MAAM,IAAIC,iBAAA;AAAA,MACR,CAAyE,sEAAA,EAAA,GAAG,CAAkC,+BAAA,EAAA,KAAK,mDAAmD,SAAU,CAAA,IAAA;AAAA,QAC9K;AAAA,OACD,CAAA,EAAA;AAAA,KACH;AAAA;AAGF,EAAO,OAAA,wBAAA;AACT;;;;"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var RateLimitStoreFactory = require('../../../lib/RateLimitStoreFactory.cjs.js');
|
|
4
|
+
var rateLimitMiddleware = require('../../../lib/rateLimitMiddleware.cjs.js');
|
|
5
|
+
|
|
6
|
+
const createRateLimitMiddleware = (options) => {
|
|
7
|
+
const { pluginId, config } = options;
|
|
8
|
+
const configKey = `backend.rateLimit.plugin.${pluginId}`;
|
|
9
|
+
const enabled = config.has(configKey);
|
|
10
|
+
if (!enabled) {
|
|
11
|
+
return (_req, _res, next) => {
|
|
12
|
+
next();
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
const rateLimitOptions = config.getConfig(configKey);
|
|
16
|
+
return rateLimitMiddleware.rateLimitMiddleware({
|
|
17
|
+
store: RateLimitStoreFactory.RateLimitStoreFactory.create({ config, prefix: pluginId }),
|
|
18
|
+
config: rateLimitOptions
|
|
19
|
+
});
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
exports.createRateLimitMiddleware = createRateLimitMiddleware;
|
|
23
|
+
//# sourceMappingURL=createRateLimitMiddleware.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createRateLimitMiddleware.cjs.js","sources":["../../../../src/entrypoints/httpRouter/http/createRateLimitMiddleware.ts"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { NextFunction, Request, Response } from 'express';\nimport { RateLimitStoreFactory } from '../../../lib/RateLimitStoreFactory.ts';\nimport { Config } from '@backstage/config';\nimport { rateLimitMiddleware } from '../../../lib/rateLimitMiddleware.ts';\n\nexport const createRateLimitMiddleware = (options: {\n pluginId: string;\n config: Config;\n}) => {\n const { pluginId, config } = options;\n const configKey = `backend.rateLimit.plugin.${pluginId}`;\n const enabled = config.has(configKey);\n if (!enabled) {\n return (_req: Request, _res: Response, next: NextFunction) => {\n next();\n };\n }\n\n const rateLimitOptions = config.getConfig(configKey);\n\n return rateLimitMiddleware({\n store: RateLimitStoreFactory.create({ config, prefix: pluginId }),\n config: rateLimitOptions,\n });\n};\n"],"names":["rateLimitMiddleware","RateLimitStoreFactory"],"mappings":";;;;;AAoBa,MAAA,yBAAA,GAA4B,CAAC,OAGpC,KAAA;AACJ,EAAM,MAAA,EAAE,QAAU,EAAA,MAAA,EAAW,GAAA,OAAA;AAC7B,EAAM,MAAA,SAAA,GAAY,4BAA4B,QAAQ,CAAA,CAAA;AACtD,EAAM,MAAA,OAAA,GAAU,MAAO,CAAA,GAAA,CAAI,SAAS,CAAA;AACpC,EAAA,IAAI,CAAC,OAAS,EAAA;AACZ,IAAO,OAAA,CAAC,IAAe,EAAA,IAAA,EAAgB,IAAuB,KAAA;AAC5D,MAAK,IAAA,EAAA;AAAA,KACP;AAAA;AAGF,EAAM,MAAA,gBAAA,GAAmB,MAAO,CAAA,SAAA,CAAU,SAAS,CAAA;AAEnD,EAAA,OAAOA,uCAAoB,CAAA;AAAA,IACzB,OAAOC,2CAAsB,CAAA,MAAA,CAAO,EAAE,MAAQ,EAAA,MAAA,EAAQ,UAAU,CAAA;AAAA,IAChE,MAAQ,EAAA;AAAA,GACT,CAAA;AACH;;;;"}
|
|
@@ -18,6 +18,7 @@ require('minimatch');
|
|
|
18
18
|
require('helmet');
|
|
19
19
|
require('lodash/kebabCase');
|
|
20
20
|
require('../rootHttpRouter/rootHttpRouterServiceFactory.cjs.js');
|
|
21
|
+
var createRateLimitMiddleware = require('./http/createRateLimitMiddleware.cjs.js');
|
|
21
22
|
|
|
22
23
|
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
|
|
23
24
|
|
|
@@ -45,6 +46,7 @@ const httpRouterServiceFactory = backendPluginApi.createServiceFactory({
|
|
|
45
46
|
logger
|
|
46
47
|
}) {
|
|
47
48
|
const router = Router__default.default();
|
|
49
|
+
router.use(createRateLimitMiddleware.createRateLimitMiddleware({ pluginId: plugin.getId(), config }));
|
|
48
50
|
rootHttpRouter.use(`/api/${plugin.getId()}`, router);
|
|
49
51
|
const credentialsBarrier = createCredentialsBarrier.createCredentialsBarrier({
|
|
50
52
|
httpAuth,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"httpRouterServiceFactory.cjs.js","sources":["../../../src/entrypoints/httpRouter/httpRouterServiceFactory.ts"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Handler } from 'express';\nimport PromiseRouter from 'express-promise-router';\nimport {\n coreServices,\n createServiceFactory,\n HttpRouterServiceAuthPolicy,\n} from '@backstage/backend-plugin-api';\nimport {\n
|
|
1
|
+
{"version":3,"file":"httpRouterServiceFactory.cjs.js","sources":["../../../src/entrypoints/httpRouter/httpRouterServiceFactory.ts"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Handler } from 'express';\nimport PromiseRouter from 'express-promise-router';\nimport {\n coreServices,\n createServiceFactory,\n HttpRouterServiceAuthPolicy,\n} from '@backstage/backend-plugin-api';\nimport {\n createAuthIntegrationRouter,\n createCookieAuthRefreshMiddleware,\n createCredentialsBarrier,\n createLifecycleMiddleware,\n} from './http';\nimport { MiddlewareFactory } from '../rootHttpRouter';\nimport { createRateLimitMiddleware } from './http/createRateLimitMiddleware.ts';\n\n/**\n * HTTP route registration for plugins.\n *\n * See {@link @backstage/code-plugin-api#HttpRouterService}\n * and {@link https://backstage.io/docs/backend-system/core-services/http-router | the service docs}\n * for more information.\n *\n * @public\n */\nexport const httpRouterServiceFactory = createServiceFactory({\n service: coreServices.httpRouter,\n initialization: 'always',\n deps: {\n plugin: coreServices.pluginMetadata,\n config: coreServices.rootConfig,\n lifecycle: coreServices.lifecycle,\n rootHttpRouter: coreServices.rootHttpRouter,\n auth: coreServices.auth,\n httpAuth: coreServices.httpAuth,\n logger: coreServices.logger,\n },\n async factory({\n auth,\n httpAuth,\n config,\n plugin,\n rootHttpRouter,\n lifecycle,\n logger,\n }) {\n const router = PromiseRouter();\n\n router.use(createRateLimitMiddleware({ pluginId: plugin.getId(), config }));\n\n rootHttpRouter.use(`/api/${plugin.getId()}`, router);\n\n const credentialsBarrier = createCredentialsBarrier({\n httpAuth,\n config,\n });\n\n router.use(createAuthIntegrationRouter({ auth }));\n router.use(createLifecycleMiddleware({ config, lifecycle }));\n router.use(credentialsBarrier.middleware);\n router.use(createCookieAuthRefreshMiddleware({ auth, httpAuth }));\n\n const pluginRoutes = PromiseRouter();\n router.use(pluginRoutes);\n\n const middleware = MiddlewareFactory.create({ config, logger });\n router.use(middleware.error());\n\n return {\n use(handler: Handler): void {\n pluginRoutes.use(handler);\n },\n addAuthPolicy(policy: HttpRouterServiceAuthPolicy): void {\n credentialsBarrier.addAuthPolicy(policy);\n },\n };\n },\n});\n"],"names":["createServiceFactory","coreServices","PromiseRouter","createRateLimitMiddleware","createCredentialsBarrier","createAuthIntegrationRouter","createLifecycleMiddleware","createCookieAuthRefreshMiddleware","MiddlewareFactory"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAyCO,MAAM,2BAA2BA,qCAAqB,CAAA;AAAA,EAC3D,SAASC,6BAAa,CAAA,UAAA;AAAA,EACtB,cAAgB,EAAA,QAAA;AAAA,EAChB,IAAM,EAAA;AAAA,IACJ,QAAQA,6BAAa,CAAA,cAAA;AAAA,IACrB,QAAQA,6BAAa,CAAA,UAAA;AAAA,IACrB,WAAWA,6BAAa,CAAA,SAAA;AAAA,IACxB,gBAAgBA,6BAAa,CAAA,cAAA;AAAA,IAC7B,MAAMA,6BAAa,CAAA,IAAA;AAAA,IACnB,UAAUA,6BAAa,CAAA,QAAA;AAAA,IACvB,QAAQA,6BAAa,CAAA;AAAA,GACvB;AAAA,EACA,MAAM,OAAQ,CAAA;AAAA,IACZ,IAAA;AAAA,IACA,QAAA;AAAA,IACA,MAAA;AAAA,IACA,MAAA;AAAA,IACA,cAAA;AAAA,IACA,SAAA;AAAA,IACA;AAAA,GACC,EAAA;AACD,IAAA,MAAM,SAASC,uBAAc,EAAA;AAE7B,IAAO,MAAA,CAAA,GAAA,CAAIC,oDAA0B,EAAE,QAAA,EAAU,OAAO,KAAM,EAAA,EAAG,MAAO,EAAC,CAAC,CAAA;AAE1E,IAAA,cAAA,CAAe,IAAI,CAAQ,KAAA,EAAA,MAAA,CAAO,KAAM,EAAC,IAAI,MAAM,CAAA;AAEnD,IAAA,MAAM,qBAAqBC,iDAAyB,CAAA;AAAA,MAClD,QAAA;AAAA,MACA;AAAA,KACD,CAAA;AAED,IAAA,MAAA,CAAO,GAAI,CAAAC,uDAAA,CAA4B,EAAE,IAAA,EAAM,CAAC,CAAA;AAChD,IAAA,MAAA,CAAO,IAAIC,mDAA0B,CAAA,EAAE,MAAQ,EAAA,SAAA,EAAW,CAAC,CAAA;AAC3D,IAAO,MAAA,CAAA,GAAA,CAAI,mBAAmB,UAAU,CAAA;AACxC,IAAA,MAAA,CAAO,IAAIC,mEAAkC,CAAA,EAAE,IAAM,EAAA,QAAA,EAAU,CAAC,CAAA;AAEhE,IAAA,MAAM,eAAeL,uBAAc,EAAA;AACnC,IAAA,MAAA,CAAO,IAAI,YAAY,CAAA;AAEvB,IAAA,MAAM,aAAaM,mCAAkB,CAAA,MAAA,CAAO,EAAE,MAAA,EAAQ,QAAQ,CAAA;AAC9D,IAAO,MAAA,CAAA,GAAA,CAAI,UAAW,CAAA,KAAA,EAAO,CAAA;AAE7B,IAAO,OAAA;AAAA,MACL,IAAI,OAAwB,EAAA;AAC1B,QAAA,YAAA,CAAa,IAAI,OAAO,CAAA;AAAA,OAC1B;AAAA,MACA,cAAc,MAA2C,EAAA;AACvD,QAAA,kBAAA,CAAmB,cAAc,MAAM,CAAA;AAAA;AACzC,KACF;AAAA;AAEJ,CAAC;;;;"}
|
|
@@ -7,6 +7,8 @@ var readHelmetOptions = require('./readHelmetOptions.cjs.js');
|
|
|
7
7
|
var readCorsOptions = require('./readCorsOptions.cjs.js');
|
|
8
8
|
var errors = require('@backstage/errors');
|
|
9
9
|
var applyInternalErrorFilter = require('./applyInternalErrorFilter.cjs.js');
|
|
10
|
+
var RateLimitStoreFactory = require('../../../lib/RateLimitStoreFactory.cjs.js');
|
|
11
|
+
var rateLimitMiddleware = require('../../../lib/rateLimitMiddleware.cjs.js');
|
|
10
12
|
|
|
11
13
|
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
|
|
12
14
|
|
|
@@ -132,6 +134,35 @@ class MiddlewareFactory {
|
|
|
132
134
|
cors() {
|
|
133
135
|
return cors__default.default(readCorsOptions.readCorsOptions(this.#config.getOptionalConfig("backend")));
|
|
134
136
|
}
|
|
137
|
+
/**
|
|
138
|
+
* Returns a middleware that implements rate limiting.
|
|
139
|
+
*
|
|
140
|
+
* @remarks
|
|
141
|
+
*
|
|
142
|
+
* Rate limiting is a common technique to prevent abuse of APIs. This middleware is
|
|
143
|
+
* configured using the config key `backend.rateLimit`.
|
|
144
|
+
*
|
|
145
|
+
* @returns An Express request handler
|
|
146
|
+
*/
|
|
147
|
+
rateLimit() {
|
|
148
|
+
const enabled = this.#config.has("backend.rateLimit");
|
|
149
|
+
if (!enabled) {
|
|
150
|
+
return (_req, _res, next) => {
|
|
151
|
+
next();
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
const useDefaults = this.#config.getOptional("backend.rateLimit") === true;
|
|
155
|
+
const rateLimitOptions = useDefaults ? void 0 : this.#config.getOptionalConfig("backend.rateLimit");
|
|
156
|
+
if (rateLimitOptions && rateLimitOptions.getOptionalBoolean("global") === false) {
|
|
157
|
+
return (_req, _res, next) => {
|
|
158
|
+
next();
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
return rateLimitMiddleware.rateLimitMiddleware({
|
|
162
|
+
store: useDefaults ? void 0 : RateLimitStoreFactory.RateLimitStoreFactory.create({ config: this.#config }),
|
|
163
|
+
config: rateLimitOptions
|
|
164
|
+
});
|
|
165
|
+
}
|
|
135
166
|
/**
|
|
136
167
|
* Express middleware to handle errors during request processing.
|
|
137
168
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MiddlewareFactory.cjs.js","sources":["../../../../src/entrypoints/rootHttpRouter/http/MiddlewareFactory.ts"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n RootConfigService,\n LoggerService,\n} from '@backstage/backend-plugin-api';\nimport {\n Request,\n Response,\n ErrorRequestHandler,\n NextFunction,\n RequestHandler,\n} from 'express';\nimport cors from 'cors';\nimport helmet from 'helmet';\nimport compression from 'compression';\nimport { readHelmetOptions } from './readHelmetOptions';\nimport { readCorsOptions } from './readCorsOptions';\nimport {\n AuthenticationError,\n ConflictError,\n ErrorResponseBody,\n InputError,\n NotAllowedError,\n NotFoundError,\n NotModifiedError,\n ServiceUnavailableError,\n serializeError,\n} from '@backstage/errors';\nimport { NotImplementedError } from '@backstage/errors';\nimport { applyInternalErrorFilter } from './applyInternalErrorFilter';\n\ntype LogMeta = {\n date: string;\n method: string;\n url: string;\n status: number;\n httpVersion: string;\n userAgent?: string;\n contentLength?: number;\n referrer?: string;\n};\n\nfunction getLogMeta(req: Request, res: Response): LogMeta {\n const referrer = req.headers.referer ?? req.headers.referrer;\n const userAgent = req.headers['user-agent'];\n const contentLength = Number(res.getHeader('content-length'));\n\n const meta: LogMeta = {\n date: new Date().toISOString(),\n method: req.method,\n url: req.originalUrl ?? req.url,\n status: res.statusCode,\n httpVersion: `${req.httpVersionMajor}.${req.httpVersionMinor}`,\n };\n\n if (userAgent) {\n meta.userAgent = userAgent;\n }\n\n if (isFinite(contentLength)) {\n meta.contentLength = contentLength;\n }\n\n if (referrer) {\n meta.referrer = Array.isArray(referrer) ? referrer.join(', ') : referrer;\n }\n\n return meta;\n}\n\n/**\n * Options used to create a {@link MiddlewareFactory}.\n *\n * @public\n */\nexport interface MiddlewareFactoryOptions {\n config: RootConfigService;\n logger: LoggerService;\n}\n\n/**\n * Options passed to the {@link MiddlewareFactory.error} middleware.\n *\n * @public\n */\nexport interface MiddlewareFactoryErrorOptions {\n /**\n * Whether error response bodies should show error stack traces or not.\n *\n * If not specified, by default shows stack traces only in development mode.\n */\n showStackTraces?: boolean;\n\n /**\n * Whether any 4xx errors should be logged or not.\n *\n * If not specified, default to only logging 5xx errors.\n */\n logAllErrors?: boolean;\n}\n\n/**\n * A utility to configure common middleware.\n *\n * @public\n */\nexport class MiddlewareFactory {\n #config: RootConfigService;\n #logger: LoggerService;\n\n /**\n * Creates a new {@link MiddlewareFactory}.\n */\n static create(options: MiddlewareFactoryOptions) {\n return new MiddlewareFactory(options);\n }\n\n private constructor(options: MiddlewareFactoryOptions) {\n this.#config = options.config;\n this.#logger = options.logger;\n }\n\n /**\n * Returns a middleware that unconditionally produces a 404 error response.\n *\n * @remarks\n *\n * Typically you want to place this middleware at the end of the chain, such\n * that it's the last one attempted after no other routes matched.\n *\n * @returns An Express request handler\n */\n notFound(): RequestHandler {\n return (_req: Request, res: Response) => {\n res.status(404).end();\n };\n }\n\n /**\n * Returns the compression middleware.\n *\n * @remarks\n *\n * The middleware will attempt to compress response bodies for all requests\n * that traverse through the middleware.\n */\n compression(): RequestHandler {\n return compression();\n }\n\n /**\n * Returns a request logging middleware.\n *\n * @remarks\n *\n * Typically you want to place this middleware at the start of the chain, such\n * that it always logs requests whether they are \"caught\" by handlers farther\n * down or not.\n *\n * @returns An Express request handler\n */\n logging(): RequestHandler {\n const logger = this.#logger;\n return (req: Request, res: Response, next: NextFunction) => {\n res.on('finish', () => {\n const meta = getLogMeta(req, res);\n logger.info(\n `[${meta.date}] \"${meta.method} ${meta.url} HTTP/${\n meta.httpVersion\n }\" ${meta.status} ${meta.contentLength ?? 0} \"${\n meta.referrer ?? '-'\n }\" \"${meta.userAgent ?? '-'}\"`,\n {\n type: 'incomingRequest',\n ...meta,\n },\n );\n });\n next();\n };\n }\n\n /**\n * Returns a middleware that implements the helmet library.\n *\n * @remarks\n *\n * This middleware applies security policies to incoming requests and outgoing\n * responses. It is configured using config keys such as `backend.csp`.\n *\n * @see {@link https://helmetjs.github.io/}\n *\n * @returns An Express request handler\n */\n helmet(): RequestHandler {\n return helmet(readHelmetOptions(this.#config.getOptionalConfig('backend')));\n }\n\n /**\n * Returns a middleware that implements the cors library.\n *\n * @remarks\n *\n * This middleware handles CORS. It is configured using the config key\n * `backend.cors`.\n *\n * @see {@link https://github.com/expressjs/cors}\n *\n * @returns An Express request handler\n */\n cors(): RequestHandler {\n return cors(readCorsOptions(this.#config.getOptionalConfig('backend')));\n }\n\n /**\n * Express middleware to handle errors during request processing.\n *\n * @remarks\n *\n * This is commonly the very last middleware in the chain.\n *\n * Its primary purpose is not to do translation of business logic exceptions,\n * but rather to be a global catch-all for uncaught \"fatal\" errors that are\n * expected to result in a 500 error. However, it also does handle some common\n * error types (such as http-error exceptions, and the well-known error types\n * in the `@backstage/errors` package) and returns the enclosed status code\n * accordingly.\n *\n * It will also produce a response body with a serialized form of the error,\n * unless a previous handler already did send a body. See\n * {@link @backstage/errors#ErrorResponseBody} for the response shape used.\n *\n * @returns An Express error request handler\n */\n error(options: MiddlewareFactoryErrorOptions = {}): ErrorRequestHandler {\n const showStackTraces =\n options.showStackTraces ?? process.env.NODE_ENV === 'development';\n\n const logger = this.#logger.child({\n type: 'errorHandler',\n });\n\n return (\n rawError: Error,\n req: Request,\n res: Response,\n next: NextFunction,\n ) => {\n const error = applyInternalErrorFilter(rawError, logger);\n\n const statusCode = getStatusCode(error);\n if (options.logAllErrors || statusCode >= 500) {\n logger.error(`Request failed with status ${statusCode}`, error);\n }\n\n if (res.headersSent) {\n // If the headers have already been sent, do not send the response again\n // as this will throw an error in the backend.\n next(error);\n return;\n }\n\n const body: ErrorResponseBody = {\n error: serializeError(error, { includeStack: showStackTraces }),\n request: { method: req.method, url: req.url },\n response: { statusCode },\n };\n\n res.status(statusCode).json(body);\n };\n }\n}\n\nfunction getStatusCode(error: Error): number {\n // Look for common http library status codes\n const knownStatusCodeFields = ['statusCode', 'status'];\n for (const field of knownStatusCodeFields) {\n const statusCode = (error as any)[field];\n if (\n typeof statusCode === 'number' &&\n (statusCode | 0) === statusCode && // is whole integer\n statusCode >= 100 &&\n statusCode <= 599\n ) {\n return statusCode;\n }\n }\n\n // Handle well-known error types\n switch (error.name) {\n case NotModifiedError.name:\n return 304;\n case InputError.name:\n return 400;\n case AuthenticationError.name:\n return 401;\n case NotAllowedError.name:\n return 403;\n case NotFoundError.name:\n return 404;\n case ConflictError.name:\n return 409;\n case NotImplementedError.name:\n return 501;\n case ServiceUnavailableError.name:\n return 503;\n default:\n break;\n }\n\n // Fall back to internal server error\n return 500;\n}\n"],"names":["compression","helmet","readHelmetOptions","cors","readCorsOptions","applyInternalErrorFilter","serializeError","NotModifiedError","InputError","AuthenticationError","NotAllowedError","NotFoundError","ConflictError","NotImplementedError","ServiceUnavailableError"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"MiddlewareFactory.cjs.js","sources":["../../../../src/entrypoints/rootHttpRouter/http/MiddlewareFactory.ts"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n LoggerService,\n RootConfigService,\n} from '@backstage/backend-plugin-api';\nimport {\n ErrorRequestHandler,\n NextFunction,\n Request,\n RequestHandler,\n Response,\n} from 'express';\nimport cors from 'cors';\nimport helmet from 'helmet';\nimport compression from 'compression';\nimport { readHelmetOptions } from './readHelmetOptions';\nimport { readCorsOptions } from './readCorsOptions';\nimport {\n AuthenticationError,\n ConflictError,\n ErrorResponseBody,\n InputError,\n NotAllowedError,\n NotFoundError,\n NotImplementedError,\n NotModifiedError,\n serializeError,\n ServiceUnavailableError,\n} from '@backstage/errors';\nimport { applyInternalErrorFilter } from './applyInternalErrorFilter';\nimport { RateLimitStoreFactory } from '../../../lib/RateLimitStoreFactory.ts';\nimport { rateLimitMiddleware } from '../../../lib/rateLimitMiddleware.ts';\n\ntype LogMeta = {\n date: string;\n method: string;\n url: string;\n status: number;\n httpVersion: string;\n userAgent?: string;\n contentLength?: number;\n referrer?: string;\n};\n\nfunction getLogMeta(req: Request, res: Response): LogMeta {\n const referrer = req.headers.referer ?? req.headers.referrer;\n const userAgent = req.headers['user-agent'];\n const contentLength = Number(res.getHeader('content-length'));\n\n const meta: LogMeta = {\n date: new Date().toISOString(),\n method: req.method,\n url: req.originalUrl ?? req.url,\n status: res.statusCode,\n httpVersion: `${req.httpVersionMajor}.${req.httpVersionMinor}`,\n };\n\n if (userAgent) {\n meta.userAgent = userAgent;\n }\n\n if (isFinite(contentLength)) {\n meta.contentLength = contentLength;\n }\n\n if (referrer) {\n meta.referrer = Array.isArray(referrer) ? referrer.join(', ') : referrer;\n }\n\n return meta;\n}\n\n/**\n * Options used to create a {@link MiddlewareFactory}.\n *\n * @public\n */\nexport interface MiddlewareFactoryOptions {\n config: RootConfigService;\n logger: LoggerService;\n}\n\n/**\n * Options passed to the {@link MiddlewareFactory.error} middleware.\n *\n * @public\n */\nexport interface MiddlewareFactoryErrorOptions {\n /**\n * Whether error response bodies should show error stack traces or not.\n *\n * If not specified, by default shows stack traces only in development mode.\n */\n showStackTraces?: boolean;\n\n /**\n * Whether any 4xx errors should be logged or not.\n *\n * If not specified, default to only logging 5xx errors.\n */\n logAllErrors?: boolean;\n}\n\n/**\n * A utility to configure common middleware.\n *\n * @public\n */\nexport class MiddlewareFactory {\n #config: RootConfigService;\n #logger: LoggerService;\n\n /**\n * Creates a new {@link MiddlewareFactory}.\n */\n static create(options: MiddlewareFactoryOptions) {\n return new MiddlewareFactory(options);\n }\n\n private constructor(options: MiddlewareFactoryOptions) {\n this.#config = options.config;\n this.#logger = options.logger;\n }\n\n /**\n * Returns a middleware that unconditionally produces a 404 error response.\n *\n * @remarks\n *\n * Typically you want to place this middleware at the end of the chain, such\n * that it's the last one attempted after no other routes matched.\n *\n * @returns An Express request handler\n */\n notFound(): RequestHandler {\n return (_req: Request, res: Response) => {\n res.status(404).end();\n };\n }\n\n /**\n * Returns the compression middleware.\n *\n * @remarks\n *\n * The middleware will attempt to compress response bodies for all requests\n * that traverse through the middleware.\n */\n compression(): RequestHandler {\n return compression();\n }\n\n /**\n * Returns a request logging middleware.\n *\n * @remarks\n *\n * Typically you want to place this middleware at the start of the chain, such\n * that it always logs requests whether they are \"caught\" by handlers farther\n * down or not.\n *\n * @returns An Express request handler\n */\n logging(): RequestHandler {\n const logger = this.#logger;\n return (req: Request, res: Response, next: NextFunction) => {\n res.on('finish', () => {\n const meta = getLogMeta(req, res);\n logger.info(\n `[${meta.date}] \"${meta.method} ${meta.url} HTTP/${\n meta.httpVersion\n }\" ${meta.status} ${meta.contentLength ?? 0} \"${\n meta.referrer ?? '-'\n }\" \"${meta.userAgent ?? '-'}\"`,\n {\n type: 'incomingRequest',\n ...meta,\n },\n );\n });\n next();\n };\n }\n\n /**\n * Returns a middleware that implements the helmet library.\n *\n * @remarks\n *\n * This middleware applies security policies to incoming requests and outgoing\n * responses. It is configured using config keys such as `backend.csp`.\n *\n * @see {@link https://helmetjs.github.io/}\n *\n * @returns An Express request handler\n */\n helmet(): RequestHandler {\n return helmet(readHelmetOptions(this.#config.getOptionalConfig('backend')));\n }\n\n /**\n * Returns a middleware that implements the cors library.\n *\n * @remarks\n *\n * This middleware handles CORS. It is configured using the config key\n * `backend.cors`.\n *\n * @see {@link https://github.com/expressjs/cors}\n *\n * @returns An Express request handler\n */\n cors(): RequestHandler {\n return cors(readCorsOptions(this.#config.getOptionalConfig('backend')));\n }\n\n /**\n * Returns a middleware that implements rate limiting.\n *\n * @remarks\n *\n * Rate limiting is a common technique to prevent abuse of APIs. This middleware is\n * configured using the config key `backend.rateLimit`.\n *\n * @returns An Express request handler\n */\n rateLimit(): RequestHandler {\n const enabled = this.#config.has('backend.rateLimit');\n if (!enabled) {\n return (_req: Request, _res: Response, next: NextFunction) => {\n next();\n };\n }\n\n const useDefaults = this.#config.getOptional('backend.rateLimit') === true;\n const rateLimitOptions = useDefaults\n ? undefined\n : this.#config.getOptionalConfig('backend.rateLimit');\n\n // Global rate limiting disabled\n if (\n rateLimitOptions &&\n rateLimitOptions.getOptionalBoolean('global') === false\n ) {\n return (_req: Request, _res: Response, next: NextFunction) => {\n next();\n };\n }\n\n return rateLimitMiddleware({\n store: useDefaults\n ? undefined\n : RateLimitStoreFactory.create({ config: this.#config }),\n config: rateLimitOptions,\n });\n }\n\n /**\n * Express middleware to handle errors during request processing.\n *\n * @remarks\n *\n * This is commonly the very last middleware in the chain.\n *\n * Its primary purpose is not to do translation of business logic exceptions,\n * but rather to be a global catch-all for uncaught \"fatal\" errors that are\n * expected to result in a 500 error. However, it also does handle some common\n * error types (such as http-error exceptions, and the well-known error types\n * in the `@backstage/errors` package) and returns the enclosed status code\n * accordingly.\n *\n * It will also produce a response body with a serialized form of the error,\n * unless a previous handler already did send a body. See\n * {@link @backstage/errors#ErrorResponseBody} for the response shape used.\n *\n * @returns An Express error request handler\n */\n error(options: MiddlewareFactoryErrorOptions = {}): ErrorRequestHandler {\n const showStackTraces =\n options.showStackTraces ?? process.env.NODE_ENV === 'development';\n\n const logger = this.#logger.child({\n type: 'errorHandler',\n });\n\n return (\n rawError: Error,\n req: Request,\n res: Response,\n next: NextFunction,\n ) => {\n const error = applyInternalErrorFilter(rawError, logger);\n\n const statusCode = getStatusCode(error);\n if (options.logAllErrors || statusCode >= 500) {\n logger.error(`Request failed with status ${statusCode}`, error);\n }\n\n if (res.headersSent) {\n // If the headers have already been sent, do not send the response again\n // as this will throw an error in the backend.\n next(error);\n return;\n }\n\n const body: ErrorResponseBody = {\n error: serializeError(error, { includeStack: showStackTraces }),\n request: { method: req.method, url: req.url },\n response: { statusCode },\n };\n\n res.status(statusCode).json(body);\n };\n }\n}\n\nfunction getStatusCode(error: Error): number {\n // Look for common http library status codes\n const knownStatusCodeFields = ['statusCode', 'status'];\n for (const field of knownStatusCodeFields) {\n const statusCode = (error as any)[field];\n if (\n typeof statusCode === 'number' &&\n (statusCode | 0) === statusCode && // is whole integer\n statusCode >= 100 &&\n statusCode <= 599\n ) {\n return statusCode;\n }\n }\n\n // Handle well-known error types\n switch (error.name) {\n case NotModifiedError.name:\n return 304;\n case InputError.name:\n return 400;\n case AuthenticationError.name:\n return 401;\n case NotAllowedError.name:\n return 403;\n case NotFoundError.name:\n return 404;\n case ConflictError.name:\n return 409;\n case NotImplementedError.name:\n return 501;\n case ServiceUnavailableError.name:\n return 503;\n default:\n break;\n }\n\n // Fall back to internal server error\n return 500;\n}\n"],"names":["compression","helmet","readHelmetOptions","cors","readCorsOptions","rateLimitMiddleware","RateLimitStoreFactory","applyInternalErrorFilter","serializeError","NotModifiedError","InputError","AuthenticationError","NotAllowedError","NotFoundError","ConflictError","NotImplementedError","ServiceUnavailableError"],"mappings":"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"}
|
|
@@ -62,6 +62,7 @@ const rootHttpRouterServiceFactoryWithOptions = (options) => backendPluginApi.cr
|
|
|
62
62
|
app.use(middleware.cors());
|
|
63
63
|
app.use(middleware.compression());
|
|
64
64
|
app.use(middleware.logging());
|
|
65
|
+
app.use(middleware.rateLimit());
|
|
65
66
|
app.use(healthRouter);
|
|
66
67
|
app.use(routes);
|
|
67
68
|
app.use(middleware.notFound());
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rootHttpRouterServiceFactory.cjs.js","sources":["../../../src/entrypoints/rootHttpRouter/rootHttpRouterServiceFactory.ts"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n
|
|
1
|
+
{"version":3,"file":"rootHttpRouterServiceFactory.cjs.js","sources":["../../../src/entrypoints/rootHttpRouter/rootHttpRouterServiceFactory.ts"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n coreServices,\n createServiceFactory,\n LifecycleService,\n LoggerService,\n RootConfigService,\n} from '@backstage/backend-plugin-api';\nimport express, { Express, RequestHandler } from 'express';\nimport type { Server } from 'node:http';\nimport {\n createHttpServer,\n MiddlewareFactory,\n readHttpServerOptions,\n} from './http';\nimport { DefaultRootHttpRouter } from './DefaultRootHttpRouter';\nimport { createHealthRouter } from './createHealthRouter';\nimport { durationToMilliseconds } from '@backstage/types';\nimport { readDurationFromConfig } from '@backstage/config';\n\n/**\n * @public\n */\nexport interface RootHttpRouterConfigureContext {\n app: Express;\n server: Server;\n middleware: MiddlewareFactory;\n routes: RequestHandler;\n config: RootConfigService;\n logger: LoggerService;\n lifecycle: LifecycleService;\n healthRouter: RequestHandler;\n applyDefaults: () => void;\n}\n\n/**\n * HTTP route registration for root services.\n *\n * See {@link @backstage/code-plugin-api#RootHttpRouterService}\n * and {@link https://backstage.io/docs/backend-system/core-services/root-http-router | the service docs}\n * for more information.\n *\n * @public\n */\nexport type RootHttpRouterFactoryOptions = {\n /**\n * The path to forward all unmatched requests to. Defaults to '/api/app' if\n * not given. Disables index path behavior if false is given.\n */\n indexPath?: string | false;\n\n configure?(context: RootHttpRouterConfigureContext): void;\n};\n\nfunction defaultConfigure({ applyDefaults }: RootHttpRouterConfigureContext) {\n applyDefaults();\n}\n\nconst rootHttpRouterServiceFactoryWithOptions = (\n options?: RootHttpRouterFactoryOptions,\n) =>\n createServiceFactory({\n service: coreServices.rootHttpRouter,\n deps: {\n config: coreServices.rootConfig,\n rootLogger: coreServices.rootLogger,\n lifecycle: coreServices.rootLifecycle,\n health: coreServices.rootHealth,\n },\n async factory({ config, rootLogger, lifecycle, health }) {\n const { indexPath, configure = defaultConfigure } = options ?? {};\n const logger = rootLogger.child({ service: 'rootHttpRouter' });\n const app = express();\n\n const trustProxy = config.getOptional('backend.trustProxy');\n\n const router = DefaultRootHttpRouter.create({ indexPath });\n const middleware = MiddlewareFactory.create({ config, logger });\n const routes = router.handler();\n\n const healthRouter = createHealthRouter({ config, health });\n\n const server = await createHttpServer(\n app,\n readHttpServerOptions(config.getOptionalConfig('backend')),\n { logger },\n );\n\n configure({\n app,\n server,\n routes,\n middleware,\n config,\n logger,\n lifecycle,\n healthRouter,\n applyDefaults() {\n if (process.env.NODE_ENV === 'development') {\n app.set('json spaces', 2);\n }\n if (trustProxy !== undefined) {\n app.set('trust proxy', trustProxy);\n }\n app.use(middleware.helmet());\n app.use(middleware.cors());\n app.use(middleware.compression());\n app.use(middleware.logging());\n app.use(middleware.rateLimit());\n app.use(healthRouter);\n app.use(routes);\n app.use(middleware.notFound());\n app.use(middleware.error());\n },\n });\n\n if (config.has('backend.lifecycle.serverShutdownDelay')) {\n const serverShutdownDelay = readDurationFromConfig(config, {\n key: 'backend.lifecycle.serverShutdownDelay',\n });\n lifecycle.addBeforeShutdownHook(async () => {\n const timeoutMs = durationToMilliseconds(serverShutdownDelay);\n return await new Promise(resolve => {\n setTimeout(resolve, timeoutMs);\n });\n });\n }\n\n lifecycle.addShutdownHook(() => server.stop());\n\n await server.start();\n\n return router;\n },\n });\n\n/** @public */\nexport const rootHttpRouterServiceFactory = Object.assign(\n rootHttpRouterServiceFactoryWithOptions,\n rootHttpRouterServiceFactoryWithOptions(),\n);\n"],"names":["createServiceFactory","coreServices","config","express","DefaultRootHttpRouter","MiddlewareFactory","createHealthRouter","createHttpServer","readHttpServerOptions","readDurationFromConfig","durationToMilliseconds"],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var rateLimitRedis = require('rate-limit-redis');
|
|
4
|
+
|
|
5
|
+
class RateLimitStoreFactory {
|
|
6
|
+
static create(options) {
|
|
7
|
+
const { config, prefix } = options;
|
|
8
|
+
const store = config.getOptionalConfig("backend.rateLimit.store");
|
|
9
|
+
if (!store) {
|
|
10
|
+
return void 0;
|
|
11
|
+
}
|
|
12
|
+
const type = store.getString("type");
|
|
13
|
+
switch (type) {
|
|
14
|
+
case "redis":
|
|
15
|
+
return this.redis({ store, prefix });
|
|
16
|
+
case "memory":
|
|
17
|
+
default:
|
|
18
|
+
return void 0;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
static redis(options) {
|
|
22
|
+
const { store, prefix } = options;
|
|
23
|
+
const connectionString = store.getString("connection");
|
|
24
|
+
const KeyvRedis = require("@keyv/redis").default;
|
|
25
|
+
const keyv = new KeyvRedis(connectionString);
|
|
26
|
+
return new rateLimitRedis.RedisStore({
|
|
27
|
+
prefix,
|
|
28
|
+
sendCommand: async (...args) => {
|
|
29
|
+
const client = await keyv.getClient();
|
|
30
|
+
return client.sendCommand(args);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
exports.RateLimitStoreFactory = RateLimitStoreFactory;
|
|
37
|
+
//# sourceMappingURL=RateLimitStoreFactory.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RateLimitStoreFactory.cjs.js","sources":["../../src/lib/RateLimitStoreFactory.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { Config } from '@backstage/config';\nimport type { Store } from 'express-rate-limit';\nimport { RedisStore } from 'rate-limit-redis';\n\n/**\n * Creates a store for `express-rate-limit` based on the configuration.\n *\n * @internal\n */\nexport class RateLimitStoreFactory {\n static create(options: {\n config: Config;\n prefix?: string;\n }): Store | undefined {\n const { config, prefix } = options;\n const store = config.getOptionalConfig('backend.rateLimit.store');\n if (!store) {\n return undefined;\n }\n const type = store.getString('type');\n switch (type) {\n case 'redis':\n return this.redis({ store, prefix });\n case 'memory':\n default:\n return undefined;\n }\n }\n\n private static redis(options: { store: Config; prefix?: string }): Store {\n const { store, prefix } = options;\n const connectionString = store.getString('connection');\n const KeyvRedis = require('@keyv/redis').default;\n const keyv = new KeyvRedis(connectionString);\n return new RedisStore({\n prefix,\n sendCommand: async (...args: string[]) => {\n const client = await keyv.getClient();\n return client.sendCommand(args);\n },\n });\n }\n}\n"],"names":["RedisStore"],"mappings":";;;;AAwBO,MAAM,qBAAsB,CAAA;AAAA,EACjC,OAAO,OAAO,OAGQ,EAAA;AACpB,IAAM,MAAA,EAAE,MAAQ,EAAA,MAAA,EAAW,GAAA,OAAA;AAC3B,IAAM,MAAA,KAAA,GAAQ,MAAO,CAAA,iBAAA,CAAkB,yBAAyB,CAAA;AAChE,IAAA,IAAI,CAAC,KAAO,EAAA;AACV,MAAO,OAAA,KAAA,CAAA;AAAA;AAET,IAAM,MAAA,IAAA,GAAO,KAAM,CAAA,SAAA,CAAU,MAAM,CAAA;AACnC,IAAA,QAAQ,IAAM;AAAA,MACZ,KAAK,OAAA;AACH,QAAA,OAAO,IAAK,CAAA,KAAA,CAAM,EAAE,KAAA,EAAO,QAAQ,CAAA;AAAA,MACrC,KAAK,QAAA;AAAA,MACL;AACE,QAAO,OAAA,KAAA,CAAA;AAAA;AACX;AACF,EAEA,OAAe,MAAM,OAAoD,EAAA;AACvE,IAAM,MAAA,EAAE,KAAO,EAAA,MAAA,EAAW,GAAA,OAAA;AAC1B,IAAM,MAAA,gBAAA,GAAmB,KAAM,CAAA,SAAA,CAAU,YAAY,CAAA;AACrD,IAAM,MAAA,SAAA,GAAY,OAAQ,CAAA,aAAa,CAAE,CAAA,OAAA;AACzC,IAAM,MAAA,IAAA,GAAO,IAAI,SAAA,CAAU,gBAAgB,CAAA;AAC3C,IAAA,OAAO,IAAIA,yBAAW,CAAA;AAAA,MACpB,MAAA;AAAA,MACA,WAAA,EAAa,UAAU,IAAmB,KAAA;AACxC,QAAM,MAAA,MAAA,GAAS,MAAM,IAAA,CAAK,SAAU,EAAA;AACpC,QAAO,OAAA,MAAA,CAAO,YAAY,IAAI,CAAA;AAAA;AAChC,KACD,CAAA;AAAA;AAEL;;;;"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var expressRateLimit = require('express-rate-limit');
|
|
4
|
+
var config = require('@backstage/config');
|
|
5
|
+
var types = require('@backstage/types');
|
|
6
|
+
|
|
7
|
+
const rateLimitMiddleware = (options) => {
|
|
8
|
+
const { store, config: config$1 } = options;
|
|
9
|
+
let windowMs = 6e4;
|
|
10
|
+
if (config$1 && config$1.has("window")) {
|
|
11
|
+
const windowDuration = config.readDurationFromConfig(config$1, {
|
|
12
|
+
key: "window"
|
|
13
|
+
});
|
|
14
|
+
windowMs = types.durationToMilliseconds(windowDuration);
|
|
15
|
+
}
|
|
16
|
+
const limit = config$1?.getOptionalNumber("incomingRequestLimit");
|
|
17
|
+
const ipAllowList = config$1?.getOptionalStringArray("ipAllowList") ?? [
|
|
18
|
+
"127.0.0.1",
|
|
19
|
+
"0:0:0:0:0:0:0:1",
|
|
20
|
+
"::1"
|
|
21
|
+
];
|
|
22
|
+
const skipSuccessfulRequests = config$1?.getOptionalBoolean(
|
|
23
|
+
"skipSuccessfulRequests"
|
|
24
|
+
);
|
|
25
|
+
const skipFailedRequests = config$1?.getOptionalBoolean("skipFailedRequests");
|
|
26
|
+
const passOnStoreError = config$1?.getOptionalBoolean("passOnStoreError");
|
|
27
|
+
return expressRateLimit.rateLimit({
|
|
28
|
+
windowMs,
|
|
29
|
+
limit,
|
|
30
|
+
skipSuccessfulRequests,
|
|
31
|
+
message: {
|
|
32
|
+
error: {
|
|
33
|
+
name: "Error",
|
|
34
|
+
message: `Too many requests, please try again later`
|
|
35
|
+
},
|
|
36
|
+
response: {
|
|
37
|
+
statusCode: 429
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
statusCode: 429,
|
|
41
|
+
skipFailedRequests,
|
|
42
|
+
passOnStoreError,
|
|
43
|
+
keyGenerator(req, _res) {
|
|
44
|
+
if (!req.ip) {
|
|
45
|
+
return req.socket.remoteAddress;
|
|
46
|
+
}
|
|
47
|
+
return req.ip;
|
|
48
|
+
},
|
|
49
|
+
skip: (req, _res) => {
|
|
50
|
+
return Boolean(req.ip && ipAllowList.includes(req.ip)) || Boolean(
|
|
51
|
+
req.socket.remoteAddress && ipAllowList.includes(req.socket.remoteAddress)
|
|
52
|
+
);
|
|
53
|
+
},
|
|
54
|
+
validate: {
|
|
55
|
+
trustProxy: false
|
|
56
|
+
},
|
|
57
|
+
store
|
|
58
|
+
});
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
exports.rateLimitMiddleware = rateLimitMiddleware;
|
|
62
|
+
//# sourceMappingURL=rateLimitMiddleware.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rateLimitMiddleware.cjs.js","sources":["../../src/lib/rateLimitMiddleware.ts"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { RequestHandler } from 'express';\nimport { rateLimit, Store } from 'express-rate-limit';\nimport { Config, readDurationFromConfig } from '@backstage/config';\nimport { durationToMilliseconds } from '@backstage/types';\n\nexport const rateLimitMiddleware = (options: {\n store?: Store;\n config?: Config;\n}): RequestHandler => {\n const { store, config } = options;\n let windowMs: number = 60000;\n if (config && config.has('window')) {\n const windowDuration = readDurationFromConfig(config, {\n key: 'window',\n });\n windowMs = durationToMilliseconds(windowDuration);\n }\n const limit = config?.getOptionalNumber('incomingRequestLimit');\n const ipAllowList = config?.getOptionalStringArray('ipAllowList') ?? [\n '127.0.0.1',\n '0:0:0:0:0:0:0:1',\n '::1',\n ];\n const skipSuccessfulRequests = config?.getOptionalBoolean(\n 'skipSuccessfulRequests',\n );\n const skipFailedRequests = config?.getOptionalBoolean('skipFailedRequests');\n const passOnStoreError = config?.getOptionalBoolean('passOnStoreError');\n\n return rateLimit({\n windowMs,\n limit,\n skipSuccessfulRequests,\n message: {\n error: {\n name: 'Error',\n message: `Too many requests, please try again later`,\n },\n response: {\n statusCode: 429,\n },\n },\n statusCode: 429,\n skipFailedRequests,\n passOnStoreError: passOnStoreError,\n keyGenerator(req, _res): string {\n if (!req.ip) {\n return req.socket.remoteAddress!;\n }\n return req.ip;\n },\n skip: (req, _res) => {\n return (\n Boolean(req.ip && ipAllowList.includes(req.ip)) ||\n Boolean(\n req.socket.remoteAddress &&\n ipAllowList.includes(req.socket.remoteAddress),\n )\n );\n },\n validate: {\n trustProxy: false,\n },\n store,\n });\n};\n"],"names":["config","readDurationFromConfig","durationToMilliseconds","rateLimit"],"mappings":";;;;;;AAoBa,MAAA,mBAAA,GAAsB,CAAC,OAGd,KAAA;AACpB,EAAM,MAAA,EAAE,KAAO,UAAAA,QAAA,EAAW,GAAA,OAAA;AAC1B,EAAA,IAAI,QAAmB,GAAA,GAAA;AACvB,EAAA,IAAIA,QAAU,IAAAA,QAAA,CAAO,GAAI,CAAA,QAAQ,CAAG,EAAA;AAClC,IAAM,MAAA,cAAA,GAAiBC,8BAAuBD,QAAQ,EAAA;AAAA,MACpD,GAAK,EAAA;AAAA,KACN,CAAA;AACD,IAAA,QAAA,GAAWE,6BAAuB,cAAc,CAAA;AAAA;AAElD,EAAM,MAAA,KAAA,GAAQF,QAAQ,EAAA,iBAAA,CAAkB,sBAAsB,CAAA;AAC9D,EAAA,MAAM,WAAc,GAAAA,QAAA,EAAQ,sBAAuB,CAAA,aAAa,CAAK,IAAA;AAAA,IACnE,WAAA;AAAA,IACA,iBAAA;AAAA,IACA;AAAA,GACF;AACA,EAAA,MAAM,yBAAyBA,QAAQ,EAAA,kBAAA;AAAA,IACrC;AAAA,GACF;AACA,EAAM,MAAA,kBAAA,GAAqBA,QAAQ,EAAA,kBAAA,CAAmB,oBAAoB,CAAA;AAC1E,EAAM,MAAA,gBAAA,GAAmBA,QAAQ,EAAA,kBAAA,CAAmB,kBAAkB,CAAA;AAEtE,EAAA,OAAOG,0BAAU,CAAA;AAAA,IACf,QAAA;AAAA,IACA,KAAA;AAAA,IACA,sBAAA;AAAA,IACA,OAAS,EAAA;AAAA,MACP,KAAO,EAAA;AAAA,QACL,IAAM,EAAA,OAAA;AAAA,QACN,OAAS,EAAA,CAAA,yCAAA;AAAA,OACX;AAAA,MACA,QAAU,EAAA;AAAA,QACR,UAAY,EAAA;AAAA;AACd,KACF;AAAA,IACA,UAAY,EAAA,GAAA;AAAA,IACZ,kBAAA;AAAA,IACA,gBAAA;AAAA,IACA,YAAA,CAAa,KAAK,IAAc,EAAA;AAC9B,MAAI,IAAA,CAAC,IAAI,EAAI,EAAA;AACX,QAAA,OAAO,IAAI,MAAO,CAAA,aAAA;AAAA;AAEpB,MAAA,OAAO,GAAI,CAAA,EAAA;AAAA,KACb;AAAA,IACA,IAAA,EAAM,CAAC,GAAA,EAAK,IAAS,KAAA;AACnB,MACE,OAAA,OAAA,CAAQ,IAAI,EAAM,IAAA,WAAA,CAAY,SAAS,GAAI,CAAA,EAAE,CAAC,CAC9C,IAAA,OAAA;AAAA,QACE,IAAI,MAAO,CAAA,aAAA,IACT,YAAY,QAAS,CAAA,GAAA,CAAI,OAAO,aAAa;AAAA,OACjD;AAAA,KAEJ;AAAA,IACA,QAAU,EAAA;AAAA,MACR,UAAY,EAAA;AAAA,KACd;AAAA,IACA;AAAA,GACD,CAAA;AACH;;;;"}
|
package/dist/package.json.cjs.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
5
|
var name = "@backstage/backend-defaults";
|
|
6
|
-
var version = "0.
|
|
6
|
+
var version = "0.11.0";
|
|
7
7
|
var description = "Backend defaults used by Backstage backend apps";
|
|
8
8
|
var backstage = {
|
|
9
9
|
role: "node-library"
|
|
@@ -23,8 +23,6 @@ var repository = {
|
|
|
23
23
|
var license = "Apache-2.0";
|
|
24
24
|
var exports$1 = {
|
|
25
25
|
".": "./src/index.ts",
|
|
26
|
-
"./actions": "./src/entrypoints/actions/index.ts",
|
|
27
|
-
"./actionsRegistry": "./src/entrypoints/actionsRegistry/index.ts",
|
|
28
26
|
"./auditor": "./src/entrypoints/auditor/index.ts",
|
|
29
27
|
"./auth": "./src/entrypoints/auth/index.ts",
|
|
30
28
|
"./cache": "./src/entrypoints/cache/index.ts",
|
|
@@ -44,18 +42,13 @@ var exports$1 = {
|
|
|
44
42
|
"./scheduler": "./src/entrypoints/scheduler/index.ts",
|
|
45
43
|
"./urlReader": "./src/entrypoints/urlReader/index.ts",
|
|
46
44
|
"./userInfo": "./src/entrypoints/userInfo/index.ts",
|
|
45
|
+
"./alpha": "./src/alpha/index.ts",
|
|
47
46
|
"./package.json": "./package.json"
|
|
48
47
|
};
|
|
49
48
|
var main = "src/index.ts";
|
|
50
49
|
var types = "src/index.ts";
|
|
51
50
|
var typesVersions = {
|
|
52
51
|
"*": {
|
|
53
|
-
actions: [
|
|
54
|
-
"src/entrypoints/actions/index.ts"
|
|
55
|
-
],
|
|
56
|
-
actionsRegistry: [
|
|
57
|
-
"src/entrypoints/actionsRegistry/index.ts"
|
|
58
|
-
],
|
|
59
52
|
auditor: [
|
|
60
53
|
"src/entrypoints/auditor/index.ts"
|
|
61
54
|
],
|
|
@@ -113,6 +106,9 @@ var typesVersions = {
|
|
|
113
106
|
userInfo: [
|
|
114
107
|
"src/entrypoints/userInfo/index.ts"
|
|
115
108
|
],
|
|
109
|
+
alpha: [
|
|
110
|
+
"src/alpha/index.ts"
|
|
111
|
+
],
|
|
116
112
|
"package.json": [
|
|
117
113
|
"package.json"
|
|
118
114
|
]
|
|
@@ -171,6 +167,7 @@ var dependencies = {
|
|
|
171
167
|
cron: "^3.0.0",
|
|
172
168
|
express: "^4.17.1",
|
|
173
169
|
"express-promise-router": "^4.1.0",
|
|
170
|
+
"express-rate-limit": "^7.5.0",
|
|
174
171
|
"fs-extra": "^11.2.0",
|
|
175
172
|
"git-url-parse": "^15.0.0",
|
|
176
173
|
helmet: "^6.0.0",
|
|
@@ -190,6 +187,7 @@ var dependencies = {
|
|
|
190
187
|
pg: "^8.11.3",
|
|
191
188
|
"pg-connection-string": "^2.3.0",
|
|
192
189
|
"pg-format": "^1.0.4",
|
|
190
|
+
"rate-limit-redis": "^4.2.0",
|
|
193
191
|
"raw-body": "^2.4.1",
|
|
194
192
|
selfsigned: "^2.0.0",
|
|
195
193
|
tar: "^6.1.12",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"package.json.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"package.json.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
package/dist/rootHttpRouter.d.ts
CHANGED
|
@@ -204,6 +204,17 @@ declare class MiddlewareFactory {
|
|
|
204
204
|
* @returns An Express request handler
|
|
205
205
|
*/
|
|
206
206
|
cors(): RequestHandler;
|
|
207
|
+
/**
|
|
208
|
+
* Returns a middleware that implements rate limiting.
|
|
209
|
+
*
|
|
210
|
+
* @remarks
|
|
211
|
+
*
|
|
212
|
+
* Rate limiting is a common technique to prevent abuse of APIs. This middleware is
|
|
213
|
+
* configured using the config key `backend.rateLimit`.
|
|
214
|
+
*
|
|
215
|
+
* @returns An Express request handler
|
|
216
|
+
*/
|
|
217
|
+
rateLimit(): RequestHandler;
|
|
207
218
|
/**
|
|
208
219
|
* Express middleware to handle errors during request processing.
|
|
209
220
|
*
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backstage/backend-defaults",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"description": "Backend defaults used by Backstage backend apps",
|
|
5
5
|
"backstage": {
|
|
6
6
|
"role": "node-library"
|
|
@@ -24,16 +24,6 @@
|
|
|
24
24
|
"types": "./dist/index.d.ts",
|
|
25
25
|
"default": "./dist/index.cjs.js"
|
|
26
26
|
},
|
|
27
|
-
"./actions": {
|
|
28
|
-
"require": "./dist/actions.cjs.js",
|
|
29
|
-
"types": "./dist/actions.d.ts",
|
|
30
|
-
"default": "./dist/actions.cjs.js"
|
|
31
|
-
},
|
|
32
|
-
"./actionsRegistry": {
|
|
33
|
-
"require": "./dist/actionsRegistry.cjs.js",
|
|
34
|
-
"types": "./dist/actionsRegistry.d.ts",
|
|
35
|
-
"default": "./dist/actionsRegistry.cjs.js"
|
|
36
|
-
},
|
|
37
27
|
"./auditor": {
|
|
38
28
|
"require": "./dist/auditor.cjs.js",
|
|
39
29
|
"types": "./dist/auditor.d.ts",
|
|
@@ -129,18 +119,17 @@
|
|
|
129
119
|
"types": "./dist/userInfo.d.ts",
|
|
130
120
|
"default": "./dist/userInfo.cjs.js"
|
|
131
121
|
},
|
|
122
|
+
"./alpha": {
|
|
123
|
+
"require": "./dist/alpha.cjs.js",
|
|
124
|
+
"types": "./dist/alpha.d.ts",
|
|
125
|
+
"default": "./dist/alpha.cjs.js"
|
|
126
|
+
},
|
|
132
127
|
"./package.json": "./package.json"
|
|
133
128
|
},
|
|
134
129
|
"main": "./dist/index.cjs.js",
|
|
135
130
|
"types": "./dist/index.d.ts",
|
|
136
131
|
"typesVersions": {
|
|
137
132
|
"*": {
|
|
138
|
-
"actions": [
|
|
139
|
-
"dist/actions.d.ts"
|
|
140
|
-
],
|
|
141
|
-
"actionsRegistry": [
|
|
142
|
-
"dist/actionsRegistry.d.ts"
|
|
143
|
-
],
|
|
144
133
|
"auditor": [
|
|
145
134
|
"dist/auditor.d.ts"
|
|
146
135
|
],
|
|
@@ -198,6 +187,9 @@
|
|
|
198
187
|
"userInfo": [
|
|
199
188
|
"dist/userInfo.d.ts"
|
|
200
189
|
],
|
|
190
|
+
"alpha": [
|
|
191
|
+
"dist/alpha.d.ts"
|
|
192
|
+
],
|
|
201
193
|
"package.json": [
|
|
202
194
|
"package.json"
|
|
203
195
|
]
|
|
@@ -224,19 +216,19 @@
|
|
|
224
216
|
"@aws-sdk/credential-providers": "^3.350.0",
|
|
225
217
|
"@aws-sdk/types": "^3.347.0",
|
|
226
218
|
"@azure/storage-blob": "^12.5.0",
|
|
227
|
-
"@backstage/backend-app-api": "1.2.4
|
|
228
|
-
"@backstage/backend-dev-utils": "0.1.5",
|
|
229
|
-
"@backstage/backend-plugin-api": "1.4.0
|
|
230
|
-
"@backstage/cli-node": "0.2.13",
|
|
231
|
-
"@backstage/config": "1.3.2",
|
|
232
|
-
"@backstage/config-loader": "1.10.1",
|
|
233
|
-
"@backstage/errors": "1.2.7",
|
|
234
|
-
"@backstage/integration": "1.17.0",
|
|
235
|
-
"@backstage/integration-aws-node": "0.1.16",
|
|
236
|
-
"@backstage/plugin-auth-node": "0.6.4
|
|
237
|
-
"@backstage/plugin-events-node": "0.4.12
|
|
238
|
-
"@backstage/plugin-permission-node": "0.10.1
|
|
239
|
-
"@backstage/types": "1.2.1",
|
|
219
|
+
"@backstage/backend-app-api": "^1.2.4",
|
|
220
|
+
"@backstage/backend-dev-utils": "^0.1.5",
|
|
221
|
+
"@backstage/backend-plugin-api": "^1.4.0",
|
|
222
|
+
"@backstage/cli-node": "^0.2.13",
|
|
223
|
+
"@backstage/config": "^1.3.2",
|
|
224
|
+
"@backstage/config-loader": "^1.10.1",
|
|
225
|
+
"@backstage/errors": "^1.2.7",
|
|
226
|
+
"@backstage/integration": "^1.17.0",
|
|
227
|
+
"@backstage/integration-aws-node": "^0.1.16",
|
|
228
|
+
"@backstage/plugin-auth-node": "^0.6.4",
|
|
229
|
+
"@backstage/plugin-events-node": "^0.4.12",
|
|
230
|
+
"@backstage/plugin-permission-node": "^0.10.1",
|
|
231
|
+
"@backstage/types": "^1.2.1",
|
|
240
232
|
"@google-cloud/storage": "^7.0.0",
|
|
241
233
|
"@keyv/memcache": "^2.0.1",
|
|
242
234
|
"@keyv/redis": "^4.0.1",
|
|
@@ -256,6 +248,7 @@
|
|
|
256
248
|
"cron": "^3.0.0",
|
|
257
249
|
"express": "^4.17.1",
|
|
258
250
|
"express-promise-router": "^4.1.0",
|
|
251
|
+
"express-rate-limit": "^7.5.0",
|
|
259
252
|
"fs-extra": "^11.2.0",
|
|
260
253
|
"git-url-parse": "^15.0.0",
|
|
261
254
|
"helmet": "^6.0.0",
|
|
@@ -275,6 +268,7 @@
|
|
|
275
268
|
"pg": "^8.11.3",
|
|
276
269
|
"pg-connection-string": "^2.3.0",
|
|
277
270
|
"pg-format": "^1.0.4",
|
|
271
|
+
"rate-limit-redis": "^4.2.0",
|
|
278
272
|
"raw-body": "^2.4.1",
|
|
279
273
|
"selfsigned": "^2.0.0",
|
|
280
274
|
"tar": "^6.1.12",
|
|
@@ -289,9 +283,9 @@
|
|
|
289
283
|
},
|
|
290
284
|
"devDependencies": {
|
|
291
285
|
"@aws-sdk/util-stream-node": "^3.350.0",
|
|
292
|
-
"@backstage/backend-plugin-api": "1.4.0
|
|
293
|
-
"@backstage/backend-test-utils": "1.6.0
|
|
294
|
-
"@backstage/cli": "0.
|
|
286
|
+
"@backstage/backend-plugin-api": "^1.4.0",
|
|
287
|
+
"@backstage/backend-test-utils": "^1.6.0",
|
|
288
|
+
"@backstage/cli": "^0.33.0",
|
|
295
289
|
"@google-cloud/cloud-sql-connector": "^1.4.0",
|
|
296
290
|
"@types/archiver": "^6.0.0",
|
|
297
291
|
"@types/base64-stream": "^1.0.2",
|
package/dist/actions.cjs.js
DELETED
package/dist/actions.cjs.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"actions.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;"}
|