@backstage/core-app-api 1.19.1-next.0 → 1.19.2-next.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 CHANGED
@@ -1,5 +1,24 @@
1
1
  # @backstage/core-app-api
2
2
 
3
+ ## 1.19.2-next.0
4
+
5
+ ### Patch Changes
6
+
7
+ - 05f60e1: Refactored constructor parameter properties to explicit property declarations for compatibility with TypeScript's `erasableSyntaxOnly` setting. This internal refactoring maintains all existing functionality while ensuring TypeScript compilation compatibility.
8
+ - Updated dependencies
9
+ - @backstage/core-plugin-api@1.11.2-next.0
10
+ - @backstage/config@1.3.6-next.0
11
+ - @backstage/types@1.2.2
12
+ - @backstage/version-bridge@1.0.11
13
+
14
+ ## 1.19.1
15
+
16
+ ### Patch Changes
17
+
18
+ - Updated dependencies
19
+ - @backstage/config@1.3.5
20
+ - @backstage/core-plugin-api@1.11.1
21
+
3
22
  ## 1.19.1-next.0
4
23
 
5
24
  ### Patch Changes
@@ -1,10 +1,6 @@
1
1
  import { UrlPatternDiscovery } from './UrlPatternDiscovery.esm.js';
2
2
 
3
3
  class FrontendHostDiscovery {
4
- constructor(endpoints, defaultEndpoint) {
5
- this.endpoints = endpoints;
6
- this.defaultEndpoint = defaultEndpoint;
7
- }
8
4
  /**
9
5
  * Creates a new FrontendHostDiscovery discovery instance by reading
10
6
  * the external target URL from the `discovery.endpoints` config section.
@@ -42,6 +38,12 @@ class FrontendHostDiscovery {
42
38
  UrlPatternDiscovery.compile(`${baseUrl}${path}`)
43
39
  );
44
40
  }
41
+ endpoints;
42
+ defaultEndpoint;
43
+ constructor(endpoints, defaultEndpoint) {
44
+ this.endpoints = endpoints;
45
+ this.defaultEndpoint = defaultEndpoint;
46
+ }
45
47
  async getBaseUrl(pluginId) {
46
48
  const endpoint = this.endpoints.get(pluginId);
47
49
  if (endpoint) {
@@ -1 +1 @@
1
- {"version":3,"file":"FrontendHostDiscovery.esm.js","sources":["../../../../src/apis/implementations/DiscoveryApi/FrontendHostDiscovery.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 */\nimport { Config } from '@backstage/config';\nimport { DiscoveryApi } from '@backstage/core-plugin-api';\nimport { UrlPatternDiscovery } from './UrlPatternDiscovery';\n\n/**\n * FrontendHostDiscovery is a config driven DiscoveryApi implementation.\n * It uses the app-config to determine the url for a plugin.\n *\n * @public\n */\nexport class FrontendHostDiscovery implements DiscoveryApi {\n /**\n * Creates a new FrontendHostDiscovery discovery instance by reading\n * the external target URL from the `discovery.endpoints` config section.\n *\n * eg.\n * ```yaml\n * discovery:\n * endpoints:\n * - target: https://internal.example.com/internal-catalog\n * plugins: [catalog]\n * - target: https://internal.example.com/secure/api/{{pluginId}}\n * plugins: [auth, permissions]\n * - target:\n * internal: https://internal.example.com/search\n * external: https://example.com/search\n * plugins: [search]\n * ```\n *\n * If a plugin is not declared in the config, the discovery will fall back to using the baseUrl with\n * the provided `pathPattern` appended. The default path pattern is `\"/api/{{ pluginId }}\"`.\n */\n static fromConfig(config: Config, options?: { pathPattern?: string }) {\n const path = options?.pathPattern ?? '/api/{{ pluginId }}';\n const baseUrl = config.getString('backend.baseUrl');\n\n const endpoints = config\n .getOptionalConfigArray('discovery.endpoints')\n ?.flatMap(e => {\n const target =\n typeof e.get('target') === 'object'\n ? e.getOptionalString('target.external')\n : e.getString('target');\n if (!target) {\n return [];\n }\n const discovery = UrlPatternDiscovery.compile(target);\n return e\n .getStringArray('plugins')\n .map(pluginId => [pluginId, discovery] as const);\n });\n\n return new FrontendHostDiscovery(\n new Map(endpoints),\n UrlPatternDiscovery.compile(`${baseUrl}${path}`),\n );\n }\n\n private constructor(\n private readonly endpoints: Map<string, DiscoveryApi>,\n private readonly defaultEndpoint: DiscoveryApi,\n ) {}\n\n async getBaseUrl(pluginId: string): Promise<string> {\n const endpoint = this.endpoints.get(pluginId);\n if (endpoint) {\n return endpoint.getBaseUrl(pluginId);\n }\n return this.defaultEndpoint.getBaseUrl(pluginId);\n }\n}\n"],"names":[],"mappings":";;AAyBO,MAAM,qBAAA,CAA8C;AAAA,EAgDjD,WAAA,CACW,WACA,eAAA,EACjB;AAFiB,IAAA,IAAA,CAAA,SAAA,GAAA,SAAA;AACA,IAAA,IAAA,CAAA,eAAA,GAAA,eAAA;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA7BH,OAAO,UAAA,CAAW,MAAA,EAAgB,OAAA,EAAoC;AACpE,IAAA,MAAM,IAAA,GAAO,SAAS,WAAA,IAAe,qBAAA;AACrC,IAAA,MAAM,OAAA,GAAU,MAAA,CAAO,SAAA,CAAU,iBAAiB,CAAA;AAElD,IAAA,MAAM,YAAY,MAAA,CACf,sBAAA,CAAuB,qBAAqB,CAAA,EAC3C,QAAQ,CAAA,CAAA,KAAK;AACb,MAAA,MAAM,MAAA,GACJ,OAAO,CAAA,CAAE,GAAA,CAAI,QAAQ,CAAA,KAAM,QAAA,GACvB,CAAA,CAAE,iBAAA,CAAkB,iBAAiB,CAAA,GACrC,CAAA,CAAE,UAAU,QAAQ,CAAA;AAC1B,MAAA,IAAI,CAAC,MAAA,EAAQ;AACX,QAAA,OAAO,EAAC;AAAA,MACV;AACA,MAAA,MAAM,SAAA,GAAY,mBAAA,CAAoB,OAAA,CAAQ,MAAM,CAAA;AACpD,MAAA,OAAO,CAAA,CACJ,eAAe,SAAS,CAAA,CACxB,IAAI,CAAA,QAAA,KAAY,CAAC,QAAA,EAAU,SAAS,CAAU,CAAA;AAAA,IACnD,CAAC,CAAA;AAEH,IAAA,OAAO,IAAI,qBAAA;AAAA,MACT,IAAI,IAAI,SAAS,CAAA;AAAA,MACjB,oBAAoB,OAAA,CAAQ,CAAA,EAAG,OAAO,CAAA,EAAG,IAAI,CAAA,CAAE;AAAA,KACjD;AAAA,EACF;AAAA,EAOA,MAAM,WAAW,QAAA,EAAmC;AAClD,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,SAAA,CAAU,GAAA,CAAI,QAAQ,CAAA;AAC5C,IAAA,IAAI,QAAA,EAAU;AACZ,MAAA,OAAO,QAAA,CAAS,WAAW,QAAQ,CAAA;AAAA,IACrC;AACA,IAAA,OAAO,IAAA,CAAK,eAAA,CAAgB,UAAA,CAAW,QAAQ,CAAA;AAAA,EACjD;AACF;;;;"}
1
+ {"version":3,"file":"FrontendHostDiscovery.esm.js","sources":["../../../../src/apis/implementations/DiscoveryApi/FrontendHostDiscovery.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 */\nimport { Config } from '@backstage/config';\nimport { DiscoveryApi } from '@backstage/core-plugin-api';\nimport { UrlPatternDiscovery } from './UrlPatternDiscovery';\n\n/**\n * FrontendHostDiscovery is a config driven DiscoveryApi implementation.\n * It uses the app-config to determine the url for a plugin.\n *\n * @public\n */\nexport class FrontendHostDiscovery implements DiscoveryApi {\n /**\n * Creates a new FrontendHostDiscovery discovery instance by reading\n * the external target URL from the `discovery.endpoints` config section.\n *\n * eg.\n * ```yaml\n * discovery:\n * endpoints:\n * - target: https://internal.example.com/internal-catalog\n * plugins: [catalog]\n * - target: https://internal.example.com/secure/api/{{pluginId}}\n * plugins: [auth, permissions]\n * - target:\n * internal: https://internal.example.com/search\n * external: https://example.com/search\n * plugins: [search]\n * ```\n *\n * If a plugin is not declared in the config, the discovery will fall back to using the baseUrl with\n * the provided `pathPattern` appended. The default path pattern is `\"/api/{{ pluginId }}\"`.\n */\n static fromConfig(config: Config, options?: { pathPattern?: string }) {\n const path = options?.pathPattern ?? '/api/{{ pluginId }}';\n const baseUrl = config.getString('backend.baseUrl');\n\n const endpoints = config\n .getOptionalConfigArray('discovery.endpoints')\n ?.flatMap(e => {\n const target =\n typeof e.get('target') === 'object'\n ? e.getOptionalString('target.external')\n : e.getString('target');\n if (!target) {\n return [];\n }\n const discovery = UrlPatternDiscovery.compile(target);\n return e\n .getStringArray('plugins')\n .map(pluginId => [pluginId, discovery] as const);\n });\n\n return new FrontendHostDiscovery(\n new Map(endpoints),\n UrlPatternDiscovery.compile(`${baseUrl}${path}`),\n );\n }\n\n private readonly endpoints: Map<string, DiscoveryApi>;\n private readonly defaultEndpoint: DiscoveryApi;\n\n private constructor(\n endpoints: Map<string, DiscoveryApi>,\n defaultEndpoint: DiscoveryApi,\n ) {\n this.endpoints = endpoints;\n this.defaultEndpoint = defaultEndpoint;\n }\n\n async getBaseUrl(pluginId: string): Promise<string> {\n const endpoint = this.endpoints.get(pluginId);\n if (endpoint) {\n return endpoint.getBaseUrl(pluginId);\n }\n return this.defaultEndpoint.getBaseUrl(pluginId);\n }\n}\n"],"names":[],"mappings":";;AAyBO,MAAM,qBAAA,CAA8C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAsBzD,OAAO,UAAA,CAAW,MAAA,EAAgB,OAAA,EAAoC;AACpE,IAAA,MAAM,IAAA,GAAO,SAAS,WAAA,IAAe,qBAAA;AACrC,IAAA,MAAM,OAAA,GAAU,MAAA,CAAO,SAAA,CAAU,iBAAiB,CAAA;AAElD,IAAA,MAAM,YAAY,MAAA,CACf,sBAAA,CAAuB,qBAAqB,CAAA,EAC3C,QAAQ,CAAA,CAAA,KAAK;AACb,MAAA,MAAM,MAAA,GACJ,OAAO,CAAA,CAAE,GAAA,CAAI,QAAQ,CAAA,KAAM,QAAA,GACvB,CAAA,CAAE,iBAAA,CAAkB,iBAAiB,CAAA,GACrC,CAAA,CAAE,UAAU,QAAQ,CAAA;AAC1B,MAAA,IAAI,CAAC,MAAA,EAAQ;AACX,QAAA,OAAO,EAAC;AAAA,MACV;AACA,MAAA,MAAM,SAAA,GAAY,mBAAA,CAAoB,OAAA,CAAQ,MAAM,CAAA;AACpD,MAAA,OAAO,CAAA,CACJ,eAAe,SAAS,CAAA,CACxB,IAAI,CAAA,QAAA,KAAY,CAAC,QAAA,EAAU,SAAS,CAAU,CAAA;AAAA,IACnD,CAAC,CAAA;AAEH,IAAA,OAAO,IAAI,qBAAA;AAAA,MACT,IAAI,IAAI,SAAS,CAAA;AAAA,MACjB,oBAAoB,OAAA,CAAQ,CAAA,EAAG,OAAO,CAAA,EAAG,IAAI,CAAA,CAAE;AAAA,KACjD;AAAA,EACF;AAAA,EAEiB,SAAA;AAAA,EACA,eAAA;AAAA,EAET,WAAA,CACN,WACA,eAAA,EACA;AACA,IAAA,IAAA,CAAK,SAAA,GAAY,SAAA;AACjB,IAAA,IAAA,CAAK,eAAA,GAAkB,eAAA;AAAA,EACzB;AAAA,EAEA,MAAM,WAAW,QAAA,EAAmC;AAClD,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,SAAA,CAAU,GAAA,CAAI,QAAQ,CAAA;AAC5C,IAAA,IAAI,QAAA,EAAU;AACZ,MAAA,OAAO,QAAA,CAAS,WAAW,QAAQ,CAAA;AAAA,IACrC;AACA,IAAA,OAAO,IAAA,CAAK,eAAA,CAAgB,UAAA,CAAW,QAAQ,CAAA;AAAA,EACjD;AACF;;;;"}
@@ -1,4 +1,6 @@
1
1
  class ErrorAlerter {
2
+ alertApi;
3
+ errorApi;
2
4
  constructor(alertApi, errorApi) {
3
5
  this.alertApi = alertApi;
4
6
  this.errorApi = errorApi;
@@ -1 +1 @@
1
- {"version":3,"file":"ErrorAlerter.esm.js","sources":["../../../../src/apis/implementations/ErrorApi/ErrorAlerter.ts"],"sourcesContent":["/*\n * Copyright 2020 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 ErrorApi,\n ErrorApiError,\n ErrorApiErrorContext,\n AlertApi,\n} from '@backstage/core-plugin-api';\n\n/**\n * Decorates an ErrorApi by also forwarding error messages\n * to the alertApi with an 'error' severity.\n *\n * @public\n */\nexport class ErrorAlerter implements ErrorApi {\n constructor(\n private readonly alertApi: AlertApi,\n private readonly errorApi: ErrorApi,\n ) {}\n\n post(error: ErrorApiError, context?: ErrorApiErrorContext) {\n if (!context?.hidden) {\n this.alertApi.post({ message: error.message, severity: 'error' });\n }\n\n return this.errorApi.post(error, context);\n }\n\n error$() {\n return this.errorApi.error$();\n }\n}\n"],"names":[],"mappings":"AA4BO,MAAM,YAAA,CAAiC;AAAA,EAC5C,WAAA,CACmB,UACA,QAAA,EACjB;AAFiB,IAAA,IAAA,CAAA,QAAA,GAAA,QAAA;AACA,IAAA,IAAA,CAAA,QAAA,GAAA,QAAA;AAAA,EAChB;AAAA,EAEH,IAAA,CAAK,OAAsB,OAAA,EAAgC;AACzD,IAAA,IAAI,CAAC,SAAS,MAAA,EAAQ;AACpB,MAAA,IAAA,CAAK,QAAA,CAAS,KAAK,EAAE,OAAA,EAAS,MAAM,OAAA,EAAS,QAAA,EAAU,SAAS,CAAA;AAAA,IAClE;AAEA,IAAA,OAAO,IAAA,CAAK,QAAA,CAAS,IAAA,CAAK,KAAA,EAAO,OAAO,CAAA;AAAA,EAC1C;AAAA,EAEA,MAAA,GAAS;AACP,IAAA,OAAO,IAAA,CAAK,SAAS,MAAA,EAAO;AAAA,EAC9B;AACF;;;;"}
1
+ {"version":3,"file":"ErrorAlerter.esm.js","sources":["../../../../src/apis/implementations/ErrorApi/ErrorAlerter.ts"],"sourcesContent":["/*\n * Copyright 2020 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 ErrorApi,\n ErrorApiError,\n ErrorApiErrorContext,\n AlertApi,\n} from '@backstage/core-plugin-api';\n\n/**\n * Decorates an ErrorApi by also forwarding error messages\n * to the alertApi with an 'error' severity.\n *\n * @public\n */\nexport class ErrorAlerter implements ErrorApi {\n private readonly alertApi: AlertApi;\n private readonly errorApi: ErrorApi;\n\n constructor(alertApi: AlertApi, errorApi: ErrorApi) {\n this.alertApi = alertApi;\n this.errorApi = errorApi;\n }\n\n post(error: ErrorApiError, context?: ErrorApiErrorContext) {\n if (!context?.hidden) {\n this.alertApi.post({ message: error.message, severity: 'error' });\n }\n\n return this.errorApi.post(error, context);\n }\n\n error$() {\n return this.errorApi.error$();\n }\n}\n"],"names":[],"mappings":"AA4BO,MAAM,YAAA,CAAiC;AAAA,EAC3B,QAAA;AAAA,EACA,QAAA;AAAA,EAEjB,WAAA,CAAY,UAAoB,QAAA,EAAoB;AAClD,IAAA,IAAA,CAAK,QAAA,GAAW,QAAA;AAChB,IAAA,IAAA,CAAK,QAAA,GAAW,QAAA;AAAA,EAClB;AAAA,EAEA,IAAA,CAAK,OAAsB,OAAA,EAAgC;AACzD,IAAA,IAAI,CAAC,SAAS,MAAA,EAAQ;AACpB,MAAA,IAAA,CAAK,QAAA,CAAS,KAAK,EAAE,OAAA,EAAS,MAAM,OAAA,EAAS,QAAA,EAAU,SAAS,CAAA;AAAA,IAClE;AAEA,IAAA,OAAO,IAAA,CAAK,QAAA,CAAS,IAAA,CAAK,KAAA,EAAO,OAAO,CAAA;AAAA,EAC1C;AAAA,EAEA,MAAA,GAAS;AACP,IAAA,OAAO,IAAA,CAAK,SAAS,MAAA,EAAO;AAAA,EAC9B;AACF;;;;"}
@@ -1,10 +1,4 @@
1
1
  class IdentityAuthInjectorFetchMiddleware {
2
- constructor(identityApi, allowUrl, headerName, headerValue) {
3
- this.identityApi = identityApi;
4
- this.allowUrl = allowUrl;
5
- this.headerName = headerName;
6
- this.headerValue = headerValue;
7
- }
8
2
  static create(options) {
9
3
  const matcher = buildMatcher(options);
10
4
  const headerName = options.header?.name || "authorization";
@@ -30,6 +24,16 @@ class IdentityAuthInjectorFetchMiddleware {
30
24
  );
31
25
  });
32
26
  }
27
+ identityApi;
28
+ allowUrl;
29
+ headerName;
30
+ headerValue;
31
+ constructor(identityApi, allowUrl, headerName, headerValue) {
32
+ this.identityApi = identityApi;
33
+ this.allowUrl = allowUrl;
34
+ this.headerName = headerName;
35
+ this.headerValue = headerValue;
36
+ }
33
37
  apply(next) {
34
38
  return async (input, init) => {
35
39
  const request = new Request(input, init);
@@ -1 +1 @@
1
- {"version":3,"file":"IdentityAuthInjectorFetchMiddleware.esm.js","sources":["../../../../src/apis/implementations/FetchApi/IdentityAuthInjectorFetchMiddleware.ts"],"sourcesContent":["/*\n * Copyright 2021 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 { Config } from '@backstage/config';\nimport { IdentityApi } from '@backstage/core-plugin-api';\nimport { FetchMiddleware } from './types';\n\n/**\n * A fetch middleware, which injects a Backstage token header when the user is\n * signed in.\n */\nexport class IdentityAuthInjectorFetchMiddleware implements FetchMiddleware {\n static create(options: {\n identityApi: IdentityApi;\n config?: Config;\n urlPrefixAllowlist?: string[];\n allowUrl?: (url: string) => boolean;\n header?: {\n name: string;\n value: (backstageToken: string) => string;\n };\n }): IdentityAuthInjectorFetchMiddleware {\n const matcher = buildMatcher(options);\n const headerName = options.header?.name || 'authorization';\n const headerValue = options.header?.value || (token => `Bearer ${token}`);\n\n return new IdentityAuthInjectorFetchMiddleware(\n options.identityApi,\n matcher,\n headerName,\n headerValue,\n );\n }\n\n /**\n * Returns an array of plugin URL prefixes derived from the static `discovery`\n * configuration, to be used as `urlPrefixAllowlist` option of {@link create}.\n */\n static getDiscoveryUrlPrefixes(config: Config): string[] {\n const endpointConfigs =\n config.getOptionalConfigArray('discovery.endpoints') || [];\n return endpointConfigs.flatMap(c => {\n const target =\n typeof c.get('target') === 'object'\n ? c.getString('target.external')\n : c.getString('target');\n const plugins = c.getStringArray('plugins');\n return plugins.map(pluginId =>\n target.replace(/\\{\\{\\s*pluginId\\s*\\}\\}/g, pluginId),\n );\n });\n }\n\n constructor(\n public readonly identityApi: IdentityApi,\n public readonly allowUrl: (url: string) => boolean,\n public readonly headerName: string,\n public readonly headerValue: (pluginId: string) => string,\n ) {}\n\n apply(next: typeof fetch): typeof fetch {\n return async (input, init) => {\n // Skip this middleware if the header already exists, or if the URL\n // doesn't match any of the allowlist items, or if there was no token.\n // NOTE(freben): The \"as any\" casts here and below are because of subtle\n // undici type differences that happened in a node types bump. Those are\n // immaterial to the code at hand at runtime, as the global fetch and\n // Request are always taken from the same place.\n const request = new Request(input as any, init);\n const { token } = await this.identityApi.getCredentials();\n if (\n request.headers.get(this.headerName) ||\n typeof token !== 'string' ||\n !token ||\n !this.allowUrl(request.url)\n ) {\n return next(input as any, init);\n }\n\n request.headers.set(this.headerName, this.headerValue(token));\n return next(request);\n };\n }\n}\n\nfunction buildMatcher(options: {\n config?: Config;\n urlPrefixAllowlist?: string[];\n allowUrl?: (url: string) => boolean;\n}): (url: string) => boolean {\n if (options.allowUrl) {\n return options.allowUrl;\n } else if (options.urlPrefixAllowlist) {\n return buildPrefixMatcher(options.urlPrefixAllowlist);\n } else if (options.config) {\n return buildPrefixMatcher([\n options.config.getString('backend.baseUrl'),\n ...IdentityAuthInjectorFetchMiddleware.getDiscoveryUrlPrefixes(\n options.config,\n ),\n ]);\n }\n return () => false;\n}\n\nfunction buildPrefixMatcher(prefixes: string[]): (url: string) => boolean {\n const trimmedPrefixes = prefixes.map(prefix => prefix.replace(/\\/$/, ''));\n return url =>\n trimmedPrefixes.some(\n prefix => url === prefix || url.startsWith(`${prefix}/`),\n );\n}\n"],"names":[],"mappings":"AAwBO,MAAM,mCAAA,CAA+D;AAAA,EA0C1E,WAAA,CACkB,WAAA,EACA,QAAA,EACA,UAAA,EACA,WAAA,EAChB;AAJgB,IAAA,IAAA,CAAA,WAAA,GAAA,WAAA;AACA,IAAA,IAAA,CAAA,QAAA,GAAA,QAAA;AACA,IAAA,IAAA,CAAA,UAAA,GAAA,UAAA;AACA,IAAA,IAAA,CAAA,WAAA,GAAA,WAAA;AAAA,EACf;AAAA,EA9CH,OAAO,OAAO,OAAA,EAS0B;AACtC,IAAA,MAAM,OAAA,GAAU,aAAa,OAAO,CAAA;AACpC,IAAA,MAAM,UAAA,GAAa,OAAA,CAAQ,MAAA,EAAQ,IAAA,IAAQ,eAAA;AAC3C,IAAA,MAAM,cAAc,OAAA,CAAQ,MAAA,EAAQ,KAAA,KAAU,CAAA,KAAA,KAAS,UAAU,KAAK,CAAA,CAAA,CAAA;AAEtE,IAAA,OAAO,IAAI,mCAAA;AAAA,MACT,OAAA,CAAQ,WAAA;AAAA,MACR,OAAA;AAAA,MACA,UAAA;AAAA,MACA;AAAA,KACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,OAAO,wBAAwB,MAAA,EAA0B;AACvD,IAAA,MAAM,eAAA,GACJ,MAAA,CAAO,sBAAA,CAAuB,qBAAqB,KAAK,EAAC;AAC3D,IAAA,OAAO,eAAA,CAAgB,QAAQ,CAAA,CAAA,KAAK;AAClC,MAAA,MAAM,MAAA,GACJ,OAAO,CAAA,CAAE,GAAA,CAAI,QAAQ,CAAA,KAAM,QAAA,GACvB,CAAA,CAAE,SAAA,CAAU,iBAAiB,CAAA,GAC7B,CAAA,CAAE,UAAU,QAAQ,CAAA;AAC1B,MAAA,MAAM,OAAA,GAAU,CAAA,CAAE,cAAA,CAAe,SAAS,CAAA;AAC1C,MAAA,OAAO,OAAA,CAAQ,GAAA;AAAA,QAAI,CAAA,QAAA,KACjB,MAAA,CAAO,OAAA,CAAQ,yBAAA,EAA2B,QAAQ;AAAA,OACpD;AAAA,IACF,CAAC,CAAA;AAAA,EACH;AAAA,EASA,MAAM,IAAA,EAAkC;AACtC,IAAA,OAAO,OAAO,OAAO,IAAA,KAAS;AAO5B,MAAA,MAAM,OAAA,GAAU,IAAI,OAAA,CAAQ,KAAA,EAAc,IAAI,CAAA;AAC9C,MAAA,MAAM,EAAE,KAAA,EAAM,GAAI,MAAM,IAAA,CAAK,YAAY,cAAA,EAAe;AACxD,MAAA,IACE,QAAQ,OAAA,CAAQ,GAAA,CAAI,IAAA,CAAK,UAAU,KACnC,OAAO,KAAA,KAAU,QAAA,IACjB,CAAC,SACD,CAAC,IAAA,CAAK,QAAA,CAAS,OAAA,CAAQ,GAAG,CAAA,EAC1B;AACA,QAAA,OAAO,IAAA,CAAK,OAAc,IAAI,CAAA;AAAA,MAChC;AAEA,MAAA,OAAA,CAAQ,QAAQ,GAAA,CAAI,IAAA,CAAK,YAAY,IAAA,CAAK,WAAA,CAAY,KAAK,CAAC,CAAA;AAC5D,MAAA,OAAO,KAAK,OAAO,CAAA;AAAA,IACrB,CAAA;AAAA,EACF;AACF;AAEA,SAAS,aAAa,OAAA,EAIO;AAC3B,EAAA,IAAI,QAAQ,QAAA,EAAU;AACpB,IAAA,OAAO,OAAA,CAAQ,QAAA;AAAA,EACjB,CAAA,MAAA,IAAW,QAAQ,kBAAA,EAAoB;AACrC,IAAA,OAAO,kBAAA,CAAmB,QAAQ,kBAAkB,CAAA;AAAA,EACtD,CAAA,MAAA,IAAW,QAAQ,MAAA,EAAQ;AACzB,IAAA,OAAO,kBAAA,CAAmB;AAAA,MACxB,OAAA,CAAQ,MAAA,CAAO,SAAA,CAAU,iBAAiB,CAAA;AAAA,MAC1C,GAAG,mCAAA,CAAoC,uBAAA;AAAA,QACrC,OAAA,CAAQ;AAAA;AACV,KACD,CAAA;AAAA,EACH;AACA,EAAA,OAAO,MAAM,KAAA;AACf;AAEA,SAAS,mBAAmB,QAAA,EAA8C;AACxE,EAAA,MAAM,eAAA,GAAkB,SAAS,GAAA,CAAI,CAAA,MAAA,KAAU,OAAO,OAAA,CAAQ,KAAA,EAAO,EAAE,CAAC,CAAA;AACxE,EAAA,OAAO,SACL,eAAA,CAAgB,IAAA;AAAA,IACd,YAAU,GAAA,KAAQ,MAAA,IAAU,IAAI,UAAA,CAAW,CAAA,EAAG,MAAM,CAAA,CAAA,CAAG;AAAA,GACzD;AACJ;;;;"}
1
+ {"version":3,"file":"IdentityAuthInjectorFetchMiddleware.esm.js","sources":["../../../../src/apis/implementations/FetchApi/IdentityAuthInjectorFetchMiddleware.ts"],"sourcesContent":["/*\n * Copyright 2021 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 { Config } from '@backstage/config';\nimport { IdentityApi } from '@backstage/core-plugin-api';\nimport { FetchMiddleware } from './types';\n\n/**\n * A fetch middleware, which injects a Backstage token header when the user is\n * signed in.\n */\nexport class IdentityAuthInjectorFetchMiddleware implements FetchMiddleware {\n static create(options: {\n identityApi: IdentityApi;\n config?: Config;\n urlPrefixAllowlist?: string[];\n allowUrl?: (url: string) => boolean;\n header?: {\n name: string;\n value: (backstageToken: string) => string;\n };\n }): IdentityAuthInjectorFetchMiddleware {\n const matcher = buildMatcher(options);\n const headerName = options.header?.name || 'authorization';\n const headerValue = options.header?.value || (token => `Bearer ${token}`);\n\n return new IdentityAuthInjectorFetchMiddleware(\n options.identityApi,\n matcher,\n headerName,\n headerValue,\n );\n }\n\n /**\n * Returns an array of plugin URL prefixes derived from the static `discovery`\n * configuration, to be used as `urlPrefixAllowlist` option of {@link create}.\n */\n static getDiscoveryUrlPrefixes(config: Config): string[] {\n const endpointConfigs =\n config.getOptionalConfigArray('discovery.endpoints') || [];\n return endpointConfigs.flatMap(c => {\n const target =\n typeof c.get('target') === 'object'\n ? c.getString('target.external')\n : c.getString('target');\n const plugins = c.getStringArray('plugins');\n return plugins.map(pluginId =>\n target.replace(/\\{\\{\\s*pluginId\\s*\\}\\}/g, pluginId),\n );\n });\n }\n\n public readonly identityApi: IdentityApi;\n public readonly allowUrl: (url: string) => boolean;\n public readonly headerName: string;\n public readonly headerValue: (pluginId: string) => string;\n\n constructor(\n identityApi: IdentityApi,\n allowUrl: (url: string) => boolean,\n headerName: string,\n headerValue: (pluginId: string) => string,\n ) {\n this.identityApi = identityApi;\n this.allowUrl = allowUrl;\n this.headerName = headerName;\n this.headerValue = headerValue;\n }\n\n apply(next: typeof fetch): typeof fetch {\n return async (input, init) => {\n // Skip this middleware if the header already exists, or if the URL\n // doesn't match any of the allowlist items, or if there was no token.\n // NOTE(freben): The \"as any\" casts here and below are because of subtle\n // undici type differences that happened in a node types bump. Those are\n // immaterial to the code at hand at runtime, as the global fetch and\n // Request are always taken from the same place.\n const request = new Request(input as any, init);\n const { token } = await this.identityApi.getCredentials();\n if (\n request.headers.get(this.headerName) ||\n typeof token !== 'string' ||\n !token ||\n !this.allowUrl(request.url)\n ) {\n return next(input as any, init);\n }\n\n request.headers.set(this.headerName, this.headerValue(token));\n return next(request);\n };\n }\n}\n\nfunction buildMatcher(options: {\n config?: Config;\n urlPrefixAllowlist?: string[];\n allowUrl?: (url: string) => boolean;\n}): (url: string) => boolean {\n if (options.allowUrl) {\n return options.allowUrl;\n } else if (options.urlPrefixAllowlist) {\n return buildPrefixMatcher(options.urlPrefixAllowlist);\n } else if (options.config) {\n return buildPrefixMatcher([\n options.config.getString('backend.baseUrl'),\n ...IdentityAuthInjectorFetchMiddleware.getDiscoveryUrlPrefixes(\n options.config,\n ),\n ]);\n }\n return () => false;\n}\n\nfunction buildPrefixMatcher(prefixes: string[]): (url: string) => boolean {\n const trimmedPrefixes = prefixes.map(prefix => prefix.replace(/\\/$/, ''));\n return url =>\n trimmedPrefixes.some(\n prefix => url === prefix || url.startsWith(`${prefix}/`),\n );\n}\n"],"names":[],"mappings":"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"}
@@ -2,6 +2,8 @@ import ObservableImpl from 'zen-observable';
2
2
 
3
3
  const buckets = /* @__PURE__ */ new Map();
4
4
  class WebStorage {
5
+ namespace;
6
+ errorApi;
5
7
  constructor(namespace, errorApi) {
6
8
  this.namespace = namespace;
7
9
  this.errorApi = errorApi;
@@ -1 +1 @@
1
- {"version":3,"file":"WebStorage.esm.js","sources":["../../../../src/apis/implementations/StorageApi/WebStorage.ts"],"sourcesContent":["/*\n * Copyright 2020 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 StorageApi,\n StorageValueSnapshot,\n ErrorApi,\n} from '@backstage/core-plugin-api';\nimport { JsonValue, Observable } from '@backstage/types';\nimport ObservableImpl from 'zen-observable';\n\nexport const buckets = new Map<string, WebStorage>();\n\n/**\n * An implementation of the storage API, that uses the browser's local storage.\n *\n * @public\n */\nexport class WebStorage implements StorageApi {\n constructor(\n private readonly namespace: string,\n private readonly errorApi: ErrorApi,\n ) {}\n\n private static hasSubscribed = false;\n\n static create(options: {\n errorApi: ErrorApi;\n namespace?: string;\n }): WebStorage {\n return new WebStorage(options.namespace ?? '', options.errorApi);\n }\n\n private static addStorageEventListener() {\n window.addEventListener('storage', event => {\n for (const [bucketPath, webStorage] of buckets.entries()) {\n if (event.key?.startsWith(bucketPath)) {\n webStorage.handleStorageChange(event.key);\n }\n }\n });\n }\n\n get<T>(key: string): T | undefined {\n return this.snapshot(key).value as T | undefined;\n }\n\n snapshot<T extends JsonValue>(key: string): StorageValueSnapshot<T> {\n let value = undefined;\n let presence: 'present' | 'absent' = 'absent';\n try {\n const item = localStorage.getItem(this.getKeyName(key));\n if (item) {\n value = JSON.parse(item, (_key, val) => {\n if (typeof val === 'object' && val !== null) {\n Object.freeze(val);\n }\n return val;\n });\n presence = 'present';\n }\n } catch (e) {\n this.errorApi.post(\n new Error(`Error when parsing JSON config from storage for: ${key}`),\n );\n }\n return { key, value, presence };\n }\n\n forBucket(name: string): WebStorage {\n const bucketPath = `${this.namespace}/${name}`;\n if (!buckets.has(bucketPath)) {\n buckets.set(bucketPath, new WebStorage(bucketPath, this.errorApi));\n }\n return buckets.get(bucketPath)!;\n }\n\n async set<T>(key: string, data: T): Promise<void> {\n localStorage.setItem(this.getKeyName(key), JSON.stringify(data));\n this.notifyChanges(key);\n }\n\n async remove(key: string): Promise<void> {\n localStorage.removeItem(this.getKeyName(key));\n this.notifyChanges(key);\n }\n\n observe$<T extends JsonValue>(\n key: string,\n ): Observable<StorageValueSnapshot<T>> {\n if (!WebStorage.hasSubscribed) {\n WebStorage.addStorageEventListener();\n WebStorage.hasSubscribed = true;\n }\n return this.observable.filter(({ key: messageKey }) => messageKey === key);\n }\n\n private handleStorageChange(eventKey: StorageEvent['key']) {\n if (!eventKey?.startsWith(this.namespace)) {\n return;\n }\n // Grab the part of this key that is local to this bucket\n const trimmedKey = eventKey?.slice(`${this.namespace}/`.length);\n\n // If the key still contains a slash, it means it's a sub-bucket\n if (!trimmedKey.includes('/')) {\n this.notifyChanges(decodeURIComponent(trimmedKey));\n }\n }\n\n private getKeyName(key: string) {\n return `${this.namespace}/${encodeURIComponent(key)}`;\n }\n\n private notifyChanges(key: string) {\n const snapshot = this.snapshot(key);\n for (const subscription of this.subscribers) {\n subscription.next(snapshot);\n }\n }\n\n private subscribers = new Set<\n ZenObservable.SubscriptionObserver<StorageValueSnapshot<JsonValue>>\n >();\n\n private readonly observable = new ObservableImpl<\n StorageValueSnapshot<JsonValue>\n >(subscriber => {\n this.subscribers.add(subscriber);\n return () => {\n this.subscribers.delete(subscriber);\n };\n });\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"WebStorage.esm.js","sources":["../../../../src/apis/implementations/StorageApi/WebStorage.ts"],"sourcesContent":["/*\n * Copyright 2020 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 StorageApi,\n StorageValueSnapshot,\n ErrorApi,\n} from '@backstage/core-plugin-api';\nimport { JsonValue, Observable } from '@backstage/types';\nimport ObservableImpl from 'zen-observable';\n\nexport const buckets = new Map<string, WebStorage>();\n\n/**\n * An implementation of the storage API, that uses the browser's local storage.\n *\n * @public\n */\nexport class WebStorage implements StorageApi {\n private readonly namespace: string;\n private readonly errorApi: ErrorApi;\n\n constructor(namespace: string, errorApi: ErrorApi) {\n this.namespace = namespace;\n this.errorApi = errorApi;\n }\n\n private static hasSubscribed = false;\n\n static create(options: {\n errorApi: ErrorApi;\n namespace?: string;\n }): WebStorage {\n return new WebStorage(options.namespace ?? '', options.errorApi);\n }\n\n private static addStorageEventListener() {\n window.addEventListener('storage', event => {\n for (const [bucketPath, webStorage] of buckets.entries()) {\n if (event.key?.startsWith(bucketPath)) {\n webStorage.handleStorageChange(event.key);\n }\n }\n });\n }\n\n get<T>(key: string): T | undefined {\n return this.snapshot(key).value as T | undefined;\n }\n\n snapshot<T extends JsonValue>(key: string): StorageValueSnapshot<T> {\n let value = undefined;\n let presence: 'present' | 'absent' = 'absent';\n try {\n const item = localStorage.getItem(this.getKeyName(key));\n if (item) {\n value = JSON.parse(item, (_key, val) => {\n if (typeof val === 'object' && val !== null) {\n Object.freeze(val);\n }\n return val;\n });\n presence = 'present';\n }\n } catch (e) {\n this.errorApi.post(\n new Error(`Error when parsing JSON config from storage for: ${key}`),\n );\n }\n return { key, value, presence };\n }\n\n forBucket(name: string): WebStorage {\n const bucketPath = `${this.namespace}/${name}`;\n if (!buckets.has(bucketPath)) {\n buckets.set(bucketPath, new WebStorage(bucketPath, this.errorApi));\n }\n return buckets.get(bucketPath)!;\n }\n\n async set<T>(key: string, data: T): Promise<void> {\n localStorage.setItem(this.getKeyName(key), JSON.stringify(data));\n this.notifyChanges(key);\n }\n\n async remove(key: string): Promise<void> {\n localStorage.removeItem(this.getKeyName(key));\n this.notifyChanges(key);\n }\n\n observe$<T extends JsonValue>(\n key: string,\n ): Observable<StorageValueSnapshot<T>> {\n if (!WebStorage.hasSubscribed) {\n WebStorage.addStorageEventListener();\n WebStorage.hasSubscribed = true;\n }\n return this.observable.filter(({ key: messageKey }) => messageKey === key);\n }\n\n private handleStorageChange(eventKey: StorageEvent['key']) {\n if (!eventKey?.startsWith(this.namespace)) {\n return;\n }\n // Grab the part of this key that is local to this bucket\n const trimmedKey = eventKey?.slice(`${this.namespace}/`.length);\n\n // If the key still contains a slash, it means it's a sub-bucket\n if (!trimmedKey.includes('/')) {\n this.notifyChanges(decodeURIComponent(trimmedKey));\n }\n }\n\n private getKeyName(key: string) {\n return `${this.namespace}/${encodeURIComponent(key)}`;\n }\n\n private notifyChanges(key: string) {\n const snapshot = this.snapshot(key);\n for (const subscription of this.subscribers) {\n subscription.next(snapshot);\n }\n }\n\n private subscribers = new Set<\n ZenObservable.SubscriptionObserver<StorageValueSnapshot<JsonValue>>\n >();\n\n private readonly observable = new ObservableImpl<\n StorageValueSnapshot<JsonValue>\n >(subscriber => {\n this.subscribers.add(subscriber);\n return () => {\n this.subscribers.delete(subscriber);\n };\n });\n}\n"],"names":[],"mappings":";;AAwBO,MAAM,OAAA,uBAAc,GAAA;AAOpB,MAAM,UAAA,CAAiC;AAAA,EAC3B,SAAA;AAAA,EACA,QAAA;AAAA,EAEjB,WAAA,CAAY,WAAmB,QAAA,EAAoB;AACjD,IAAA,IAAA,CAAK,SAAA,GAAY,SAAA;AACjB,IAAA,IAAA,CAAK,QAAA,GAAW,QAAA;AAAA,EAClB;AAAA,EAEA,OAAe,aAAA,GAAgB,KAAA;AAAA,EAE/B,OAAO,OAAO,OAAA,EAGC;AACb,IAAA,OAAO,IAAI,UAAA,CAAW,OAAA,CAAQ,SAAA,IAAa,EAAA,EAAI,QAAQ,QAAQ,CAAA;AAAA,EACjE;AAAA,EAEA,OAAe,uBAAA,GAA0B;AACvC,IAAA,MAAA,CAAO,gBAAA,CAAiB,WAAW,CAAA,KAAA,KAAS;AAC1C,MAAA,KAAA,MAAW,CAAC,UAAA,EAAY,UAAU,CAAA,IAAK,OAAA,CAAQ,SAAQ,EAAG;AACxD,QAAA,IAAI,KAAA,CAAM,GAAA,EAAK,UAAA,CAAW,UAAU,CAAA,EAAG;AACrC,UAAA,UAAA,CAAW,mBAAA,CAAoB,MAAM,GAAG,CAAA;AAAA,QAC1C;AAAA,MACF;AAAA,IACF,CAAC,CAAA;AAAA,EACH;AAAA,EAEA,IAAO,GAAA,EAA4B;AACjC,IAAA,OAAO,IAAA,CAAK,QAAA,CAAS,GAAG,CAAA,CAAE,KAAA;AAAA,EAC5B;AAAA,EAEA,SAA8B,GAAA,EAAsC;AAClE,IAAA,IAAI,KAAA,GAAQ,MAAA;AACZ,IAAA,IAAI,QAAA,GAAiC,QAAA;AACrC,IAAA,IAAI;AACF,MAAA,MAAM,OAAO,YAAA,CAAa,OAAA,CAAQ,IAAA,CAAK,UAAA,CAAW,GAAG,CAAC,CAAA;AACtD,MAAA,IAAI,IAAA,EAAM;AACR,QAAA,KAAA,GAAQ,IAAA,CAAK,KAAA,CAAM,IAAA,EAAM,CAAC,MAAM,GAAA,KAAQ;AACtC,UAAA,IAAI,OAAO,GAAA,KAAQ,QAAA,IAAY,GAAA,KAAQ,IAAA,EAAM;AAC3C,YAAA,MAAA,CAAO,OAAO,GAAG,CAAA;AAAA,UACnB;AACA,UAAA,OAAO,GAAA;AAAA,QACT,CAAC,CAAA;AACD,QAAA,QAAA,GAAW,SAAA;AAAA,MACb;AAAA,IACF,SAAS,CAAA,EAAG;AACV,MAAA,IAAA,CAAK,QAAA,CAAS,IAAA;AAAA,QACZ,IAAI,KAAA,CAAM,CAAA,iDAAA,EAAoD,GAAG,CAAA,CAAE;AAAA,OACrE;AAAA,IACF;AACA,IAAA,OAAO,EAAE,GAAA,EAAK,KAAA,EAAO,QAAA,EAAS;AAAA,EAChC;AAAA,EAEA,UAAU,IAAA,EAA0B;AAClC,IAAA,MAAM,UAAA,GAAa,CAAA,EAAG,IAAA,CAAK,SAAS,IAAI,IAAI,CAAA,CAAA;AAC5C,IAAA,IAAI,CAAC,OAAA,CAAQ,GAAA,CAAI,UAAU,CAAA,EAAG;AAC5B,MAAA,OAAA,CAAQ,IAAI,UAAA,EAAY,IAAI,WAAW,UAAA,EAAY,IAAA,CAAK,QAAQ,CAAC,CAAA;AAAA,IACnE;AACA,IAAA,OAAO,OAAA,CAAQ,IAAI,UAAU,CAAA;AAAA,EAC/B;AAAA,EAEA,MAAM,GAAA,CAAO,GAAA,EAAa,IAAA,EAAwB;AAChD,IAAA,YAAA,CAAa,OAAA,CAAQ,KAAK,UAAA,CAAW,GAAG,GAAG,IAAA,CAAK,SAAA,CAAU,IAAI,CAAC,CAAA;AAC/D,IAAA,IAAA,CAAK,cAAc,GAAG,CAAA;AAAA,EACxB;AAAA,EAEA,MAAM,OAAO,GAAA,EAA4B;AACvC,IAAA,YAAA,CAAa,UAAA,CAAW,IAAA,CAAK,UAAA,CAAW,GAAG,CAAC,CAAA;AAC5C,IAAA,IAAA,CAAK,cAAc,GAAG,CAAA;AAAA,EACxB;AAAA,EAEA,SACE,GAAA,EACqC;AACrC,IAAA,IAAI,CAAC,WAAW,aAAA,EAAe;AAC7B,MAAA,UAAA,CAAW,uBAAA,EAAwB;AACnC,MAAA,UAAA,CAAW,aAAA,GAAgB,IAAA;AAAA,IAC7B;AACA,IAAA,OAAO,IAAA,CAAK,WAAW,MAAA,CAAO,CAAC,EAAE,GAAA,EAAK,UAAA,EAAW,KAAM,UAAA,KAAe,GAAG,CAAA;AAAA,EAC3E;AAAA,EAEQ,oBAAoB,QAAA,EAA+B;AACzD,IAAA,IAAI,CAAC,QAAA,EAAU,UAAA,CAAW,IAAA,CAAK,SAAS,CAAA,EAAG;AACzC,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,aAAa,QAAA,EAAU,KAAA,CAAM,GAAG,IAAA,CAAK,SAAS,IAAI,MAAM,CAAA;AAG9D,IAAA,IAAI,CAAC,UAAA,CAAW,QAAA,CAAS,GAAG,CAAA,EAAG;AAC7B,MAAA,IAAA,CAAK,aAAA,CAAc,kBAAA,CAAmB,UAAU,CAAC,CAAA;AAAA,IACnD;AAAA,EACF;AAAA,EAEQ,WAAW,GAAA,EAAa;AAC9B,IAAA,OAAO,GAAG,IAAA,CAAK,SAAS,CAAA,CAAA,EAAI,kBAAA,CAAmB,GAAG,CAAC,CAAA,CAAA;AAAA,EACrD;AAAA,EAEQ,cAAc,GAAA,EAAa;AACjC,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,QAAA,CAAS,GAAG,CAAA;AAClC,IAAA,KAAA,MAAW,YAAA,IAAgB,KAAK,WAAA,EAAa;AAC3C,MAAA,YAAA,CAAa,KAAK,QAAQ,CAAA;AAAA,IAC5B;AAAA,EACF;AAAA,EAEQ,WAAA,uBAAkB,GAAA,EAExB;AAAA,EAEe,UAAA,GAAa,IAAI,cAAA,CAEhC,CAAA,UAAA,KAAc;AACd,IAAA,IAAA,CAAK,WAAA,CAAY,IAAI,UAAU,CAAA;AAC/B,IAAA,OAAO,MAAM;AACX,MAAA,IAAA,CAAK,WAAA,CAAY,OAAO,UAAU,CAAA;AAAA,IACpC,CAAA;AAAA,EACF,CAAC,CAAA;AACH;;;;"}
package/dist/index.d.ts CHANGED
@@ -529,8 +529,6 @@ declare class UrlPatternDiscovery implements DiscoveryApi {
529
529
  * @public
530
530
  */
531
531
  declare class FrontendHostDiscovery implements DiscoveryApi {
532
- private readonly endpoints;
533
- private readonly defaultEndpoint;
534
532
  /**
535
533
  * Creates a new FrontendHostDiscovery discovery instance by reading
536
534
  * the external target URL from the `discovery.endpoints` config section.
@@ -555,6 +553,8 @@ declare class FrontendHostDiscovery implements DiscoveryApi {
555
553
  static fromConfig(config: Config, options?: {
556
554
  pathPattern?: string;
557
555
  }): FrontendHostDiscovery;
556
+ private readonly endpoints;
557
+ private readonly defaultEndpoint;
558
558
  private constructor();
559
559
  getBaseUrl(pluginId: string): Promise<string>;
560
560
  }
@@ -75,6 +75,12 @@ function resolveBasePath(targetRef, sourceLocation, routePaths, routeParents, ro
75
75
  return `${joinPaths(parentPath, ...diffPaths)}/`;
76
76
  }
77
77
  class RouteResolver {
78
+ routePaths;
79
+ routeParents;
80
+ routeObjects;
81
+ routeBindings;
82
+ appBasePath;
83
+ // base path without a trailing slash
78
84
  constructor(routePaths, routeParents, routeObjects, routeBindings, appBasePath) {
79
85
  this.routePaths = routePaths;
80
86
  this.routeParents = routeParents;
@@ -1 +1 @@
1
- {"version":3,"file":"RouteResolver.esm.js","sources":["../../src/routing/RouteResolver.ts"],"sourcesContent":["/*\n * Copyright 2020 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 { generatePath, matchRoutes } from 'react-router-dom';\nimport {\n AnyRouteRef,\n BackstageRouteObject,\n AnyParams,\n RouteFunc,\n routeRefType,\n isRouteRef,\n isSubRouteRef,\n isExternalRouteRef,\n} from './types';\nimport {\n RouteRef,\n ExternalRouteRef,\n SubRouteRef,\n} from '@backstage/core-plugin-api';\nimport { joinPaths } from './helpers';\nimport mapValues from 'lodash/mapValues';\n\n/**\n * Resolves the absolute route ref that our target route ref is pointing pointing to, as well\n * as the relative target path.\n *\n * Returns an undefined target ref if one could not be fully resolved.\n */\nfunction resolveTargetRef(\n anyRouteRef: AnyRouteRef,\n routePaths: Map<RouteRef, string>,\n routeBindings: Map<AnyRouteRef, AnyRouteRef | undefined>,\n): readonly [RouteRef | undefined, string] {\n // First we figure out which absolute route ref we're dealing with, an if there was an sub route path to append.\n // For sub routes it will be the parent path, while for external routes it will be the bound route.\n let targetRef: RouteRef;\n let subRoutePath = '';\n if (isRouteRef(anyRouteRef)) {\n targetRef = anyRouteRef;\n } else if (isSubRouteRef(anyRouteRef)) {\n targetRef = anyRouteRef.parent;\n subRoutePath = anyRouteRef.path;\n } else if (isExternalRouteRef(anyRouteRef)) {\n const resolvedRoute = routeBindings.get(anyRouteRef);\n if (!resolvedRoute) {\n return [undefined, ''];\n }\n if (isRouteRef(resolvedRoute)) {\n targetRef = resolvedRoute;\n } else if (isSubRouteRef(resolvedRoute)) {\n targetRef = resolvedRoute.parent;\n subRoutePath = resolvedRoute.path;\n } else {\n throw new Error(\n `ExternalRouteRef was bound to invalid target, ${resolvedRoute}`,\n );\n }\n } else if (anyRouteRef[routeRefType]) {\n throw new Error(\n `Unknown or invalid route ref type, ${anyRouteRef[routeRefType]}`,\n );\n } else {\n throw new Error(`Unknown object passed to useRouteRef, got ${anyRouteRef}`);\n }\n\n // Bail if no absolute path could be resolved\n if (!targetRef) {\n return [undefined, ''];\n }\n\n // Find the path that our target route is bound to\n const resolvedPath = routePaths.get(targetRef);\n if (resolvedPath === undefined) {\n return [undefined, ''];\n }\n\n // SubRouteRefs join the path from the parent route with its own path\n const targetPath = joinPaths(resolvedPath, subRoutePath);\n return [targetRef, targetPath];\n}\n\n/**\n * Resolves the complete base path for navigating to the target RouteRef.\n */\nfunction resolveBasePath(\n targetRef: RouteRef,\n sourceLocation: Parameters<typeof matchRoutes>[1],\n routePaths: Map<RouteRef, string>,\n routeParents: Map<RouteRef, RouteRef | undefined>,\n routeObjects: BackstageRouteObject[],\n) {\n // While traversing the app element tree we build up the routeObjects structure\n // used here. It is the same kind of structure that react-router creates, with the\n // addition that associated route refs are stored throughout the tree. This lets\n // us look up all route refs that can be reached from our source location.\n // Because of the similar route object structure, we can use `matchRoutes` from\n // react-router to do the lookup of our current location.\n const match = matchRoutes(routeObjects, sourceLocation) ?? [];\n\n // While we search for a common routing root between our current location and\n // the target route, we build a list of all route refs we find that we need\n // to traverse to reach the target.\n const refDiffList = Array<RouteRef>();\n\n let matchIndex = -1;\n for (\n let targetSearchRef: RouteRef | undefined = targetRef;\n targetSearchRef;\n targetSearchRef = routeParents.get(targetSearchRef)\n ) {\n // The match contains a list of all ancestral route refs present at our current location\n // Starting at the desired target ref and traversing back through its parents, we search\n // for a target ref that is present in the match for our current location. When a match\n // is found it means we have found a common base to resolve the route from.\n matchIndex = match.findIndex(m =>\n (m.route as BackstageRouteObject).routeRefs.has(targetSearchRef!),\n );\n if (matchIndex !== -1) {\n break;\n }\n\n // Every time we move a step up in the ancestry of the target ref, we add the current ref\n // to the diff list, which ends up being the list of route refs to traverse form the common base\n // in order to reach our target.\n refDiffList.unshift(targetSearchRef);\n }\n\n // If our target route is present in the initial match we need to construct the final path\n // from the parent of the matched route segment. That's to allow the caller of the route\n // function to supply their own params.\n if (refDiffList.length === 0) {\n matchIndex -= 1;\n }\n\n // This is the part of the route tree that the target and source locations have in common.\n // We re-use the existing pathname directly along with all params.\n const parentPath = matchIndex === -1 ? '' : match[matchIndex].pathname;\n\n // This constructs the mid section of the path using paths resolved from all route refs\n // we need to traverse to reach our target except for the very last one. None of these\n // paths are allowed to require any parameters, as the caller would have no way of knowing\n // what parameters those are.\n const diffPaths = refDiffList.slice(0, -1).map(ref => {\n const path = routePaths.get(ref);\n if (path === undefined) {\n throw new Error(`No path for ${ref}`);\n }\n if (path.includes(':')) {\n throw new Error(\n `Cannot route to ${targetRef} with parent ${ref} as it has parameters`,\n );\n }\n return path;\n });\n\n return `${joinPaths(parentPath, ...diffPaths)}/`;\n}\n\nexport class RouteResolver {\n constructor(\n private readonly routePaths: Map<RouteRef, string>,\n private readonly routeParents: Map<RouteRef, RouteRef | undefined>,\n private readonly routeObjects: BackstageRouteObject[],\n private readonly routeBindings: Map<\n ExternalRouteRef,\n RouteRef | SubRouteRef\n >,\n private readonly appBasePath: string, // base path without a trailing slash\n ) {}\n\n resolve<Params extends AnyParams>(\n anyRouteRef:\n | RouteRef<Params>\n | SubRouteRef<Params>\n | ExternalRouteRef<Params, any>,\n sourceLocation: Parameters<typeof matchRoutes>[1],\n ): RouteFunc<Params> | undefined {\n // First figure out what our target absolute ref is, as well as our target path.\n const [targetRef, targetPath] = resolveTargetRef(\n anyRouteRef,\n this.routePaths,\n this.routeBindings,\n );\n if (!targetRef) {\n return undefined;\n }\n\n // The location that we get passed in uses the full path, so start by trimming off\n // the app base path prefix in case we're running the app on a sub-path.\n let relativeSourceLocation: Parameters<typeof matchRoutes>[1];\n if (typeof sourceLocation === 'string') {\n relativeSourceLocation = this.trimPath(sourceLocation);\n } else if (sourceLocation.pathname) {\n relativeSourceLocation = {\n ...sourceLocation,\n pathname: this.trimPath(sourceLocation.pathname),\n };\n } else {\n relativeSourceLocation = sourceLocation;\n }\n\n // Next we figure out the base path, which is the combination of the common parent path\n // between our current location and our target location, as well as the additional path\n // that is the difference between the parent path and the base of our target location.\n const basePath =\n this.appBasePath +\n resolveBasePath(\n targetRef,\n relativeSourceLocation,\n this.routePaths,\n this.routeParents,\n this.routeObjects,\n );\n\n const routeFunc: RouteFunc<Params> = (...[params]) => {\n // We selectively encode some some known-dangerous characters in the\n // params. The reason that we don't perform a blanket `encodeURIComponent`\n // here is that this encoding was added defensively long after the initial\n // release of this code. There's likely to be many users of this code that\n // already encode their parameters knowing that this code didn't do this\n // for them in the past. Therefore, we are extra careful NOT to include\n // the percent character in this set, even though that might seem like a\n // bad idea.\n const encodedParams =\n params &&\n mapValues(params, value => {\n if (typeof value === 'string') {\n return value.replaceAll(/[&?#;\\/]/g, c => encodeURIComponent(c));\n }\n return value;\n });\n return joinPaths(basePath, generatePath(targetPath, encodedParams));\n };\n return routeFunc;\n }\n\n private trimPath(targetPath: string) {\n if (!targetPath) {\n return targetPath;\n }\n\n if (targetPath.startsWith(this.appBasePath)) {\n return targetPath.slice(this.appBasePath.length);\n }\n return targetPath;\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"RouteResolver.esm.js","sources":["../../src/routing/RouteResolver.ts"],"sourcesContent":["/*\n * Copyright 2020 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 { generatePath, matchRoutes } from 'react-router-dom';\nimport {\n AnyRouteRef,\n BackstageRouteObject,\n AnyParams,\n RouteFunc,\n routeRefType,\n isRouteRef,\n isSubRouteRef,\n isExternalRouteRef,\n} from './types';\nimport {\n RouteRef,\n ExternalRouteRef,\n SubRouteRef,\n} from '@backstage/core-plugin-api';\nimport { joinPaths } from './helpers';\nimport mapValues from 'lodash/mapValues';\n\n/**\n * Resolves the absolute route ref that our target route ref is pointing pointing to, as well\n * as the relative target path.\n *\n * Returns an undefined target ref if one could not be fully resolved.\n */\nfunction resolveTargetRef(\n anyRouteRef: AnyRouteRef,\n routePaths: Map<RouteRef, string>,\n routeBindings: Map<AnyRouteRef, AnyRouteRef | undefined>,\n): readonly [RouteRef | undefined, string] {\n // First we figure out which absolute route ref we're dealing with, an if there was an sub route path to append.\n // For sub routes it will be the parent path, while for external routes it will be the bound route.\n let targetRef: RouteRef;\n let subRoutePath = '';\n if (isRouteRef(anyRouteRef)) {\n targetRef = anyRouteRef;\n } else if (isSubRouteRef(anyRouteRef)) {\n targetRef = anyRouteRef.parent;\n subRoutePath = anyRouteRef.path;\n } else if (isExternalRouteRef(anyRouteRef)) {\n const resolvedRoute = routeBindings.get(anyRouteRef);\n if (!resolvedRoute) {\n return [undefined, ''];\n }\n if (isRouteRef(resolvedRoute)) {\n targetRef = resolvedRoute;\n } else if (isSubRouteRef(resolvedRoute)) {\n targetRef = resolvedRoute.parent;\n subRoutePath = resolvedRoute.path;\n } else {\n throw new Error(\n `ExternalRouteRef was bound to invalid target, ${resolvedRoute}`,\n );\n }\n } else if (anyRouteRef[routeRefType]) {\n throw new Error(\n `Unknown or invalid route ref type, ${anyRouteRef[routeRefType]}`,\n );\n } else {\n throw new Error(`Unknown object passed to useRouteRef, got ${anyRouteRef}`);\n }\n\n // Bail if no absolute path could be resolved\n if (!targetRef) {\n return [undefined, ''];\n }\n\n // Find the path that our target route is bound to\n const resolvedPath = routePaths.get(targetRef);\n if (resolvedPath === undefined) {\n return [undefined, ''];\n }\n\n // SubRouteRefs join the path from the parent route with its own path\n const targetPath = joinPaths(resolvedPath, subRoutePath);\n return [targetRef, targetPath];\n}\n\n/**\n * Resolves the complete base path for navigating to the target RouteRef.\n */\nfunction resolveBasePath(\n targetRef: RouteRef,\n sourceLocation: Parameters<typeof matchRoutes>[1],\n routePaths: Map<RouteRef, string>,\n routeParents: Map<RouteRef, RouteRef | undefined>,\n routeObjects: BackstageRouteObject[],\n) {\n // While traversing the app element tree we build up the routeObjects structure\n // used here. It is the same kind of structure that react-router creates, with the\n // addition that associated route refs are stored throughout the tree. This lets\n // us look up all route refs that can be reached from our source location.\n // Because of the similar route object structure, we can use `matchRoutes` from\n // react-router to do the lookup of our current location.\n const match = matchRoutes(routeObjects, sourceLocation) ?? [];\n\n // While we search for a common routing root between our current location and\n // the target route, we build a list of all route refs we find that we need\n // to traverse to reach the target.\n const refDiffList = Array<RouteRef>();\n\n let matchIndex = -1;\n for (\n let targetSearchRef: RouteRef | undefined = targetRef;\n targetSearchRef;\n targetSearchRef = routeParents.get(targetSearchRef)\n ) {\n // The match contains a list of all ancestral route refs present at our current location\n // Starting at the desired target ref and traversing back through its parents, we search\n // for a target ref that is present in the match for our current location. When a match\n // is found it means we have found a common base to resolve the route from.\n matchIndex = match.findIndex(m =>\n (m.route as BackstageRouteObject).routeRefs.has(targetSearchRef!),\n );\n if (matchIndex !== -1) {\n break;\n }\n\n // Every time we move a step up in the ancestry of the target ref, we add the current ref\n // to the diff list, which ends up being the list of route refs to traverse form the common base\n // in order to reach our target.\n refDiffList.unshift(targetSearchRef);\n }\n\n // If our target route is present in the initial match we need to construct the final path\n // from the parent of the matched route segment. That's to allow the caller of the route\n // function to supply their own params.\n if (refDiffList.length === 0) {\n matchIndex -= 1;\n }\n\n // This is the part of the route tree that the target and source locations have in common.\n // We re-use the existing pathname directly along with all params.\n const parentPath = matchIndex === -1 ? '' : match[matchIndex].pathname;\n\n // This constructs the mid section of the path using paths resolved from all route refs\n // we need to traverse to reach our target except for the very last one. None of these\n // paths are allowed to require any parameters, as the caller would have no way of knowing\n // what parameters those are.\n const diffPaths = refDiffList.slice(0, -1).map(ref => {\n const path = routePaths.get(ref);\n if (path === undefined) {\n throw new Error(`No path for ${ref}`);\n }\n if (path.includes(':')) {\n throw new Error(\n `Cannot route to ${targetRef} with parent ${ref} as it has parameters`,\n );\n }\n return path;\n });\n\n return `${joinPaths(parentPath, ...diffPaths)}/`;\n}\n\nexport class RouteResolver {\n private readonly routePaths: Map<RouteRef, string>;\n private readonly routeParents: Map<RouteRef, RouteRef | undefined>;\n private readonly routeObjects: BackstageRouteObject[];\n private readonly routeBindings: Map<ExternalRouteRef, RouteRef | SubRouteRef>;\n private readonly appBasePath: string; // base path without a trailing slash\n\n constructor(\n routePaths: Map<RouteRef, string>,\n routeParents: Map<RouteRef, RouteRef | undefined>,\n routeObjects: BackstageRouteObject[],\n routeBindings: Map<ExternalRouteRef, RouteRef | SubRouteRef>,\n appBasePath: string, // base path without a trailing slash\n ) {\n this.routePaths = routePaths;\n this.routeParents = routeParents;\n this.routeObjects = routeObjects;\n this.routeBindings = routeBindings;\n this.appBasePath = appBasePath;\n }\n\n resolve<Params extends AnyParams>(\n anyRouteRef:\n | RouteRef<Params>\n | SubRouteRef<Params>\n | ExternalRouteRef<Params, any>,\n sourceLocation: Parameters<typeof matchRoutes>[1],\n ): RouteFunc<Params> | undefined {\n // First figure out what our target absolute ref is, as well as our target path.\n const [targetRef, targetPath] = resolveTargetRef(\n anyRouteRef,\n this.routePaths,\n this.routeBindings,\n );\n if (!targetRef) {\n return undefined;\n }\n\n // The location that we get passed in uses the full path, so start by trimming off\n // the app base path prefix in case we're running the app on a sub-path.\n let relativeSourceLocation: Parameters<typeof matchRoutes>[1];\n if (typeof sourceLocation === 'string') {\n relativeSourceLocation = this.trimPath(sourceLocation);\n } else if (sourceLocation.pathname) {\n relativeSourceLocation = {\n ...sourceLocation,\n pathname: this.trimPath(sourceLocation.pathname),\n };\n } else {\n relativeSourceLocation = sourceLocation;\n }\n\n // Next we figure out the base path, which is the combination of the common parent path\n // between our current location and our target location, as well as the additional path\n // that is the difference between the parent path and the base of our target location.\n const basePath =\n this.appBasePath +\n resolveBasePath(\n targetRef,\n relativeSourceLocation,\n this.routePaths,\n this.routeParents,\n this.routeObjects,\n );\n\n const routeFunc: RouteFunc<Params> = (...[params]) => {\n // We selectively encode some some known-dangerous characters in the\n // params. The reason that we don't perform a blanket `encodeURIComponent`\n // here is that this encoding was added defensively long after the initial\n // release of this code. There's likely to be many users of this code that\n // already encode their parameters knowing that this code didn't do this\n // for them in the past. Therefore, we are extra careful NOT to include\n // the percent character in this set, even though that might seem like a\n // bad idea.\n const encodedParams =\n params &&\n mapValues(params, value => {\n if (typeof value === 'string') {\n return value.replaceAll(/[&?#;\\/]/g, c => encodeURIComponent(c));\n }\n return value;\n });\n return joinPaths(basePath, generatePath(targetPath, encodedParams));\n };\n return routeFunc;\n }\n\n private trimPath(targetPath: string) {\n if (!targetPath) {\n return targetPath;\n }\n\n if (targetPath.startsWith(this.appBasePath)) {\n return targetPath.slice(this.appBasePath.length);\n }\n return targetPath;\n }\n}\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/core-app-api",
3
- "version": "1.19.1-next.0",
3
+ "version": "1.19.2-next.0",
4
4
  "description": "Core app API used by Backstage apps",
5
5
  "backstage": {
6
6
  "role": "web-library"
@@ -50,8 +50,8 @@
50
50
  "test": "backstage-cli package test"
51
51
  },
52
52
  "dependencies": {
53
- "@backstage/config": "1.3.4-next.0",
54
- "@backstage/core-plugin-api": "1.11.1-next.0",
53
+ "@backstage/config": "1.3.6-next.0",
54
+ "@backstage/core-plugin-api": "1.11.2-next.0",
55
55
  "@backstage/types": "1.2.2",
56
56
  "@backstage/version-bridge": "1.0.11",
57
57
  "@types/prop-types": "^15.7.3",
@@ -64,8 +64,8 @@
64
64
  "zod": "^3.22.4"
65
65
  },
66
66
  "devDependencies": {
67
- "@backstage/cli": "0.34.4-next.1",
68
- "@backstage/test-utils": "1.7.12-next.0",
67
+ "@backstage/cli": "0.34.5-next.0",
68
+ "@backstage/test-utils": "1.7.13-next.0",
69
69
  "@testing-library/dom": "^10.0.0",
70
70
  "@testing-library/jest-dom": "^6.0.0",
71
71
  "@testing-library/react": "^16.0.0",