@backstage/core-app-api 1.19.6-next.1 → 1.19.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # @backstage/core-app-api
2
2
 
3
+ ## 1.19.6
4
+
5
+ ### Patch Changes
6
+
7
+ - 12d8afe: Added `BUIProvider` from `@backstage/ui` to the app shell provider tree, enabling BUI components to fire analytics events through the Backstage analytics system.
8
+ - 59752a2: Deprecated `AlertApiForwarder` in favor of the new `ToastApi`. The `AlertApiForwarder` now emits a console warning on first use, guiding developers to migrate to `ToastApi` from `@backstage/frontend-plugin-api`.
9
+ - 0452d02: Add optional `description` field to plugin-level feature flags.
10
+ - 42f8c9b: Added `BUIProvider` inside the legacy app router to enable client-side routing for all BUI components.
11
+ - a49a40d: Updated dependency `zod` to `^3.25.76 || ^4.0.0` & migrated to `/v3` or `/v4` imports.
12
+ - Updated dependencies
13
+ - @backstage/ui@0.13.0
14
+ - @backstage/core-plugin-api@1.12.4
15
+
3
16
  ## 1.19.6-next.1
4
17
 
5
18
  ### Patch Changes
@@ -5,7 +5,14 @@ class AlertApiForwarder {
5
5
  subject = new PublishSubject();
6
6
  recentAlerts = [];
7
7
  maxBufferSize = 10;
8
+ hasWarnedDeprecation = false;
8
9
  post(alert) {
10
+ if (!this.hasWarnedDeprecation) {
11
+ this.hasWarnedDeprecation = true;
12
+ console.warn(
13
+ 'AlertApi is deprecated and will be removed in a future release. Please migrate to ToastApi from @backstage/frontend-plugin-api. ToastApi provides richer features including title/description, links, icons, and per-toast timeouts. Example: toastApi.post({ title: "Saved!", status: "success", timeout: 5000 })'
14
+ );
15
+ }
9
16
  this.recentAlerts.push(alert);
10
17
  if (this.recentAlerts.length > this.maxBufferSize) {
11
18
  this.recentAlerts.shift();
@@ -1 +1 @@
1
- {"version":3,"file":"AlertApiForwarder.esm.js","sources":["../../../../src/apis/implementations/AlertApi/AlertApiForwarder.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 { AlertApi, AlertMessage } from '@backstage/core-plugin-api';\nimport { Observable } from '@backstage/types';\nimport { PublishSubject } from '../../../lib/subjects';\nimport ObservableImpl from 'zen-observable';\n\n/**\n * Base implementation for the AlertApi that simply forwards alerts to consumers.\n *\n * Recent alerts are buffered and replayed to new subscribers to prevent\n * missing alerts that were posted before subscription.\n *\n * @public\n */\nexport class AlertApiForwarder implements AlertApi {\n private readonly subject = new PublishSubject<AlertMessage>();\n private readonly recentAlerts: AlertMessage[] = [];\n private readonly maxBufferSize = 10;\n\n post(alert: AlertMessage) {\n this.recentAlerts.push(alert);\n if (this.recentAlerts.length > this.maxBufferSize) {\n this.recentAlerts.shift();\n }\n this.subject.next(alert);\n }\n\n alert$(): Observable<AlertMessage> {\n return new ObservableImpl<AlertMessage>(subscriber => {\n for (const alert of this.recentAlerts) {\n subscriber.next(alert);\n }\n return this.subject.subscribe(subscriber);\n });\n }\n}\n"],"names":[],"mappings":";;;AA6BO,MAAM,iBAAA,CAAsC;AAAA,EAChC,OAAA,GAAU,IAAI,cAAA,EAA6B;AAAA,EAC3C,eAA+B,EAAC;AAAA,EAChC,aAAA,GAAgB,EAAA;AAAA,EAEjC,KAAK,KAAA,EAAqB;AACxB,IAAA,IAAA,CAAK,YAAA,CAAa,KAAK,KAAK,CAAA;AAC5B,IAAA,IAAI,IAAA,CAAK,YAAA,CAAa,MAAA,GAAS,IAAA,CAAK,aAAA,EAAe;AACjD,MAAA,IAAA,CAAK,aAAa,KAAA,EAAM;AAAA,IAC1B;AACA,IAAA,IAAA,CAAK,OAAA,CAAQ,KAAK,KAAK,CAAA;AAAA,EACzB;AAAA,EAEA,MAAA,GAAmC;AACjC,IAAA,OAAO,IAAI,eAA6B,CAAA,UAAA,KAAc;AACpD,MAAA,KAAA,MAAW,KAAA,IAAS,KAAK,YAAA,EAAc;AACrC,QAAA,UAAA,CAAW,KAAK,KAAK,CAAA;AAAA,MACvB;AACA,MAAA,OAAO,IAAA,CAAK,OAAA,CAAQ,SAAA,CAAU,UAAU,CAAA;AAAA,IAC1C,CAAC,CAAA;AAAA,EACH;AACF;;;;"}
1
+ {"version":3,"file":"AlertApiForwarder.esm.js","sources":["../../../../src/apis/implementations/AlertApi/AlertApiForwarder.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 { AlertApi, AlertMessage } from '@backstage/core-plugin-api';\nimport { Observable } from '@backstage/types';\nimport { PublishSubject } from '../../../lib/subjects';\nimport ObservableImpl from 'zen-observable';\n\n/**\n * Base implementation for the AlertApi that simply forwards alerts to consumers.\n *\n * Recent alerts are buffered and replayed to new subscribers to prevent\n * missing alerts that were posted before subscription.\n *\n * @public\n * @deprecated Use ToastApi instead. AlertApi will be removed in a future release.\n */\nexport class AlertApiForwarder implements AlertApi {\n private readonly subject = new PublishSubject<AlertMessage>();\n private readonly recentAlerts: AlertMessage[] = [];\n private readonly maxBufferSize = 10;\n private hasWarnedDeprecation = false;\n\n post(alert: AlertMessage) {\n if (!this.hasWarnedDeprecation) {\n this.hasWarnedDeprecation = true;\n // eslint-disable-next-line no-console\n console.warn(\n 'AlertApi is deprecated and will be removed in a future release. ' +\n 'Please migrate to ToastApi from @backstage/frontend-plugin-api. ' +\n 'ToastApi provides richer features including title/description, links, icons, and per-toast timeouts. ' +\n 'Example: toastApi.post({ title: \"Saved!\", status: \"success\", timeout: 5000 })',\n );\n }\n this.recentAlerts.push(alert);\n if (this.recentAlerts.length > this.maxBufferSize) {\n this.recentAlerts.shift();\n }\n this.subject.next(alert);\n }\n\n alert$(): Observable<AlertMessage> {\n return new ObservableImpl<AlertMessage>(subscriber => {\n for (const alert of this.recentAlerts) {\n subscriber.next(alert);\n }\n return this.subject.subscribe(subscriber);\n });\n }\n}\n"],"names":[],"mappings":";;;AA8BO,MAAM,iBAAA,CAAsC;AAAA,EAChC,OAAA,GAAU,IAAI,cAAA,EAA6B;AAAA,EAC3C,eAA+B,EAAC;AAAA,EAChC,aAAA,GAAgB,EAAA;AAAA,EACzB,oBAAA,GAAuB,KAAA;AAAA,EAE/B,KAAK,KAAA,EAAqB;AACxB,IAAA,IAAI,CAAC,KAAK,oBAAA,EAAsB;AAC9B,MAAA,IAAA,CAAK,oBAAA,GAAuB,IAAA;AAE5B,MAAA,OAAA,CAAQ,IAAA;AAAA,QACN;AAAA,OAIF;AAAA,IACF;AACA,IAAA,IAAA,CAAK,YAAA,CAAa,KAAK,KAAK,CAAA;AAC5B,IAAA,IAAI,IAAA,CAAK,YAAA,CAAa,MAAA,GAAS,IAAA,CAAK,aAAA,EAAe;AACjD,MAAA,IAAA,CAAK,aAAa,KAAA,EAAM;AAAA,IAC1B;AACA,IAAA,IAAA,CAAK,OAAA,CAAQ,KAAK,KAAK,CAAA;AAAA,EACzB;AAAA,EAEA,MAAA,GAAmC;AACjC,IAAA,OAAO,IAAI,eAA6B,CAAA,UAAA,KAAc;AACpD,MAAA,KAAA,MAAW,KAAA,IAAS,KAAK,YAAA,EAAc;AACrC,QAAA,UAAA,CAAW,KAAK,KAAK,CAAA;AAAA,MACvB;AACA,MAAA,OAAO,IAAA,CAAK,OAAA,CAAQ,SAAA,CAAU,UAAU,CAAA;AAAA,IAC1C,CAAC,CAAA;AAAA,EACH;AACF;;;;"}
@@ -1,4 +1,4 @@
1
- import { z } from 'zod';
1
+ import { z } from 'zod/v3';
2
2
 
3
3
  const samlSessionSchema = z.object({
4
4
  profile: z.object({
@@ -1 +1 @@
1
- {"version":3,"file":"types.esm.js","sources":["../../../../../src/apis/implementations/auth/saml/types.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 BackstageIdentityResponse,\n ProfileInfo,\n} from '@backstage/core-plugin-api';\nimport { z } from 'zod';\n\n/** @internal */\nexport type SamlSession = {\n profile: ProfileInfo;\n backstageIdentity: BackstageIdentityResponse;\n};\n\n/** @internal */\nexport const samlSessionSchema: z.ZodSchema<SamlSession> = z.object({\n profile: z.object({\n email: z.string().optional(),\n displayName: z.string().optional(),\n picture: z.string().optional(),\n }),\n backstageIdentity: z.object({\n token: z.string(),\n identity: z.object({\n type: z.literal('user'),\n userEntityRef: z.string(),\n ownershipEntityRefs: z.array(z.string()),\n }),\n }),\n});\n"],"names":[],"mappings":";;AA6BO,MAAM,iBAAA,GAA8C,EAAE,MAAA,CAAO;AAAA,EAClE,OAAA,EAAS,EAAE,MAAA,CAAO;AAAA,IAChB,KAAA,EAAO,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,IAC3B,WAAA,EAAa,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,IACjC,OAAA,EAAS,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA;AAAS,GAC9B,CAAA;AAAA,EACD,iBAAA,EAAmB,EAAE,MAAA,CAAO;AAAA,IAC1B,KAAA,EAAO,EAAE,MAAA,EAAO;AAAA,IAChB,QAAA,EAAU,EAAE,MAAA,CAAO;AAAA,MACjB,IAAA,EAAM,CAAA,CAAE,OAAA,CAAQ,MAAM,CAAA;AAAA,MACtB,aAAA,EAAe,EAAE,MAAA,EAAO;AAAA,MACxB,mBAAA,EAAqB,CAAA,CAAE,KAAA,CAAM,CAAA,CAAE,QAAQ;AAAA,KACxC;AAAA,GACF;AACH,CAAC;;;;"}
1
+ {"version":3,"file":"types.esm.js","sources":["../../../../../src/apis/implementations/auth/saml/types.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 BackstageIdentityResponse,\n ProfileInfo,\n} from '@backstage/core-plugin-api';\nimport { z } from 'zod/v3';\n\n/** @internal */\nexport type SamlSession = {\n profile: ProfileInfo;\n backstageIdentity: BackstageIdentityResponse;\n};\n\n/** @internal */\nexport const samlSessionSchema: z.ZodSchema<SamlSession> = z.object({\n profile: z.object({\n email: z.string().optional(),\n displayName: z.string().optional(),\n picture: z.string().optional(),\n }),\n backstageIdentity: z.object({\n token: z.string(),\n identity: z.object({\n type: z.literal('user'),\n userEntityRef: z.string(),\n ownershipEntityRefs: z.array(z.string()),\n }),\n }),\n});\n"],"names":[],"mappings":";;AA6BO,MAAM,iBAAA,GAA8C,EAAE,MAAA,CAAO;AAAA,EAClE,OAAA,EAAS,EAAE,MAAA,CAAO;AAAA,IAChB,KAAA,EAAO,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,IAC3B,WAAA,EAAa,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,IACjC,OAAA,EAAS,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA;AAAS,GAC9B,CAAA;AAAA,EACD,iBAAA,EAAmB,EAAE,MAAA,CAAO;AAAA,IAC1B,KAAA,EAAO,EAAE,MAAA,EAAO;AAAA,IAChB,QAAA,EAAU,EAAE,MAAA,CAAO;AAAA,MACjB,IAAA,EAAM,CAAA,CAAE,OAAA,CAAQ,MAAM,CAAA;AAAA,MACtB,aAAA,EAAe,EAAE,MAAA,EAAO;AAAA,MACxB,mBAAA,EAAqB,CAAA,CAAE,KAAA,CAAM,CAAA,CAAE,QAAQ;AAAA,KACxC;AAAA,GACF;AACH,CAAC;;;;"}
@@ -1,6 +1,7 @@
1
- import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
1
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
2
  import { useContext, useState } from 'react';
3
- import { attachComponentData, useApp, useApi, configApiRef } from '@backstage/core-plugin-api';
3
+ import { attachComponentData, useApp, useApi, configApiRef, useAnalytics } from '@backstage/core-plugin-api';
4
+ import { BUIProvider } from '@backstage/ui';
4
5
  import { InternalAppContext } from './InternalAppContext.esm.js';
5
6
  import { isReactRouterBeta } from './isReactRouterBeta.esm.js';
6
7
  import { RouteTracker } from '../routing/RouteTracker.esm.js';
@@ -72,18 +73,18 @@ function AppRouter(props) {
72
73
  { signOutTargetUrl: basePath || "/" }
73
74
  );
74
75
  if (isReactRouterBeta()) {
75
- return /* @__PURE__ */ jsxs(RouterComponent, { children: [
76
+ return /* @__PURE__ */ jsx(RouterComponent, { children: /* @__PURE__ */ jsxs(BUIProvider, { useAnalytics, children: [
76
77
  /* @__PURE__ */ jsx(RouteTracker, { routeObjects }),
77
78
  /* @__PURE__ */ jsx(Routes, { children: /* @__PURE__ */ jsx(Route, { path: mountPath, element: /* @__PURE__ */ jsx(Fragment, { children: props.children }) }) })
78
- ] });
79
+ ] }) });
79
80
  }
80
- return /* @__PURE__ */ jsxs(RouterComponent, { basename: basePath, children: [
81
+ return /* @__PURE__ */ jsx(RouterComponent, { basename: basePath, children: /* @__PURE__ */ jsxs(BUIProvider, { useAnalytics, children: [
81
82
  /* @__PURE__ */ jsx(RouteTracker, { routeObjects }),
82
83
  props.children
83
- ] });
84
+ ] }) });
84
85
  }
85
86
  if (isReactRouterBeta()) {
86
- return /* @__PURE__ */ jsxs(RouterComponent, { children: [
87
+ return /* @__PURE__ */ jsx(RouterComponent, { children: /* @__PURE__ */ jsxs(BUIProvider, { useAnalytics, children: [
87
88
  /* @__PURE__ */ jsx(RouteTracker, { routeObjects }),
88
89
  /* @__PURE__ */ jsx(
89
90
  SignInPageWrapper,
@@ -93,9 +94,9 @@ function AppRouter(props) {
93
94
  children: /* @__PURE__ */ jsx(Routes, { children: /* @__PURE__ */ jsx(Route, { path: mountPath, element: /* @__PURE__ */ jsx(Fragment, { children: props.children }) }) })
94
95
  }
95
96
  )
96
- ] });
97
+ ] }) });
97
98
  }
98
- return /* @__PURE__ */ jsxs(RouterComponent, { basename: basePath, children: [
99
+ return /* @__PURE__ */ jsx(RouterComponent, { basename: basePath, children: /* @__PURE__ */ jsxs(BUIProvider, { useAnalytics, children: [
99
100
  /* @__PURE__ */ jsx(RouteTracker, { routeObjects }),
100
101
  /* @__PURE__ */ jsx(
101
102
  SignInPageWrapper,
@@ -105,7 +106,7 @@ function AppRouter(props) {
105
106
  children: props.children
106
107
  }
107
108
  )
108
- ] });
109
+ ] }) });
109
110
  }
110
111
  attachComponentData(AppRouter, "core.type", "AppRouter");
111
112
 
@@ -1 +1 @@
1
- {"version":3,"file":"AppRouter.esm.js","sources":["../../src/app/AppRouter.tsx"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useContext, ReactNode, ComponentType, useState } from 'react';\nimport {\n attachComponentData,\n ConfigApi,\n configApiRef,\n IdentityApi,\n SignInPageProps,\n useApi,\n useApp,\n} from '@backstage/core-plugin-api';\nimport { InternalAppContext } from './InternalAppContext';\nimport { isReactRouterBeta } from './isReactRouterBeta';\nimport { RouteTracker } from '../routing/RouteTracker';\nimport { Route, Routes } from 'react-router-dom';\nimport { AppIdentityProxy } from '../apis/implementations/IdentityApi/AppIdentityProxy';\n\n/**\n * Get the app base path from the configured app baseUrl.\n *\n * The returned path does not have a trailing slash.\n */\nexport function getBasePath(configApi: ConfigApi) {\n if (!isReactRouterBeta()) {\n // When using rr v6 stable the base path is handled through the\n // basename prop on the router component instead.\n return '';\n }\n\n return readBasePath(configApi);\n}\n\n/**\n * Read the configured base path.\n *\n * The returned path does not have a trailing slash.\n */\nfunction readBasePath(configApi: ConfigApi) {\n let { pathname } = new URL(\n configApi.getOptionalString('app.baseUrl') ?? '/',\n 'http://sample.dev', // baseUrl can be specified as just a path\n );\n pathname = pathname.replace(/\\/*$/, '');\n return pathname;\n}\n\n// This wraps the sign-in page and waits for sign-in to be completed before rendering the app\nfunction SignInPageWrapper({\n component: Component,\n appIdentityProxy,\n children,\n}: {\n component: ComponentType<SignInPageProps>;\n appIdentityProxy: AppIdentityProxy;\n children: ReactNode;\n}) {\n const [identityApi, setIdentityApi] = useState<IdentityApi>();\n const configApi = useApi(configApiRef);\n const basePath = readBasePath(configApi);\n\n if (!identityApi) {\n return <Component onSignInSuccess={setIdentityApi} />;\n }\n\n appIdentityProxy.setTarget(identityApi, {\n signOutTargetUrl: basePath || '/',\n });\n return <>{children}</>;\n}\n\n/**\n * Props for the {@link AppRouter} component.\n * @public\n */\nexport interface AppRouterProps {\n children?: ReactNode;\n}\n\n/**\n * App router and sign-in page wrapper.\n *\n * @public\n * @remarks\n *\n * The AppRouter provides the routing context and renders the sign-in page.\n * Until the user has successfully signed in, this component will render\n * the sign-in page. Once the user has signed-in, it will instead render\n * the app, while providing routing and route tracking for the app.\n */\nexport function AppRouter(props: AppRouterProps) {\n const { Router: RouterComponent, SignInPage: SignInPageComponent } =\n useApp().getComponents();\n\n const configApi = useApi(configApiRef);\n const basePath = readBasePath(configApi);\n const mountPath = `${basePath}/*`;\n const internalAppContext = useContext(InternalAppContext);\n if (!internalAppContext) {\n throw new Error('AppRouter must be rendered within the AppProvider');\n }\n const { routeObjects, appIdentityProxy } = internalAppContext;\n\n // If the app hasn't configured a sign-in page, we just continue as guest.\n if (!SignInPageComponent) {\n appIdentityProxy.setTarget(\n {\n getUserId: () => 'guest',\n getIdToken: async () => undefined,\n getProfile: () => ({\n email: 'guest@example.com',\n displayName: 'Guest',\n }),\n getProfileInfo: async () => ({\n email: 'guest@example.com',\n displayName: 'Guest',\n }),\n getBackstageIdentity: async () => ({\n type: 'user',\n userEntityRef: 'user:default/guest',\n ownershipEntityRefs: ['user:default/guest'],\n }),\n getCredentials: async () => ({}),\n signOut: async () => {},\n },\n { signOutTargetUrl: basePath || '/' },\n );\n\n if (isReactRouterBeta()) {\n return (\n <RouterComponent>\n <RouteTracker routeObjects={routeObjects} />\n <Routes>\n <Route path={mountPath} element={<>{props.children}</>} />\n </Routes>\n </RouterComponent>\n );\n }\n\n return (\n <RouterComponent basename={basePath}>\n <RouteTracker routeObjects={routeObjects} />\n {props.children}\n </RouterComponent>\n );\n }\n\n if (isReactRouterBeta()) {\n return (\n <RouterComponent>\n <RouteTracker routeObjects={routeObjects} />\n <SignInPageWrapper\n component={SignInPageComponent}\n appIdentityProxy={appIdentityProxy}\n >\n <Routes>\n <Route path={mountPath} element={<>{props.children}</>} />\n </Routes>\n </SignInPageWrapper>\n </RouterComponent>\n );\n }\n\n return (\n <RouterComponent basename={basePath}>\n <RouteTracker routeObjects={routeObjects} />\n <SignInPageWrapper\n component={SignInPageComponent}\n appIdentityProxy={appIdentityProxy}\n >\n {props.children}\n </SignInPageWrapper>\n </RouterComponent>\n );\n}\n\nattachComponentData(AppRouter, 'core.type', 'AppRouter');\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"AppRouter.esm.js","sources":["../../src/app/AppRouter.tsx"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useContext, ReactNode, ComponentType, useState } from 'react';\nimport {\n attachComponentData,\n ConfigApi,\n configApiRef,\n IdentityApi,\n SignInPageProps,\n useApi,\n useApp,\n useAnalytics,\n} from '@backstage/core-plugin-api';\nimport { BUIProvider } from '@backstage/ui';\nimport { InternalAppContext } from './InternalAppContext';\nimport { isReactRouterBeta } from './isReactRouterBeta';\nimport { RouteTracker } from '../routing/RouteTracker';\nimport { Route, Routes } from 'react-router-dom';\nimport { AppIdentityProxy } from '../apis/implementations/IdentityApi/AppIdentityProxy';\n\n/**\n * Get the app base path from the configured app baseUrl.\n *\n * The returned path does not have a trailing slash.\n */\nexport function getBasePath(configApi: ConfigApi) {\n if (!isReactRouterBeta()) {\n // When using rr v6 stable the base path is handled through the\n // basename prop on the router component instead.\n return '';\n }\n\n return readBasePath(configApi);\n}\n\n/**\n * Read the configured base path.\n *\n * The returned path does not have a trailing slash.\n */\nfunction readBasePath(configApi: ConfigApi) {\n let { pathname } = new URL(\n configApi.getOptionalString('app.baseUrl') ?? '/',\n 'http://sample.dev', // baseUrl can be specified as just a path\n );\n pathname = pathname.replace(/\\/*$/, '');\n return pathname;\n}\n\n// This wraps the sign-in page and waits for sign-in to be completed before rendering the app\nfunction SignInPageWrapper({\n component: Component,\n appIdentityProxy,\n children,\n}: {\n component: ComponentType<SignInPageProps>;\n appIdentityProxy: AppIdentityProxy;\n children: ReactNode;\n}) {\n const [identityApi, setIdentityApi] = useState<IdentityApi>();\n const configApi = useApi(configApiRef);\n const basePath = readBasePath(configApi);\n\n if (!identityApi) {\n return <Component onSignInSuccess={setIdentityApi} />;\n }\n\n appIdentityProxy.setTarget(identityApi, {\n signOutTargetUrl: basePath || '/',\n });\n return <>{children}</>;\n}\n\n/**\n * Props for the {@link AppRouter} component.\n * @public\n */\nexport interface AppRouterProps {\n children?: ReactNode;\n}\n\n/**\n * App router and sign-in page wrapper.\n *\n * @public\n * @remarks\n *\n * The AppRouter provides the routing context and renders the sign-in page.\n * Until the user has successfully signed in, this component will render\n * the sign-in page. Once the user has signed-in, it will instead render\n * the app, while providing routing and route tracking for the app.\n */\nexport function AppRouter(props: AppRouterProps) {\n const { Router: RouterComponent, SignInPage: SignInPageComponent } =\n useApp().getComponents();\n\n const configApi = useApi(configApiRef);\n const basePath = readBasePath(configApi);\n const mountPath = `${basePath}/*`;\n const internalAppContext = useContext(InternalAppContext);\n if (!internalAppContext) {\n throw new Error('AppRouter must be rendered within the AppProvider');\n }\n const { routeObjects, appIdentityProxy } = internalAppContext;\n\n // If the app hasn't configured a sign-in page, we just continue as guest.\n if (!SignInPageComponent) {\n appIdentityProxy.setTarget(\n {\n getUserId: () => 'guest',\n getIdToken: async () => undefined,\n getProfile: () => ({\n email: 'guest@example.com',\n displayName: 'Guest',\n }),\n getProfileInfo: async () => ({\n email: 'guest@example.com',\n displayName: 'Guest',\n }),\n getBackstageIdentity: async () => ({\n type: 'user',\n userEntityRef: 'user:default/guest',\n ownershipEntityRefs: ['user:default/guest'],\n }),\n getCredentials: async () => ({}),\n signOut: async () => {},\n },\n { signOutTargetUrl: basePath || '/' },\n );\n\n if (isReactRouterBeta()) {\n return (\n <RouterComponent>\n <BUIProvider useAnalytics={useAnalytics}>\n <RouteTracker routeObjects={routeObjects} />\n <Routes>\n <Route path={mountPath} element={<>{props.children}</>} />\n </Routes>\n </BUIProvider>\n </RouterComponent>\n );\n }\n\n return (\n <RouterComponent basename={basePath}>\n <BUIProvider useAnalytics={useAnalytics}>\n <RouteTracker routeObjects={routeObjects} />\n {props.children}\n </BUIProvider>\n </RouterComponent>\n );\n }\n\n if (isReactRouterBeta()) {\n return (\n <RouterComponent>\n <BUIProvider useAnalytics={useAnalytics}>\n <RouteTracker routeObjects={routeObjects} />\n <SignInPageWrapper\n component={SignInPageComponent}\n appIdentityProxy={appIdentityProxy}\n >\n <Routes>\n <Route path={mountPath} element={<>{props.children}</>} />\n </Routes>\n </SignInPageWrapper>\n </BUIProvider>\n </RouterComponent>\n );\n }\n\n return (\n <RouterComponent basename={basePath}>\n <BUIProvider useAnalytics={useAnalytics}>\n <RouteTracker routeObjects={routeObjects} />\n <SignInPageWrapper\n component={SignInPageComponent}\n appIdentityProxy={appIdentityProxy}\n >\n {props.children}\n </SignInPageWrapper>\n </BUIProvider>\n </RouterComponent>\n );\n}\n\nattachComponentData(AppRouter, 'core.type', 'AppRouter');\n"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -428,11 +428,13 @@ declare class OpenShiftAuth {
428
428
  * missing alerts that were posted before subscription.
429
429
  *
430
430
  * @public
431
+ * @deprecated Use ToastApi instead. AlertApi will be removed in a future release.
431
432
  */
432
433
  declare class AlertApiForwarder implements AlertApi {
433
434
  private readonly subject;
434
435
  private readonly recentAlerts;
435
436
  private readonly maxBufferSize;
437
+ private hasWarnedDeprecation;
436
438
  post(alert: AlertMessage): void;
437
439
  alert$(): Observable<AlertMessage>;
438
440
  }
@@ -1 +1 @@
1
- {"version":3,"file":"AuthSessionStore.esm.js","sources":["../../../src/lib/AuthSessionManager/AuthSessionStore.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 { ZodSchema } from 'zod';\nimport {\n MutableSessionManager,\n SessionScopesFunc,\n SessionShouldRefreshFunc,\n GetSessionOptions,\n} from './types';\nimport { SessionScopeHelper } from './common';\n\ntype Options<T> = {\n /** The connector used for acting on the auth session */\n manager: MutableSessionManager<T>;\n /** Storage key to use to store sessions */\n storageKey: string;\n /** The schema used to validate the stored data */\n schema: ZodSchema<T>;\n /** Used to get the scope of the session */\n sessionScopes?: SessionScopesFunc<T>;\n /** Used to check if the session needs to be refreshed, defaults to never refresh */\n sessionShouldRefresh?: SessionShouldRefreshFunc<T>;\n};\n\n/**\n * AuthSessionStore decorates another SessionManager with a functionality\n * to store the session in local storage.\n *\n * Session is serialized to JSON with special support for following types: Set.\n */\nexport class AuthSessionStore<T> implements MutableSessionManager<T> {\n private readonly manager: MutableSessionManager<T>;\n private readonly storageKey: string;\n private readonly schema: ZodSchema<T>;\n private readonly sessionShouldRefreshFunc: SessionShouldRefreshFunc<T>;\n private readonly helper: SessionScopeHelper<T>;\n\n constructor(options: Options<T>) {\n const {\n manager,\n storageKey,\n schema,\n sessionScopes,\n sessionShouldRefresh = () => false,\n } = options;\n\n this.manager = manager;\n this.storageKey = storageKey;\n this.schema = schema;\n this.sessionShouldRefreshFunc = sessionShouldRefresh;\n this.helper = new SessionScopeHelper({\n sessionScopes,\n defaultScopes: new Set(),\n });\n }\n\n setSession(session: T | undefined): void {\n this.manager.setSession(session);\n this.saveSession(session);\n }\n\n async getSession(options: GetSessionOptions): Promise<T | undefined> {\n const { scopes } = options;\n const session = this.loadSession();\n\n if (this.helper.sessionExistsAndHasScope(session, scopes)) {\n const shouldRefresh = this.sessionShouldRefreshFunc(session!);\n\n if (!shouldRefresh) {\n this.manager.setSession(session!);\n return session!;\n }\n }\n\n const newSession = await this.manager.getSession(options);\n this.saveSession(newSession);\n return newSession;\n }\n\n async removeSession() {\n localStorage.removeItem(this.storageKey);\n await this.manager.removeSession();\n }\n\n sessionState$() {\n return this.manager.sessionState$();\n }\n\n private loadSession(): T | undefined {\n try {\n const sessionJson = localStorage.getItem(this.storageKey);\n if (sessionJson) {\n const session = JSON.parse(sessionJson, (_key, value) => {\n if (value?.__type === 'Set') {\n return new Set(value.__value);\n }\n return value;\n });\n\n try {\n return this.schema.parse(session);\n } catch (e) {\n // eslint-disable-next-line no-console\n console.log(\n `Failed to load session from local storage because it did not conform to the expected schema, ${e}`,\n );\n throw e;\n }\n }\n\n return undefined;\n } catch (error) {\n localStorage.removeItem(this.storageKey);\n return undefined;\n }\n }\n\n private saveSession(session: T | undefined) {\n if (session === undefined) {\n localStorage.removeItem(this.storageKey);\n return;\n }\n\n try {\n this.schema.parse(session);\n } catch (e) {\n // eslint-disable-next-line no-console\n console.warn(\n `Failed to save session to local storage because it did not conform to the expected schema, ${e}`,\n );\n return;\n }\n\n localStorage.setItem(\n this.storageKey,\n JSON.stringify(session, (_key, value) => {\n if (value instanceof Set) {\n return {\n __type: 'Set',\n __value: Array.from(value),\n };\n }\n return value;\n }),\n );\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"AuthSessionStore.esm.js","sources":["../../../src/lib/AuthSessionManager/AuthSessionStore.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 type { ZodSchema } from 'zod/v3';\nimport {\n MutableSessionManager,\n SessionScopesFunc,\n SessionShouldRefreshFunc,\n GetSessionOptions,\n} from './types';\nimport { SessionScopeHelper } from './common';\n\ntype Options<T> = {\n /** The connector used for acting on the auth session */\n manager: MutableSessionManager<T>;\n /** Storage key to use to store sessions */\n storageKey: string;\n /** The schema used to validate the stored data */\n schema: ZodSchema<T>;\n /** Used to get the scope of the session */\n sessionScopes?: SessionScopesFunc<T>;\n /** Used to check if the session needs to be refreshed, defaults to never refresh */\n sessionShouldRefresh?: SessionShouldRefreshFunc<T>;\n};\n\n/**\n * AuthSessionStore decorates another SessionManager with a functionality\n * to store the session in local storage.\n *\n * Session is serialized to JSON with special support for following types: Set.\n */\nexport class AuthSessionStore<T> implements MutableSessionManager<T> {\n private readonly manager: MutableSessionManager<T>;\n private readonly storageKey: string;\n private readonly schema: ZodSchema<T>;\n private readonly sessionShouldRefreshFunc: SessionShouldRefreshFunc<T>;\n private readonly helper: SessionScopeHelper<T>;\n\n constructor(options: Options<T>) {\n const {\n manager,\n storageKey,\n schema,\n sessionScopes,\n sessionShouldRefresh = () => false,\n } = options;\n\n this.manager = manager;\n this.storageKey = storageKey;\n this.schema = schema;\n this.sessionShouldRefreshFunc = sessionShouldRefresh;\n this.helper = new SessionScopeHelper({\n sessionScopes,\n defaultScopes: new Set(),\n });\n }\n\n setSession(session: T | undefined): void {\n this.manager.setSession(session);\n this.saveSession(session);\n }\n\n async getSession(options: GetSessionOptions): Promise<T | undefined> {\n const { scopes } = options;\n const session = this.loadSession();\n\n if (this.helper.sessionExistsAndHasScope(session, scopes)) {\n const shouldRefresh = this.sessionShouldRefreshFunc(session!);\n\n if (!shouldRefresh) {\n this.manager.setSession(session!);\n return session!;\n }\n }\n\n const newSession = await this.manager.getSession(options);\n this.saveSession(newSession);\n return newSession;\n }\n\n async removeSession() {\n localStorage.removeItem(this.storageKey);\n await this.manager.removeSession();\n }\n\n sessionState$() {\n return this.manager.sessionState$();\n }\n\n private loadSession(): T | undefined {\n try {\n const sessionJson = localStorage.getItem(this.storageKey);\n if (sessionJson) {\n const session = JSON.parse(sessionJson, (_key, value) => {\n if (value?.__type === 'Set') {\n return new Set(value.__value);\n }\n return value;\n });\n\n try {\n return this.schema.parse(session);\n } catch (e) {\n // eslint-disable-next-line no-console\n console.log(\n `Failed to load session from local storage because it did not conform to the expected schema, ${e}`,\n );\n throw e;\n }\n }\n\n return undefined;\n } catch (error) {\n localStorage.removeItem(this.storageKey);\n return undefined;\n }\n }\n\n private saveSession(session: T | undefined) {\n if (session === undefined) {\n localStorage.removeItem(this.storageKey);\n return;\n }\n\n try {\n this.schema.parse(session);\n } catch (e) {\n // eslint-disable-next-line no-console\n console.warn(\n `Failed to save session to local storage because it did not conform to the expected schema, ${e}`,\n );\n return;\n }\n\n localStorage.setItem(\n this.storageKey,\n JSON.stringify(session, (_key, value) => {\n if (value instanceof Set) {\n return {\n __type: 'Set',\n __value: Array.from(value),\n };\n }\n return value;\n }),\n );\n }\n}\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/core-app-api",
3
- "version": "1.19.6-next.1",
3
+ "version": "1.19.6",
4
4
  "description": "Core app API used by Backstage apps",
5
5
  "backstage": {
6
6
  "role": "web-library"
@@ -50,11 +50,11 @@
50
50
  "test": "backstage-cli package test"
51
51
  },
52
52
  "dependencies": {
53
- "@backstage/config": "1.3.6",
54
- "@backstage/core-plugin-api": "1.12.4-next.1",
55
- "@backstage/types": "1.2.2",
56
- "@backstage/ui": "0.13.0-next.2",
57
- "@backstage/version-bridge": "1.0.12",
53
+ "@backstage/config": "^1.3.6",
54
+ "@backstage/core-plugin-api": "^1.12.4",
55
+ "@backstage/types": "^1.2.2",
56
+ "@backstage/ui": "^0.13.0",
57
+ "@backstage/version-bridge": "^1.0.12",
58
58
  "@types/prop-types": "^15.7.3",
59
59
  "history": "^5.0.0",
60
60
  "i18next": "^22.4.15",
@@ -62,11 +62,11 @@
62
62
  "prop-types": "^15.7.2",
63
63
  "react-use": "^17.2.4",
64
64
  "zen-observable": "^0.10.0",
65
- "zod": "^3.25.76"
65
+ "zod": "^3.25.76 || ^4.0.0"
66
66
  },
67
67
  "devDependencies": {
68
- "@backstage/cli": "0.36.0-next.2",
69
- "@backstage/test-utils": "1.7.16-next.0",
68
+ "@backstage/cli": "^0.36.0",
69
+ "@backstage/test-utils": "^1.7.16",
70
70
  "@testing-library/dom": "^10.0.0",
71
71
  "@testing-library/jest-dom": "^6.0.0",
72
72
  "@testing-library/react": "^16.0.0",