@backstage/backend-defaults 0.11.0-next.2 → 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 +48 -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/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
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,53 @@
|
|
|
1
1
|
# @backstage/backend-defaults
|
|
2
2
|
|
|
3
|
+
## 0.11.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 3ccb7fc: Enhanced error handling in the auditor service factory to pass errors as objects. Aligned WinstonRootAuditorService with the default service factory's error handling.
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- 1220cf8: Added new rate limit middleware to allow rate limiting requests to the backend
|
|
12
|
+
|
|
13
|
+
If you are using the `configure` callback of the root HTTP router service and do NOT call `applyDefaults()` inside it, please see [the relevant changes](https://github.com/backstage/backstage/pull/28708/files#diff-86ad1b6a694dd250823aee39d410428dd837c9d9a04ca8c33bd1081fbe3f22af) that were made, to see if you want to apply them as well to your custom configuration.
|
|
14
|
+
Rate limiting can be turned on by adding the following configuration to `app-config.yaml`:
|
|
15
|
+
|
|
16
|
+
```yaml
|
|
17
|
+
backend:
|
|
18
|
+
rateLimit:
|
|
19
|
+
window: 6s
|
|
20
|
+
incomingRequestLimit: 100
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Plugin specific rate limiting can be configured by adding the following configuration to `app-config.yaml`:
|
|
24
|
+
|
|
25
|
+
```yaml
|
|
26
|
+
backend:
|
|
27
|
+
rateLimit:
|
|
28
|
+
global: false # This will disable the global rate limiting
|
|
29
|
+
plugin:
|
|
30
|
+
catalog:
|
|
31
|
+
window: 6s
|
|
32
|
+
incomingRequestLimit: 100
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
- c999c25: Added some default implementations for the experimental `ActionsService` and `ActionsRegistryService` under `/alpha` that allow registration of actions for a particular plugin.
|
|
36
|
+
- Updated dependencies
|
|
37
|
+
- @backstage/plugin-auth-node@0.6.4
|
|
38
|
+
- @backstage/backend-app-api@1.2.4
|
|
39
|
+
- @backstage/backend-plugin-api@1.4.0
|
|
40
|
+
- @backstage/backend-dev-utils@0.1.5
|
|
41
|
+
- @backstage/cli-node@0.2.13
|
|
42
|
+
- @backstage/config@1.3.2
|
|
43
|
+
- @backstage/config-loader@1.10.1
|
|
44
|
+
- @backstage/errors@1.2.7
|
|
45
|
+
- @backstage/integration@1.17.0
|
|
46
|
+
- @backstage/integration-aws-node@0.1.16
|
|
47
|
+
- @backstage/types@1.2.1
|
|
48
|
+
- @backstage/plugin-events-node@0.4.12
|
|
49
|
+
- @backstage/plugin-permission-node@0.10.1
|
|
50
|
+
|
|
3
51
|
## 0.11.0-next.2
|
|
4
52
|
|
|
5
53
|
### Minor Changes
|
package/config.d.ts
CHANGED
|
@@ -790,6 +790,92 @@ export interface Config {
|
|
|
790
790
|
headers?: { [name: string]: string };
|
|
791
791
|
};
|
|
792
792
|
|
|
793
|
+
/**
|
|
794
|
+
* Rate limiting options. Defining this as `true` will enable rate limiting with default values.
|
|
795
|
+
*/
|
|
796
|
+
rateLimit?:
|
|
797
|
+
| true
|
|
798
|
+
| {
|
|
799
|
+
store?:
|
|
800
|
+
| {
|
|
801
|
+
type: 'redis';
|
|
802
|
+
connection: string;
|
|
803
|
+
}
|
|
804
|
+
| {
|
|
805
|
+
type: 'memory';
|
|
806
|
+
};
|
|
807
|
+
/**
|
|
808
|
+
* Enable/disable global rate limiting. If this is disabled, plugin specific rate limiting must be
|
|
809
|
+
* used.
|
|
810
|
+
*/
|
|
811
|
+
global?: boolean;
|
|
812
|
+
/**
|
|
813
|
+
* Time frame in milliseconds or as human duration for which requests are checked/remembered.
|
|
814
|
+
* Defaults to one minute.
|
|
815
|
+
*/
|
|
816
|
+
window?: string | HumanDuration;
|
|
817
|
+
/**
|
|
818
|
+
* The maximum number of connections to allow during the `window` before rate limiting the client.
|
|
819
|
+
* Defaults to 5.
|
|
820
|
+
*/
|
|
821
|
+
incomingRequestLimit?: number;
|
|
822
|
+
/**
|
|
823
|
+
* Whether to pass requests in case of store failure.
|
|
824
|
+
* Defaults to false.
|
|
825
|
+
*/
|
|
826
|
+
passOnStoreError?: boolean;
|
|
827
|
+
/**
|
|
828
|
+
* List of allowed IP addresses that are not rate limited.
|
|
829
|
+
* Defaults to [127.0.0.1, 0:0:0:0:0:0:0:1, ::1].
|
|
830
|
+
*/
|
|
831
|
+
ipAllowList?: string[];
|
|
832
|
+
/**
|
|
833
|
+
* Skip rate limiting for requests that have been successful.
|
|
834
|
+
* Defaults to false.
|
|
835
|
+
*/
|
|
836
|
+
skipSuccessfulRequests?: boolean;
|
|
837
|
+
/**
|
|
838
|
+
* Skip rate limiting for requests that have failed.
|
|
839
|
+
* Defaults to false.
|
|
840
|
+
*/
|
|
841
|
+
skipFailedRequests?: boolean;
|
|
842
|
+
/** Plugin specific rate limiting configuration */
|
|
843
|
+
plugin?: {
|
|
844
|
+
[pluginId: string]: {
|
|
845
|
+
/**
|
|
846
|
+
* Time frame in milliseconds or as human duration for which requests are checked/remembered.
|
|
847
|
+
* Defaults to one minute.
|
|
848
|
+
*/
|
|
849
|
+
window?: string | HumanDuration;
|
|
850
|
+
/**
|
|
851
|
+
* The maximum number of connections to allow during the `window` before rate limiting the client.
|
|
852
|
+
* Defaults to 5.
|
|
853
|
+
*/
|
|
854
|
+
incomingRequestLimit?: number;
|
|
855
|
+
/**
|
|
856
|
+
* Whether to pass requests in case of store failure.
|
|
857
|
+
* Defaults to false.
|
|
858
|
+
*/
|
|
859
|
+
passOnStoreError?: boolean;
|
|
860
|
+
/**
|
|
861
|
+
* List of allowed IP addresses that are not rate limited.
|
|
862
|
+
* Defaults to [127.0.0.1, 0:0:0:0:0:0:0:1, ::1].
|
|
863
|
+
*/
|
|
864
|
+
ipAllowList?: string[];
|
|
865
|
+
/**
|
|
866
|
+
* Skip rate limiting for requests that have been successful.
|
|
867
|
+
* Defaults to false.
|
|
868
|
+
*/
|
|
869
|
+
skipSuccessfulRequests?: boolean;
|
|
870
|
+
/**
|
|
871
|
+
* Skip rate limiting for requests that have failed.
|
|
872
|
+
* Defaults to false.
|
|
873
|
+
*/
|
|
874
|
+
skipFailedRequests?: boolean;
|
|
875
|
+
};
|
|
876
|
+
};
|
|
877
|
+
};
|
|
878
|
+
|
|
793
879
|
/**
|
|
794
880
|
* Configuration related to URL reading, used for example for reading catalog info
|
|
795
881
|
* files, scaffolder templates, and techdocs content.
|
|
@@ -21,12 +21,9 @@ var scheduler = require('@backstage/backend-defaults/scheduler');
|
|
|
21
21
|
var urlReader = require('@backstage/backend-defaults/urlReader');
|
|
22
22
|
var userInfo = require('@backstage/backend-defaults/userInfo');
|
|
23
23
|
var pluginEventsNode = require('@backstage/plugin-events-node');
|
|
24
|
-
var
|
|
25
|
-
var actionsServiceFactory = require('./entrypoints/actions/actionsServiceFactory.cjs.js');
|
|
24
|
+
var alpha = require('@backstage/backend-defaults/alpha');
|
|
26
25
|
|
|
27
26
|
const defaultServiceFactories = [
|
|
28
|
-
actionsRegistryServiceFactory.actionsRegistryServiceFactory,
|
|
29
|
-
actionsServiceFactory.actionsServiceFactory,
|
|
30
27
|
auditor.auditorServiceFactory,
|
|
31
28
|
auth.authServiceFactory,
|
|
32
29
|
cache.cacheServiceFactory,
|
|
@@ -46,7 +43,10 @@ const defaultServiceFactories = [
|
|
|
46
43
|
scheduler.schedulerServiceFactory,
|
|
47
44
|
userInfo.userInfoServiceFactory,
|
|
48
45
|
urlReader.urlReaderServiceFactory,
|
|
49
|
-
pluginEventsNode.eventsServiceFactory
|
|
46
|
+
pluginEventsNode.eventsServiceFactory,
|
|
47
|
+
// alpha services
|
|
48
|
+
alpha.actionsRegistryServiceFactory,
|
|
49
|
+
alpha.actionsServiceFactory
|
|
50
50
|
];
|
|
51
51
|
function createBackend() {
|
|
52
52
|
return backendAppApi.createSpecializedBackend({ defaultServiceFactories });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CreateBackend.cjs.js","sources":["../src/CreateBackend.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 { Backend, createSpecializedBackend } from '@backstage/backend-app-api';\nimport { auditorServiceFactory } from '@backstage/backend-defaults/auditor';\nimport { authServiceFactory } from '@backstage/backend-defaults/auth';\nimport { cacheServiceFactory } from '@backstage/backend-defaults/cache';\nimport { databaseServiceFactory } from '@backstage/backend-defaults/database';\nimport { discoveryServiceFactory } from '@backstage/backend-defaults/discovery';\nimport { httpAuthServiceFactory } from '@backstage/backend-defaults/httpAuth';\nimport { httpRouterServiceFactory } from '@backstage/backend-defaults/httpRouter';\nimport { lifecycleServiceFactory } from '@backstage/backend-defaults/lifecycle';\nimport { loggerServiceFactory } from '@backstage/backend-defaults/logger';\nimport { permissionsServiceFactory } from '@backstage/backend-defaults/permissions';\nimport { permissionsRegistryServiceFactory } from '@backstage/backend-defaults/permissionsRegistry';\nimport { rootConfigServiceFactory } from '@backstage/backend-defaults/rootConfig';\nimport { rootHealthServiceFactory } from '@backstage/backend-defaults/rootHealth';\nimport { rootHttpRouterServiceFactory } from '@backstage/backend-defaults/rootHttpRouter';\nimport { rootLifecycleServiceFactory } from '@backstage/backend-defaults/rootLifecycle';\nimport { rootLoggerServiceFactory } from '@backstage/backend-defaults/rootLogger';\nimport { schedulerServiceFactory } from '@backstage/backend-defaults/scheduler';\nimport { urlReaderServiceFactory } from '@backstage/backend-defaults/urlReader';\nimport { userInfoServiceFactory } from '@backstage/backend-defaults/userInfo';\nimport { eventsServiceFactory } from '@backstage/plugin-events-node';\nimport {
|
|
1
|
+
{"version":3,"file":"CreateBackend.cjs.js","sources":["../src/CreateBackend.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 { Backend, createSpecializedBackend } from '@backstage/backend-app-api';\nimport { auditorServiceFactory } from '@backstage/backend-defaults/auditor';\nimport { authServiceFactory } from '@backstage/backend-defaults/auth';\nimport { cacheServiceFactory } from '@backstage/backend-defaults/cache';\nimport { databaseServiceFactory } from '@backstage/backend-defaults/database';\nimport { discoveryServiceFactory } from '@backstage/backend-defaults/discovery';\nimport { httpAuthServiceFactory } from '@backstage/backend-defaults/httpAuth';\nimport { httpRouterServiceFactory } from '@backstage/backend-defaults/httpRouter';\nimport { lifecycleServiceFactory } from '@backstage/backend-defaults/lifecycle';\nimport { loggerServiceFactory } from '@backstage/backend-defaults/logger';\nimport { permissionsServiceFactory } from '@backstage/backend-defaults/permissions';\nimport { permissionsRegistryServiceFactory } from '@backstage/backend-defaults/permissionsRegistry';\nimport { rootConfigServiceFactory } from '@backstage/backend-defaults/rootConfig';\nimport { rootHealthServiceFactory } from '@backstage/backend-defaults/rootHealth';\nimport { rootHttpRouterServiceFactory } from '@backstage/backend-defaults/rootHttpRouter';\nimport { rootLifecycleServiceFactory } from '@backstage/backend-defaults/rootLifecycle';\nimport { rootLoggerServiceFactory } from '@backstage/backend-defaults/rootLogger';\nimport { schedulerServiceFactory } from '@backstage/backend-defaults/scheduler';\nimport { urlReaderServiceFactory } from '@backstage/backend-defaults/urlReader';\nimport { userInfoServiceFactory } from '@backstage/backend-defaults/userInfo';\nimport { eventsServiceFactory } from '@backstage/plugin-events-node';\nimport {\n actionsRegistryServiceFactory,\n actionsServiceFactory,\n} from '@backstage/backend-defaults/alpha';\n\nexport const defaultServiceFactories = [\n auditorServiceFactory,\n authServiceFactory,\n cacheServiceFactory,\n rootConfigServiceFactory,\n databaseServiceFactory,\n discoveryServiceFactory,\n httpAuthServiceFactory,\n httpRouterServiceFactory,\n lifecycleServiceFactory,\n loggerServiceFactory,\n permissionsServiceFactory,\n permissionsRegistryServiceFactory,\n rootHealthServiceFactory,\n rootHttpRouterServiceFactory,\n rootLifecycleServiceFactory,\n rootLoggerServiceFactory,\n schedulerServiceFactory,\n userInfoServiceFactory,\n urlReaderServiceFactory,\n eventsServiceFactory,\n\n // alpha services\n actionsRegistryServiceFactory,\n actionsServiceFactory,\n];\n\n/**\n * @public\n */\nexport function createBackend(): Backend {\n return createSpecializedBackend({ defaultServiceFactories });\n}\n"],"names":["auditorServiceFactory","authServiceFactory","cacheServiceFactory","rootConfigServiceFactory","databaseServiceFactory","discoveryServiceFactory","httpAuthServiceFactory","httpRouterServiceFactory","lifecycleServiceFactory","loggerServiceFactory","permissionsServiceFactory","permissionsRegistryServiceFactory","rootHealthServiceFactory","rootHttpRouterServiceFactory","rootLifecycleServiceFactory","rootLoggerServiceFactory","schedulerServiceFactory","userInfoServiceFactory","urlReaderServiceFactory","eventsServiceFactory","actionsRegistryServiceFactory","actionsServiceFactory","createSpecializedBackend"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AA0CO,MAAM,uBAA0B,GAAA;AAAA,EACrCA,6BAAA;AAAA,EACAC,uBAAA;AAAA,EACAC,yBAAA;AAAA,EACAC,mCAAA;AAAA,EACAC,+BAAA;AAAA,EACAC,iCAAA;AAAA,EACAC,+BAAA;AAAA,EACAC,mCAAA;AAAA,EACAC,iCAAA;AAAA,EACAC,2BAAA;AAAA,EACAC,qCAAA;AAAA,EACAC,qDAAA;AAAA,EACAC,mCAAA;AAAA,EACAC,2CAAA;AAAA,EACAC,yCAAA;AAAA,EACAC,mCAAA;AAAA,EACAC,iCAAA;AAAA,EACAC,+BAAA;AAAA,EACAC,iCAAA;AAAA,EACAC,qCAAA;AAAA;AAAA,EAGAC,mCAAA;AAAA,EACAC;AACF;AAKO,SAAS,aAAyB,GAAA;AACvC,EAAO,OAAAC,sCAAA,CAAyB,EAAE,uBAAA,EAAyB,CAAA;AAC7D;;;;;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DefaultActionsService.cjs.js","sources":["../../../../src/alpha/entrypoints/actions/DefaultActionsService.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 {\n AuthService,\n BackstageCredentials,\n DiscoveryService,\n LoggerService,\n RootConfigService,\n} from '@backstage/backend-plugin-api';\nimport { ResponseError } from '@backstage/errors';\nimport { JsonObject } from '@backstage/types';\nimport {\n ActionsService,\n ActionsServiceAction,\n} from '@backstage/backend-plugin-api/alpha';\n\nexport class DefaultActionsService implements ActionsService {\n private constructor(\n private readonly discovery: DiscoveryService,\n private readonly config: RootConfigService,\n private readonly logger: LoggerService,\n private readonly auth: AuthService,\n ) {}\n\n static create({\n discovery,\n config,\n logger,\n auth,\n }: {\n discovery: DiscoveryService;\n config: RootConfigService;\n logger: LoggerService;\n auth: AuthService;\n }) {\n return new DefaultActionsService(discovery, config, logger, auth);\n }\n\n async list({ credentials }: { credentials: BackstageCredentials }) {\n const pluginSources =\n this.config.getOptionalStringArray('backend.actions.pluginSources') ?? [];\n\n const remoteActionsList = await Promise.all(\n pluginSources.map(async source => {\n try {\n const response = await this.makeRequest({\n path: `/.backstage/actions/v1/actions`,\n pluginId: source,\n credentials,\n });\n if (!response.ok) {\n throw await ResponseError.fromResponse(response);\n }\n const { actions } = (await response.json()) as {\n actions: ActionsServiceAction;\n };\n\n return actions;\n } catch (error) {\n this.logger.warn(`Failed to fetch actions from ${source}`, error);\n return [];\n }\n }),\n );\n\n return { actions: remoteActionsList.flat() };\n }\n\n async invoke(opts: {\n id: string;\n input?: JsonObject;\n credentials: BackstageCredentials;\n }) {\n const pluginId = this.pluginIdFromActionId(opts.id);\n const response = await this.makeRequest({\n path: `/.backstage/actions/v1/actions/${encodeURIComponent(\n opts.id,\n )}/invoke`,\n pluginId,\n credentials: opts.credentials,\n options: {\n method: 'POST',\n body: JSON.stringify(opts.input),\n headers: {\n 'Content-Type': 'application/json',\n },\n },\n });\n\n if (!response.ok) {\n throw await ResponseError.fromResponse(response);\n }\n\n const { output } = await response.json();\n return { output };\n }\n\n private async makeRequest(opts: {\n path: string;\n pluginId: string;\n options?: RequestInit;\n credentials: BackstageCredentials;\n }) {\n const { path, pluginId, credentials, options } = opts;\n const baseUrl = await this.discovery.getBaseUrl(pluginId);\n\n const { token } = await this.auth.getPluginRequestToken({\n onBehalfOf: credentials,\n targetPluginId: opts.pluginId,\n });\n\n return fetch(`${baseUrl}${path}`, {\n ...options,\n headers: {\n ...options?.headers,\n Authorization: `Bearer ${token}`,\n },\n });\n }\n\n private pluginIdFromActionId(id: string): string {\n const colonIndex = id.indexOf(':');\n if (colonIndex === -1) {\n throw new Error(`Invalid action id: ${id}`);\n }\n return id.substring(0, colonIndex);\n }\n}\n"],"names":["ResponseError"],"mappings":"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"}
|
|
@@ -2,9 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
var backendPluginApi = require('@backstage/backend-plugin-api');
|
|
4
4
|
var DefaultActionsService = require('./DefaultActionsService.cjs.js');
|
|
5
|
+
var alpha = require('@backstage/backend-plugin-api/alpha');
|
|
5
6
|
|
|
6
7
|
const actionsServiceFactory = backendPluginApi.createServiceFactory({
|
|
7
|
-
service:
|
|
8
|
+
service: alpha.actionsServiceRef,
|
|
8
9
|
deps: {
|
|
9
10
|
discovery: backendPluginApi.coreServices.discovery,
|
|
10
11
|
config: backendPluginApi.coreServices.rootConfig,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"actionsServiceFactory.cjs.js","sources":["../../../../src/alpha/entrypoints/actions/actionsServiceFactory.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 { createServiceFactory } from '@backstage/backend-plugin-api';\nimport { coreServices } from '@backstage/backend-plugin-api';\nimport { DefaultActionsService } from './DefaultActionsService';\nimport { actionsServiceRef } from '@backstage/backend-plugin-api/alpha';\n\n/**\n * @public\n */\nexport const actionsServiceFactory = createServiceFactory({\n service: actionsServiceRef,\n deps: {\n discovery: coreServices.discovery,\n config: coreServices.rootConfig,\n logger: coreServices.logger,\n auth: coreServices.auth,\n },\n factory: ({ discovery, config, logger, auth }) =>\n DefaultActionsService.create({\n discovery,\n config,\n logger,\n auth,\n }),\n});\n"],"names":["createServiceFactory","actionsServiceRef","coreServices","DefaultActionsService"],"mappings":";;;;;;AAuBO,MAAM,wBAAwBA,qCAAqB,CAAA;AAAA,EACxD,OAAS,EAAAC,uBAAA;AAAA,EACT,IAAM,EAAA;AAAA,IACJ,WAAWC,6BAAa,CAAA,SAAA;AAAA,IACxB,QAAQA,6BAAa,CAAA,UAAA;AAAA,IACrB,QAAQA,6BAAa,CAAA,MAAA;AAAA,IACrB,MAAMA,6BAAa,CAAA;AAAA,GACrB;AAAA,EACA,OAAA,EAAS,CAAC,EAAE,SAAA,EAAW,QAAQ,MAAQ,EAAA,IAAA,EACrC,KAAAC,2CAAA,CAAsB,MAAO,CAAA;AAAA,IAC3B,SAAA;AAAA,IACA,MAAA;AAAA,IACA,MAAA;AAAA,IACA;AAAA,GACD;AACL,CAAC;;;;"}
|
package/dist/{entrypoints → alpha/entrypoints}/actionsRegistry/DefaultActionsRegistryService.cjs.js
RENAMED
|
@@ -35,9 +35,16 @@ class DefaultActionsRegistryService {
|
|
|
35
35
|
actions: Array.from(this.actions.entries()).map(([id, action]) => ({
|
|
36
36
|
id,
|
|
37
37
|
...action,
|
|
38
|
+
attributes: {
|
|
39
|
+
// Inspired by the @modelcontextprotocol/sdk defaults for the hints.
|
|
40
|
+
// https://github.com/modelcontextprotocol/typescript-sdk/blob/dd69efa1de8646bb6b195ff8d5f52e13739f4550/src/types.ts#L777-L812
|
|
41
|
+
destructive: action.attributes?.destructive ?? true,
|
|
42
|
+
idempotent: action.attributes?.idempotent ?? false,
|
|
43
|
+
readOnly: action.attributes?.readOnly ?? false
|
|
44
|
+
},
|
|
38
45
|
schema: {
|
|
39
|
-
input: action.schema?.input ? zodToJsonSchema__default.default(action.schema.input(zod.z)) : zodToJsonSchema__default.default(zod.z.
|
|
40
|
-
output: action.schema?.output ? zodToJsonSchema__default.default(action.schema.output(zod.z)) : zodToJsonSchema__default.default(zod.z.
|
|
46
|
+
input: action.schema?.input ? zodToJsonSchema__default.default(action.schema.input(zod.z)) : zodToJsonSchema__default.default(zod.z.object({})),
|
|
47
|
+
output: action.schema?.output ? zodToJsonSchema__default.default(action.schema.output(zod.z)) : zodToJsonSchema__default.default(zod.z.object({}))
|
|
41
48
|
}
|
|
42
49
|
}))
|
|
43
50
|
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DefaultActionsRegistryService.cjs.js","sources":["../../../../src/alpha/entrypoints/actionsRegistry/DefaultActionsRegistryService.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 {\n AuthService,\n HttpAuthService,\n LoggerService,\n PluginMetadataService,\n} from '@backstage/backend-plugin-api';\nimport PromiseRouter from 'express-promise-router';\nimport { Router, json } from 'express';\nimport { z, AnyZodObject } from 'zod';\nimport zodToJsonSchema from 'zod-to-json-schema';\nimport {\n ActionsRegistryActionOptions,\n ActionsRegistryService,\n} from '@backstage/backend-plugin-api/alpha';\nimport {\n ForwardedError,\n InputError,\n NotAllowedError,\n NotFoundError,\n} from '@backstage/errors';\n\nexport class DefaultActionsRegistryService implements ActionsRegistryService {\n private actions: Map<string, ActionsRegistryActionOptions<any, any>> =\n new Map();\n\n private constructor(\n private readonly logger: LoggerService,\n private readonly httpAuth: HttpAuthService,\n private readonly auth: AuthService,\n private readonly metadata: PluginMetadataService,\n ) {}\n\n static create({\n httpAuth,\n logger,\n auth,\n metadata,\n }: {\n httpAuth: HttpAuthService;\n logger: LoggerService;\n auth: AuthService;\n metadata: PluginMetadataService;\n }): DefaultActionsRegistryService {\n return new DefaultActionsRegistryService(logger, httpAuth, auth, metadata);\n }\n\n createRouter(): Router {\n const router = PromiseRouter();\n router.use(json());\n\n router.get('/.backstage/actions/v1/actions', (_, res) => {\n return res.json({\n actions: Array.from(this.actions.entries()).map(([id, action]) => ({\n id,\n ...action,\n attributes: {\n // Inspired by the @modelcontextprotocol/sdk defaults for the hints.\n // https://github.com/modelcontextprotocol/typescript-sdk/blob/dd69efa1de8646bb6b195ff8d5f52e13739f4550/src/types.ts#L777-L812\n destructive: action.attributes?.destructive ?? true,\n idempotent: action.attributes?.idempotent ?? false,\n readOnly: action.attributes?.readOnly ?? false,\n },\n schema: {\n input: action.schema?.input\n ? zodToJsonSchema(action.schema.input(z))\n : zodToJsonSchema(z.object({})),\n output: action.schema?.output\n ? zodToJsonSchema(action.schema.output(z))\n : zodToJsonSchema(z.object({})),\n },\n })),\n });\n });\n\n router.post(\n '/.backstage/actions/v1/actions/:actionId/invoke',\n async (req, res) => {\n const credentials = await this.httpAuth.credentials(req);\n if (this.auth.isPrincipal(credentials, 'user')) {\n if (!credentials.principal.actor) {\n throw new NotAllowedError(\n `Actions must be invoked by a service, not a user`,\n );\n }\n } else if (this.auth.isPrincipal(credentials, 'none')) {\n throw new NotAllowedError(\n `Actions must be invoked by a service, not an anonymous request`,\n );\n }\n\n const action = this.actions.get(req.params.actionId);\n\n if (!action) {\n throw new NotFoundError(`Action \"${req.params.actionId}\" not found`);\n }\n\n const input = action.schema?.input\n ? action.schema.input(z).safeParse(req.body)\n : ({ success: true, data: undefined } as const);\n\n if (!input.success) {\n throw new InputError(\n `Invalid input to action \"${req.params.actionId}\"`,\n input.error,\n );\n }\n\n try {\n const result = await action.action({\n input: input.data,\n credentials,\n logger: this.logger,\n });\n\n const output = action.schema?.output\n ? action.schema.output(z).safeParse(result?.output)\n : ({ success: true, data: result?.output } as const);\n\n if (!output.success) {\n throw new InputError(\n `Invalid output from action \"${req.params.actionId}\"`,\n output.error,\n );\n }\n\n res.json({ output: output.data });\n } catch (error) {\n throw new ForwardedError(\n `Failed execution of action \"${req.params.actionId}\"`,\n error,\n );\n }\n },\n );\n return router;\n }\n\n register<\n TInputSchema extends AnyZodObject,\n TOutputSchema extends AnyZodObject,\n >(options: ActionsRegistryActionOptions<TInputSchema, TOutputSchema>): void {\n const id = `${this.metadata.getId()}:${options.name}`;\n\n if (this.actions.has(id)) {\n throw new Error(`Action with id \"${id}\" is already registered`);\n }\n\n this.actions.set(id, options);\n }\n}\n"],"names":["PromiseRouter","json","zodToJsonSchema","z","NotAllowedError","NotFoundError","InputError","ForwardedError"],"mappings":"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"}
|
package/dist/{entrypoints → alpha/entrypoints}/actionsRegistry/actionsRegistryServiceFactory.cjs.js
RENAMED
|
@@ -2,9 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
var backendPluginApi = require('@backstage/backend-plugin-api');
|
|
4
4
|
var DefaultActionsRegistryService = require('./DefaultActionsRegistryService.cjs.js');
|
|
5
|
+
var alpha = require('@backstage/backend-plugin-api/alpha');
|
|
5
6
|
|
|
6
7
|
const actionsRegistryServiceFactory = backendPluginApi.createServiceFactory({
|
|
7
|
-
service:
|
|
8
|
+
service: alpha.actionsRegistryServiceRef,
|
|
8
9
|
deps: {
|
|
9
10
|
metadata: backendPluginApi.coreServices.pluginMetadata,
|
|
10
11
|
httpRouter: backendPluginApi.coreServices.httpRouter,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"actionsRegistryServiceFactory.cjs.js","sources":["../../../../src/alpha/entrypoints/actionsRegistry/actionsRegistryServiceFactory.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 {\n coreServices,\n createServiceFactory,\n} from '@backstage/backend-plugin-api';\nimport { DefaultActionsRegistryService } from './DefaultActionsRegistryService';\nimport { actionsRegistryServiceRef } from '@backstage/backend-plugin-api/alpha';\n\n/**\n * @public\n */\nexport const actionsRegistryServiceFactory = createServiceFactory({\n service: actionsRegistryServiceRef,\n deps: {\n metadata: coreServices.pluginMetadata,\n httpRouter: coreServices.httpRouter,\n httpAuth: coreServices.httpAuth,\n logger: coreServices.logger,\n auth: coreServices.auth,\n },\n factory: ({ metadata, httpRouter, httpAuth, logger, auth }) => {\n const actionsRegistryService = DefaultActionsRegistryService.create({\n httpAuth,\n logger,\n auth,\n metadata,\n });\n\n httpRouter.use(actionsRegistryService.createRouter());\n\n return actionsRegistryService;\n },\n});\n"],"names":["createServiceFactory","actionsRegistryServiceRef","coreServices","DefaultActionsRegistryService"],"mappings":";;;;;;AA0BO,MAAM,gCAAgCA,qCAAqB,CAAA;AAAA,EAChE,OAAS,EAAAC,+BAAA;AAAA,EACT,IAAM,EAAA;AAAA,IACJ,UAAUC,6BAAa,CAAA,cAAA;AAAA,IACvB,YAAYA,6BAAa,CAAA,UAAA;AAAA,IACzB,UAAUA,6BAAa,CAAA,QAAA;AAAA,IACvB,QAAQA,6BAAa,CAAA,MAAA;AAAA,IACrB,MAAMA,6BAAa,CAAA;AAAA,GACrB;AAAA,EACA,OAAA,EAAS,CAAC,EAAE,QAAA,EAAU,YAAY,QAAU,EAAA,MAAA,EAAQ,MAAW,KAAA;AAC7D,IAAM,MAAA,sBAAA,GAAyBC,4DAA8B,MAAO,CAAA;AAAA,MAClE,QAAA;AAAA,MACA,MAAA;AAAA,MACA,IAAA;AAAA,MACA;AAAA,KACD,CAAA;AAED,IAAW,UAAA,CAAA,GAAA,CAAI,sBAAuB,CAAA,YAAA,EAAc,CAAA;AAEpD,IAAO,OAAA,sBAAA;AAAA;AAEX,CAAC;;;;"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var actionsRegistryServiceFactory = require('./alpha/entrypoints/actionsRegistry/actionsRegistryServiceFactory.cjs.js');
|
|
4
|
+
var actionsServiceFactory = require('./alpha/entrypoints/actions/actionsServiceFactory.cjs.js');
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
exports.actionsRegistryServiceFactory = actionsRegistryServiceFactory.actionsRegistryServiceFactory;
|
|
9
|
+
exports.actionsServiceFactory = actionsServiceFactory.actionsServiceFactory;
|
|
10
|
+
//# sourceMappingURL=alpha.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"alpha.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;"}
|
package/dist/alpha.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import * as _backstage_backend_plugin_api from '@backstage/backend-plugin-api';
|
|
2
|
+
import * as _backstage_backend_plugin_api_alpha from '@backstage/backend-plugin-api/alpha';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @public
|
|
6
|
+
*/
|
|
7
|
+
declare const actionsRegistryServiceFactory: _backstage_backend_plugin_api.ServiceFactory<_backstage_backend_plugin_api_alpha.ActionsRegistryService, "plugin", "singleton">;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @public
|
|
11
|
+
*/
|
|
12
|
+
declare const actionsServiceFactory: _backstage_backend_plugin_api.ServiceFactory<_backstage_backend_plugin_api_alpha.ActionsService, "plugin", "singleton">;
|
|
13
|
+
|
|
14
|
+
export { actionsRegistryServiceFactory, actionsServiceFactory };
|
|
@@ -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.11.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.11.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.33.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":";;;;;;"}
|
package/dist/actions.d.ts
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import * as _backstage_backend_plugin_api from '@backstage/backend-plugin-api';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* @public
|
|
5
|
-
*/
|
|
6
|
-
declare const actionsServiceFactory: _backstage_backend_plugin_api.ServiceFactory<_backstage_backend_plugin_api.ActionsService, "plugin", "singleton">;
|
|
7
|
-
|
|
8
|
-
export { actionsServiceFactory };
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var actionsRegistryServiceFactory = require('./entrypoints/actionsRegistry/actionsRegistryServiceFactory.cjs.js');
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
exports.actionsRegistryServiceFactory = actionsRegistryServiceFactory.actionsRegistryServiceFactory;
|
|
8
|
-
//# sourceMappingURL=actionsRegistry.cjs.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"actionsRegistry.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;"}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import * as _backstage_backend_plugin_api from '@backstage/backend-plugin-api';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* @public
|
|
5
|
-
*/
|
|
6
|
-
declare const actionsRegistryServiceFactory: _backstage_backend_plugin_api.ServiceFactory<_backstage_backend_plugin_api.ActionsRegistryService, "plugin", "singleton">;
|
|
7
|
-
|
|
8
|
-
export { actionsRegistryServiceFactory };
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"DefaultActionsService.cjs.js","sources":["../../../src/entrypoints/actions/DefaultActionsService.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 {\n ActionsService,\n ActionsServiceAction,\n AuthService,\n BackstageCredentials,\n DiscoveryService,\n LoggerService,\n RootConfigService,\n} from '@backstage/backend-plugin-api';\nimport { ResponseError } from '@backstage/errors';\nimport { JsonObject } from '@backstage/types';\n\nexport class DefaultActionsService implements ActionsService {\n private constructor(\n private readonly discovery: DiscoveryService,\n private readonly config: RootConfigService,\n private readonly logger: LoggerService,\n private readonly auth: AuthService,\n ) {}\n\n static create({\n discovery,\n config,\n logger,\n auth,\n }: {\n discovery: DiscoveryService;\n config: RootConfigService;\n logger: LoggerService;\n auth: AuthService;\n }) {\n return new DefaultActionsService(discovery, config, logger, auth);\n }\n\n async list({ credentials }: { credentials: BackstageCredentials }) {\n const pluginSources =\n this.config.getOptionalStringArray('backend.actions.pluginSources') ?? [];\n\n const remoteActionsList = await Promise.all(\n pluginSources.map(async source => {\n try {\n const response = await this.makeRequest({\n path: `/.backstage/actions/v1/actions`,\n pluginId: source,\n credentials,\n });\n if (!response.ok) {\n throw await ResponseError.fromResponse(response);\n }\n const { actions } = (await response.json()) as {\n actions: ActionsServiceAction;\n };\n\n return actions;\n } catch (error) {\n this.logger.warn(`Failed to fetch actions from ${source}`, error);\n return [];\n }\n }),\n );\n\n return { actions: remoteActionsList.flat() };\n }\n\n async invoke(opts: {\n id: string;\n input?: JsonObject;\n credentials: BackstageCredentials;\n }) {\n const pluginId = this.pluginIdFromActionId(opts.id);\n const response = await this.makeRequest({\n path: `/.backstage/actions/v1/actions/${encodeURIComponent(\n opts.id,\n )}/invoke`,\n pluginId,\n credentials: opts.credentials,\n options: {\n method: 'POST',\n body: JSON.stringify(opts.input),\n headers: {\n 'Content-Type': 'application/json',\n },\n },\n });\n\n if (!response.ok) {\n throw await ResponseError.fromResponse(response);\n }\n\n const { output } = await response.json();\n return { output };\n }\n\n private async makeRequest(opts: {\n path: string;\n pluginId: string;\n options?: RequestInit;\n credentials: BackstageCredentials;\n }) {\n const { path, pluginId, credentials, options } = opts;\n const baseUrl = await this.discovery.getBaseUrl(pluginId);\n\n const { token } = await this.auth.getPluginRequestToken({\n onBehalfOf: credentials,\n targetPluginId: opts.pluginId,\n });\n\n return fetch(`${baseUrl}${path}`, {\n ...options,\n headers: {\n ...options?.headers,\n Authorization: `Bearer ${token}`,\n },\n });\n }\n\n private pluginIdFromActionId(id: string): string {\n const colonIndex = id.indexOf(':');\n if (colonIndex === -1) {\n throw new Error(`Invalid action id: ${id}`);\n }\n return id.substring(0, colonIndex);\n }\n}\n"],"names":["ResponseError"],"mappings":";;;;AA2BO,MAAM,qBAAgD,CAAA;AAAA,EACnD,WACW,CAAA,SAAA,EACA,MACA,EAAA,MAAA,EACA,IACjB,EAAA;AAJiB,IAAA,IAAA,CAAA,SAAA,GAAA,SAAA;AACA,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA;AACA,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA;AACA,IAAA,IAAA,CAAA,IAAA,GAAA,IAAA;AAAA;AAChB,EAEH,OAAO,MAAO,CAAA;AAAA,IACZ,SAAA;AAAA,IACA,MAAA;AAAA,IACA,MAAA;AAAA,IACA;AAAA,GAMC,EAAA;AACD,IAAA,OAAO,IAAI,qBAAA,CAAsB,SAAW,EAAA,MAAA,EAAQ,QAAQ,IAAI,CAAA;AAAA;AAClE,EAEA,MAAM,IAAA,CAAK,EAAE,WAAA,EAAsD,EAAA;AACjE,IAAA,MAAM,gBACJ,IAAK,CAAA,MAAA,CAAO,sBAAuB,CAAA,+BAA+B,KAAK,EAAC;AAE1E,IAAM,MAAA,iBAAA,GAAoB,MAAM,OAAQ,CAAA,GAAA;AAAA,MACtC,aAAA,CAAc,GAAI,CAAA,OAAM,MAAU,KAAA;AAChC,QAAI,IAAA;AACF,UAAM,MAAA,QAAA,GAAW,MAAM,IAAA,CAAK,WAAY,CAAA;AAAA,YACtC,IAAM,EAAA,CAAA,8BAAA,CAAA;AAAA,YACN,QAAU,EAAA,MAAA;AAAA,YACV;AAAA,WACD,CAAA;AACD,UAAI,IAAA,CAAC,SAAS,EAAI,EAAA;AAChB,YAAM,MAAA,MAAMA,oBAAc,CAAA,YAAA,CAAa,QAAQ,CAAA;AAAA;AAEjD,UAAA,MAAM,EAAE,OAAA,EAAa,GAAA,MAAM,SAAS,IAAK,EAAA;AAIzC,UAAO,OAAA,OAAA;AAAA,iBACA,KAAO,EAAA;AACd,UAAA,IAAA,CAAK,MAAO,CAAA,IAAA,CAAK,CAAgC,6BAAA,EAAA,MAAM,IAAI,KAAK,CAAA;AAChE,UAAA,OAAO,EAAC;AAAA;AACV,OACD;AAAA,KACH;AAEA,IAAA,OAAO,EAAE,OAAA,EAAS,iBAAkB,CAAA,IAAA,EAAO,EAAA;AAAA;AAC7C,EAEA,MAAM,OAAO,IAIV,EAAA;AACD,IAAA,MAAM,QAAW,GAAA,IAAA,CAAK,oBAAqB,CAAA,IAAA,CAAK,EAAE,CAAA;AAClD,IAAM,MAAA,QAAA,GAAW,MAAM,IAAA,CAAK,WAAY,CAAA;AAAA,MACtC,MAAM,CAAkC,+BAAA,EAAA,kBAAA;AAAA,QACtC,IAAK,CAAA;AAAA,OACN,CAAA,OAAA,CAAA;AAAA,MACD,QAAA;AAAA,MACA,aAAa,IAAK,CAAA,WAAA;AAAA,MAClB,OAAS,EAAA;AAAA,QACP,MAAQ,EAAA,MAAA;AAAA,QACR,IAAM,EAAA,IAAA,CAAK,SAAU,CAAA,IAAA,CAAK,KAAK,CAAA;AAAA,QAC/B,OAAS,EAAA;AAAA,UACP,cAAgB,EAAA;AAAA;AAClB;AACF,KACD,CAAA;AAED,IAAI,IAAA,CAAC,SAAS,EAAI,EAAA;AAChB,MAAM,MAAA,MAAMA,oBAAc,CAAA,YAAA,CAAa,QAAQ,CAAA;AAAA;AAGjD,IAAA,MAAM,EAAE,MAAA,EAAW,GAAA,MAAM,SAAS,IAAK,EAAA;AACvC,IAAA,OAAO,EAAE,MAAO,EAAA;AAAA;AAClB,EAEA,MAAc,YAAY,IAKvB,EAAA;AACD,IAAA,MAAM,EAAE,IAAA,EAAM,QAAU,EAAA,WAAA,EAAa,SAAY,GAAA,IAAA;AACjD,IAAA,MAAM,OAAU,GAAA,MAAM,IAAK,CAAA,SAAA,CAAU,WAAW,QAAQ,CAAA;AAExD,IAAA,MAAM,EAAE,KAAM,EAAA,GAAI,MAAM,IAAA,CAAK,KAAK,qBAAsB,CAAA;AAAA,MACtD,UAAY,EAAA,WAAA;AAAA,MACZ,gBAAgB,IAAK,CAAA;AAAA,KACtB,CAAA;AAED,IAAA,OAAO,KAAM,CAAA,CAAA,EAAG,OAAO,CAAA,EAAG,IAAI,CAAI,CAAA,EAAA;AAAA,MAChC,GAAG,OAAA;AAAA,MACH,OAAS,EAAA;AAAA,QACP,GAAG,OAAS,EAAA,OAAA;AAAA,QACZ,aAAA,EAAe,UAAU,KAAK,CAAA;AAAA;AAChC,KACD,CAAA;AAAA;AACH,EAEQ,qBAAqB,EAAoB,EAAA;AAC/C,IAAM,MAAA,UAAA,GAAa,EAAG,CAAA,OAAA,CAAQ,GAAG,CAAA;AACjC,IAAA,IAAI,eAAe,CAAI,CAAA,EAAA;AACrB,MAAA,MAAM,IAAI,KAAA,CAAM,CAAsB,mBAAA,EAAA,EAAE,CAAE,CAAA,CAAA;AAAA;AAE5C,IAAO,OAAA,EAAA,CAAG,SAAU,CAAA,CAAA,EAAG,UAAU,CAAA;AAAA;AAErC;;;;"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"actionsServiceFactory.cjs.js","sources":["../../../src/entrypoints/actions/actionsServiceFactory.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 { createServiceFactory } from '@backstage/backend-plugin-api';\nimport { coreServices } from '@backstage/backend-plugin-api';\nimport { DefaultActionsService } from './DefaultActionsService';\n\n/**\n * @public\n */\nexport const actionsServiceFactory = createServiceFactory({\n service: coreServices.actions,\n deps: {\n discovery: coreServices.discovery,\n config: coreServices.rootConfig,\n logger: coreServices.logger,\n auth: coreServices.auth,\n },\n factory: ({ discovery, config, logger, auth }) =>\n DefaultActionsService.create({\n discovery,\n config,\n logger,\n auth,\n }),\n});\n"],"names":["createServiceFactory","coreServices","DefaultActionsService"],"mappings":";;;;;AAsBO,MAAM,wBAAwBA,qCAAqB,CAAA;AAAA,EACxD,SAASC,6BAAa,CAAA,OAAA;AAAA,EACtB,IAAM,EAAA;AAAA,IACJ,WAAWA,6BAAa,CAAA,SAAA;AAAA,IACxB,QAAQA,6BAAa,CAAA,UAAA;AAAA,IACrB,QAAQA,6BAAa,CAAA,MAAA;AAAA,IACrB,MAAMA,6BAAa,CAAA;AAAA,GACrB;AAAA,EACA,OAAA,EAAS,CAAC,EAAE,SAAA,EAAW,QAAQ,MAAQ,EAAA,IAAA,EACrC,KAAAC,2CAAA,CAAsB,MAAO,CAAA;AAAA,IAC3B,SAAA;AAAA,IACA,MAAA;AAAA,IACA,MAAA;AAAA,IACA;AAAA,GACD;AACL,CAAC;;;;"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"DefaultActionsRegistryService.cjs.js","sources":["../../../src/entrypoints/actionsRegistry/DefaultActionsRegistryService.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 {\n ActionsRegistryActionOptions,\n ActionsRegistryService,\n AuthService,\n HttpAuthService,\n LoggerService,\n PluginMetadataService,\n} from '@backstage/backend-plugin-api';\nimport PromiseRouter from 'express-promise-router';\nimport { Router, json } from 'express';\nimport { z, ZodType } from 'zod';\nimport zodToJsonSchema from 'zod-to-json-schema';\nimport {\n ForwardedError,\n InputError,\n NotAllowedError,\n NotFoundError,\n} from '@backstage/errors';\n\nexport class DefaultActionsRegistryService implements ActionsRegistryService {\n private actions: Map<string, ActionsRegistryActionOptions<any, any>> =\n new Map();\n\n private constructor(\n private readonly logger: LoggerService,\n private readonly httpAuth: HttpAuthService,\n private readonly auth: AuthService,\n private readonly metadata: PluginMetadataService,\n ) {}\n\n static create({\n httpAuth,\n logger,\n auth,\n metadata,\n }: {\n httpAuth: HttpAuthService;\n logger: LoggerService;\n auth: AuthService;\n metadata: PluginMetadataService;\n }): DefaultActionsRegistryService {\n return new DefaultActionsRegistryService(logger, httpAuth, auth, metadata);\n }\n\n createRouter(): Router {\n const router = PromiseRouter();\n router.use(json());\n\n router.get('/.backstage/actions/v1/actions', (_, res) => {\n return res.json({\n actions: Array.from(this.actions.entries()).map(([id, action]) => ({\n id,\n ...action,\n schema: {\n input: action.schema?.input\n ? zodToJsonSchema(action.schema.input(z))\n : zodToJsonSchema(z.any()),\n output: action.schema?.output\n ? zodToJsonSchema(action.schema.output(z))\n : zodToJsonSchema(z.any()),\n },\n })),\n });\n });\n\n router.post(\n '/.backstage/actions/v1/actions/:actionId/invoke',\n async (req, res) => {\n const credentials = await this.httpAuth.credentials(req);\n if (this.auth.isPrincipal(credentials, 'user')) {\n if (!credentials.principal.actor) {\n throw new NotAllowedError(\n `Actions must be invoked by a service, not a user`,\n );\n }\n } else if (this.auth.isPrincipal(credentials, 'none')) {\n throw new NotAllowedError(\n `Actions must be invoked by a service, not an anonymous request`,\n );\n }\n\n const action = this.actions.get(req.params.actionId);\n\n if (!action) {\n throw new NotFoundError(`Action \"${req.params.actionId}\" not found`);\n }\n\n const input = action.schema?.input\n ? action.schema.input(z).safeParse(req.body)\n : ({ success: true, data: undefined } as const);\n\n if (!input.success) {\n throw new InputError(\n `Invalid input to action \"${req.params.actionId}\"`,\n input.error,\n );\n }\n\n try {\n const result = await action.action({\n input: input.data,\n credentials,\n logger: this.logger,\n });\n\n const output = action.schema?.output\n ? action.schema.output(z).safeParse(result?.output)\n : ({ success: true, data: result?.output } as const);\n\n if (!output.success) {\n throw new InputError(\n `Invalid output from action \"${req.params.actionId}\"`,\n output.error,\n );\n }\n\n res.json({ output: output.data });\n } catch (error) {\n throw new ForwardedError(\n `Failed execution of action \"${req.params.actionId}\"`,\n error,\n );\n }\n },\n );\n return router;\n }\n\n register<TInputSchema extends ZodType, TOutputSchema extends ZodType>(\n options: ActionsRegistryActionOptions<TInputSchema, TOutputSchema>,\n ): void {\n const id = `${this.metadata.getId()}:${options.name}`;\n\n if (this.actions.has(id)) {\n throw new Error(`Action with id \"${id}\" is already registered`);\n }\n\n this.actions.set(id, options);\n }\n}\n"],"names":["PromiseRouter","json","zodToJsonSchema","z","NotAllowedError","NotFoundError","InputError","ForwardedError"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"actionsRegistryServiceFactory.cjs.js","sources":["../../../src/entrypoints/actionsRegistry/actionsRegistryServiceFactory.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 {\n coreServices,\n createServiceFactory,\n} from '@backstage/backend-plugin-api';\nimport { DefaultActionsRegistryService } from './DefaultActionsRegistryService';\n\n/**\n * @public\n */\nexport const actionsRegistryServiceFactory = createServiceFactory({\n service: coreServices.actionsRegistry,\n deps: {\n metadata: coreServices.pluginMetadata,\n httpRouter: coreServices.httpRouter,\n httpAuth: coreServices.httpAuth,\n logger: coreServices.logger,\n auth: coreServices.auth,\n },\n factory: ({ metadata, httpRouter, httpAuth, logger, auth }) => {\n const actionsRegistryService = DefaultActionsRegistryService.create({\n httpAuth,\n logger,\n auth,\n metadata,\n });\n\n httpRouter.use(actionsRegistryService.createRouter());\n\n return actionsRegistryService;\n },\n});\n"],"names":["createServiceFactory","coreServices","DefaultActionsRegistryService"],"mappings":";;;;;AAyBO,MAAM,gCAAgCA,qCAAqB,CAAA;AAAA,EAChE,SAASC,6BAAa,CAAA,eAAA;AAAA,EACtB,IAAM,EAAA;AAAA,IACJ,UAAUA,6BAAa,CAAA,cAAA;AAAA,IACvB,YAAYA,6BAAa,CAAA,UAAA;AAAA,IACzB,UAAUA,6BAAa,CAAA,QAAA;AAAA,IACvB,QAAQA,6BAAa,CAAA,MAAA;AAAA,IACrB,MAAMA,6BAAa,CAAA;AAAA,GACrB;AAAA,EACA,OAAA,EAAS,CAAC,EAAE,QAAA,EAAU,YAAY,QAAU,EAAA,MAAA,EAAQ,MAAW,KAAA;AAC7D,IAAM,MAAA,sBAAA,GAAyBC,4DAA8B,MAAO,CAAA;AAAA,MAClE,QAAA;AAAA,MACA,MAAA;AAAA,MACA,IAAA;AAAA,MACA;AAAA,KACD,CAAA;AAED,IAAW,UAAA,CAAA,GAAA,CAAI,sBAAuB,CAAA,YAAA,EAAc,CAAA;AAEpD,IAAO,OAAA,sBAAA;AAAA;AAEX,CAAC;;;;"}
|
|
File without changes
|