@backstage/frontend-app-api 0.16.8-next.2 → 0.16.9-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.
Files changed (39) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/dist/catalog-model/src/entity/constants.esm.js.map +1 -1
  3. package/dist/catalog-model/src/entity/ref.esm.js +1 -3
  4. package/dist/catalog-model/src/entity/ref.esm.js.map +1 -1
  5. package/dist/core-app-api/src/apis/implementations/IdentityApi/AppIdentityProxy.esm.js.map +1 -1
  6. package/dist/core-app-api/src/apis/implementations/IdentityApi/startCookieAuthRefresh.esm.js.map +1 -1
  7. package/dist/extensions/Root.esm.js.map +1 -1
  8. package/dist/frontend-internal/src/apis/OpaqueApiRef.esm.js.map +1 -1
  9. package/dist/frontend-internal/src/routing/OpaqueExternalRouteRef.esm.js.map +1 -1
  10. package/dist/frontend-internal/src/routing/OpaqueRouteRef.esm.js.map +1 -1
  11. package/dist/frontend-internal/src/routing/OpaqueSubRouteRef.esm.js.map +1 -1
  12. package/dist/frontend-internal/src/wiring/InternalExtensionDefinition.esm.js.map +1 -1
  13. package/dist/frontend-internal/src/wiring/InternalExtensionInput.esm.js.map +1 -1
  14. package/dist/frontend-internal/src/wiring/InternalFrontendPlugin.esm.js.map +1 -1
  15. package/dist/frontend-internal/src/wiring/createExtensionDataContainer.esm.js.map +1 -1
  16. package/dist/frontend-plugin-api/src/wiring/createFrontendModule.esm.js.map +1 -1
  17. package/dist/frontend-plugin-api/src/wiring/resolveExtensionDefinition.esm.js.map +1 -1
  18. package/dist/opaque-internal/src/OpaqueType.esm.js.map +1 -1
  19. package/dist/routing/RouteAliasResolver.esm.js.map +1 -1
  20. package/dist/routing/RouteResolver.esm.js.map +1 -1
  21. package/dist/routing/collectRouteIds.esm.js.map +1 -1
  22. package/dist/routing/extractRouteInfoFromAppNode.esm.js.map +1 -1
  23. package/dist/routing/getBasePath.esm.js.map +1 -1
  24. package/dist/routing/joinPaths.esm.js.map +1 -1
  25. package/dist/routing/resolveRouteBindings.esm.js.map +1 -1
  26. package/dist/tree/instantiateAppNodeTree.esm.js.map +1 -1
  27. package/dist/tree/readAppExtensionsConfig.esm.js.map +1 -1
  28. package/dist/tree/resolveAppNodeSpecs.esm.js.map +1 -1
  29. package/dist/tree/resolveAppTree.esm.js.map +1 -1
  30. package/dist/wiring/FrontendApiRegistry.esm.js.map +1 -1
  31. package/dist/wiring/apiFactories.esm.js.map +1 -1
  32. package/dist/wiring/createErrorCollector.esm.js.map +1 -1
  33. package/dist/wiring/createPluginInfoAttacher.esm.js.map +1 -1
  34. package/dist/wiring/createSpecializedApp.esm.js.map +1 -1
  35. package/dist/wiring/phaseApis.esm.js.map +1 -1
  36. package/dist/wiring/predicates.esm.js.map +1 -1
  37. package/dist/wiring/prepareSpecializedApp.esm.js.map +1 -1
  38. package/dist/wiring/treeLifecycle.esm.js.map +1 -1
  39. package/package.json +13 -13
package/CHANGELOG.md CHANGED
@@ -1,5 +1,31 @@
1
1
  # @backstage/frontend-app-api
2
2
 
3
+ ## 0.16.9-next.0
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies
8
+ - @backstage/config@1.3.10-next.0
9
+ - @backstage/errors@1.3.2-next.0
10
+ - @backstage/core-app-api@1.20.6-next.0
11
+ - @backstage/core-plugin-api@1.12.11-next.0
12
+ - @backstage/filter-predicates@0.1.6-next.0
13
+ - @backstage/frontend-defaults@0.5.7-next.0
14
+ - @backstage/frontend-plugin-api@0.18.2-next.0
15
+
16
+ ## 0.16.8
17
+
18
+ ### Patch Changes
19
+
20
+ - 52022b9: Fixed `app.extensions` shorthand and `disabled` field to accept boolean-ish strings (`'true'`/`'false'`), so environment variable substitution can be used to toggle extensions, e.g. `${CATALOG_OVERVIEW_ENABLED}`.
21
+ - Updated dependencies
22
+ - @backstage/core-app-api@1.20.5
23
+ - @backstage/filter-predicates@0.1.5
24
+ - @backstage/config@1.3.9
25
+ - @backstage/frontend-plugin-api@0.18.1
26
+ - @backstage/core-plugin-api@1.12.10
27
+ - @backstage/frontend-defaults@0.5.6
28
+
3
29
  ## 0.16.8-next.2
4
30
 
5
31
  ### Patch Changes
@@ -1 +1 @@
1
- {"version":3,"file":"constants.esm.js","sources":["../../../../../catalog-model/src/entity/constants.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\n/**\n * The namespace that entities without an explicit namespace fall into.\n *\n * @public\n */\nexport const DEFAULT_NAMESPACE = 'default';\n\n/**\n * Annotation for linking to entity page from catalog pages.\n *\n * @public\n */\nexport const ANNOTATION_VIEW_URL = 'backstage.io/view-url';\n\n/**\n * Annotation for linking to entity edit page from catalog pages.\n *\n * @public\n */\nexport const ANNOTATION_EDIT_URL = 'backstage.io/edit-url';\n\n/**\n * Annotation for specifying the API server of a Kubernetes cluster\n *\n * @deprecated Import this constant from `@backstage/plugin-kubernetes-common` instead\n * @public\n */\nexport const ANNOTATION_KUBERNETES_API_SERVER = 'kubernetes.io/api-server';\n\n/**\n * Annotation for specifying the Certificate Authority of an API server for a Kubernetes cluster\n *\n * @deprecated Import this constant from `@backstage/plugin-kubernetes-common` instead\n * @public\n */\nexport const ANNOTATION_KUBERNETES_API_SERVER_CA =\n 'kubernetes.io/api-server-certificate-authority';\n\n/**\n * Annotation for specifying the auth provider for a Kubernetes cluster\n *\n * @deprecated Import this constant from `@backstage/plugin-kubernetes-common` instead\n * @public\n */\nexport const ANNOTATION_KUBERNETES_AUTH_PROVIDER =\n 'kubernetes.io/auth-provider';\n"],"names":[],"mappings":"AAqBO,MAAM,iBAAA,GAAoB;;;;"}
1
+ {"version":3,"file":"constants.esm.js","sources":["../../../../../catalog-model/src/entity/constants.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\n/**\n * The namespace that entities without an explicit namespace fall into.\n *\n * @public\n */\nexport const DEFAULT_NAMESPACE = 'default';\n\n/**\n * Annotation for linking to entity page from catalog pages.\n *\n * @public\n */\nexport const ANNOTATION_VIEW_URL = 'backstage.io/view-url';\n\n/**\n * Annotation for linking to entity edit page from catalog pages.\n *\n * @public\n */\nexport const ANNOTATION_EDIT_URL = 'backstage.io/edit-url';\n\n/**\n * Annotation for specifying the API server of a Kubernetes cluster\n *\n * @deprecated Import this constant from `@backstage/plugin-kubernetes-common` instead\n * @public\n */\nexport const ANNOTATION_KUBERNETES_API_SERVER = 'kubernetes.io/api-server';\n\n/**\n * Annotation for specifying the Certificate Authority of an API server for a Kubernetes cluster\n *\n * @deprecated Import this constant from `@backstage/plugin-kubernetes-common` instead\n * @public\n */\nexport const ANNOTATION_KUBERNETES_API_SERVER_CA =\n 'kubernetes.io/api-server-certificate-authority';\n\n/**\n * Annotation for specifying the auth provider for a Kubernetes cluster\n *\n * @deprecated Import this constant from `@backstage/plugin-kubernetes-common` instead\n * @public\n */\nexport const ANNOTATION_KUBERNETES_AUTH_PROVIDER =\n 'kubernetes.io/auth-provider';\n"],"names":[],"mappings":"AAqBO,MAAM,iBAAA,GAAoB;;"}
@@ -64,9 +64,7 @@ function stringifyEntityRef(ref) {
64
64
  namespace = ref.namespace ?? DEFAULT_NAMESPACE;
65
65
  name = ref.name;
66
66
  }
67
- return `${kind.toLocaleLowerCase("en-US")}:${namespace.toLocaleLowerCase(
68
- "en-US"
69
- )}/${name.toLocaleLowerCase("en-US")}`;
67
+ return `${kind.toLowerCase()}:${namespace.toLowerCase()}/${name.toLowerCase()}`;
70
68
  }
71
69
 
72
70
  export { parseEntityRef, stringifyEntityRef };
@@ -1 +1 @@
1
- {"version":3,"file":"ref.esm.js","sources":["../../../../../catalog-model/src/entity/ref.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 { DEFAULT_NAMESPACE } from './constants';\nimport { CompoundEntityRef } from '../types';\nimport { Entity } from './Entity';\n\nfunction parseRefString(ref: string): {\n kind?: string;\n namespace?: string;\n name: string;\n} {\n let colonI = ref.indexOf(':');\n const slashI = ref.indexOf('/');\n\n // If the / is ahead of the :, treat the rest as the name\n if (slashI !== -1 && slashI < colonI) {\n colonI = -1;\n }\n\n const kind = colonI === -1 ? undefined : ref.slice(0, colonI);\n const namespace = slashI === -1 ? undefined : ref.slice(colonI + 1, slashI);\n const name = ref.slice(Math.max(colonI + 1, slashI + 1));\n\n if (kind === '' || namespace === '' || name === '') {\n throw new TypeError(\n `Entity reference \"${ref}\" was not on the form [<kind>:][<namespace>/]<name>`,\n );\n }\n\n return { kind, namespace, name };\n}\n\n/**\n * Extracts the kind, namespace and name that form the compound entity ref\n * triplet of the given entity.\n *\n * @public\n * @param entity - An entity\n * @returns The compound entity ref\n */\nexport function getCompoundEntityRef(entity: Entity): CompoundEntityRef {\n return {\n kind: entity.kind,\n namespace: entity.metadata.namespace || DEFAULT_NAMESPACE,\n name: entity.metadata.name,\n };\n}\n\n/**\n * Parses an entity reference, either on string or compound form, and returns\n * a structure with a name, and optional kind and namespace.\n *\n * @remarks\n *\n * The context object can contain default values for the kind and namespace,\n * that will be used if the input reference did not specify any.\n *\n * @public\n * @param ref - The reference to parse\n * @param context - The context of defaults that the parsing happens within\n * @returns The compound form of the reference\n */\nexport function parseEntityRef(\n ref: string | { kind?: string; namespace?: string; name: string },\n context?: {\n /** The default kind, if none is given in the reference */\n defaultKind?: string;\n /** The default namespace, if none is given in the reference */\n defaultNamespace?: string;\n },\n): CompoundEntityRef {\n if (!ref) {\n throw new Error(`Entity reference must not be empty`);\n }\n\n const defaultKind = context?.defaultKind;\n const defaultNamespace = context?.defaultNamespace || DEFAULT_NAMESPACE;\n\n let kind: string | undefined;\n let namespace: string | undefined;\n let name: string | undefined;\n\n if (typeof ref === 'string') {\n const parsed = parseRefString(ref);\n kind = parsed.kind ?? defaultKind;\n namespace = parsed.namespace ?? defaultNamespace;\n name = parsed.name;\n } else {\n kind = ref.kind ?? defaultKind;\n namespace = ref.namespace ?? defaultNamespace;\n name = ref.name;\n }\n\n if (!kind) {\n const textual = JSON.stringify(ref);\n throw new Error(\n `Entity reference ${textual} had missing or empty kind (e.g. did not start with \"component:\" or similar)`,\n );\n } else if (!namespace) {\n const textual = JSON.stringify(ref);\n throw new Error(\n `Entity reference ${textual} had missing or empty namespace`,\n );\n } else if (!name) {\n const textual = JSON.stringify(ref);\n throw new Error(`Entity reference ${textual} had missing or empty name`);\n }\n\n return { kind, namespace, name };\n}\n\n/**\n * Takes an entity or entity name/reference, and returns the string form of an\n * entity ref.\n *\n * @remarks\n *\n * This function creates a canonical and unique reference to the entity, converting\n * all parts of the name to lowercase and inserts the default namespace if needed.\n * It is typically not the best way to represent the entity reference to the user.\n *\n * @public\n * @param ref - The reference to serialize\n * @returns The same reference on either string or compound form\n */\nexport function stringifyEntityRef(\n ref: Entity | { kind: string; namespace?: string; name: string },\n): string {\n let kind;\n let namespace;\n let name;\n\n if ('metadata' in ref) {\n kind = ref.kind;\n namespace = ref.metadata.namespace ?? DEFAULT_NAMESPACE;\n name = ref.metadata.name;\n } else {\n kind = ref.kind;\n namespace = ref.namespace ?? DEFAULT_NAMESPACE;\n name = ref.name;\n }\n\n return `${kind.toLocaleLowerCase('en-US')}:${namespace.toLocaleLowerCase(\n 'en-US',\n )}/${name.toLocaleLowerCase('en-US')}`;\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ref.esm.js","sources":["../../../../../catalog-model/src/entity/ref.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 { DEFAULT_NAMESPACE } from './constants';\nimport { CompoundEntityRef } from '../types';\nimport { Entity } from './Entity';\n\nfunction parseRefString(ref: string): {\n kind?: string;\n namespace?: string;\n name: string;\n} {\n let colonI = ref.indexOf(':');\n const slashI = ref.indexOf('/');\n\n // If the / is ahead of the :, treat the rest as the name\n if (slashI !== -1 && slashI < colonI) {\n colonI = -1;\n }\n\n const kind = colonI === -1 ? undefined : ref.slice(0, colonI);\n const namespace = slashI === -1 ? undefined : ref.slice(colonI + 1, slashI);\n const name = ref.slice(Math.max(colonI + 1, slashI + 1));\n\n if (kind === '' || namespace === '' || name === '') {\n throw new TypeError(\n `Entity reference \"${ref}\" was not on the form [<kind>:][<namespace>/]<name>`,\n );\n }\n\n return { kind, namespace, name };\n}\n\n/**\n * Extracts the kind, namespace and name that form the compound entity ref\n * triplet of the given entity.\n *\n * @public\n * @param entity - An entity\n * @returns The compound entity ref\n */\nexport function getCompoundEntityRef(entity: Entity): CompoundEntityRef {\n return {\n kind: entity.kind,\n namespace: entity.metadata.namespace || DEFAULT_NAMESPACE,\n name: entity.metadata.name,\n };\n}\n\n/**\n * Parses an entity reference, either on string or compound form, and returns\n * a structure with a name, and optional kind and namespace.\n *\n * @remarks\n *\n * The context object can contain default values for the kind and namespace,\n * that will be used if the input reference did not specify any.\n *\n * @public\n * @param ref - The reference to parse\n * @param context - The context of defaults that the parsing happens within\n * @returns The compound form of the reference\n */\nexport function parseEntityRef(\n ref: string | { kind?: string; namespace?: string; name: string },\n context?: {\n /** The default kind, if none is given in the reference */\n defaultKind?: string;\n /** The default namespace, if none is given in the reference */\n defaultNamespace?: string;\n },\n): CompoundEntityRef {\n if (!ref) {\n throw new Error(`Entity reference must not be empty`);\n }\n\n const defaultKind = context?.defaultKind;\n const defaultNamespace = context?.defaultNamespace || DEFAULT_NAMESPACE;\n\n let kind: string | undefined;\n let namespace: string | undefined;\n let name: string | undefined;\n\n if (typeof ref === 'string') {\n const parsed = parseRefString(ref);\n kind = parsed.kind ?? defaultKind;\n namespace = parsed.namespace ?? defaultNamespace;\n name = parsed.name;\n } else {\n kind = ref.kind ?? defaultKind;\n namespace = ref.namespace ?? defaultNamespace;\n name = ref.name;\n }\n\n if (!kind) {\n const textual = JSON.stringify(ref);\n throw new Error(\n `Entity reference ${textual} had missing or empty kind (e.g. did not start with \"component:\" or similar)`,\n );\n } else if (!namespace) {\n const textual = JSON.stringify(ref);\n throw new Error(\n `Entity reference ${textual} had missing or empty namespace`,\n );\n } else if (!name) {\n const textual = JSON.stringify(ref);\n throw new Error(`Entity reference ${textual} had missing or empty name`);\n }\n\n return { kind, namespace, name };\n}\n\n/**\n * Takes an entity or entity name/reference, and returns the string form of an\n * entity ref.\n *\n * @remarks\n *\n * This function creates a canonical and unique reference to the entity, converting\n * all parts of the name to lowercase and inserts the default namespace if needed.\n * It is typically not the best way to represent the entity reference to the user.\n *\n * @public\n * @param ref - The reference to serialize\n * @returns The same reference on either string or compound form\n */\nexport function stringifyEntityRef(\n ref: Entity | { kind: string; namespace?: string; name: string },\n): string {\n let kind;\n let namespace;\n let name;\n\n if ('metadata' in ref) {\n kind = ref.kind;\n namespace = ref.metadata.namespace ?? DEFAULT_NAMESPACE;\n name = ref.metadata.name;\n } else {\n kind = ref.kind;\n namespace = ref.namespace ?? DEFAULT_NAMESPACE;\n name = ref.name;\n }\n\n return `${kind.toLowerCase()}:${namespace.toLowerCase()}/${name.toLowerCase()}`;\n}\n"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"AppIdentityProxy.esm.js","sources":["../../../../../../../core-app-api/src/apis/implementations/IdentityApi/AppIdentityProxy.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 IdentityApi,\n ProfileInfo,\n BackstageUserIdentity,\n ErrorApi,\n DiscoveryApi,\n FetchApi,\n} from '@backstage/core-plugin-api';\nimport { startCookieAuthRefresh } from './startCookieAuthRefresh';\n\nfunction mkError(thing: string) {\n return new Error(\n `Tried to access IdentityApi ${thing} before app was loaded`,\n );\n}\n\nfunction logDeprecation(thing: string) {\n // eslint-disable-next-line no-console\n console.warn(\n `WARNING: Call to ${thing} is deprecated and will break in the future`,\n );\n}\n\n// We use this for a period of backwards compatibility. It is a hidden\n// compatibility that will allow old plugins to continue working for a limited time.\ntype CompatibilityIdentityApi = IdentityApi & {\n getUserId?(): string;\n getIdToken?(): Promise<string | undefined>;\n getProfile?(): ProfileInfo;\n};\n\n/**\n * Implementation of the connection between the App-wide IdentityApi\n * and sign-in page.\n */\nexport class AppIdentityProxy implements IdentityApi {\n private target?: CompatibilityIdentityApi;\n private waitForTarget: Promise<CompatibilityIdentityApi>;\n private resolveTarget: (api: CompatibilityIdentityApi) => void = () => {};\n private signOutTargetUrl = '/';\n\n #cookieAuthSignOut?: () => Promise<void>;\n\n constructor() {\n this.waitForTarget = new Promise<CompatibilityIdentityApi>(resolve => {\n this.resolveTarget = resolve;\n });\n }\n\n // This is called by the app manager once the sign-in page provides us with an implementation\n setTarget(\n identityApi: CompatibilityIdentityApi,\n targetOptions: { signOutTargetUrl: string },\n ) {\n if (this.target) {\n return;\n }\n this.target = identityApi;\n this.signOutTargetUrl = targetOptions.signOutTargetUrl;\n this.resolveTarget(identityApi);\n }\n\n isTargetSet(): boolean {\n return Boolean(this.target);\n }\n\n getUserId(): string {\n if (!this.target) {\n throw mkError('getUserId');\n }\n if (!this.target.getUserId) {\n throw new Error('IdentityApi does not implement getUserId');\n }\n logDeprecation('getUserId');\n return this.target.getUserId();\n }\n\n getProfile(): ProfileInfo {\n if (!this.target) {\n throw mkError('getProfile');\n }\n if (!this.target.getProfile) {\n throw new Error('IdentityApi does not implement getProfile');\n }\n logDeprecation('getProfile');\n return this.target.getProfile();\n }\n\n async getProfileInfo(): Promise<ProfileInfo> {\n return this.waitForTarget.then(target => target.getProfileInfo());\n }\n\n async getBackstageIdentity(): Promise<BackstageUserIdentity> {\n const identity = await this.waitForTarget.then(target =>\n target.getBackstageIdentity(),\n );\n if (!identity.userEntityRef.match(/^.*:.*\\/.*$/)) {\n // eslint-disable-next-line no-console\n console.warn(\n `WARNING: The App IdentityApi provided an invalid userEntityRef, '${identity.userEntityRef}'. ` +\n `It must be a full Entity Reference of the form '<kind>:<namespace>/<name>'.`,\n );\n }\n\n return identity;\n }\n\n async getCredentials(): Promise<{ token?: string | undefined }> {\n return this.waitForTarget.then(target => target.getCredentials());\n }\n\n async getIdToken(): Promise<string | undefined> {\n return this.waitForTarget.then(target => {\n if (!target.getIdToken) {\n throw new Error('IdentityApi does not implement getIdToken');\n }\n logDeprecation('getIdToken');\n return target.getIdToken();\n });\n }\n\n async signOut(): Promise<void> {\n await this.waitForTarget.then(target => target.signOut());\n\n await this.#cookieAuthSignOut?.();\n\n this.navigateToUrl(this.signOutTargetUrl);\n }\n\n private navigateToUrl(url: string): void {\n window.location.href = url;\n }\n\n enableCookieAuth(ctx: {\n errorApi: ErrorApi;\n fetchApi: FetchApi;\n discoveryApi: DiscoveryApi;\n }) {\n if (this.#cookieAuthSignOut) {\n return;\n }\n\n const stopRefresh = startCookieAuthRefresh(ctx);\n\n this.#cookieAuthSignOut = async () => {\n stopRefresh();\n\n // It is fine if we do NOT worry yet about deleting cookies for OTHER backends like techdocs\n const appBaseUrl = await ctx.discoveryApi.getBaseUrl('app');\n try {\n await fetch(`${appBaseUrl}/.backstage/auth/v1/cookie`, {\n method: 'DELETE',\n credentials: 'include',\n });\n } catch {\n // Ignore the error for those who use static serving of the frontend\n }\n };\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"AppIdentityProxy.esm.js","sources":["../../../../../../../core-app-api/src/apis/implementations/IdentityApi/AppIdentityProxy.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 IdentityApi,\n ProfileInfo,\n BackstageUserIdentity,\n ErrorApi,\n DiscoveryApi,\n FetchApi,\n} from '@backstage/core-plugin-api';\nimport { startCookieAuthRefresh } from './startCookieAuthRefresh';\n\nfunction mkError(thing: string) {\n return new Error(\n `Tried to access IdentityApi ${thing} before app was loaded`,\n );\n}\n\nfunction logDeprecation(thing: string) {\n // eslint-disable-next-line no-console\n console.warn(\n `WARNING: Call to ${thing} is deprecated and will break in the future`,\n );\n}\n\n// We use this for a period of backwards compatibility. It is a hidden\n// compatibility that will allow old plugins to continue working for a limited time.\ntype CompatibilityIdentityApi = IdentityApi & {\n getUserId?(): string;\n getIdToken?(): Promise<string | undefined>;\n getProfile?(): ProfileInfo;\n};\n\n/**\n * Implementation of the connection between the App-wide IdentityApi\n * and sign-in page.\n */\nexport class AppIdentityProxy implements IdentityApi {\n private target?: CompatibilityIdentityApi;\n private waitForTarget: Promise<CompatibilityIdentityApi>;\n private resolveTarget: (api: CompatibilityIdentityApi) => void = () => {};\n private signOutTargetUrl = '/';\n\n #cookieAuthSignOut?: () => Promise<void>;\n\n constructor() {\n this.waitForTarget = new Promise<CompatibilityIdentityApi>(resolve => {\n this.resolveTarget = resolve;\n });\n }\n\n // This is called by the app manager once the sign-in page provides us with an implementation\n setTarget(\n identityApi: CompatibilityIdentityApi,\n targetOptions: { signOutTargetUrl: string },\n ) {\n if (this.target) {\n return;\n }\n this.target = identityApi;\n this.signOutTargetUrl = targetOptions.signOutTargetUrl;\n this.resolveTarget(identityApi);\n }\n\n isTargetSet(): boolean {\n return Boolean(this.target);\n }\n\n getUserId(): string {\n if (!this.target) {\n throw mkError('getUserId');\n }\n if (!this.target.getUserId) {\n throw new Error('IdentityApi does not implement getUserId');\n }\n logDeprecation('getUserId');\n return this.target.getUserId();\n }\n\n getProfile(): ProfileInfo {\n if (!this.target) {\n throw mkError('getProfile');\n }\n if (!this.target.getProfile) {\n throw new Error('IdentityApi does not implement getProfile');\n }\n logDeprecation('getProfile');\n return this.target.getProfile();\n }\n\n async getProfileInfo(): Promise<ProfileInfo> {\n return this.waitForTarget.then(target => target.getProfileInfo());\n }\n\n async getBackstageIdentity(): Promise<BackstageUserIdentity> {\n const identity = await this.waitForTarget.then(target =>\n target.getBackstageIdentity(),\n );\n if (!identity.userEntityRef.match(/^.*:.*\\/.*$/)) {\n // eslint-disable-next-line no-console\n console.warn(\n `WARNING: The App IdentityApi provided an invalid userEntityRef, '${identity.userEntityRef}'. ` +\n `It must be a full Entity Reference of the form '<kind>:<namespace>/<name>'.`,\n );\n }\n\n return identity;\n }\n\n async getCredentials(): Promise<{ token?: string | undefined }> {\n return this.waitForTarget.then(target => target.getCredentials());\n }\n\n async getIdToken(): Promise<string | undefined> {\n return this.waitForTarget.then(target => {\n if (!target.getIdToken) {\n throw new Error('IdentityApi does not implement getIdToken');\n }\n logDeprecation('getIdToken');\n return target.getIdToken();\n });\n }\n\n async signOut(): Promise<void> {\n await this.waitForTarget.then(target => target.signOut());\n\n await this.#cookieAuthSignOut?.();\n\n this.navigateToUrl(this.signOutTargetUrl);\n }\n\n private navigateToUrl(url: string): void {\n window.location.href = url;\n }\n\n enableCookieAuth(ctx: {\n errorApi: ErrorApi;\n fetchApi: FetchApi;\n discoveryApi: DiscoveryApi;\n }) {\n if (this.#cookieAuthSignOut) {\n return;\n }\n\n const stopRefresh = startCookieAuthRefresh(ctx);\n\n this.#cookieAuthSignOut = async () => {\n stopRefresh();\n\n // It is fine if we do NOT worry yet about deleting cookies for OTHER backends like techdocs\n const appBaseUrl = await ctx.discoveryApi.getBaseUrl('app');\n try {\n await fetch(`${appBaseUrl}/.backstage/auth/v1/cookie`, {\n method: 'DELETE',\n credentials: 'include',\n });\n } catch {\n // Ignore the error for those who use static serving of the frontend\n }\n };\n }\n}\n"],"names":[],"mappings":";;AA0BA,SAAS,QAAQ,KAAA,EAAe;AAC9B,EAAA,OAAO,IAAI,KAAA;AAAA,IACT,+BAA+B,KAAK,CAAA,sBAAA;AAAA,GACtC;AACF;AAEA,SAAS,eAAe,KAAA,EAAe;AAErC,EAAA,OAAA,CAAQ,IAAA;AAAA,IACN,oBAAoB,KAAK,CAAA,2CAAA;AAAA,GAC3B;AACF;AAcO,MAAM,gBAAA,CAAwC;AAAA,EAC3C,MAAA;AAAA,EACA,aAAA;AAAA,EACA,gBAAyD,MAAM;AAAA,EAAC,CAAA;AAAA,EAChE,gBAAA,GAAmB,GAAA;AAAA,EAE3B,kBAAA;AAAA,EAEA,WAAA,GAAc;AACZ,IAAA,IAAA,CAAK,aAAA,GAAgB,IAAI,OAAA,CAAkC,CAAA,OAAA,KAAW;AACpE,MAAA,IAAA,CAAK,aAAA,GAAgB,OAAA;AAAA,IACvB,CAAC,CAAA;AAAA,EACH;AAAA;AAAA,EAGA,SAAA,CACE,aACA,aAAA,EACA;AACA,IAAA,IAAI,KAAK,MAAA,EAAQ;AACf,MAAA;AAAA,IACF;AACA,IAAA,IAAA,CAAK,MAAA,GAAS,WAAA;AACd,IAAA,IAAA,CAAK,mBAAmB,aAAA,CAAc,gBAAA;AACtC,IAAA,IAAA,CAAK,cAAc,WAAW,CAAA;AAAA,EAChC;AAAA,EAEA,WAAA,GAAuB;AACrB,IAAA,OAAO,OAAA,CAAQ,KAAK,MAAM,CAAA;AAAA,EAC5B;AAAA,EAEA,SAAA,GAAoB;AAClB,IAAA,IAAI,CAAC,KAAK,MAAA,EAAQ;AAChB,MAAA,MAAM,QAAQ,WAAW,CAAA;AAAA,IAC3B;AACA,IAAA,IAAI,CAAC,IAAA,CAAK,MAAA,CAAO,SAAA,EAAW;AAC1B,MAAA,MAAM,IAAI,MAAM,0CAA0C,CAAA;AAAA,IAC5D;AACA,IAAA,cAAA,CAAe,WAAW,CAAA;AAC1B,IAAA,OAAO,IAAA,CAAK,OAAO,SAAA,EAAU;AAAA,EAC/B;AAAA,EAEA,UAAA,GAA0B;AACxB,IAAA,IAAI,CAAC,KAAK,MAAA,EAAQ;AAChB,MAAA,MAAM,QAAQ,YAAY,CAAA;AAAA,IAC5B;AACA,IAAA,IAAI,CAAC,IAAA,CAAK,MAAA,CAAO,UAAA,EAAY;AAC3B,MAAA,MAAM,IAAI,MAAM,2CAA2C,CAAA;AAAA,IAC7D;AACA,IAAA,cAAA,CAAe,YAAY,CAAA;AAC3B,IAAA,OAAO,IAAA,CAAK,OAAO,UAAA,EAAW;AAAA,EAChC;AAAA,EAEA,MAAM,cAAA,GAAuC;AAC3C,IAAA,OAAO,KAAK,aAAA,CAAc,IAAA,CAAK,CAAA,MAAA,KAAU,MAAA,CAAO,gBAAgB,CAAA;AAAA,EAClE;AAAA,EAEA,MAAM,oBAAA,GAAuD;AAC3D,IAAA,MAAM,QAAA,GAAW,MAAM,IAAA,CAAK,aAAA,CAAc,IAAA;AAAA,MAAK,CAAA,MAAA,KAC7C,OAAO,oBAAA;AAAqB,KAC9B;AACA,IAAA,IAAI,CAAC,QAAA,CAAS,aAAA,CAAc,KAAA,CAAM,aAAa,CAAA,EAAG;AAEhD,MAAA,OAAA,CAAQ,IAAA;AAAA,QACN,CAAA,iEAAA,EAAoE,SAAS,aAAa,CAAA,8EAAA;AAAA,OAE5F;AAAA,IACF;AAEA,IAAA,OAAO,QAAA;AAAA,EACT;AAAA,EAEA,MAAM,cAAA,GAA0D;AAC9D,IAAA,OAAO,KAAK,aAAA,CAAc,IAAA,CAAK,CAAA,MAAA,KAAU,MAAA,CAAO,gBAAgB,CAAA;AAAA,EAClE;AAAA,EAEA,MAAM,UAAA,GAA0C;AAC9C,IAAA,OAAO,IAAA,CAAK,aAAA,CAAc,IAAA,CAAK,CAAA,MAAA,KAAU;AACvC,MAAA,IAAI,CAAC,OAAO,UAAA,EAAY;AACtB,QAAA,MAAM,IAAI,MAAM,2CAA2C,CAAA;AAAA,MAC7D;AACA,MAAA,cAAA,CAAe,YAAY,CAAA;AAC3B,MAAA,OAAO,OAAO,UAAA,EAAW;AAAA,IAC3B,CAAC,CAAA;AAAA,EACH;AAAA,EAEA,MAAM,OAAA,GAAyB;AAC7B,IAAA,MAAM,KAAK,aAAA,CAAc,IAAA,CAAK,CAAA,MAAA,KAAU,MAAA,CAAO,SAAS,CAAA;AAExD,IAAA,MAAM,KAAK,kBAAA,IAAqB;AAEhC,IAAA,IAAA,CAAK,aAAA,CAAc,KAAK,gBAAgB,CAAA;AAAA,EAC1C;AAAA,EAEQ,cAAc,GAAA,EAAmB;AACvC,IAAA,MAAA,CAAO,SAAS,IAAA,GAAO,GAAA;AAAA,EACzB;AAAA,EAEA,iBAAiB,GAAA,EAId;AACD,IAAA,IAAI,KAAK,kBAAA,EAAoB;AAC3B,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,WAAA,GAAc,uBAAuB,GAAG,CAAA;AAE9C,IAAA,IAAA,CAAK,qBAAqB,YAAY;AACpC,MAAA,WAAA,EAAY;AAGZ,MAAA,MAAM,UAAA,GAAa,MAAM,GAAA,CAAI,YAAA,CAAa,WAAW,KAAK,CAAA;AAC1D,MAAA,IAAI;AACF,QAAA,MAAM,KAAA,CAAM,CAAA,EAAG,UAAU,CAAA,0BAAA,CAAA,EAA8B;AAAA,UACrD,MAAA,EAAQ,QAAA;AAAA,UACR,WAAA,EAAa;AAAA,SACd,CAAA;AAAA,MACH,CAAA,CAAA,MAAQ;AAAA,MAER;AAAA,IACF,CAAA;AAAA,EACF;AACF;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"startCookieAuthRefresh.esm.js","sources":["../../../../../../../core-app-api/src/apis/implementations/IdentityApi/startCookieAuthRefresh.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 */\n\nimport { DiscoveryApi, ErrorApi, FetchApi } from '@backstage/core-plugin-api';\n\nconst PLUGIN_ID = 'app';\nconst CHANNEL_ID = `${PLUGIN_ID}-auth-cookie-expires-at`;\n\nconst MIN_BASE_DELAY_MS = 5 * 60_000;\n\nconst ERROR_BACKOFF_START = 5_000;\nconst ERROR_BACKOFF_FACTOR = 2;\nconst ERROR_BACKOFF_MAX = 5 * 60_000;\n\n// Messaging implementation and IDs must match\n// plugins/auth-react/src/hooks/useCookieAuthRefresh/useCookieAuthRefresh.tsx\nexport function startCookieAuthRefresh({\n discoveryApi,\n fetchApi,\n errorApi,\n}: {\n discoveryApi: DiscoveryApi;\n fetchApi: FetchApi;\n errorApi: ErrorApi;\n}) {\n let stopped = false;\n let timeout: NodeJS.Timeout | undefined;\n let firstError = true;\n let errorBackoff = ERROR_BACKOFF_START;\n\n const channel =\n 'BroadcastChannel' in window ? new BroadcastChannel(CHANNEL_ID) : undefined;\n\n // Randomize the refreshing margin with a margin of 1-4 minutes to avoid all tabs refreshing at the same time\n const getDelay = (expiresAt: number) => {\n const margin = (1 + 3 * Math.random()) * 60000;\n const delay = Math.max(expiresAt - Date.now(), MIN_BASE_DELAY_MS) - margin;\n return delay;\n };\n\n const refresh = async () => {\n try {\n const baseUrl = await discoveryApi.getBaseUrl(PLUGIN_ID);\n const requestUrl = `${baseUrl}/.backstage/auth/v1/cookie`;\n const res = await fetchApi.fetch(requestUrl, {\n credentials: 'include',\n });\n\n if (!res.ok) {\n throw new Error(\n `Request failed with status ${res.status} ${res.statusText}, see request towards ${requestUrl} for more details`,\n );\n }\n\n const data = await res.json();\n if (!data.expiresAt) {\n throw new Error('No expiration date in response');\n }\n\n const expiresAt = Date.parse(data.expiresAt);\n if (Number.isNaN(expiresAt)) {\n throw new Error('Invalid expiration date in response');\n }\n\n firstError = true;\n\n channel?.postMessage({\n action: 'COOKIE_REFRESH_SUCCESS',\n payload: { expiresAt: new Date(expiresAt).toISOString() },\n });\n\n scheduleRefresh(getDelay(expiresAt));\n } catch (error) {\n // Ignore the first error after successful requests\n if (firstError) {\n firstError = false;\n errorBackoff = ERROR_BACKOFF_START;\n } else {\n errorBackoff = Math.min(\n ERROR_BACKOFF_MAX,\n errorBackoff * ERROR_BACKOFF_FACTOR,\n );\n // eslint-disable-next-line no-console\n console.error('Session cookie refresh failed', error);\n errorApi.post(\n new Error(\n `Session refresh failed, see developer console for details`,\n ),\n );\n }\n\n scheduleRefresh(errorBackoff);\n }\n };\n\n const onMessage = (\n event: MessageEvent<\n | {\n action: 'COOKIE_REFRESH_SUCCESS';\n payload: { expiresAt: string };\n }\n | object\n >,\n ) => {\n const { data } = event;\n if (data === null || typeof data !== 'object') {\n return;\n }\n if ('action' in data && data.action === 'COOKIE_REFRESH_SUCCESS') {\n const expiresAt = Date.parse(data.payload.expiresAt);\n if (Number.isNaN(expiresAt)) {\n // eslint-disable-next-line no-console\n console.warn(\n 'Received invalid expiration from session refresh channel',\n );\n return;\n }\n\n scheduleRefresh(getDelay(expiresAt));\n }\n };\n\n function scheduleRefresh(delayMs: number) {\n if (stopped) {\n return;\n }\n if (timeout) {\n clearTimeout(timeout);\n }\n timeout = setTimeout(refresh, delayMs);\n }\n\n channel?.addEventListener('message', onMessage);\n refresh();\n\n return () => {\n stopped = true;\n if (timeout) {\n clearTimeout(timeout);\n }\n channel?.removeEventListener('message', onMessage);\n channel?.close();\n };\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"startCookieAuthRefresh.esm.js","sources":["../../../../../../../core-app-api/src/apis/implementations/IdentityApi/startCookieAuthRefresh.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 */\n\nimport { DiscoveryApi, ErrorApi, FetchApi } from '@backstage/core-plugin-api';\n\nconst PLUGIN_ID = 'app';\nconst CHANNEL_ID = `${PLUGIN_ID}-auth-cookie-expires-at`;\n\nconst MIN_BASE_DELAY_MS = 5 * 60_000;\n\nconst ERROR_BACKOFF_START = 5_000;\nconst ERROR_BACKOFF_FACTOR = 2;\nconst ERROR_BACKOFF_MAX = 5 * 60_000;\n\n// Messaging implementation and IDs must match\n// plugins/auth-react/src/hooks/useCookieAuthRefresh/useCookieAuthRefresh.tsx\nexport function startCookieAuthRefresh({\n discoveryApi,\n fetchApi,\n errorApi,\n}: {\n discoveryApi: DiscoveryApi;\n fetchApi: FetchApi;\n errorApi: ErrorApi;\n}) {\n let stopped = false;\n let timeout: NodeJS.Timeout | undefined;\n let firstError = true;\n let errorBackoff = ERROR_BACKOFF_START;\n\n const channel =\n 'BroadcastChannel' in window ? new BroadcastChannel(CHANNEL_ID) : undefined;\n\n // Randomize the refreshing margin with a margin of 1-4 minutes to avoid all tabs refreshing at the same time\n const getDelay = (expiresAt: number) => {\n const margin = (1 + 3 * Math.random()) * 60000;\n const delay = Math.max(expiresAt - Date.now(), MIN_BASE_DELAY_MS) - margin;\n return delay;\n };\n\n const refresh = async () => {\n try {\n const baseUrl = await discoveryApi.getBaseUrl(PLUGIN_ID);\n const requestUrl = `${baseUrl}/.backstage/auth/v1/cookie`;\n const res = await fetchApi.fetch(requestUrl, {\n credentials: 'include',\n });\n\n if (!res.ok) {\n throw new Error(\n `Request failed with status ${res.status} ${res.statusText}, see request towards ${requestUrl} for more details`,\n );\n }\n\n const data = await res.json();\n if (!data.expiresAt) {\n throw new Error('No expiration date in response');\n }\n\n const expiresAt = Date.parse(data.expiresAt);\n if (Number.isNaN(expiresAt)) {\n throw new Error('Invalid expiration date in response');\n }\n\n firstError = true;\n\n channel?.postMessage({\n action: 'COOKIE_REFRESH_SUCCESS',\n payload: { expiresAt: new Date(expiresAt).toISOString() },\n });\n\n scheduleRefresh(getDelay(expiresAt));\n } catch (error) {\n // Ignore the first error after successful requests\n if (firstError) {\n firstError = false;\n errorBackoff = ERROR_BACKOFF_START;\n } else {\n errorBackoff = Math.min(\n ERROR_BACKOFF_MAX,\n errorBackoff * ERROR_BACKOFF_FACTOR,\n );\n // eslint-disable-next-line no-console\n console.error('Session cookie refresh failed', error);\n errorApi.post(\n new Error(\n `Session refresh failed, see developer console for details`,\n ),\n );\n }\n\n scheduleRefresh(errorBackoff);\n }\n };\n\n const onMessage = (\n event: MessageEvent<\n | {\n action: 'COOKIE_REFRESH_SUCCESS';\n payload: { expiresAt: string };\n }\n | object\n >,\n ) => {\n const { data } = event;\n if (data === null || typeof data !== 'object') {\n return;\n }\n if ('action' in data && data.action === 'COOKIE_REFRESH_SUCCESS') {\n const expiresAt = Date.parse(data.payload.expiresAt);\n if (Number.isNaN(expiresAt)) {\n // eslint-disable-next-line no-console\n console.warn(\n 'Received invalid expiration from session refresh channel',\n );\n return;\n }\n\n scheduleRefresh(getDelay(expiresAt));\n }\n };\n\n function scheduleRefresh(delayMs: number) {\n if (stopped) {\n return;\n }\n if (timeout) {\n clearTimeout(timeout);\n }\n timeout = setTimeout(refresh, delayMs);\n }\n\n channel?.addEventListener('message', onMessage);\n refresh();\n\n return () => {\n stopped = true;\n if (timeout) {\n clearTimeout(timeout);\n }\n channel?.removeEventListener('message', onMessage);\n channel?.close();\n };\n}\n"],"names":[],"mappings":"AAkBA,MAAM,SAAA,GAAY,KAAA;AAClB,MAAM,UAAA,GAAa,GAAG,SAAS,CAAA,uBAAA,CAAA;AAE/B,MAAM,oBAAoB,CAAA,GAAI,GAAA;AAE9B,MAAM,mBAAA,GAAsB,GAAA;AAC5B,MAAM,oBAAA,GAAuB,CAAA;AAC7B,MAAM,oBAAoB,CAAA,GAAI,GAAA;AAIvB,SAAS,sBAAA,CAAuB;AAAA,EACrC,YAAA;AAAA,EACA,QAAA;AAAA,EACA;AACF,CAAA,EAIG;AACD,EAAA,IAAI,OAAA,GAAU,KAAA;AACd,EAAA,IAAI,OAAA;AACJ,EAAA,IAAI,UAAA,GAAa,IAAA;AACjB,EAAA,IAAI,YAAA,GAAe,mBAAA;AAEnB,EAAA,MAAM,UACJ,kBAAA,IAAsB,MAAA,GAAS,IAAI,gBAAA,CAAiB,UAAU,CAAA,GAAI,MAAA;AAGpE,EAAA,MAAM,QAAA,GAAW,CAAC,SAAA,KAAsB;AACtC,IAAA,MAAM,MAAA,GAAA,CAAU,CAAA,GAAI,CAAA,GAAI,IAAA,CAAK,QAAO,IAAK,GAAA;AACzC,IAAA,MAAM,KAAA,GAAQ,KAAK,GAAA,CAAI,SAAA,GAAY,KAAK,GAAA,EAAI,EAAG,iBAAiB,CAAA,GAAI,MAAA;AACpE,IAAA,OAAO,KAAA;AAAA,EACT,CAAA;AAEA,EAAA,MAAM,UAAU,YAAY;AAC1B,IAAA,IAAI;AACF,MAAA,MAAM,OAAA,GAAU,MAAM,YAAA,CAAa,UAAA,CAAW,SAAS,CAAA;AACvD,MAAA,MAAM,UAAA,GAAa,GAAG,OAAO,CAAA,0BAAA,CAAA;AAC7B,MAAA,MAAM,GAAA,GAAM,MAAM,QAAA,CAAS,KAAA,CAAM,UAAA,EAAY;AAAA,QAC3C,WAAA,EAAa;AAAA,OACd,CAAA;AAED,MAAA,IAAI,CAAC,IAAI,EAAA,EAAI;AACX,QAAA,MAAM,IAAI,KAAA;AAAA,UACR,8BAA8B,GAAA,CAAI,MAAM,IAAI,GAAA,CAAI,UAAU,yBAAyB,UAAU,CAAA,iBAAA;AAAA,SAC/F;AAAA,MACF;AAEA,MAAA,MAAM,IAAA,GAAO,MAAM,GAAA,CAAI,IAAA,EAAK;AAC5B,MAAA,IAAI,CAAC,KAAK,SAAA,EAAW;AACnB,QAAA,MAAM,IAAI,MAAM,gCAAgC,CAAA;AAAA,MAClD;AAEA,MAAA,MAAM,SAAA,GAAY,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,SAAS,CAAA;AAC3C,MAAA,IAAI,MAAA,CAAO,KAAA,CAAM,SAAS,CAAA,EAAG;AAC3B,QAAA,MAAM,IAAI,MAAM,qCAAqC,CAAA;AAAA,MACvD;AAEA,MAAA,UAAA,GAAa,IAAA;AAEb,MAAA,OAAA,EAAS,WAAA,CAAY;AAAA,QACnB,MAAA,EAAQ,wBAAA;AAAA,QACR,OAAA,EAAS,EAAE,SAAA,EAAW,IAAI,KAAK,SAAS,CAAA,CAAE,aAAY;AAAE,OACzD,CAAA;AAED,MAAA,eAAA,CAAgB,QAAA,CAAS,SAAS,CAAC,CAAA;AAAA,IACrC,SAAS,KAAA,EAAO;AAEd,MAAA,IAAI,UAAA,EAAY;AACd,QAAA,UAAA,GAAa,KAAA;AACb,QAAA,YAAA,GAAe,mBAAA;AAAA,MACjB,CAAA,MAAO;AACL,QAAA,YAAA,GAAe,IAAA,CAAK,GAAA;AAAA,UAClB,iBAAA;AAAA,UACA,YAAA,GAAe;AAAA,SACjB;AAEA,QAAA,OAAA,CAAQ,KAAA,CAAM,iCAAiC,KAAK,CAAA;AACpD,QAAA,QAAA,CAAS,IAAA;AAAA,UACP,IAAI,KAAA;AAAA,YACF,CAAA,yDAAA;AAAA;AACF,SACF;AAAA,MACF;AAEA,MAAA,eAAA,CAAgB,YAAY,CAAA;AAAA,IAC9B;AAAA,EACF,CAAA;AAEA,EAAA,MAAM,SAAA,GAAY,CAChB,KAAA,KAOG;AACH,IAAA,MAAM,EAAE,MAAK,GAAI,KAAA;AACjB,IAAA,IAAI,IAAA,KAAS,IAAA,IAAQ,OAAO,IAAA,KAAS,QAAA,EAAU;AAC7C,MAAA;AAAA,IACF;AACA,IAAA,IAAI,QAAA,IAAY,IAAA,IAAQ,IAAA,CAAK,MAAA,KAAW,wBAAA,EAA0B;AAChE,MAAA,MAAM,SAAA,GAAY,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,QAAQ,SAAS,CAAA;AACnD,MAAA,IAAI,MAAA,CAAO,KAAA,CAAM,SAAS,CAAA,EAAG;AAE3B,QAAA,OAAA,CAAQ,IAAA;AAAA,UACN;AAAA,SACF;AACA,QAAA;AAAA,MACF;AAEA,MAAA,eAAA,CAAgB,QAAA,CAAS,SAAS,CAAC,CAAA;AAAA,IACrC;AAAA,EACF,CAAA;AAEA,EAAA,SAAS,gBAAgB,OAAA,EAAiB;AACxC,IAAA,IAAI,OAAA,EAAS;AACX,MAAA;AAAA,IACF;AACA,IAAA,IAAI,OAAA,EAAS;AACX,MAAA,YAAA,CAAa,OAAO,CAAA;AAAA,IACtB;AACA,IAAA,OAAA,GAAU,UAAA,CAAW,SAAS,OAAO,CAAA;AAAA,EACvC;AAEA,EAAA,OAAA,EAAS,gBAAA,CAAiB,WAAW,SAAS,CAAA;AAC9C,EAAA,OAAA,EAAQ;AAER,EAAA,OAAO,MAAM;AACX,IAAA,OAAA,GAAU,IAAA;AACV,IAAA,IAAI,OAAA,EAAS;AACX,MAAA,YAAA,CAAa,OAAO,CAAA;AAAA,IACtB;AACA,IAAA,OAAA,EAAS,mBAAA,CAAoB,WAAW,SAAS,CAAA;AACjD,IAAA,OAAA,EAAS,KAAA,EAAM;AAAA,EACjB,CAAA;AACF;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"Root.esm.js","sources":["../../src/extensions/Root.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 */\n\nimport {\n ApiBlueprint,\n coreExtensionData,\n createExtension,\n createExtensionInput,\n} from '@backstage/frontend-plugin-api';\n\nexport const Root = createExtension({\n attachTo: { id: 'ignored', input: 'ignored' },\n inputs: {\n app: createExtensionInput([coreExtensionData.reactElement], {\n singleton: true,\n }),\n apis: createExtensionInput([ApiBlueprint.dataRefs.factory], {\n replaces: [{ id: 'app', input: 'apis' }],\n }),\n },\n output: [coreExtensionData.reactElement],\n factory: ({ inputs }) => inputs.app,\n});\n"],"names":[],"mappings":";;AAuBO,MAAM,OAAO,eAAA,CAAgB;AAAA,EAClC,QAAA,EAAU,EAAE,EAAA,EAAI,SAAA,EAAW,OAAO,SAAA,EAAU;AAAA,EAC5C,MAAA,EAAQ;AAAA,IACN,GAAA,EAAK,oBAAA,CAAqB,CAAC,iBAAA,CAAkB,YAAY,CAAA,EAAG;AAAA,MAC1D,SAAA,EAAW;AAAA,KACZ,CAAA;AAAA,IACD,MAAM,oBAAA,CAAqB,CAAC,YAAA,CAAa,QAAA,CAAS,OAAO,CAAA,EAAG;AAAA,MAC1D,UAAU,CAAC,EAAE,IAAI,KAAA,EAAO,KAAA,EAAO,QAAQ;AAAA,KACxC;AAAA,GACH;AAAA,EACA,MAAA,EAAQ,CAAC,iBAAA,CAAkB,YAAY,CAAA;AAAA,EACvC,OAAA,EAAS,CAAC,EAAE,MAAA,OAAa,MAAA,CAAO;AAClC,CAAC;;;;"}
1
+ {"version":3,"file":"Root.esm.js","sources":["../../src/extensions/Root.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 */\n\nimport {\n ApiBlueprint,\n coreExtensionData,\n createExtension,\n createExtensionInput,\n} from '@backstage/frontend-plugin-api';\n\nexport const Root = createExtension({\n attachTo: { id: 'ignored', input: 'ignored' },\n inputs: {\n app: createExtensionInput([coreExtensionData.reactElement], {\n singleton: true,\n }),\n apis: createExtensionInput([ApiBlueprint.dataRefs.factory], {\n replaces: [{ id: 'app', input: 'apis' }],\n }),\n },\n output: [coreExtensionData.reactElement],\n factory: ({ inputs }) => inputs.app,\n});\n"],"names":[],"mappings":";;AAuBO,MAAM,OAAO,eAAA,CAAgB;AAAA,EAClC,QAAA,EAAU,EAAE,EAAA,EAAI,SAAA,EAAW,OAAO,SAAA,EAAU;AAAA,EAC5C,MAAA,EAAQ;AAAA,IACN,GAAA,EAAK,oBAAA,CAAqB,CAAC,iBAAA,CAAkB,YAAY,CAAA,EAAG;AAAA,MAC1D,SAAA,EAAW;AAAA,KACZ,CAAA;AAAA,IACD,MAAM,oBAAA,CAAqB,CAAC,YAAA,CAAa,QAAA,CAAS,OAAO,CAAA,EAAG;AAAA,MAC1D,UAAU,CAAC,EAAE,IAAI,KAAA,EAAO,KAAA,EAAO,QAAQ;AAAA,KACxC;AAAA,GACH;AAAA,EACA,MAAA,EAAQ,CAAC,iBAAA,CAAkB,YAAY,CAAA;AAAA,EACvC,OAAA,EAAS,CAAC,EAAE,MAAA,OAAa,MAAA,CAAO;AAClC,CAAC;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"OpaqueApiRef.esm.js","sources":["../../../../../frontend-internal/src/apis/OpaqueApiRef.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 */\n\nimport type { ApiRef } from '@backstage/frontend-plugin-api';\nimport { OpaqueType } from '@internal/opaque';\n\nexport const OpaqueApiRef = OpaqueType.create<{\n public: ApiRef<unknown> & {\n readonly $$type: '@backstage/ApiRef';\n };\n versions: {\n readonly version: 'v1';\n readonly pluginId?: string;\n };\n}>({\n type: '@backstage/ApiRef',\n versions: ['v1'],\n});\n"],"names":[],"mappings":";;AAmBO,MAAM,YAAA,GAAe,WAAW,MAAA,CAQpC;AAAA,EACD,IAAA,EAAM,mBAAA;AAAA,EACN,QAAA,EAAU,CAAC,IAAI;AACjB,CAAC;;;;"}
1
+ {"version":3,"file":"OpaqueApiRef.esm.js","sources":["../../../../../frontend-internal/src/apis/OpaqueApiRef.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 */\n\nimport type { ApiRef } from '@backstage/frontend-plugin-api';\nimport { OpaqueType } from '@internal/opaque';\n\nexport const OpaqueApiRef = OpaqueType.create<{\n public: ApiRef<unknown> & {\n readonly $$type: '@backstage/ApiRef';\n };\n versions: {\n readonly version: 'v1';\n readonly pluginId?: string;\n };\n}>({\n type: '@backstage/ApiRef',\n versions: ['v1'],\n});\n"],"names":[],"mappings":";;AAmBO,MAAM,YAAA,GAAe,WAAW,MAAA,CAQpC;AAAA,EACD,IAAA,EAAM,mBAAA;AAAA,EACN,QAAA,EAAU,CAAC,IAAI;AACjB,CAAC;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"OpaqueExternalRouteRef.esm.js","sources":["../../../../../frontend-internal/src/routing/OpaqueExternalRouteRef.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 { ExternalRouteRef } from '@backstage/frontend-plugin-api';\nimport { OpaqueType } from '@internal/opaque';\n\nexport const OpaqueExternalRouteRef = OpaqueType.create<{\n public: ExternalRouteRef;\n versions: {\n readonly version: 'v1';\n\n getParams(): string[];\n getDescription(): string;\n getDefaultTarget(): string | undefined;\n\n setId(id: string): void;\n };\n}>({\n type: '@backstage/ExternalRouteRef',\n versions: ['v1'],\n});\n"],"names":[],"mappings":";;AAmBO,MAAM,sBAAA,GAAyB,WAAW,MAAA,CAW9C;AAAA,EACD,IAAA,EAAM,6BAAA;AAAA,EACN,QAAA,EAAU,CAAC,IAAI;AACjB,CAAC;;;;"}
1
+ {"version":3,"file":"OpaqueExternalRouteRef.esm.js","sources":["../../../../../frontend-internal/src/routing/OpaqueExternalRouteRef.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 { ExternalRouteRef } from '@backstage/frontend-plugin-api';\nimport { OpaqueType } from '@internal/opaque';\n\nexport const OpaqueExternalRouteRef = OpaqueType.create<{\n public: ExternalRouteRef;\n versions: {\n readonly version: 'v1';\n\n getParams(): string[];\n getDescription(): string;\n getDefaultTarget(): string | undefined;\n\n setId(id: string): void;\n };\n}>({\n type: '@backstage/ExternalRouteRef',\n versions: ['v1'],\n});\n"],"names":[],"mappings":";;AAmBO,MAAM,sBAAA,GAAyB,WAAW,MAAA,CAW9C;AAAA,EACD,IAAA,EAAM,6BAAA;AAAA,EACN,QAAA,EAAU,CAAC,IAAI;AACjB,CAAC;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"OpaqueRouteRef.esm.js","sources":["../../../../../frontend-internal/src/routing/OpaqueRouteRef.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 { RouteRef } from '@backstage/frontend-plugin-api';\nimport { OpaqueType } from '@internal/opaque';\n\nexport const OpaqueRouteRef = OpaqueType.create<{\n public: RouteRef;\n versions: {\n readonly version: 'v1';\n\n getParams(): string[];\n getDescription(): string;\n\n alias: string | undefined;\n\n setId(id: string): void;\n };\n}>({\n type: '@backstage/RouteRef',\n versions: ['v1'],\n});\n"],"names":[],"mappings":";;AAmBO,MAAM,cAAA,GAAiB,WAAW,MAAA,CAYtC;AAAA,EACD,IAAA,EAAM,qBAAA;AAAA,EACN,QAAA,EAAU,CAAC,IAAI;AACjB,CAAC;;;;"}
1
+ {"version":3,"file":"OpaqueRouteRef.esm.js","sources":["../../../../../frontend-internal/src/routing/OpaqueRouteRef.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 { RouteRef } from '@backstage/frontend-plugin-api';\nimport { OpaqueType } from '@internal/opaque';\n\nexport const OpaqueRouteRef = OpaqueType.create<{\n public: RouteRef;\n versions: {\n readonly version: 'v1';\n\n getParams(): string[];\n getDescription(): string;\n\n alias: string | undefined;\n\n setId(id: string): void;\n };\n}>({\n type: '@backstage/RouteRef',\n versions: ['v1'],\n});\n"],"names":[],"mappings":";;AAmBO,MAAM,cAAA,GAAiB,WAAW,MAAA,CAYtC;AAAA,EACD,IAAA,EAAM,qBAAA;AAAA,EACN,QAAA,EAAU,CAAC,IAAI;AACjB,CAAC;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"OpaqueSubRouteRef.esm.js","sources":["../../../../../frontend-internal/src/routing/OpaqueSubRouteRef.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 { RouteRef, SubRouteRef } from '@backstage/frontend-plugin-api';\nimport { OpaqueType } from '@internal/opaque';\n\nexport const OpaqueSubRouteRef = OpaqueType.create<{\n public: SubRouteRef;\n versions: {\n readonly version: 'v1';\n\n getParams(): string[];\n getParent(): RouteRef;\n getDescription(): string;\n };\n}>({\n type: '@backstage/SubRouteRef',\n versions: ['v1'],\n});\n"],"names":[],"mappings":";;AAmBO,MAAM,iBAAA,GAAoB,WAAW,MAAA,CASzC;AAAA,EACD,IAAA,EAAM,wBAAA;AAAA,EACN,QAAA,EAAU,CAAC,IAAI;AACjB,CAAC;;;;"}
1
+ {"version":3,"file":"OpaqueSubRouteRef.esm.js","sources":["../../../../../frontend-internal/src/routing/OpaqueSubRouteRef.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 { RouteRef, SubRouteRef } from '@backstage/frontend-plugin-api';\nimport { OpaqueType } from '@internal/opaque';\n\nexport const OpaqueSubRouteRef = OpaqueType.create<{\n public: SubRouteRef;\n versions: {\n readonly version: 'v1';\n\n getParams(): string[];\n getParent(): RouteRef;\n getDescription(): string;\n };\n}>({\n type: '@backstage/SubRouteRef',\n versions: ['v1'],\n});\n"],"names":[],"mappings":";;AAmBO,MAAM,iBAAA,GAAoB,WAAW,MAAA,CASzC;AAAA,EACD,IAAA,EAAM,wBAAA;AAAA,EACN,QAAA,EAAU,CAAC,IAAI;AACjB,CAAC;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"InternalExtensionDefinition.esm.js","sources":["../../../../../frontend-internal/src/wiring/InternalExtensionDefinition.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 */\n\nimport {\n ApiHolder,\n AppNode,\n ExtensionDefinitionAttachTo,\n ExtensionDataValue,\n ExtensionDataRef,\n OverridableExtensionDefinition,\n ExtensionDefinitionParameters,\n ExtensionInput,\n PortableSchema,\n} from '@backstage/frontend-plugin-api';\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport { ResolvedExtensionInputs } from '../../../frontend-plugin-api/src/wiring/createExtension';\nimport { OpaqueType } from '@internal/opaque';\nimport { FilterPredicate } from '@backstage/filter-predicates';\n\nexport const OpaqueExtensionDefinition = OpaqueType.create<{\n public: OverridableExtensionDefinition<ExtensionDefinitionParameters>;\n versions:\n | {\n readonly version: 'v1';\n readonly kind?: string;\n readonly namespace?: string;\n readonly name?: string;\n readonly attachTo: ExtensionDefinitionAttachTo;\n readonly disabled: boolean;\n readonly configSchema?: PortableSchema<any, any>;\n readonly inputs: {\n [inputName in string]: {\n $$type: '@backstage/ExtensionInput';\n extensionData: {\n [name in string]: ExtensionDataRef;\n };\n config: { optional: boolean; singleton: boolean };\n };\n };\n readonly output: {\n [name in string]: ExtensionDataRef;\n };\n factory(context: {\n node: AppNode;\n apis: ApiHolder;\n config: object;\n inputs: {\n [inputName in string]: unknown;\n };\n }): {\n [inputName in string]: unknown;\n };\n }\n | {\n readonly version: 'v2';\n readonly kind?: string;\n readonly namespace?: string;\n readonly name?: string;\n readonly attachTo: ExtensionDefinitionAttachTo;\n readonly disabled: boolean;\n readonly if?: FilterPredicate;\n readonly configSchema?: PortableSchema<any, any>;\n readonly inputs: { [inputName in string]: ExtensionInput };\n readonly output: Array<ExtensionDataRef>;\n factory(context: {\n node: AppNode;\n apis: ApiHolder;\n config: object;\n inputs: ResolvedExtensionInputs<{\n [inputName in string]: ExtensionInput;\n }>;\n }): Iterable<ExtensionDataValue<any, any>>;\n };\n}>({\n type: '@backstage/ExtensionDefinition',\n versions: ['v1', 'v2'],\n});\n"],"names":[],"mappings":";;AAgCO,MAAM,yBAAA,GAA4B,WAAW,MAAA,CAsDjD;AAAA,EACD,IAAA,EAAM,gCAAA;AAAA,EACN,QAAA,EAAU,CAAC,IAAA,EAAM,IAAI;AACvB,CAAC;;;;"}
1
+ {"version":3,"file":"InternalExtensionDefinition.esm.js","sources":["../../../../../frontend-internal/src/wiring/InternalExtensionDefinition.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 */\n\nimport {\n ApiHolder,\n AppNode,\n ExtensionDefinitionAttachTo,\n ExtensionDataValue,\n ExtensionDataRef,\n OverridableExtensionDefinition,\n ExtensionDefinitionParameters,\n ExtensionInput,\n PortableSchema,\n} from '@backstage/frontend-plugin-api';\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport { ResolvedExtensionInputs } from '../../../frontend-plugin-api/src/wiring/createExtension';\nimport { OpaqueType } from '@internal/opaque';\nimport { FilterPredicate } from '@backstage/filter-predicates';\n\nexport const OpaqueExtensionDefinition = OpaqueType.create<{\n public: OverridableExtensionDefinition<ExtensionDefinitionParameters>;\n versions:\n | {\n readonly version: 'v1';\n readonly kind?: string;\n readonly namespace?: string;\n readonly name?: string;\n readonly attachTo: ExtensionDefinitionAttachTo;\n readonly disabled: boolean;\n readonly configSchema?: PortableSchema<any, any>;\n readonly inputs: {\n [inputName in string]: {\n $$type: '@backstage/ExtensionInput';\n extensionData: {\n [name in string]: ExtensionDataRef;\n };\n config: { optional: boolean; singleton: boolean };\n };\n };\n readonly output: {\n [name in string]: ExtensionDataRef;\n };\n factory(context: {\n node: AppNode;\n apis: ApiHolder;\n config: object;\n inputs: {\n [inputName in string]: unknown;\n };\n }): {\n [inputName in string]: unknown;\n };\n }\n | {\n readonly version: 'v2';\n readonly kind?: string;\n readonly namespace?: string;\n readonly name?: string;\n readonly attachTo: ExtensionDefinitionAttachTo;\n readonly disabled: boolean;\n readonly if?: FilterPredicate;\n readonly configSchema?: PortableSchema<any, any>;\n readonly inputs: { [inputName in string]: ExtensionInput };\n readonly output: Array<ExtensionDataRef>;\n factory(context: {\n node: AppNode;\n apis: ApiHolder;\n config: object;\n inputs: ResolvedExtensionInputs<{\n [inputName in string]: ExtensionInput;\n }>;\n }): Iterable<ExtensionDataValue<any, any>>;\n };\n}>({\n type: '@backstage/ExtensionDefinition',\n versions: ['v1', 'v2'],\n});\n"],"names":[],"mappings":";;AAgCO,MAAM,yBAAA,GAA4B,WAAW,MAAA,CAsDjD;AAAA,EACD,IAAA,EAAM,gCAAA;AAAA,EACN,QAAA,EAAU,CAAC,IAAA,EAAM,IAAI;AACvB,CAAC;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"InternalExtensionInput.esm.js","sources":["../../../../../frontend-internal/src/wiring/InternalExtensionInput.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 */\n\nimport { ExtensionInput } from '@backstage/frontend-plugin-api';\nimport { OpaqueType } from '@internal/opaque';\n\nexport type ExtensionInputContext = {\n input: string;\n kind?: string;\n name?: string;\n};\n\nexport const OpaqueExtensionInput = OpaqueType.create<{\n public: ExtensionInput;\n versions: {\n readonly version: undefined;\n readonly context?: ExtensionInputContext;\n withContext?(context: ExtensionInputContext): ExtensionInput;\n };\n}>({\n type: '@backstage/ExtensionInput',\n versions: [undefined],\n});\n"],"names":[],"mappings":";;AAyBO,MAAM,oBAAA,GAAuB,WAAW,MAAA,CAO5C;AAAA,EACD,IAAA,EAAM,2BAAA;AAAA,EACN,QAAA,EAAU,CAAC,MAAS;AACtB,CAAC;;;;"}
1
+ {"version":3,"file":"InternalExtensionInput.esm.js","sources":["../../../../../frontend-internal/src/wiring/InternalExtensionInput.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 */\n\nimport { ExtensionInput } from '@backstage/frontend-plugin-api';\nimport { OpaqueType } from '@internal/opaque';\n\nexport type ExtensionInputContext = {\n input: string;\n kind?: string;\n name?: string;\n};\n\nexport const OpaqueExtensionInput = OpaqueType.create<{\n public: ExtensionInput;\n versions: {\n readonly version: undefined;\n readonly context?: ExtensionInputContext;\n withContext?(context: ExtensionInputContext): ExtensionInput;\n };\n}>({\n type: '@backstage/ExtensionInput',\n versions: [undefined],\n});\n"],"names":[],"mappings":";;AAyBO,MAAM,oBAAA,GAAuB,WAAW,MAAA,CAO5C;AAAA,EACD,IAAA,EAAM,2BAAA;AAAA,EACN,QAAA,EAAU,CAAC,MAAS;AACtB,CAAC;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"InternalFrontendPlugin.esm.js","sources":["../../../../../frontend-internal/src/wiring/InternalFrontendPlugin.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 */\n\nimport {\n Extension,\n FeatureFlagConfig,\n IconElement,\n OverridableFrontendPlugin,\n} from '@backstage/frontend-plugin-api';\nimport { FilterPredicate } from '@backstage/filter-predicates';\nimport { JsonObject } from '@backstage/types';\nimport { OpaqueType } from '@internal/opaque';\n\nexport const OpaqueFrontendPlugin = OpaqueType.create<{\n public: OverridableFrontendPlugin;\n versions: {\n readonly version: 'v1';\n readonly title?: string;\n readonly icon?: IconElement;\n readonly extensions: Extension<unknown>[];\n readonly featureFlags: FeatureFlagConfig[];\n readonly if?: FilterPredicate;\n readonly infoOptions?: {\n packageJson?: () => Promise<JsonObject>;\n manifest?: () => Promise<JsonObject>;\n };\n };\n}>({\n type: '@backstage/FrontendPlugin',\n versions: ['v1'],\n});\n"],"names":[],"mappings":";;AA0BO,MAAM,oBAAA,GAAuB,WAAW,MAAA,CAc5C;AAAA,EACD,IAAA,EAAM,2BAAA;AAAA,EACN,QAAA,EAAU,CAAC,IAAI;AACjB,CAAC;;;;"}
1
+ {"version":3,"file":"InternalFrontendPlugin.esm.js","sources":["../../../../../frontend-internal/src/wiring/InternalFrontendPlugin.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 */\n\nimport {\n Extension,\n FeatureFlagConfig,\n IconElement,\n OverridableFrontendPlugin,\n} from '@backstage/frontend-plugin-api';\nimport { FilterPredicate } from '@backstage/filter-predicates';\nimport { JsonObject } from '@backstage/types';\nimport { OpaqueType } from '@internal/opaque';\n\nexport const OpaqueFrontendPlugin = OpaqueType.create<{\n public: OverridableFrontendPlugin;\n versions: {\n readonly version: 'v1';\n readonly title?: string;\n readonly icon?: IconElement;\n readonly extensions: Extension<unknown>[];\n readonly featureFlags: FeatureFlagConfig[];\n readonly if?: FilterPredicate;\n readonly infoOptions?: {\n packageJson?: () => Promise<JsonObject>;\n manifest?: () => Promise<JsonObject>;\n };\n };\n}>({\n type: '@backstage/FrontendPlugin',\n versions: ['v1'],\n});\n"],"names":[],"mappings":";;AA0BO,MAAM,oBAAA,GAAuB,WAAW,MAAA,CAc5C;AAAA,EACD,IAAA,EAAM,2BAAA;AAAA,EACN,QAAA,EAAU,CAAC,IAAI;AACjB,CAAC;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"createExtensionDataContainer.esm.js","sources":["../../../../../frontend-internal/src/wiring/createExtensionDataContainer.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 */\n\nimport {\n ExtensionDataContainer,\n ExtensionDataRef,\n ExtensionDataValue,\n} from '@backstage/frontend-plugin-api';\n\nexport function createExtensionDataContainer<UData extends ExtensionDataRef>(\n values: Iterable<\n UData extends ExtensionDataRef<infer IData, infer IId>\n ? ExtensionDataValue<IData, IId>\n : never\n >,\n contextName: string,\n declaredRefs?: ExtensionDataRef<any, any, any>[],\n): ExtensionDataContainer<UData> {\n if (typeof values !== 'object' || !values?.[Symbol.iterator]) {\n throw new Error(`${contextName} did not provide an iterable object`);\n }\n\n const container = new Map<string, ExtensionDataValue<any, any>>();\n const verifyRefs =\n declaredRefs && new Map(declaredRefs.map(ref => [ref.id, ref]));\n\n for (const output of values) {\n if (verifyRefs) {\n if (!verifyRefs.delete(output.id)) {\n throw new Error(\n `extension data '${output.id}' was provided but not declared`,\n );\n }\n }\n container.set(output.id, output);\n }\n\n const remainingRefs =\n verifyRefs &&\n Array.from(verifyRefs.values()).filter(ref => !ref.config.optional);\n if (remainingRefs && remainingRefs.length > 0) {\n throw new Error(\n `missing required extension data value(s) '${remainingRefs\n .map(ref => ref.id)\n .join(', ')}'`,\n );\n }\n\n return {\n get(ref) {\n return container.get(ref.id)?.value;\n },\n [Symbol.iterator]() {\n return container.values();\n },\n } as ExtensionDataContainer<UData>;\n}\n"],"names":[],"mappings":"AAsBO,SAAS,4BAAA,CACd,MAAA,EAKA,WAAA,EACA,YAAA,EAC+B;AAC/B,EAAA,IAAI,OAAO,MAAA,KAAW,QAAA,IAAY,CAAC,MAAA,GAAS,MAAA,CAAO,QAAQ,CAAA,EAAG;AAC5D,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,EAAG,WAAW,CAAA,mCAAA,CAAqC,CAAA;AAAA,EACrE;AAEA,EAAA,MAAM,SAAA,uBAAgB,GAAA,EAA0C;AAIhE,EAAA,KAAA,MAAW,UAAU,MAAA,EAAQ;AAQ3B,IAAA,SAAA,CAAU,GAAA,CAAI,MAAA,CAAO,EAAA,EAAI,MAAM,CAAA;AAAA,EACjC;AAaA,EAAA,OAAO;AAAA,IACL,IAAI,GAAA,EAAK;AACP,MAAA,OAAO,SAAA,CAAU,GAAA,CAAI,GAAA,CAAI,EAAE,CAAA,EAAG,KAAA;AAAA,IAChC,CAAA;AAAA,IACA,CAAC,MAAA,CAAO,QAAQ,CAAA,GAAI;AAClB,MAAA,OAAO,UAAU,MAAA,EAAO;AAAA,IAC1B;AAAA,GACF;AACF;;;;"}
1
+ {"version":3,"file":"createExtensionDataContainer.esm.js","sources":["../../../../../frontend-internal/src/wiring/createExtensionDataContainer.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 */\n\nimport {\n ExtensionDataContainer,\n ExtensionDataRef,\n ExtensionDataValue,\n} from '@backstage/frontend-plugin-api';\n\nexport function createExtensionDataContainer<UData extends ExtensionDataRef>(\n values: Iterable<\n UData extends ExtensionDataRef<infer IData, infer IId>\n ? ExtensionDataValue<IData, IId>\n : never\n >,\n contextName: string,\n declaredRefs?: ExtensionDataRef<any, any, any>[],\n): ExtensionDataContainer<UData> {\n if (typeof values !== 'object' || !values?.[Symbol.iterator]) {\n throw new Error(`${contextName} did not provide an iterable object`);\n }\n\n const container = new Map<string, ExtensionDataValue<any, any>>();\n const verifyRefs =\n declaredRefs && new Map(declaredRefs.map(ref => [ref.id, ref]));\n\n for (const output of values) {\n if (verifyRefs) {\n if (!verifyRefs.delete(output.id)) {\n throw new Error(\n `extension data '${output.id}' was provided but not declared`,\n );\n }\n }\n container.set(output.id, output);\n }\n\n const remainingRefs =\n verifyRefs &&\n Array.from(verifyRefs.values()).filter(ref => !ref.config.optional);\n if (remainingRefs && remainingRefs.length > 0) {\n throw new Error(\n `missing required extension data value(s) '${remainingRefs\n .map(ref => ref.id)\n .join(', ')}'`,\n );\n }\n\n return {\n get(ref) {\n return container.get(ref.id)?.value;\n },\n [Symbol.iterator]() {\n return container.values();\n },\n } as ExtensionDataContainer<UData>;\n}\n"],"names":[],"mappings":"AAsBO,SAAS,4BAAA,CACd,MAAA,EAKA,WAAA,EACA,YAAA,EAC+B;AAC/B,EAAA,IAAI,OAAO,MAAA,KAAW,QAAA,IAAY,CAAC,MAAA,GAAS,MAAA,CAAO,QAAQ,CAAA,EAAG;AAC5D,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,EAAG,WAAW,CAAA,mCAAA,CAAqC,CAAA;AAAA,EACrE;AAEA,EAAA,MAAM,SAAA,uBAAgB,GAAA,EAA0C;AAIhE,EAAA,KAAA,MAAW,UAAU,MAAA,EAAQ;AAQ3B,IAAA,SAAA,CAAU,GAAA,CAAI,MAAA,CAAO,EAAA,EAAI,MAAM,CAAA;AAAA,EACjC;AAaA,EAAA,OAAO;AAAA,IACL,IAAI,GAAA,EAAK;AACP,MAAA,OAAO,SAAA,CAAU,GAAA,CAAI,GAAA,CAAI,EAAE,CAAA,EAAG,KAAA;AAAA,IAChC,CAAA;AAAA,IACA,CAAC,MAAA,CAAO,QAAQ,CAAA,GAAI;AAClB,MAAA,OAAO,UAAU,MAAA,EAAO;AAAA,IAC1B;AAAA,GACF;AACF;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"createFrontendModule.esm.js","sources":["../../../../../frontend-plugin-api/src/wiring/createFrontendModule.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 { ExtensionDefinition } from './createExtension';\nimport {\n Extension,\n resolveExtensionDefinitions,\n} from './resolveExtensionDefinition';\nimport { FeatureFlagConfig } from './types';\nimport { FilterPredicate } from '@backstage/filter-predicates';\n\n/** @public */\nexport interface CreateFrontendModuleOptions<\n TPluginId extends string,\n TExtensions extends readonly ExtensionDefinition[],\n> {\n pluginId: TPluginId;\n extensions?: TExtensions;\n featureFlags?: FeatureFlagConfig[];\n if?: FilterPredicate;\n}\n\n/** @public */\nexport interface FrontendModule {\n readonly $$type: '@backstage/FrontendModule';\n readonly pluginId: string;\n}\n\n/** @internal */\nexport interface InternalFrontendModule extends FrontendModule {\n readonly version: 'v1';\n readonly extensions: Extension<unknown>[];\n readonly featureFlags: FeatureFlagConfig[];\n readonly if?: FilterPredicate;\n}\n\n/**\n * Creates a new module that can be installed in a Backstage app.\n *\n * @remarks\n *\n * Modules are used to add or override extensions for an existing plugin. If a\n * module provides an extension with the same ID as one provided by the plugin,\n * the extension provided by the module will always take precedence.\n *\n * Every module is created for a specific plugin by providing the\n * unique ID of the plugin that the module should be installed for. If that\n * plugin is not present in the app, the module will be ignored and have no\n * effect.\n *\n * For more information on how modules work, see the\n * {@link https://backstage.io/docs/frontend-system/architecture/extension-overrides#creating-a-frontend-module | documentation for modules}\n * in the frontend system documentation.\n *\n * It is recommended to name the module variable of the form `<pluginId>Module<ModuleName>`.\n *\n * @example\n *\n * ```tsx\n * import { createFrontendModule } from '@backstage/frontend-plugin-api';\n *\n * export const exampleModuleCustomPage = createFrontendModule({\n * pluginId: 'example',\n * extensions: [\n * // Overrides the default page for the 'example' plugin\n * PageBlueprint.make({\n * path: '/example',\n * loader: () => import('./CustomPage').then(m => <m.CustomPage />),\n * }),\n * ],\n * });\n * ```\n *\n * @public\n */\nexport function createFrontendModule<\n TId extends string,\n TExtensions extends readonly ExtensionDefinition[],\n>(options: CreateFrontendModuleOptions<TId, TExtensions>): FrontendModule {\n const { pluginId } = options;\n\n const { extensions } = resolveExtensionDefinitions(options.extensions ?? [], {\n namespace: pluginId,\n featureType: 'Module',\n });\n\n return {\n $$type: '@backstage/FrontendModule',\n version: 'v1',\n pluginId,\n featureFlags: options.featureFlags ?? [],\n if: options.if,\n extensions,\n toString() {\n return `Module{pluginId=${pluginId}}`;\n },\n } as InternalFrontendModule;\n}\n\n/** @internal */\nexport function isInternalFrontendModule(opaque: {\n $$type: string;\n}): opaque is InternalFrontendModule {\n if (opaque.$$type === '@backstage/FrontendModule') {\n // Make sure we throw if invalid\n toInternalFrontendModule(opaque as FrontendModule);\n return true;\n }\n return false;\n}\n\n/** @internal */\nexport function toInternalFrontendModule(\n plugin: FrontendModule,\n): InternalFrontendModule {\n const internal = plugin as InternalFrontendModule;\n if (internal.$$type !== '@backstage/FrontendModule') {\n throw new Error(`Invalid plugin instance, bad type '${internal.$$type}'`);\n }\n if (internal.version !== 'v1') {\n throw new Error(\n `Invalid plugin instance, bad version '${internal.version}'`,\n );\n }\n return internal;\n}\n"],"names":[],"mappings":"AAiHO,SAAS,yBAAyB,MAAA,EAEJ;AACnC,EAAA,IAAI,MAAA,CAAO,WAAW,2BAAA,EAA6B;AAEjD,IAAA,wBAAA,CAAyB,MAAwB,CAAA;AACjD,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,OAAO,KAAA;AACT;AAGO,SAAS,yBACd,MAAA,EACwB;AACxB,EAAA,MAAM,QAAA,GAAW,MAAA;AACjB,EAAA,IAAI,QAAA,CAAS,WAAW,2BAAA,EAA6B;AACnD,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,mCAAA,EAAsC,QAAA,CAAS,MAAM,CAAA,CAAA,CAAG,CAAA;AAAA,EAC1E;AACA,EAAA,IAAI,QAAA,CAAS,YAAY,IAAA,EAAM;AAC7B,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,CAAA,sCAAA,EAAyC,SAAS,OAAO,CAAA,CAAA;AAAA,KAC3D;AAAA,EACF;AACA,EAAA,OAAO,QAAA;AACT;;;;"}
1
+ {"version":3,"file":"createFrontendModule.esm.js","sources":["../../../../../frontend-plugin-api/src/wiring/createFrontendModule.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 { ExtensionDefinition } from './createExtension';\nimport {\n Extension,\n resolveExtensionDefinitions,\n} from './resolveExtensionDefinition';\nimport { FeatureFlagConfig } from './types';\nimport { FilterPredicate } from '@backstage/filter-predicates';\n\n/** @public */\nexport interface CreateFrontendModuleOptions<\n TPluginId extends string,\n TExtensions extends readonly ExtensionDefinition[],\n> {\n pluginId: TPluginId;\n extensions?: TExtensions;\n featureFlags?: FeatureFlagConfig[];\n if?: FilterPredicate;\n}\n\n/** @public */\nexport interface FrontendModule {\n readonly $$type: '@backstage/FrontendModule';\n readonly pluginId: string;\n}\n\n/** @internal */\nexport interface InternalFrontendModule extends FrontendModule {\n readonly version: 'v1';\n readonly extensions: Extension<unknown>[];\n readonly featureFlags: FeatureFlagConfig[];\n readonly if?: FilterPredicate;\n}\n\n/**\n * Creates a new module that can be installed in a Backstage app.\n *\n * @remarks\n *\n * Modules are used to add or override extensions for an existing plugin. If a\n * module provides an extension with the same ID as one provided by the plugin,\n * the extension provided by the module will always take precedence.\n *\n * Every module is created for a specific plugin by providing the\n * unique ID of the plugin that the module should be installed for. If that\n * plugin is not present in the app, the module will be ignored and have no\n * effect.\n *\n * For more information on how modules work, see the\n * {@link https://backstage.io/docs/frontend-system/architecture/extension-overrides#creating-a-frontend-module | documentation for modules}\n * in the frontend system documentation.\n *\n * It is recommended to name the module variable of the form `<pluginId>Module<ModuleName>`.\n *\n * @example\n *\n * ```tsx\n * import { createFrontendModule } from '@backstage/frontend-plugin-api';\n *\n * export const exampleModuleCustomPage = createFrontendModule({\n * pluginId: 'example',\n * extensions: [\n * // Overrides the default page for the 'example' plugin\n * PageBlueprint.make({\n * path: '/example',\n * loader: () => import('./CustomPage').then(m => <m.CustomPage />),\n * }),\n * ],\n * });\n * ```\n *\n * @public\n */\nexport function createFrontendModule<\n TId extends string,\n TExtensions extends readonly ExtensionDefinition[],\n>(options: CreateFrontendModuleOptions<TId, TExtensions>): FrontendModule {\n const { pluginId } = options;\n\n const { extensions } = resolveExtensionDefinitions(options.extensions ?? [], {\n namespace: pluginId,\n featureType: 'Module',\n });\n\n return {\n $$type: '@backstage/FrontendModule',\n version: 'v1',\n pluginId,\n featureFlags: options.featureFlags ?? [],\n if: options.if,\n extensions,\n toString() {\n return `Module{pluginId=${pluginId}}`;\n },\n } as InternalFrontendModule;\n}\n\n/** @internal */\nexport function isInternalFrontendModule(opaque: {\n $$type: string;\n}): opaque is InternalFrontendModule {\n if (opaque.$$type === '@backstage/FrontendModule') {\n // Make sure we throw if invalid\n toInternalFrontendModule(opaque as FrontendModule);\n return true;\n }\n return false;\n}\n\n/** @internal */\nexport function toInternalFrontendModule(\n plugin: FrontendModule,\n): InternalFrontendModule {\n const internal = plugin as InternalFrontendModule;\n if (internal.$$type !== '@backstage/FrontendModule') {\n throw new Error(`Invalid plugin instance, bad type '${internal.$$type}'`);\n }\n if (internal.version !== 'v1') {\n throw new Error(\n `Invalid plugin instance, bad version '${internal.version}'`,\n );\n }\n return internal;\n}\n"],"names":[],"mappings":"AAiHO,SAAS,yBAAyB,MAAA,EAEJ;AACnC,EAAA,IAAI,MAAA,CAAO,WAAW,2BAAA,EAA6B;AAEjD,IAAA,wBAAA,CAAyB,MAAwB,CAAA;AACjD,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,OAAO,KAAA;AACT;AAGO,SAAS,yBACd,MAAA,EACwB;AACxB,EAAA,MAAM,QAAA,GAAW,MAAA;AACjB,EAAA,IAAI,QAAA,CAAS,WAAW,2BAAA,EAA6B;AACnD,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,mCAAA,EAAsC,QAAA,CAAS,MAAM,CAAA,CAAA,CAAG,CAAA;AAAA,EAC1E;AACA,EAAA,IAAI,QAAA,CAAS,YAAY,IAAA,EAAM;AAC7B,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,CAAA,sCAAA,EAAyC,SAAS,OAAO,CAAA,CAAA;AAAA,KAC3D;AAAA,EACF;AACA,EAAA,OAAO,QAAA;AACT;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"resolveExtensionDefinition.esm.js","sources":["../../../../../frontend-plugin-api/src/wiring/resolveExtensionDefinition.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 { ApiHolder, AppNode } from '../apis';\nimport {\n ExtensionDefinitionAttachTo,\n ExtensionDefinition,\n ExtensionDefinitionParameters,\n ResolvedExtensionInputs,\n} from './createExtension';\nimport { PortableSchema } from '../schema';\nimport { ExtensionInput } from './createExtensionInput';\nimport { ExtensionDataRef, ExtensionDataValue } from './createExtensionDataRef';\nimport {\n OpaqueExtensionDefinition,\n OpaqueExtensionInput,\n} from '@internal/frontend';\nimport { FilterPredicate } from '@backstage/filter-predicates';\n\n/** @public */\nexport type ExtensionAttachTo = { id: string; input: string };\n\n/** @public */\nexport interface Extension<TConfig, TConfigInput = TConfig> {\n $$type: '@backstage/Extension';\n readonly id: string;\n readonly attachTo: ExtensionAttachTo;\n readonly disabled: boolean;\n readonly configSchema?: PortableSchema<TConfig, TConfigInput>;\n}\n\n/** @internal */\nexport type InternalExtension<TConfig, TConfigInput> = Extension<\n TConfig,\n TConfigInput\n> &\n (\n | {\n readonly version: 'v1';\n readonly inputs: {\n [inputName in string]: {\n $$type: '@backstage/ExtensionInput';\n extensionData: {\n [name in string]: ExtensionDataRef;\n };\n config: { optional: boolean; singleton: boolean };\n };\n };\n readonly output: {\n [name in string]: ExtensionDataRef;\n };\n factory(context: {\n apis: ApiHolder;\n node: AppNode;\n config: TConfig;\n inputs: {\n [inputName in string]: unknown;\n };\n }): {\n [inputName in string]: unknown;\n };\n }\n | {\n readonly version: 'v2';\n readonly if?: FilterPredicate;\n readonly inputs: { [inputName in string]: ExtensionInput };\n readonly output: Array<ExtensionDataRef>;\n factory(options: {\n apis: ApiHolder;\n node: AppNode;\n config: TConfig;\n inputs: ResolvedExtensionInputs<{\n [inputName in string]: ExtensionInput;\n }>;\n }): Iterable<ExtensionDataValue<any, any>>;\n }\n );\n\n/** @internal */\nexport function toInternalExtension<TConfig, TConfigInput>(\n overrides: Extension<TConfig, TConfigInput>,\n): InternalExtension<TConfig, TConfigInput> {\n const internal = overrides as InternalExtension<TConfig, TConfigInput>;\n if (internal.$$type !== '@backstage/Extension') {\n throw new Error(\n `Invalid extension instance, bad type '${internal.$$type}'`,\n );\n }\n const version = internal.version;\n if (version !== 'v1' && version !== 'v2') {\n throw new Error(`Invalid extension instance, bad version '${version}'`);\n }\n return internal;\n}\n\n/** @ignore */\nexport type ResolveExtensionId<\n TExtension extends ExtensionDefinition,\n TNamespace extends string,\n> = TExtension extends ExtensionDefinition<{\n kind: infer IKind extends string | undefined;\n name: infer IName extends string | undefined;\n params: any;\n}>\n ? [string] extends [IKind | IName]\n ? never\n : (\n undefined extends IName ? TNamespace : `${TNamespace}/${IName}`\n ) extends infer INamePart extends string\n ? IKind extends string\n ? `${IKind}:${INamePart}`\n : INamePart\n : never\n : never;\n\nfunction resolveExtensionId(\n kind?: string,\n namespace?: string,\n name?: string,\n): string {\n const namePart =\n name && namespace ? `${namespace}/${name}` : namespace || name;\n if (!namePart) {\n throw new Error(\n `Extension must declare an explicit namespace or name as it could not be resolved from context, kind=${kind} namespace=${namespace} name=${name}`,\n );\n }\n\n return kind ? `${kind}:${namePart}` : namePart;\n}\n\nfunction resolveAttachTo(\n attachTo: ExtensionDefinitionAttachTo | ExtensionDefinitionAttachTo[],\n namespace?: string,\n): ExtensionAttachTo | ExtensionAttachTo[] {\n const resolveSpec = (\n spec: ExtensionDefinitionAttachTo,\n ): { id: string; input: string } => {\n if (OpaqueExtensionInput.isType(spec)) {\n const { context } = OpaqueExtensionInput.toInternal(spec);\n if (!context) {\n throw new Error(\n 'Invalid input object without a parent extension used as attachment point',\n );\n }\n return {\n id: resolveExtensionId(context.kind, namespace, context.name),\n input: context.input,\n };\n }\n if ('relative' in spec && spec.relative) {\n return {\n id: resolveExtensionId(\n spec.relative.kind,\n namespace,\n spec.relative.name,\n ),\n input: spec.input,\n };\n }\n if ('id' in spec) {\n return { id: spec.id, input: spec.input };\n }\n throw new Error('Invalid attachment point specification');\n };\n\n if (Array.isArray(attachTo)) {\n return attachTo.map(resolveSpec);\n }\n\n return resolveSpec(attachTo);\n}\n\n/**\n * Resolves a list of extension definitions into extensions, returning both the\n * resolved extensions and a map of extension definitions keyed by resolved ID.\n * Throws if any two definitions resolve to the same ID.\n *\n * @internal\n */\nexport function resolveExtensionDefinitions(\n definitions: Iterable<ExtensionDefinition>,\n context: { namespace: string; featureType: string },\n): {\n extensions: Extension<any>[];\n extensionDefinitionsById: Map<\n string,\n typeof OpaqueExtensionDefinition.TInternal\n >;\n} {\n const extensions = new Array<Extension<any>>();\n const extensionDefinitionsById = new Map<\n string,\n typeof OpaqueExtensionDefinition.TInternal\n >();\n\n for (const def of definitions) {\n const internal = OpaqueExtensionDefinition.toInternal(def);\n const ext = resolveExtensionDefinition(def, {\n namespace: context.namespace,\n });\n extensions.push(ext);\n extensionDefinitionsById.set(ext.id, {\n ...internal,\n namespace: context.namespace,\n });\n }\n\n if (extensions.length !== extensionDefinitionsById.size) {\n const extensionIds = extensions.map(e => e.id);\n const duplicates = Array.from(\n new Set(\n extensionIds.filter((id, index) => extensionIds.indexOf(id) !== index),\n ),\n );\n throw new Error(\n `${context.featureType} '${\n context.namespace\n }' provided duplicate extensions: ${duplicates.join(', ')}`,\n );\n }\n\n return { extensions, extensionDefinitionsById };\n}\n\n/** @internal */\nexport function resolveExtensionDefinition<\n T extends ExtensionDefinitionParameters,\n>(\n definition: ExtensionDefinition<T>,\n context?: { namespace?: string },\n): Extension<T['config'], T['configInput']> {\n const internalDefinition = OpaqueExtensionDefinition.toInternal(definition);\n\n const {\n name,\n kind,\n namespace: internalNamespace,\n override: _skip2,\n attachTo,\n ...rest\n } = internalDefinition;\n\n const namespace = internalNamespace ?? context?.namespace;\n const id = resolveExtensionId(kind, namespace, name);\n\n return {\n ...rest,\n attachTo: resolveAttachTo(attachTo, namespace) as ExtensionAttachTo,\n $$type: '@backstage/Extension',\n version: internalDefinition.version,\n id,\n toString() {\n return `Extension{id=${id}}`;\n },\n } as InternalExtension<T['config'], T['configInput']> & Object;\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"resolveExtensionDefinition.esm.js","sources":["../../../../../frontend-plugin-api/src/wiring/resolveExtensionDefinition.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 { ApiHolder, AppNode } from '../apis';\nimport {\n ExtensionDefinitionAttachTo,\n ExtensionDefinition,\n ExtensionDefinitionParameters,\n ResolvedExtensionInputs,\n} from './createExtension';\nimport { PortableSchema } from '../schema';\nimport { ExtensionInput } from './createExtensionInput';\nimport { ExtensionDataRef, ExtensionDataValue } from './createExtensionDataRef';\nimport {\n OpaqueExtensionDefinition,\n OpaqueExtensionInput,\n} from '@internal/frontend';\nimport { FilterPredicate } from '@backstage/filter-predicates';\n\n/** @public */\nexport type ExtensionAttachTo = { id: string; input: string };\n\n/** @public */\nexport interface Extension<TConfig, TConfigInput = TConfig> {\n $$type: '@backstage/Extension';\n readonly id: string;\n readonly attachTo: ExtensionAttachTo;\n readonly disabled: boolean;\n readonly configSchema?: PortableSchema<TConfig, TConfigInput>;\n}\n\n/** @internal */\nexport type InternalExtension<TConfig, TConfigInput> = Extension<\n TConfig,\n TConfigInput\n> &\n (\n | {\n readonly version: 'v1';\n readonly inputs: {\n [inputName in string]: {\n $$type: '@backstage/ExtensionInput';\n extensionData: {\n [name in string]: ExtensionDataRef;\n };\n config: { optional: boolean; singleton: boolean };\n };\n };\n readonly output: {\n [name in string]: ExtensionDataRef;\n };\n factory(context: {\n apis: ApiHolder;\n node: AppNode;\n config: TConfig;\n inputs: {\n [inputName in string]: unknown;\n };\n }): {\n [inputName in string]: unknown;\n };\n }\n | {\n readonly version: 'v2';\n readonly if?: FilterPredicate;\n readonly inputs: { [inputName in string]: ExtensionInput };\n readonly output: Array<ExtensionDataRef>;\n factory(options: {\n apis: ApiHolder;\n node: AppNode;\n config: TConfig;\n inputs: ResolvedExtensionInputs<{\n [inputName in string]: ExtensionInput;\n }>;\n }): Iterable<ExtensionDataValue<any, any>>;\n }\n );\n\n/** @internal */\nexport function toInternalExtension<TConfig, TConfigInput>(\n overrides: Extension<TConfig, TConfigInput>,\n): InternalExtension<TConfig, TConfigInput> {\n const internal = overrides as InternalExtension<TConfig, TConfigInput>;\n if (internal.$$type !== '@backstage/Extension') {\n throw new Error(\n `Invalid extension instance, bad type '${internal.$$type}'`,\n );\n }\n const version = internal.version;\n if (version !== 'v1' && version !== 'v2') {\n throw new Error(`Invalid extension instance, bad version '${version}'`);\n }\n return internal;\n}\n\n/** @ignore */\nexport type ResolveExtensionId<\n TExtension extends ExtensionDefinition,\n TNamespace extends string,\n> = TExtension extends ExtensionDefinition<{\n kind: infer IKind extends string | undefined;\n name: infer IName extends string | undefined;\n params: any;\n}>\n ? [string] extends [IKind | IName]\n ? never\n : (\n undefined extends IName ? TNamespace : `${TNamespace}/${IName}`\n ) extends infer INamePart extends string\n ? IKind extends string\n ? `${IKind}:${INamePart}`\n : INamePart\n : never\n : never;\n\nfunction resolveExtensionId(\n kind?: string,\n namespace?: string,\n name?: string,\n): string {\n const namePart =\n name && namespace ? `${namespace}/${name}` : namespace || name;\n if (!namePart) {\n throw new Error(\n `Extension must declare an explicit namespace or name as it could not be resolved from context, kind=${kind} namespace=${namespace} name=${name}`,\n );\n }\n\n return kind ? `${kind}:${namePart}` : namePart;\n}\n\nfunction resolveAttachTo(\n attachTo: ExtensionDefinitionAttachTo | ExtensionDefinitionAttachTo[],\n namespace?: string,\n): ExtensionAttachTo | ExtensionAttachTo[] {\n const resolveSpec = (\n spec: ExtensionDefinitionAttachTo,\n ): { id: string; input: string } => {\n if (OpaqueExtensionInput.isType(spec)) {\n const { context } = OpaqueExtensionInput.toInternal(spec);\n if (!context) {\n throw new Error(\n 'Invalid input object without a parent extension used as attachment point',\n );\n }\n return {\n id: resolveExtensionId(context.kind, namespace, context.name),\n input: context.input,\n };\n }\n if ('relative' in spec && spec.relative) {\n return {\n id: resolveExtensionId(\n spec.relative.kind,\n namespace,\n spec.relative.name,\n ),\n input: spec.input,\n };\n }\n if ('id' in spec) {\n return { id: spec.id, input: spec.input };\n }\n throw new Error('Invalid attachment point specification');\n };\n\n if (Array.isArray(attachTo)) {\n return attachTo.map(resolveSpec);\n }\n\n return resolveSpec(attachTo);\n}\n\n/**\n * Resolves a list of extension definitions into extensions, returning both the\n * resolved extensions and a map of extension definitions keyed by resolved ID.\n * Throws if any two definitions resolve to the same ID.\n *\n * @internal\n */\nexport function resolveExtensionDefinitions(\n definitions: Iterable<ExtensionDefinition>,\n context: { namespace: string; featureType: string },\n): {\n extensions: Extension<any>[];\n extensionDefinitionsById: Map<\n string,\n typeof OpaqueExtensionDefinition.TInternal\n >;\n} {\n const extensions = new Array<Extension<any>>();\n const extensionDefinitionsById = new Map<\n string,\n typeof OpaqueExtensionDefinition.TInternal\n >();\n\n for (const def of definitions) {\n const internal = OpaqueExtensionDefinition.toInternal(def);\n const ext = resolveExtensionDefinition(def, {\n namespace: context.namespace,\n });\n extensions.push(ext);\n extensionDefinitionsById.set(ext.id, {\n ...internal,\n namespace: context.namespace,\n });\n }\n\n throwOnDuplicateExtensionIds(\n extensions.map(e => e.id),\n context,\n );\n\n return { extensions, extensionDefinitionsById };\n}\n\n/**\n * Throws if the provided list of resolved extension IDs contains duplicates.\n *\n * @internal\n */\nexport function throwOnDuplicateExtensionIds(\n extensionIds: string[],\n context: { namespace: string; featureType: string },\n): void {\n const seen = new Set<string>();\n const duplicates = new Set<string>();\n for (const id of extensionIds) {\n if (seen.has(id)) {\n duplicates.add(id);\n } else {\n seen.add(id);\n }\n }\n if (duplicates.size > 0) {\n throw new Error(\n `${context.featureType} '${\n context.namespace\n }' provided duplicate extensions: ${Array.from(duplicates).join(', ')}`,\n );\n }\n}\n\n/** @internal */\nexport function resolveExtensionDefinition<\n T extends ExtensionDefinitionParameters,\n>(\n definition: ExtensionDefinition<T>,\n context?: { namespace?: string },\n): Extension<T['config'], T['configInput']> {\n const internalDefinition = OpaqueExtensionDefinition.toInternal(definition);\n\n const {\n name,\n kind,\n namespace: internalNamespace,\n override: _skip2,\n attachTo,\n ...rest\n } = internalDefinition;\n\n const namespace = internalNamespace ?? context?.namespace;\n const id = resolveExtensionId(kind, namespace, name);\n\n return {\n ...rest,\n attachTo: resolveAttachTo(attachTo, namespace) as ExtensionAttachTo,\n $$type: '@backstage/Extension',\n version: internalDefinition.version,\n id,\n toString() {\n return `Extension{id=${id}}`;\n },\n } as InternalExtension<T['config'], T['configInput']> & Object;\n}\n"],"names":[],"mappings":";;;;;AA4FO,SAAS,oBACd,SAAA,EAC0C;AAC1C,EAAA,MAAM,QAAA,GAAW,SAAA;AACjB,EAAA,IAAI,QAAA,CAAS,WAAW,sBAAA,EAAwB;AAC9C,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,CAAA,sCAAA,EAAyC,SAAS,MAAM,CAAA,CAAA;AAAA,KAC1D;AAAA,EACF;AACA,EAAA,MAAM,UAAU,QAAA,CAAS,OAAA;AACzB,EAAA,IAAI,OAAA,KAAY,IAAA,IAAQ,OAAA,KAAY,IAAA,EAAM;AACxC,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,yCAAA,EAA4C,OAAO,CAAA,CAAA,CAAG,CAAA;AAAA,EACxE;AACA,EAAA,OAAO,QAAA;AACT;AAsBA,SAAS,kBAAA,CACP,IAAA,EACA,SAAA,EACA,IAAA,EACQ;AACR,EAAA,MAAM,QAAA,GACJ,QAAQ,SAAA,GAAY,CAAA,EAAG,SAAS,CAAA,CAAA,EAAI,IAAI,KAAK,SAAA,IAAa,IAAA;AAC5D,EAAA,IAAI,CAAC,QAAA,EAAU;AACb,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,CAAA,oGAAA,EAAuG,IAAI,CAAA,WAAA,EAAc,SAAS,SAAS,IAAI,CAAA;AAAA,KACjJ;AAAA,EACF;AAEA,EAAA,OAAO,IAAA,GAAO,CAAA,EAAG,IAAI,CAAA,CAAA,EAAI,QAAQ,CAAA,CAAA,GAAK,QAAA;AACxC;AAEA,SAAS,eAAA,CACP,UACA,SAAA,EACyC;AACzC,EAAA,MAAM,WAAA,GAAc,CAClB,IAAA,KACkC;AAClC,IAAA,IAAI,oBAAA,CAAqB,MAAA,CAAO,IAAI,CAAA,EAAG;AACrC,MAAA,MAAM,EAAE,OAAA,EAAQ,GAAI,oBAAA,CAAqB,WAAW,IAAI,CAAA;AACxD,MAAA,IAAI,CAAC,OAAA,EAAS;AACZ,QAAA,MAAM,IAAI,KAAA;AAAA,UACR;AAAA,SACF;AAAA,MACF;AACA,MAAA,OAAO;AAAA,QACL,IAAI,kBAAA,CAAmB,OAAA,CAAQ,IAAA,EAAM,SAAA,EAAW,QAAQ,IAAI,CAAA;AAAA,QAC5D,OAAO,OAAA,CAAQ;AAAA,OACjB;AAAA,IACF;AACA,IAAA,IAAI,UAAA,IAAc,IAAA,IAAQ,IAAA,CAAK,QAAA,EAAU;AACvC,MAAA,OAAO;AAAA,QACL,EAAA,EAAI,kBAAA;AAAA,UACF,KAAK,QAAA,CAAS,IAAA;AAAA,UACd,SAAA;AAAA,UACA,KAAK,QAAA,CAAS;AAAA,SAChB;AAAA,QACA,OAAO,IAAA,CAAK;AAAA,OACd;AAAA,IACF;AACA,IAAA,IAAI,QAAQ,IAAA,EAAM;AAChB,MAAA,OAAO,EAAE,EAAA,EAAI,IAAA,CAAK,EAAA,EAAI,KAAA,EAAO,KAAK,KAAA,EAAM;AAAA,IAC1C;AACA,IAAA,MAAM,IAAI,MAAM,wCAAwC,CAAA;AAAA,EAC1D,CAAA;AAEA,EAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,QAAQ,CAAA,EAAG;AAC3B,IAAA,OAAO,QAAA,CAAS,IAAI,WAAW,CAAA;AAAA,EACjC;AAEA,EAAA,OAAO,YAAY,QAAQ,CAAA;AAC7B;AAyEO,SAAS,0BAAA,CAGd,YACA,OAAA,EAC0C;AAC1C,EAAA,MAAM,kBAAA,GAAqB,yBAAA,CAA0B,UAAA,CAAW,UAAU,CAAA;AAE1E,EAAA,MAAM;AAAA,IACJ,IAAA;AAAA,IACA,IAAA;AAAA,IACA,SAAA,EAAW,iBAAA;AAAA,IACX,QAAA,EAAU,MAAA;AAAA,IACV,QAAA;AAAA,IACA,GAAG;AAAA,GACL,GAAI,kBAAA;AAEJ,EAAA,MAAM,SAAA,GAAY,qBAAqB,OAAA,EAAS,SAAA;AAChD,EAAA,MAAM,EAAA,GAAK,kBAAA,CAAmB,IAAA,EAAM,SAAA,EAAW,IAAI,CAAA;AAEnD,EAAA,OAAO;AAAA,IACL,GAAG,IAAA;AAAA,IACH,QAAA,EAAU,eAAA,CAAgB,QAAA,EAAU,SAAS,CAAA;AAAA,IAC7C,MAAA,EAAQ,sBAAA;AAAA,IACR,SAAS,kBAAA,CAAmB,OAAA;AAAA,IAC5B,EAAA;AAAA,IACA,QAAA,GAAW;AACT,MAAA,OAAO,gBAAgB,EAAE,CAAA,CAAA,CAAA;AAAA,IAC3B;AAAA,GACF;AACF;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"OpaqueType.esm.js","sources":["../../../../opaque-internal/src/OpaqueType.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 */\n\n// TODO(Rugvip): This lives here temporarily, but should be moved to a more\n// central location. It's useful for backend packages too so we'll need to have\n// it in a common package, but it might also be that we want to make it\n// available publicly too in which case it would make sense to have this be part\n// of @backstage/version-bridge. The problem with exporting it from there is\n// that it would need to be very stable at that point, so it might be a bit\n// early to put it there already.\n\n/**\n * A helper for working with opaque types.\n */\nexport class OpaqueType<\n T extends {\n public: { $$type: string };\n versions: { version: string | undefined };\n },\n> {\n /**\n * Creates a new opaque type.\n *\n * @param options.type The type identifier of the opaque type\n * @param options.versions The available versions of the opaque type\n * @returns A new opaque type helper\n */\n static create<\n T extends {\n public: { $$type: string };\n versions: { version: string | undefined };\n },\n >(options: {\n type: T['public']['$$type'];\n versions: Array<T['versions']['version']>;\n }) {\n return new OpaqueType<T>(options.type, new Set(options.versions));\n }\n\n #type: string;\n #versions: Set<string | undefined>;\n\n private constructor(type: string, versions: Set<string | undefined>) {\n this.#type = type;\n this.#versions = versions;\n }\n\n /**\n * The internal version of the opaque type, used like this: `typeof MyOpaqueType.TPublic`\n *\n * @remarks\n *\n * This property is only useful for type checking, its runtime value is `undefined`.\n */\n TPublic: T['public'] = undefined as any;\n\n /**\n * The internal version of the opaque type, used like this: `typeof MyOpaqueType.TInternal`\n *\n * @remarks\n *\n * This property is only useful for type checking, its runtime value is `undefined`.\n */\n TInternal: T['public'] & T['versions'] = undefined as any;\n\n /**\n * @param value Input value expected to be an instance of this opaque type\n * @returns True if the value matches this opaque type\n */\n isType = (value: unknown): value is T['public'] => {\n return this.#isThisInternalType(value);\n };\n\n /**\n * @param value Input value expected to be an instance of this opaque type\n * @throws If the value is not an instance of this opaque type or is of an unsupported version\n * @returns The internal version of the opaque type\n */\n toInternal = (value: unknown): T['public'] & T['versions'] => {\n if (!this.#isThisInternalType(value)) {\n throw new TypeError(\n `Invalid opaque type, expected '${\n this.#type\n }', but got '${this.#stringifyUnknown(value)}'`,\n );\n }\n\n if (!this.#versions.has(value.version)) {\n const versions = Array.from(this.#versions).map(this.#stringifyVersion);\n if (versions.length > 1) {\n versions[versions.length - 1] = `or ${versions[versions.length - 1]}`;\n }\n const expected =\n versions.length > 2 ? versions.join(', ') : versions.join(' ');\n throw new TypeError(\n `Invalid opaque type instance, got version ${this.#stringifyVersion(\n value.version,\n )}, expected ${expected}`,\n );\n }\n\n return value;\n };\n\n /**\n * Creates an instance of the opaque type, returning the public type.\n *\n * @param version The version of the instance to create\n * @param value The remaining public and internal properties of the instance\n * @returns An instance of the opaque type\n */\n createInstance<\n TVersion extends T['versions']['version'],\n TPublic extends T['public'],\n >(\n version: TVersion,\n props: Omit<T['public'], '$$type'> &\n (T['versions'] extends infer UVersion\n ? UVersion extends { version: TVersion }\n ? Omit<UVersion, 'version'>\n : never\n : never) &\n Object, // & Object to allow for object properties too, e.g. toString()\n ): TPublic {\n return Object.assign(props as object, {\n $$type: this.#type,\n ...(version && { version }),\n }) as unknown as TPublic;\n }\n\n #isThisInternalType(value: unknown): value is T['public'] & T['versions'] {\n if (value === null || typeof value !== 'object') {\n return false;\n }\n return (value as T['public']).$$type === this.#type;\n }\n\n #stringifyUnknown(value: unknown) {\n if (typeof value !== 'object') {\n return `<${typeof value}>`;\n }\n if (value === null) {\n return '<null>';\n }\n if ('$$type' in value) {\n return String(value.$$type);\n }\n return String(value);\n }\n\n #stringifyVersion = (version: string | undefined) => {\n return version ? `'${version}'` : 'undefined';\n };\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"OpaqueType.esm.js","sources":["../../../../opaque-internal/src/OpaqueType.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 */\n\n// TODO(Rugvip): This lives here temporarily, but should be moved to a more\n// central location. It's useful for backend packages too so we'll need to have\n// it in a common package, but it might also be that we want to make it\n// available publicly too in which case it would make sense to have this be part\n// of @backstage/version-bridge. The problem with exporting it from there is\n// that it would need to be very stable at that point, so it might be a bit\n// early to put it there already.\n\n/**\n * A helper for working with opaque types.\n */\nexport class OpaqueType<\n T extends {\n public: { $$type: string };\n versions: { version: string | undefined };\n },\n> {\n /**\n * Creates a new opaque type.\n *\n * @param options.type The type identifier of the opaque type\n * @param options.versions The available versions of the opaque type\n * @returns A new opaque type helper\n */\n static create<\n T extends {\n public: { $$type: string };\n versions: { version: string | undefined };\n },\n >(options: {\n type: T['public']['$$type'];\n versions: Array<T['versions']['version']>;\n }) {\n return new OpaqueType<T>(options.type, new Set(options.versions));\n }\n\n #type: string;\n #versions: Set<string | undefined>;\n\n private constructor(type: string, versions: Set<string | undefined>) {\n this.#type = type;\n this.#versions = versions;\n }\n\n /**\n * The internal version of the opaque type, used like this: `typeof MyOpaqueType.TPublic`\n *\n * @remarks\n *\n * This property is only useful for type checking, its runtime value is `undefined`.\n */\n TPublic: T['public'] = undefined as any;\n\n /**\n * The internal version of the opaque type, used like this: `typeof MyOpaqueType.TInternal`\n *\n * @remarks\n *\n * This property is only useful for type checking, its runtime value is `undefined`.\n */\n TInternal: T['public'] & T['versions'] = undefined as any;\n\n /**\n * @param value Input value expected to be an instance of this opaque type\n * @returns True if the value matches this opaque type\n */\n isType = (value: unknown): value is T['public'] => {\n return this.#isThisInternalType(value);\n };\n\n /**\n * @param value Input value expected to be an instance of this opaque type\n * @throws If the value is not an instance of this opaque type or is of an unsupported version\n * @returns The internal version of the opaque type\n */\n toInternal = (value: unknown): T['public'] & T['versions'] => {\n if (!this.#isThisInternalType(value)) {\n throw new TypeError(\n `Invalid opaque type, expected '${\n this.#type\n }', but got '${this.#stringifyUnknown(value)}'`,\n );\n }\n\n if (!this.#versions.has(value.version)) {\n const versions = Array.from(this.#versions).map(this.#stringifyVersion);\n if (versions.length > 1) {\n versions[versions.length - 1] = `or ${versions[versions.length - 1]}`;\n }\n const expected =\n versions.length > 2 ? versions.join(', ') : versions.join(' ');\n throw new TypeError(\n `Invalid opaque type instance, got version ${this.#stringifyVersion(\n value.version,\n )}, expected ${expected}`,\n );\n }\n\n return value;\n };\n\n /**\n * Creates an instance of the opaque type, returning the public type.\n *\n * @param version The version of the instance to create\n * @param value The remaining public and internal properties of the instance\n * @returns An instance of the opaque type\n */\n createInstance<\n TVersion extends T['versions']['version'],\n TPublic extends T['public'],\n >(\n version: TVersion,\n props: Omit<T['public'], '$$type'> &\n (T['versions'] extends infer UVersion\n ? UVersion extends { version: TVersion }\n ? Omit<UVersion, 'version'>\n : never\n : never) &\n Object, // & Object to allow for object properties too, e.g. toString()\n ): TPublic {\n return Object.assign(props as object, {\n $$type: this.#type,\n ...(version && { version }),\n }) as unknown as TPublic;\n }\n\n #isThisInternalType(value: unknown): value is T['public'] & T['versions'] {\n if (value === null || typeof value !== 'object') {\n return false;\n }\n return (value as T['public']).$$type === this.#type;\n }\n\n #stringifyUnknown(value: unknown) {\n if (typeof value !== 'object') {\n return `<${typeof value}>`;\n }\n if (value === null) {\n return '<null>';\n }\n if ('$$type' in value) {\n return String(value.$$type);\n }\n return String(value);\n }\n\n #stringifyVersion = (version: string | undefined) => {\n return version ? `'${version}'` : 'undefined';\n };\n}\n"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"RouteAliasResolver.esm.js","sources":["../../src/routing/RouteAliasResolver.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 { RouteRef } from '@backstage/frontend-plugin-api';\nimport { RouteRefsById } from './collectRouteIds';\nimport { OpaqueRouteRef } from '@internal/frontend';\n\n/**\n * @internal\n */\nexport type RouteAliasResolver = {\n (routeRef: RouteRef, pluginId?: string): RouteRef;\n (routeRef?: RouteRef, pluginId?: string): RouteRef | undefined;\n};\n\n/**\n * Creates a route alias resolver that resolves aliases based on the route IDs\n * @internal\n */\nexport function createRouteAliasResolver(\n routeRefsById: RouteRefsById,\n): RouteAliasResolver {\n const resolver = (routeRef: RouteRef | undefined, pluginId?: string) => {\n if (!routeRef) {\n return undefined;\n }\n\n let currentRef = routeRef;\n for (let i = 0; i < 100; i++) {\n const alias = OpaqueRouteRef.toInternal(currentRef).alias;\n if (alias) {\n if (pluginId) {\n const [aliasPluginId] = alias.split('.');\n if (aliasPluginId !== pluginId) {\n throw new Error(\n `Refused to resolve alias '${alias}' for ${currentRef} as it points to a different plugin, the expected plugin is '${pluginId}' but the alias points to '${aliasPluginId}'`,\n );\n }\n }\n const aliasRef = routeRefsById.routes.get(alias);\n if (!aliasRef) {\n throw new Error(\n `Unable to resolve RouteRef alias '${alias}' for ${currentRef}`,\n );\n }\n if (aliasRef.$$type === '@backstage/SubRouteRef') {\n throw new Error(\n `RouteRef alias '${alias}' for ${currentRef} points to a SubRouteRef, which is not supported`,\n );\n }\n currentRef = aliasRef;\n } else {\n return currentRef;\n }\n }\n throw new Error(`Alias loop detected for ${routeRef}`);\n };\n\n return resolver as RouteAliasResolver;\n}\n\n/**\n * Creates a route alias resolver that resolves aliases based on a map of route refs to their aliases\n * @internal\n */\nexport function createExactRouteAliasResolver(\n routeAliases: Map<RouteRef, RouteRef | undefined>,\n): RouteAliasResolver {\n const resolver = (routeRef?: RouteRef) => {\n if (routeRef && routeAliases.has(routeRef)) {\n return routeAliases.get(routeRef);\n }\n return routeRef;\n };\n return resolver as RouteAliasResolver;\n}\n"],"names":[],"mappings":";;;;AAgCO,SAAS,yBACd,aAAA,EACoB;AACpB,EAAA,MAAM,QAAA,GAAW,CAAC,QAAA,EAAgC,QAAA,KAAsB;AACtE,IAAA,IAAI,CAAC,QAAA,EAAU;AACb,MAAA,OAAO,MAAA;AAAA,IACT;AAEA,IAAA,IAAI,UAAA,GAAa,QAAA;AACjB,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,GAAA,EAAK,CAAA,EAAA,EAAK;AAC5B,MAAA,MAAM,KAAA,GAAQ,cAAA,CAAe,UAAA,CAAW,UAAU,CAAA,CAAE,KAAA;AACpD,MAAA,IAAI,KAAA,EAAO;AACT,QAAA,IAAI,QAAA,EAAU;AACZ,UAAA,MAAM,CAAC,aAAa,CAAA,GAAI,KAAA,CAAM,MAAM,GAAG,CAAA;AACvC,UAAA,IAAI,kBAAkB,QAAA,EAAU;AAC9B,YAAA,MAAM,IAAI,KAAA;AAAA,cACR,6BAA6B,KAAK,CAAA,MAAA,EAAS,UAAU,CAAA,6DAAA,EAAgE,QAAQ,8BAA8B,aAAa,CAAA,CAAA;AAAA,aAC1K;AAAA,UACF;AAAA,QACF;AACA,QAAA,MAAM,QAAA,GAAW,aAAA,CAAc,MAAA,CAAO,GAAA,CAAI,KAAK,CAAA;AAC/C,QAAA,IAAI,CAAC,QAAA,EAAU;AACb,UAAA,MAAM,IAAI,KAAA;AAAA,YACR,CAAA,kCAAA,EAAqC,KAAK,CAAA,MAAA,EAAS,UAAU,CAAA;AAAA,WAC/D;AAAA,QACF;AACA,QAAA,IAAI,QAAA,CAAS,WAAW,wBAAA,EAA0B;AAChD,UAAA,MAAM,IAAI,KAAA;AAAA,YACR,CAAA,gBAAA,EAAmB,KAAK,CAAA,MAAA,EAAS,UAAU,CAAA,gDAAA;AAAA,WAC7C;AAAA,QACF;AACA,QAAA,UAAA,GAAa,QAAA;AAAA,MACf,CAAA,MAAO;AACL,QAAA,OAAO,UAAA;AAAA,MACT;AAAA,IACF;AACA,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,wBAAA,EAA2B,QAAQ,CAAA,CAAE,CAAA;AAAA,EACvD,CAAA;AAEA,EAAA,OAAO,QAAA;AACT;AAMO,SAAS,8BACd,YAAA,EACoB;AACpB,EAAA,MAAM,QAAA,GAAW,CAAC,QAAA,KAAwB;AACxC,IAAA,IAAI,QAAA,IAAY,YAAA,CAAa,GAAA,CAAI,QAAQ,CAAA,EAAG;AAC1C,MAAA,OAAO,YAAA,CAAa,IAAI,QAAQ,CAAA;AAAA,IAClC;AACA,IAAA,OAAO,QAAA;AAAA,EACT,CAAA;AACA,EAAA,OAAO,QAAA;AACT;;;;"}
1
+ {"version":3,"file":"RouteAliasResolver.esm.js","sources":["../../src/routing/RouteAliasResolver.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 { RouteRef } from '@backstage/frontend-plugin-api';\nimport { RouteRefsById } from './collectRouteIds';\nimport { OpaqueRouteRef } from '@internal/frontend';\n\n/**\n * @internal\n */\nexport type RouteAliasResolver = {\n (routeRef: RouteRef, pluginId?: string): RouteRef;\n (routeRef?: RouteRef, pluginId?: string): RouteRef | undefined;\n};\n\n/**\n * Creates a route alias resolver that resolves aliases based on the route IDs\n * @internal\n */\nexport function createRouteAliasResolver(\n routeRefsById: RouteRefsById,\n): RouteAliasResolver {\n const resolver = (routeRef: RouteRef | undefined, pluginId?: string) => {\n if (!routeRef) {\n return undefined;\n }\n\n let currentRef = routeRef;\n for (let i = 0; i < 100; i++) {\n const alias = OpaqueRouteRef.toInternal(currentRef).alias;\n if (alias) {\n if (pluginId) {\n const [aliasPluginId] = alias.split('.');\n if (aliasPluginId !== pluginId) {\n throw new Error(\n `Refused to resolve alias '${alias}' for ${currentRef} as it points to a different plugin, the expected plugin is '${pluginId}' but the alias points to '${aliasPluginId}'`,\n );\n }\n }\n const aliasRef = routeRefsById.routes.get(alias);\n if (!aliasRef) {\n throw new Error(\n `Unable to resolve RouteRef alias '${alias}' for ${currentRef}`,\n );\n }\n if (aliasRef.$$type === '@backstage/SubRouteRef') {\n throw new Error(\n `RouteRef alias '${alias}' for ${currentRef} points to a SubRouteRef, which is not supported`,\n );\n }\n currentRef = aliasRef;\n } else {\n return currentRef;\n }\n }\n throw new Error(`Alias loop detected for ${routeRef}`);\n };\n\n return resolver as RouteAliasResolver;\n}\n\n/**\n * Creates a route alias resolver that resolves aliases based on a map of route refs to their aliases\n * @internal\n */\nexport function createExactRouteAliasResolver(\n routeAliases: Map<RouteRef, RouteRef | undefined>,\n): RouteAliasResolver {\n const resolver = (routeRef?: RouteRef) => {\n if (routeRef && routeAliases.has(routeRef)) {\n return routeAliases.get(routeRef);\n }\n return routeRef;\n };\n return resolver as RouteAliasResolver;\n}\n"],"names":[],"mappings":";;;;AAgCO,SAAS,yBACd,aAAA,EACoB;AACpB,EAAA,MAAM,QAAA,GAAW,CAAC,QAAA,EAAgC,QAAA,KAAsB;AACtE,IAAA,IAAI,CAAC,QAAA,EAAU;AACb,MAAA,OAAO,MAAA;AAAA,IACT;AAEA,IAAA,IAAI,UAAA,GAAa,QAAA;AACjB,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,GAAA,EAAK,CAAA,EAAA,EAAK;AAC5B,MAAA,MAAM,KAAA,GAAQ,cAAA,CAAe,UAAA,CAAW,UAAU,CAAA,CAAE,KAAA;AACpD,MAAA,IAAI,KAAA,EAAO;AACT,QAAA,IAAI,QAAA,EAAU;AACZ,UAAA,MAAM,CAAC,aAAa,CAAA,GAAI,KAAA,CAAM,MAAM,GAAG,CAAA;AACvC,UAAA,IAAI,kBAAkB,QAAA,EAAU;AAC9B,YAAA,MAAM,IAAI,KAAA;AAAA,cACR,6BAA6B,KAAK,CAAA,MAAA,EAAS,UAAU,CAAA,6DAAA,EAAgE,QAAQ,8BAA8B,aAAa,CAAA,CAAA;AAAA,aAC1K;AAAA,UACF;AAAA,QACF;AACA,QAAA,MAAM,QAAA,GAAW,aAAA,CAAc,MAAA,CAAO,GAAA,CAAI,KAAK,CAAA;AAC/C,QAAA,IAAI,CAAC,QAAA,EAAU;AACb,UAAA,MAAM,IAAI,KAAA;AAAA,YACR,CAAA,kCAAA,EAAqC,KAAK,CAAA,MAAA,EAAS,UAAU,CAAA;AAAA,WAC/D;AAAA,QACF;AACA,QAAA,IAAI,QAAA,CAAS,WAAW,wBAAA,EAA0B;AAChD,UAAA,MAAM,IAAI,KAAA;AAAA,YACR,CAAA,gBAAA,EAAmB,KAAK,CAAA,MAAA,EAAS,UAAU,CAAA,gDAAA;AAAA,WAC7C;AAAA,QACF;AACA,QAAA,UAAA,GAAa,QAAA;AAAA,MACf,CAAA,MAAO;AACL,QAAA,OAAO,UAAA;AAAA,MACT;AAAA,IACF;AACA,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,wBAAA,EAA2B,QAAQ,CAAA,CAAE,CAAA;AAAA,EACvD,CAAA;AAEA,EAAA,OAAO,QAAA;AACT;AAMO,SAAS,8BACd,YAAA,EACoB;AACpB,EAAA,MAAM,QAAA,GAAW,CAAC,QAAA,KAAwB;AACxC,IAAA,IAAI,QAAA,IAAY,YAAA,CAAa,GAAA,CAAI,QAAQ,CAAA,EAAG;AAC1C,MAAA,OAAO,YAAA,CAAa,IAAI,QAAQ,CAAA;AAAA,IAClC;AACA,IAAA,OAAO,QAAA;AAAA,EACT,CAAA;AACA,EAAA,OAAO,QAAA;AACT;;"}
@@ -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 RouteRef,\n ExternalRouteRef,\n SubRouteRef,\n AnyRouteRefParams,\n RouteFunc,\n RouteResolutionApi,\n} from '@backstage/frontend-plugin-api';\nimport mapValues from 'lodash/mapValues';\nimport { AnyRouteRef, BackstageRouteObject } from './types';\nimport {\n OpaqueRouteRef,\n OpaqueExternalRouteRef,\n OpaqueSubRouteRef,\n} from '@internal/frontend';\nimport { RouteAliasResolver } from './RouteAliasResolver';\nimport { joinPaths } from './joinPaths';\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 targetRouteRef: AnyRouteRef,\n routePaths: Map<RouteRef, string>,\n routeBindings: Map<AnyRouteRef, AnyRouteRef | undefined>,\n routeRefsById: Map<string, RouteRef | SubRouteRef>,\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 ref: AnyRouteRef = targetRouteRef;\n let path = '';\n\n if (OpaqueExternalRouteRef.isType(ref)) {\n let resolvedRoute = routeBindings.get(ref);\n if (!resolvedRoute) {\n const internal = OpaqueExternalRouteRef.toInternal(ref);\n const defaultTarget = internal.getDefaultTarget();\n if (defaultTarget) {\n resolvedRoute = routeRefsById.get(defaultTarget);\n }\n }\n if (!resolvedRoute) {\n return [undefined, ''];\n }\n ref = resolvedRoute;\n }\n\n if (OpaqueSubRouteRef.isType(ref)) {\n const internal = OpaqueSubRouteRef.toInternal(ref);\n path = ref.path;\n ref = internal.getParent();\n }\n\n if (!OpaqueRouteRef.isType(ref)) {\n throw new Error(\n `Unexpectedly resolved ${targetRouteRef} to a non-route ref ${ref}`,\n );\n }\n\n // Find the path that our target route is bound to\n const resolvedPath = routePaths.get(ref);\n if (resolvedPath === undefined) {\n return [undefined, ''];\n }\n\n return [ref, path ? joinPaths(resolvedPath, path) : resolvedPath];\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 implements RouteResolutionApi {\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 private readonly routeAliasResolver: RouteAliasResolver;\n private readonly routeRefsById: Map<string, RouteRef | SubRouteRef>;\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 routeAliasResolver: RouteAliasResolver,\n routeRefsById: Map<string, RouteRef | SubRouteRef>,\n ) {\n this.routePaths = routePaths;\n this.routeParents = routeParents;\n this.routeObjects = routeObjects;\n this.routeBindings = routeBindings;\n this.appBasePath = appBasePath;\n this.routeAliasResolver = routeAliasResolver;\n this.routeRefsById = routeRefsById;\n }\n\n resolve<TParams extends AnyRouteRefParams>(\n anyRouteRef:\n | RouteRef<TParams>\n | SubRouteRef<TParams>\n | ExternalRouteRef<TParams>,\n options?: { sourcePath?: string },\n ): RouteFunc<TParams> | undefined {\n // First figure out what our target absolute ref is, as well as our target path.\n const [targetRef, targetPath] = resolveTargetRef(\n anyRouteRef?.$$type === '@backstage/RouteRef'\n ? this.routeAliasResolver(anyRouteRef)\n : anyRouteRef,\n this.routePaths,\n this.routeBindings,\n this.routeRefsById,\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 const relativeSourceLocation = this.trimPath(options?.sourcePath ?? '');\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 = resolveBasePath(\n targetRef,\n relativeSourceLocation,\n this.routePaths,\n this.routeParents,\n this.routeObjects,\n );\n\n const routeFunc: RouteFunc<TParams> = (...[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":";;;;;;;AAyCA,SAAS,gBAAA,CACP,cAAA,EACA,UAAA,EACA,aAAA,EACA,aAAA,EACyC;AAGzC,EAAA,IAAI,GAAA,GAAmB,cAAA;AACvB,EAAA,IAAI,IAAA,GAAO,EAAA;AAEX,EAAA,IAAI,sBAAA,CAAuB,MAAA,CAAO,GAAG,CAAA,EAAG;AACtC,IAAA,IAAI,aAAA,GAAgB,aAAA,CAAc,GAAA,CAAI,GAAG,CAAA;AACzC,IAAA,IAAI,CAAC,aAAA,EAAe;AAClB,MAAA,MAAM,QAAA,GAAW,sBAAA,CAAuB,UAAA,CAAW,GAAG,CAAA;AACtD,MAAA,MAAM,aAAA,GAAgB,SAAS,gBAAA,EAAiB;AAChD,MAAA,IAAI,aAAA,EAAe;AACjB,QAAA,aAAA,GAAgB,aAAA,CAAc,IAAI,aAAa,CAAA;AAAA,MACjD;AAAA,IACF;AACA,IAAA,IAAI,CAAC,aAAA,EAAe;AAClB,MAAA,OAAO,CAAC,QAAW,EAAE,CAAA;AAAA,IACvB;AACA,IAAA,GAAA,GAAM,aAAA;AAAA,EACR;AAEA,EAAA,IAAI,iBAAA,CAAkB,MAAA,CAAO,GAAG,CAAA,EAAG;AACjC,IAAA,MAAM,QAAA,GAAW,iBAAA,CAAkB,UAAA,CAAW,GAAG,CAAA;AACjD,IAAA,IAAA,GAAO,GAAA,CAAI,IAAA;AACX,IAAA,GAAA,GAAM,SAAS,SAAA,EAAU;AAAA,EAC3B;AAEA,EAAA,IAAI,CAAC,cAAA,CAAe,MAAA,CAAO,GAAG,CAAA,EAAG;AAC/B,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,CAAA,sBAAA,EAAyB,cAAc,CAAA,oBAAA,EAAuB,GAAG,CAAA;AAAA,KACnE;AAAA,EACF;AAGA,EAAA,MAAM,YAAA,GAAe,UAAA,CAAW,GAAA,CAAI,GAAG,CAAA;AACvC,EAAA,IAAI,iBAAiB,MAAA,EAAW;AAC9B,IAAA,OAAO,CAAC,QAAW,EAAE,CAAA;AAAA,EACvB;AAEA,EAAA,OAAO,CAAC,GAAA,EAAK,IAAA,GAAO,UAAU,YAAA,EAAc,IAAI,IAAI,YAAY,CAAA;AAClE;AAKA,SAAS,eAAA,CACP,SAAA,EACA,cAAA,EACA,UAAA,EACA,cACA,YAAA,EACA;AAOA,EAAA,MAAM,KAAA,GAAQ,WAAA,CAAY,YAAA,EAAc,cAAc,KAAK,EAAC;AAK5D,EAAA,MAAM,cAAc,KAAA,EAAgB;AAEpC,EAAA,IAAI,UAAA,GAAa,EAAA;AACjB,EAAA,KAAA,IACM,kBAAwC,SAAA,EAC5C,eAAA,EACA,kBAAkB,YAAA,CAAa,GAAA,CAAI,eAAe,CAAA,EAClD;AAKA,IAAA,UAAA,GAAa,KAAA,CAAM,SAAA;AAAA,MAAU,CAAA,CAAA,KAC1B,CAAA,CAAE,KAAA,CAA+B,SAAA,CAAU,IAAI,eAAgB;AAAA,KAClE;AACA,IAAA,IAAI,eAAe,EAAA,EAAI;AACrB,MAAA;AAAA,IACF;AAKA,IAAA,WAAA,CAAY,QAAQ,eAAe,CAAA;AAAA,EACrC;AAKA,EAAA,IAAI,WAAA,CAAY,WAAW,CAAA,EAAG;AAC5B,IAAA,UAAA,IAAc,CAAA;AAAA,EAChB;AAIA,EAAA,MAAM,aAAa,UAAA,KAAe,EAAA,GAAK,EAAA,GAAK,KAAA,CAAM,UAAU,CAAA,CAAE,QAAA;AAM9D,EAAA,MAAM,YAAY,WAAA,CAAY,KAAA,CAAM,GAAG,EAAE,CAAA,CAAE,IAAI,CAAA,GAAA,KAAO;AACpD,IAAA,MAAM,IAAA,GAAO,UAAA,CAAW,GAAA,CAAI,GAAG,CAAA;AAC/B,IAAA,IAAI,SAAS,MAAA,EAAW;AACtB,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,YAAA,EAAe,GAAG,CAAA,CAAE,CAAA;AAAA,IACtC;AACA,IAAA,IAAI,IAAA,CAAK,QAAA,CAAS,GAAG,CAAA,EAAG;AACtB,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,CAAA,gBAAA,EAAmB,SAAS,CAAA,aAAA,EAAgB,GAAG,CAAA,qBAAA;AAAA,OACjD;AAAA,IACF;AACA,IAAA,OAAO,IAAA;AAAA,EACT,CAAC,CAAA;AAED,EAAA,OAAO,CAAA,EAAG,SAAA,CAAU,UAAA,EAAY,GAAG,SAAS,CAAC,CAAA,CAAA,CAAA;AAC/C;AAEO,MAAM,aAAA,CAA4C;AAAA,EACtC,UAAA;AAAA,EACA,YAAA;AAAA,EACA,YAAA;AAAA,EACA,aAAA;AAAA,EACA,WAAA;AAAA;AAAA,EACA,kBAAA;AAAA,EACA,aAAA;AAAA,EAEjB,YACE,UAAA,EACA,YAAA,EACA,cACA,aAAA,EACA,WAAA,EACA,oBACA,aAAA,EACA;AACA,IAAA,IAAA,CAAK,UAAA,GAAa,UAAA;AAClB,IAAA,IAAA,CAAK,YAAA,GAAe,YAAA;AACpB,IAAA,IAAA,CAAK,YAAA,GAAe,YAAA;AACpB,IAAA,IAAA,CAAK,aAAA,GAAgB,aAAA;AACrB,IAAA,IAAA,CAAK,WAAA,GAAc,WAAA;AACnB,IAAA,IAAA,CAAK,kBAAA,GAAqB,kBAAA;AAC1B,IAAA,IAAA,CAAK,aAAA,GAAgB,aAAA;AAAA,EACvB;AAAA,EAEA,OAAA,CACE,aAIA,OAAA,EACgC;AAEhC,IAAA,MAAM,CAAC,SAAA,EAAW,UAAU,CAAA,GAAI,gBAAA;AAAA,MAC9B,aAAa,MAAA,KAAW,qBAAA,GACpB,IAAA,CAAK,kBAAA,CAAmB,WAAW,CAAA,GACnC,WAAA;AAAA,MACJ,IAAA,CAAK,UAAA;AAAA,MACL,IAAA,CAAK,aAAA;AAAA,MACL,IAAA,CAAK;AAAA,KACP;AACA,IAAA,IAAI,CAAC,SAAA,EAAW;AACd,MAAA,OAAO,MAAA;AAAA,IACT;AAIA,IAAA,MAAM,sBAAA,GAAyB,IAAA,CAAK,QAAA,CAAS,OAAA,EAAS,cAAc,EAAE,CAAA;AAKtE,IAAA,MAAM,QAAA,GAAW,eAAA;AAAA,MACf,SAAA;AAAA,MACA,sBAAA;AAAA,MACA,IAAA,CAAK,UAAA;AAAA,MACL,IAAA,CAAK,YAAA;AAAA,MACL,IAAA,CAAK;AAAA,KACP;AAEA,IAAA,MAAM,SAAA,GAAgC,CAAA,GAAI,CAAC,MAAM,CAAA,KAAM;AASrD,MAAA,MAAM,aAAA,GACJ,MAAA,IACA,SAAA,CAAU,MAAA,EAAQ,CAAA,KAAA,KAAS;AACzB,QAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,UAAA,OAAO,MAAM,UAAA,CAAW,WAAA,EAAa,CAAA,CAAA,KAAK,kBAAA,CAAmB,CAAC,CAAC,CAAA;AAAA,QACjE;AACA,QAAA,OAAO,KAAA;AAAA,MACT,CAAC,CAAA;AACH,MAAA,OAAO,SAAA,CAAU,QAAA,EAAU,YAAA,CAAa,UAAA,EAAY,aAAa,CAAC,CAAA;AAAA,IACpE,CAAA;AACA,IAAA,OAAO,SAAA;AAAA,EACT;AAAA,EAEQ,SAAS,UAAA,EAAoB;AACnC,IAAA,IAAI,CAAC,UAAA,EAAY;AACf,MAAA,OAAO,UAAA;AAAA,IACT;AAEA,IAAA,IAAI,UAAA,CAAW,UAAA,CAAW,IAAA,CAAK,WAAW,CAAA,EAAG;AAC3C,MAAA,OAAO,UAAA,CAAW,KAAA,CAAM,IAAA,CAAK,WAAA,CAAY,MAAM,CAAA;AAAA,IACjD;AACA,IAAA,OAAO,UAAA;AAAA,EACT;AACF;;;;"}
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 RouteRef,\n ExternalRouteRef,\n SubRouteRef,\n AnyRouteRefParams,\n RouteFunc,\n RouteResolutionApi,\n} from '@backstage/frontend-plugin-api';\nimport mapValues from 'lodash/mapValues';\nimport { AnyRouteRef, BackstageRouteObject } from './types';\nimport {\n OpaqueRouteRef,\n OpaqueExternalRouteRef,\n OpaqueSubRouteRef,\n} from '@internal/frontend';\nimport { RouteAliasResolver } from './RouteAliasResolver';\nimport { joinPaths } from './joinPaths';\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 targetRouteRef: AnyRouteRef,\n routePaths: Map<RouteRef, string>,\n routeBindings: Map<AnyRouteRef, AnyRouteRef | undefined>,\n routeRefsById: Map<string, RouteRef | SubRouteRef>,\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 ref: AnyRouteRef = targetRouteRef;\n let path = '';\n\n if (OpaqueExternalRouteRef.isType(ref)) {\n let resolvedRoute = routeBindings.get(ref);\n if (!resolvedRoute) {\n const internal = OpaqueExternalRouteRef.toInternal(ref);\n const defaultTarget = internal.getDefaultTarget();\n if (defaultTarget) {\n resolvedRoute = routeRefsById.get(defaultTarget);\n }\n }\n if (!resolvedRoute) {\n return [undefined, ''];\n }\n ref = resolvedRoute;\n }\n\n if (OpaqueSubRouteRef.isType(ref)) {\n const internal = OpaqueSubRouteRef.toInternal(ref);\n path = ref.path;\n ref = internal.getParent();\n }\n\n if (!OpaqueRouteRef.isType(ref)) {\n throw new Error(\n `Unexpectedly resolved ${targetRouteRef} to a non-route ref ${ref}`,\n );\n }\n\n // Find the path that our target route is bound to\n const resolvedPath = routePaths.get(ref);\n if (resolvedPath === undefined) {\n return [undefined, ''];\n }\n\n return [ref, path ? joinPaths(resolvedPath, path) : resolvedPath];\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 implements RouteResolutionApi {\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 private readonly routeAliasResolver: RouteAliasResolver;\n private readonly routeRefsById: Map<string, RouteRef | SubRouteRef>;\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 routeAliasResolver: RouteAliasResolver,\n routeRefsById: Map<string, RouteRef | SubRouteRef>,\n ) {\n this.routePaths = routePaths;\n this.routeParents = routeParents;\n this.routeObjects = routeObjects;\n this.routeBindings = routeBindings;\n this.appBasePath = appBasePath;\n this.routeAliasResolver = routeAliasResolver;\n this.routeRefsById = routeRefsById;\n }\n\n resolve<TParams extends AnyRouteRefParams>(\n anyRouteRef:\n | RouteRef<TParams>\n | SubRouteRef<TParams>\n | ExternalRouteRef<TParams>,\n options?: { sourcePath?: string },\n ): RouteFunc<TParams> | undefined {\n // First figure out what our target absolute ref is, as well as our target path.\n const [targetRef, targetPath] = resolveTargetRef(\n anyRouteRef?.$$type === '@backstage/RouteRef'\n ? this.routeAliasResolver(anyRouteRef)\n : anyRouteRef,\n this.routePaths,\n this.routeBindings,\n this.routeRefsById,\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 const relativeSourceLocation = this.trimPath(options?.sourcePath ?? '');\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 = resolveBasePath(\n targetRef,\n relativeSourceLocation,\n this.routePaths,\n this.routeParents,\n this.routeObjects,\n );\n\n const routeFunc: RouteFunc<TParams> = (...[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 +1 @@
1
- {"version":3,"file":"collectRouteIds.esm.js","sources":["../../src/routing/collectRouteIds.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 RouteRef,\n SubRouteRef,\n ExternalRouteRef,\n FrontendFeature,\n} from '@backstage/frontend-plugin-api';\nimport {\n OpaqueRouteRef,\n OpaqueSubRouteRef,\n OpaqueExternalRouteRef,\n OpaqueFrontendPlugin,\n} from '@internal/frontend';\nimport { ErrorCollector } from '../wiring/createErrorCollector';\n\n/** @internal */\nexport interface RouteRefsById {\n routes: Map<string, RouteRef | SubRouteRef>;\n externalRoutes: Map<string, ExternalRouteRef>;\n}\n\n/** @internal */\nexport function collectRouteIds(\n features: FrontendFeature[],\n collector: ErrorCollector,\n): RouteRefsById {\n const routesById = new Map<string, RouteRef | SubRouteRef>();\n const externalRoutesById = new Map<string, ExternalRouteRef>();\n\n for (const feature of features) {\n if (!OpaqueFrontendPlugin.isType(feature)) {\n continue;\n }\n\n for (const [name, ref] of Object.entries(feature.routes)) {\n const refId = `${feature.id}.${name}`;\n if (routesById.has(refId)) {\n collector.report({\n code: 'ROUTE_DUPLICATE',\n message: `Duplicate route id '${refId}' encountered while collecting routes`,\n context: { routeId: refId },\n });\n continue;\n }\n\n if (OpaqueRouteRef.isType(ref)) {\n const internalRef = OpaqueRouteRef.toInternal(ref);\n internalRef.setId(refId);\n routesById.set(refId, ref);\n } else {\n const internalRef = OpaqueSubRouteRef.toInternal(ref);\n routesById.set(refId, internalRef);\n }\n }\n for (const [name, ref] of Object.entries(feature.externalRoutes)) {\n const refId = `${feature.id}.${name}`;\n if (externalRoutesById.has(refId)) {\n collector.report({\n code: 'ROUTE_DUPLICATE',\n message: `Duplicate external route id '${refId}' encountered while collecting routes`,\n context: { routeId: refId },\n });\n continue;\n }\n\n const internalRef = OpaqueExternalRouteRef.toInternal(ref);\n internalRef.setId(refId);\n externalRoutesById.set(refId, ref);\n }\n }\n\n return { routes: routesById, externalRoutes: externalRoutesById };\n}\n"],"names":[],"mappings":";;;;;;;;AAqCO,SAAS,eAAA,CACd,UACA,SAAA,EACe;AACf,EAAA,MAAM,UAAA,uBAAiB,GAAA,EAAoC;AAC3D,EAAA,MAAM,kBAAA,uBAAyB,GAAA,EAA8B;AAE7D,EAAA,KAAA,MAAW,WAAW,QAAA,EAAU;AAC9B,IAAA,IAAI,CAAC,oBAAA,CAAqB,MAAA,CAAO,OAAO,CAAA,EAAG;AACzC,MAAA;AAAA,IACF;AAEA,IAAA,KAAA,MAAW,CAAC,MAAM,GAAG,CAAA,IAAK,OAAO,OAAA,CAAQ,OAAA,CAAQ,MAAM,CAAA,EAAG;AACxD,MAAA,MAAM,KAAA,GAAQ,CAAA,EAAG,OAAA,CAAQ,EAAE,IAAI,IAAI,CAAA,CAAA;AACnC,MAAA,IAAI,UAAA,CAAW,GAAA,CAAI,KAAK,CAAA,EAAG;AACzB,QAAA,SAAA,CAAU,MAAA,CAAO;AAAA,UACf,IAAA,EAAM,iBAAA;AAAA,UACN,OAAA,EAAS,uBAAuB,KAAK,CAAA,qCAAA,CAAA;AAAA,UACrC,OAAA,EAAS,EAAE,OAAA,EAAS,KAAA;AAAM,SAC3B,CAAA;AACD,QAAA;AAAA,MACF;AAEA,MAAA,IAAI,cAAA,CAAe,MAAA,CAAO,GAAG,CAAA,EAAG;AAC9B,QAAA,MAAM,WAAA,GAAc,cAAA,CAAe,UAAA,CAAW,GAAG,CAAA;AACjD,QAAA,WAAA,CAAY,MAAM,KAAK,CAAA;AACvB,QAAA,UAAA,CAAW,GAAA,CAAI,OAAO,GAAG,CAAA;AAAA,MAC3B,CAAA,MAAO;AACL,QAAA,MAAM,WAAA,GAAc,iBAAA,CAAkB,UAAA,CAAW,GAAG,CAAA;AACpD,QAAA,UAAA,CAAW,GAAA,CAAI,OAAO,WAAW,CAAA;AAAA,MACnC;AAAA,IACF;AACA,IAAA,KAAA,MAAW,CAAC,MAAM,GAAG,CAAA,IAAK,OAAO,OAAA,CAAQ,OAAA,CAAQ,cAAc,CAAA,EAAG;AAChE,MAAA,MAAM,KAAA,GAAQ,CAAA,EAAG,OAAA,CAAQ,EAAE,IAAI,IAAI,CAAA,CAAA;AACnC,MAAA,IAAI,kBAAA,CAAmB,GAAA,CAAI,KAAK,CAAA,EAAG;AACjC,QAAA,SAAA,CAAU,MAAA,CAAO;AAAA,UACf,IAAA,EAAM,iBAAA;AAAA,UACN,OAAA,EAAS,gCAAgC,KAAK,CAAA,qCAAA,CAAA;AAAA,UAC9C,OAAA,EAAS,EAAE,OAAA,EAAS,KAAA;AAAM,SAC3B,CAAA;AACD,QAAA;AAAA,MACF;AAEA,MAAA,MAAM,WAAA,GAAc,sBAAA,CAAuB,UAAA,CAAW,GAAG,CAAA;AACzD,MAAA,WAAA,CAAY,MAAM,KAAK,CAAA;AACvB,MAAA,kBAAA,CAAmB,GAAA,CAAI,OAAO,GAAG,CAAA;AAAA,IACnC;AAAA,EACF;AAEA,EAAA,OAAO,EAAE,MAAA,EAAQ,UAAA,EAAY,cAAA,EAAgB,kBAAA,EAAmB;AAClE;;;;"}
1
+ {"version":3,"file":"collectRouteIds.esm.js","sources":["../../src/routing/collectRouteIds.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 RouteRef,\n SubRouteRef,\n ExternalRouteRef,\n FrontendFeature,\n} from '@backstage/frontend-plugin-api';\nimport {\n OpaqueRouteRef,\n OpaqueSubRouteRef,\n OpaqueExternalRouteRef,\n OpaqueFrontendPlugin,\n} from '@internal/frontend';\nimport { ErrorCollector } from '../wiring/createErrorCollector';\n\n/** @internal */\nexport interface RouteRefsById {\n routes: Map<string, RouteRef | SubRouteRef>;\n externalRoutes: Map<string, ExternalRouteRef>;\n}\n\n/** @internal */\nexport function collectRouteIds(\n features: FrontendFeature[],\n collector: ErrorCollector,\n): RouteRefsById {\n const routesById = new Map<string, RouteRef | SubRouteRef>();\n const externalRoutesById = new Map<string, ExternalRouteRef>();\n\n for (const feature of features) {\n if (!OpaqueFrontendPlugin.isType(feature)) {\n continue;\n }\n\n for (const [name, ref] of Object.entries(feature.routes)) {\n const refId = `${feature.id}.${name}`;\n if (routesById.has(refId)) {\n collector.report({\n code: 'ROUTE_DUPLICATE',\n message: `Duplicate route id '${refId}' encountered while collecting routes`,\n context: { routeId: refId },\n });\n continue;\n }\n\n if (OpaqueRouteRef.isType(ref)) {\n const internalRef = OpaqueRouteRef.toInternal(ref);\n internalRef.setId(refId);\n routesById.set(refId, ref);\n } else {\n const internalRef = OpaqueSubRouteRef.toInternal(ref);\n routesById.set(refId, internalRef);\n }\n }\n for (const [name, ref] of Object.entries(feature.externalRoutes)) {\n const refId = `${feature.id}.${name}`;\n if (externalRoutesById.has(refId)) {\n collector.report({\n code: 'ROUTE_DUPLICATE',\n message: `Duplicate external route id '${refId}' encountered while collecting routes`,\n context: { routeId: refId },\n });\n continue;\n }\n\n const internalRef = OpaqueExternalRouteRef.toInternal(ref);\n internalRef.setId(refId);\n externalRoutesById.set(refId, ref);\n }\n }\n\n return { routes: routesById, externalRoutes: externalRoutesById };\n}\n"],"names":[],"mappings":";;;;;;;;AAqCO,SAAS,eAAA,CACd,UACA,SAAA,EACe;AACf,EAAA,MAAM,UAAA,uBAAiB,GAAA,EAAoC;AAC3D,EAAA,MAAM,kBAAA,uBAAyB,GAAA,EAA8B;AAE7D,EAAA,KAAA,MAAW,WAAW,QAAA,EAAU;AAC9B,IAAA,IAAI,CAAC,oBAAA,CAAqB,MAAA,CAAO,OAAO,CAAA,EAAG;AACzC,MAAA;AAAA,IACF;AAEA,IAAA,KAAA,MAAW,CAAC,MAAM,GAAG,CAAA,IAAK,OAAO,OAAA,CAAQ,OAAA,CAAQ,MAAM,CAAA,EAAG;AACxD,MAAA,MAAM,KAAA,GAAQ,CAAA,EAAG,OAAA,CAAQ,EAAE,IAAI,IAAI,CAAA,CAAA;AACnC,MAAA,IAAI,UAAA,CAAW,GAAA,CAAI,KAAK,CAAA,EAAG;AACzB,QAAA,SAAA,CAAU,MAAA,CAAO;AAAA,UACf,IAAA,EAAM,iBAAA;AAAA,UACN,OAAA,EAAS,uBAAuB,KAAK,CAAA,qCAAA,CAAA;AAAA,UACrC,OAAA,EAAS,EAAE,OAAA,EAAS,KAAA;AAAM,SAC3B,CAAA;AACD,QAAA;AAAA,MACF;AAEA,MAAA,IAAI,cAAA,CAAe,MAAA,CAAO,GAAG,CAAA,EAAG;AAC9B,QAAA,MAAM,WAAA,GAAc,cAAA,CAAe,UAAA,CAAW,GAAG,CAAA;AACjD,QAAA,WAAA,CAAY,MAAM,KAAK,CAAA;AACvB,QAAA,UAAA,CAAW,GAAA,CAAI,OAAO,GAAG,CAAA;AAAA,MAC3B,CAAA,MAAO;AACL,QAAA,MAAM,WAAA,GAAc,iBAAA,CAAkB,UAAA,CAAW,GAAG,CAAA;AACpD,QAAA,UAAA,CAAW,GAAA,CAAI,OAAO,WAAW,CAAA;AAAA,MACnC;AAAA,IACF;AACA,IAAA,KAAA,MAAW,CAAC,MAAM,GAAG,CAAA,IAAK,OAAO,OAAA,CAAQ,OAAA,CAAQ,cAAc,CAAA,EAAG;AAChE,MAAA,MAAM,KAAA,GAAQ,CAAA,EAAG,OAAA,CAAQ,EAAE,IAAI,IAAI,CAAA,CAAA;AACnC,MAAA,IAAI,kBAAA,CAAmB,GAAA,CAAI,KAAK,CAAA,EAAG;AACjC,QAAA,SAAA,CAAU,MAAA,CAAO;AAAA,UACf,IAAA,EAAM,iBAAA;AAAA,UACN,OAAA,EAAS,gCAAgC,KAAK,CAAA,qCAAA,CAAA;AAAA,UAC9C,OAAA,EAAS,EAAE,OAAA,EAAS,KAAA;AAAM,SAC3B,CAAA;AACD,QAAA;AAAA,MACF;AAEA,MAAA,MAAM,WAAA,GAAc,sBAAA,CAAuB,UAAA,CAAW,GAAG,CAAA;AACzD,MAAA,WAAA,CAAY,MAAM,KAAK,CAAA;AACvB,MAAA,kBAAA,CAAmB,GAAA,CAAI,OAAO,GAAG,CAAA;AAAA,IACnC;AAAA,EACF;AAEA,EAAA,OAAO,EAAE,MAAA,EAAQ,UAAA,EAAY,cAAA,EAAgB,kBAAA,EAAmB;AAClE;;"}