@backstage/frontend-plugin-api 0.16.0 → 0.16.2

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,17 @@
1
1
  # @backstage/frontend-plugin-api
2
2
 
3
+ ## 0.16.2
4
+
5
+ ### Patch Changes
6
+
7
+ - bc41a91: Updated error messages and deprecation warnings to clarify that the `zod/v4` subpath export from the Zod v3 package is not supported by `configSchema`, since it does not include JSON Schema conversion. The `zod` dependency has been bumped to `^4.0.0`.
8
+
9
+ ## 0.16.1
10
+
11
+ ### Patch Changes
12
+
13
+ - 6b60bd7: Replaced old config schema values from existing extensions and blueprints.
14
+
3
15
  ## 0.16.0
4
16
 
5
17
  ### Minor Changes
@@ -12,7 +24,7 @@
12
24
  - 4c09967: Fixed the duplicate extension error message in `createFrontendModule` to correctly say "Module" instead of "Plugin".
13
25
  - e4804ab: Added `open` method to `DialogApi` that renders dialogs without any built-in dialog chrome, giving the caller full control over the dialog presentation. This avoids focus trap conflicts that occur when mixing components from different design libraries. The existing `show` and `showModal` methods are now deprecated in favor of `open`.
14
26
  - ddc5247: Fixed `FlattenedMessages` type to avoid excessive type instantiation depth in TypeScript 6 when using `createTranslationRef` with the `translations` option.
15
- - a2a6c3b: Added a new `configSchema` option for `createExtension` and `createExtensionBlueprint` that accepts direct schema values from any [Standard Schema](https://github.com/standard-schema/standard-schema) compatible library with JSON Schema support, such as zod v4 or the `zod/v4` subpath from zod v3. The old `config.schema` option is now deprecated. Note that direct zod v3 schemas are not supported by the new `configSchema` option use `import { z } from 'zod/v4'` from the zod v3 package, or upgrade to zod v4. See the [1.50 migration documentation](https://backstage.io/docs/frontend-system/architecture/migrations#150) for more information.
27
+ - a2a6c3b: Added a new `configSchema` option for `createExtension` and `createExtensionBlueprint` that accepts direct schema values from any [Standard Schema](https://github.com/standard-schema/standard-schema) compatible library with JSON Schema support, such as zod v4 (`zod@^4.0.0`). The old `config.schema` option is now deprecated. Note that Zod v3 is not supported by the new `configSchema` option, including the `zod/v4` subpath export which does not include JSON Schema conversion support. You must upgrade to the `zod` v4 package. See the [1.50 migration documentation](https://backstage.io/docs/frontend-system/architecture/migrations#150) for more information.
16
28
  - d66a3ec: Added `titleLink` prop to `PageLayoutProps` so the plugin header title can link back to the plugin root.
17
29
  - e220589: Removed the unnecessary need to use `defineParams` callback from `PluginHeaderActionBlueprint`. It still works, but is no longer required.
18
30
  - Updated dependencies
@@ -1,3 +1,4 @@
1
+ import { z } from 'zod/v4';
1
2
  import '../wiring/coreExtensionData.esm.js';
2
3
  import 'zod/v3';
3
4
  import 'zod-to-json-schema';
@@ -23,10 +24,8 @@ const NavItemBlueprint = createExtensionBlueprint({
23
24
  routeRef
24
25
  })
25
26
  ],
26
- config: {
27
- schema: {
28
- title: (z) => z.string().optional()
29
- }
27
+ configSchema: {
28
+ title: z.string().optional()
30
29
  }
31
30
  });
32
31
 
@@ -1 +1 @@
1
- {"version":3,"file":"NavItemBlueprint.esm.js","sources":["../../src/blueprints/NavItemBlueprint.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 { IconComponent } from '../icons/types';\nimport { RouteRef } from '../routing';\nimport { createExtensionBlueprint, createExtensionDataRef } from '../wiring';\n\n// TODO(Rugvip): Should this be broken apart into separate refs? title/icon/routeRef\nconst targetDataRef = createExtensionDataRef<{\n title: string;\n icon: IconComponent;\n routeRef: RouteRef<undefined>;\n}>().with({ id: 'core.nav-item.target' });\n\n/**\n * Creates extensions that make up the items of the nav bar.\n *\n * @public\n * @deprecated Nav items are now automatically inferred from `PageBlueprint`\n * extensions based on their `title` and `icon` params. You can remove your\n * `NavItemBlueprint` usage and instead pass `title` and `icon` directly to\n * the `PageBlueprint`.\n */\nexport const NavItemBlueprint = createExtensionBlueprint({\n kind: 'nav-item',\n attachTo: { id: 'app/nav', input: 'items' },\n output: [targetDataRef],\n dataRefs: {\n target: targetDataRef,\n },\n factory: (\n {\n icon,\n routeRef,\n title,\n }: {\n title: string;\n icon: IconComponent;\n routeRef: RouteRef<undefined>;\n },\n { config },\n ) => [\n targetDataRef({\n title: config.title ?? title,\n icon,\n routeRef,\n }),\n ],\n config: {\n schema: {\n title: z => z.string().optional(),\n },\n },\n});\n"],"names":[],"mappings":";;;;;;AAqBA,MAAM,gBAAgB,sBAAA,EAInB,CAAE,KAAK,EAAE,EAAA,EAAI,wBAAwB,CAAA;AAWjC,MAAM,mBAAmB,wBAAA,CAAyB;AAAA,EACvD,IAAA,EAAM,UAAA;AAAA,EACN,QAAA,EAAU,EAAE,EAAA,EAAI,SAAA,EAAW,OAAO,OAAA,EAAQ;AAAA,EAC1C,MAAA,EAAQ,CAAC,aAAa,CAAA;AAAA,EACtB,QAAA,EAAU;AAAA,IACR,MAAA,EAAQ;AAAA,GACV;AAAA,EACA,SAAS,CACP;AAAA,IACE,IAAA;AAAA,IACA,QAAA;AAAA,IACA;AAAA,GACF,EAKA,EAAE,MAAA,EAAO,KACN;AAAA,IACH,aAAA,CAAc;AAAA,MACZ,KAAA,EAAO,OAAO,KAAA,IAAS,KAAA;AAAA,MACvB,IAAA;AAAA,MACA;AAAA,KACD;AAAA,GACH;AAAA,EACA,MAAA,EAAQ;AAAA,IACN,MAAA,EAAQ;AAAA,MACN,KAAA,EAAO,CAAA,CAAA,KAAK,CAAA,CAAE,MAAA,GAAS,QAAA;AAAS;AAClC;AAEJ,CAAC;;;;"}
1
+ {"version":3,"file":"NavItemBlueprint.esm.js","sources":["../../src/blueprints/NavItemBlueprint.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 { z } from 'zod/v4';\nimport { IconComponent } from '../icons/types';\nimport { RouteRef } from '../routing';\nimport { createExtensionBlueprint, createExtensionDataRef } from '../wiring';\n\n// TODO(Rugvip): Should this be broken apart into separate refs? title/icon/routeRef\nconst targetDataRef = createExtensionDataRef<{\n title: string;\n icon: IconComponent;\n routeRef: RouteRef<undefined>;\n}>().with({ id: 'core.nav-item.target' });\n\n/**\n * Creates extensions that make up the items of the nav bar.\n *\n * @public\n * @deprecated Nav items are now automatically inferred from `PageBlueprint`\n * extensions based on their `title` and `icon` params. You can remove your\n * `NavItemBlueprint` usage and instead pass `title` and `icon` directly to\n * the `PageBlueprint`.\n */\nexport const NavItemBlueprint = createExtensionBlueprint({\n kind: 'nav-item',\n attachTo: { id: 'app/nav', input: 'items' },\n output: [targetDataRef],\n dataRefs: {\n target: targetDataRef,\n },\n factory: (\n {\n icon,\n routeRef,\n title,\n }: {\n title: string;\n icon: IconComponent;\n routeRef: RouteRef<undefined>;\n },\n { config },\n ) => [\n targetDataRef({\n title: config.title ?? title,\n icon,\n routeRef,\n }),\n ],\n configSchema: {\n title: z.string().optional(),\n },\n});\n"],"names":[],"mappings":";;;;;;;AAsBA,MAAM,gBAAgB,sBAAA,EAInB,CAAE,KAAK,EAAE,EAAA,EAAI,wBAAwB,CAAA;AAWjC,MAAM,mBAAmB,wBAAA,CAAyB;AAAA,EACvD,IAAA,EAAM,UAAA;AAAA,EACN,QAAA,EAAU,EAAE,EAAA,EAAI,SAAA,EAAW,OAAO,OAAA,EAAQ;AAAA,EAC1C,MAAA,EAAQ,CAAC,aAAa,CAAA;AAAA,EACtB,QAAA,EAAU;AAAA,IACR,MAAA,EAAQ;AAAA,GACV;AAAA,EACA,SAAS,CACP;AAAA,IACE,IAAA;AAAA,IACA,QAAA;AAAA,IACA;AAAA,GACF,EAKA,EAAE,MAAA,EAAO,KACN;AAAA,IACH,aAAA,CAAc;AAAA,MACZ,KAAA,EAAO,OAAO,KAAA,IAAS,KAAA;AAAA,MACvB,IAAA;AAAA,MACA;AAAA,KACD;AAAA,GACH;AAAA,EACA,YAAA,EAAc;AAAA,IACZ,KAAA,EAAO,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA;AAAS;AAE/B,CAAC;;;;"}
@@ -1,4 +1,5 @@
1
1
  import { jsx, jsxs } from 'react/jsx-runtime';
2
+ import { z } from 'zod/v4';
2
3
  import { Routes, Route, Navigate } from 'react-router-dom';
3
4
  import { coreExtensionData } from '../wiring/coreExtensionData.esm.js';
4
5
  import 'zod/v3';
@@ -63,11 +64,9 @@ const PageBlueprint = createExtensionBlueprint({
63
64
  coreExtensionData.title.optional(),
64
65
  coreExtensionData.icon.optional()
65
66
  ],
66
- config: {
67
- schema: {
68
- path: (z) => z.string().optional(),
69
- title: (z) => z.string().optional()
70
- }
67
+ configSchema: {
68
+ path: z.string().optional(),
69
+ title: z.string().optional()
71
70
  },
72
71
  *factory(params, { config, node, inputs }) {
73
72
  const title = config.title ?? params.title;
@@ -1 +1 @@
1
- {"version":3,"file":"PageBlueprint.esm.js","sources":["../../src/blueprints/PageBlueprint.tsx"],"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 { JSX } from 'react';\nimport { Routes, Route, Navigate } from 'react-router-dom';\nimport { IconElement } from '../icons/types';\nimport { RouteRef } from '../routing';\nimport {\n coreExtensionData,\n createExtensionBlueprint,\n createExtensionInput,\n} from '../wiring';\nimport { ExtensionBoundary, PageLayout, PageLayoutTab } from '../components';\nimport { useApi } from '../apis/system';\nimport { routeResolutionApiRef } from '../apis/definitions/RouteResolutionApi';\nimport { pluginHeaderActionsApiRef } from '../apis/definitions/PluginHeaderActionsApi';\nimport { RouteResolutionApi } from '../apis/definitions/RouteResolutionApi';\n\nfunction resolveTitleLink(\n routeResolutionApi: RouteResolutionApi,\n routeRef: RouteRef | undefined,\n): string | undefined {\n if (!routeRef) {\n return undefined;\n }\n try {\n return routeResolutionApi.resolve(routeRef)?.();\n } catch {\n // Route ref may require params not available in the current context\n return undefined;\n }\n}\n\n/**\n * Creates extensions that are routable React page components.\n *\n * @public\n */\nexport const PageBlueprint = createExtensionBlueprint({\n kind: 'page',\n attachTo: { id: 'app/routes', input: 'routes' },\n inputs: {\n pages: createExtensionInput([\n coreExtensionData.routePath,\n coreExtensionData.routeRef.optional(),\n coreExtensionData.reactElement,\n coreExtensionData.title.optional(),\n coreExtensionData.icon.optional(),\n ]),\n },\n output: [\n coreExtensionData.routePath,\n coreExtensionData.reactElement,\n coreExtensionData.routeRef.optional(),\n coreExtensionData.title.optional(),\n coreExtensionData.icon.optional(),\n ],\n config: {\n schema: {\n path: z => z.string().optional(),\n title: z => z.string().optional(),\n },\n },\n *factory(\n params: {\n path: string;\n title?: string;\n icon?: IconElement;\n loader?: () => Promise<JSX.Element>;\n routeRef?: RouteRef;\n /**\n * Hide the default plugin page header, making the page fill up all available space.\n */\n noHeader?: boolean;\n },\n { config, node, inputs },\n ) {\n const title = config.title ?? params.title;\n const icon = params.icon;\n const pluginId = node.spec.plugin.pluginId;\n const noHeader = params.noHeader ?? false;\n const resolvedTitle =\n title ?? node.spec.plugin.title ?? node.spec.plugin.pluginId;\n const resolvedIcon = icon ?? node.spec.plugin.icon;\n const titleRouteRef =\n (node.spec.plugin.routes as { root?: RouteRef }).root ?? params.routeRef;\n\n yield coreExtensionData.routePath(config.path ?? params.path);\n if (params.loader) {\n const loader = params.loader;\n const PageContent = () => {\n const routeResolutionApi = useApi(routeResolutionApiRef);\n const titleLink = resolveTitleLink(routeResolutionApi, titleRouteRef);\n const headerActionsApi = useApi(pluginHeaderActionsApiRef);\n const headerActions = headerActionsApi.getPluginHeaderActions(pluginId);\n\n return (\n <PageLayout\n title={resolvedTitle}\n icon={resolvedIcon}\n noHeader={noHeader}\n titleLink={titleLink}\n headerActions={headerActions}\n >\n {ExtensionBoundary.lazy(node, loader)}\n </PageLayout>\n );\n };\n yield coreExtensionData.reactElement(<PageContent />);\n } else if (inputs.pages.length > 0) {\n // Parent page with sub-pages - render header with tabs\n const tabs: PageLayoutTab[] = inputs.pages.map(page => {\n const path = page.get(coreExtensionData.routePath);\n const tabTitle = page.get(coreExtensionData.title);\n const tabIcon = page.get(coreExtensionData.icon);\n return {\n id: path,\n label: tabTitle || path,\n icon: tabIcon,\n href: path,\n };\n });\n\n const PageContent = () => {\n const firstPagePath = inputs.pages[0]?.get(coreExtensionData.routePath);\n const routeResolutionApi = useApi(routeResolutionApiRef);\n const titleLink = resolveTitleLink(routeResolutionApi, titleRouteRef);\n\n const headerActionsApi = useApi(pluginHeaderActionsApiRef);\n const headerActions = headerActionsApi.getPluginHeaderActions(pluginId);\n\n return (\n <PageLayout\n title={resolvedTitle}\n icon={resolvedIcon}\n tabs={tabs}\n titleLink={titleLink}\n headerActions={headerActions}\n >\n <Routes>\n {firstPagePath && (\n <Route\n index\n element={<Navigate to={firstPagePath} replace />}\n />\n )}\n {inputs.pages.map((page, index) => {\n const path = page.get(coreExtensionData.routePath);\n const element = page.get(coreExtensionData.reactElement);\n return (\n <Route key={index} path={`${path}/*`} element={element} />\n );\n })}\n </Routes>\n </PageLayout>\n );\n };\n\n yield coreExtensionData.reactElement(<PageContent />);\n } else {\n const PageContent = () => {\n const routeResolutionApi = useApi(routeResolutionApiRef);\n const titleLink = resolveTitleLink(routeResolutionApi, titleRouteRef);\n const headerActionsApi = useApi(pluginHeaderActionsApiRef);\n const headerActions = headerActionsApi.getPluginHeaderActions(pluginId);\n return (\n <PageLayout\n title={resolvedTitle}\n icon={resolvedIcon}\n titleLink={titleLink}\n headerActions={headerActions}\n />\n );\n };\n yield coreExtensionData.reactElement(<PageContent />);\n }\n if (params.routeRef) {\n yield coreExtensionData.routeRef(params.routeRef);\n }\n if (title) {\n yield coreExtensionData.title(title);\n }\n if (icon) {\n yield coreExtensionData.icon(icon);\n }\n },\n});\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"PageBlueprint.esm.js","sources":["../../src/blueprints/PageBlueprint.tsx"],"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 { z } from 'zod/v4';\nimport { JSX } from 'react';\nimport { Routes, Route, Navigate } from 'react-router-dom';\nimport { IconElement } from '../icons/types';\nimport { RouteRef } from '../routing';\nimport {\n coreExtensionData,\n createExtensionBlueprint,\n createExtensionInput,\n} from '../wiring';\nimport { ExtensionBoundary, PageLayout, PageLayoutTab } from '../components';\nimport { useApi } from '../apis/system';\nimport { routeResolutionApiRef } from '../apis/definitions/RouteResolutionApi';\nimport { pluginHeaderActionsApiRef } from '../apis/definitions/PluginHeaderActionsApi';\nimport { RouteResolutionApi } from '../apis/definitions/RouteResolutionApi';\n\nfunction resolveTitleLink(\n routeResolutionApi: RouteResolutionApi,\n routeRef: RouteRef | undefined,\n): string | undefined {\n if (!routeRef) {\n return undefined;\n }\n try {\n return routeResolutionApi.resolve(routeRef)?.();\n } catch {\n // Route ref may require params not available in the current context\n return undefined;\n }\n}\n\n/**\n * Creates extensions that are routable React page components.\n *\n * @public\n */\nexport const PageBlueprint = createExtensionBlueprint({\n kind: 'page',\n attachTo: { id: 'app/routes', input: 'routes' },\n inputs: {\n pages: createExtensionInput([\n coreExtensionData.routePath,\n coreExtensionData.routeRef.optional(),\n coreExtensionData.reactElement,\n coreExtensionData.title.optional(),\n coreExtensionData.icon.optional(),\n ]),\n },\n output: [\n coreExtensionData.routePath,\n coreExtensionData.reactElement,\n coreExtensionData.routeRef.optional(),\n coreExtensionData.title.optional(),\n coreExtensionData.icon.optional(),\n ],\n configSchema: {\n path: z.string().optional(),\n title: z.string().optional(),\n },\n *factory(\n params: {\n path: string;\n title?: string;\n icon?: IconElement;\n loader?: () => Promise<JSX.Element>;\n routeRef?: RouteRef;\n /**\n * Hide the default plugin page header, making the page fill up all available space.\n */\n noHeader?: boolean;\n },\n { config, node, inputs },\n ) {\n const title = config.title ?? params.title;\n const icon = params.icon;\n const pluginId = node.spec.plugin.pluginId;\n const noHeader = params.noHeader ?? false;\n const resolvedTitle =\n title ?? node.spec.plugin.title ?? node.spec.plugin.pluginId;\n const resolvedIcon = icon ?? node.spec.plugin.icon;\n const titleRouteRef =\n (node.spec.plugin.routes as { root?: RouteRef }).root ?? params.routeRef;\n\n yield coreExtensionData.routePath(config.path ?? params.path);\n if (params.loader) {\n const loader = params.loader;\n const PageContent = () => {\n const routeResolutionApi = useApi(routeResolutionApiRef);\n const titleLink = resolveTitleLink(routeResolutionApi, titleRouteRef);\n const headerActionsApi = useApi(pluginHeaderActionsApiRef);\n const headerActions = headerActionsApi.getPluginHeaderActions(pluginId);\n\n return (\n <PageLayout\n title={resolvedTitle}\n icon={resolvedIcon}\n noHeader={noHeader}\n titleLink={titleLink}\n headerActions={headerActions}\n >\n {ExtensionBoundary.lazy(node, loader)}\n </PageLayout>\n );\n };\n yield coreExtensionData.reactElement(<PageContent />);\n } else if (inputs.pages.length > 0) {\n // Parent page with sub-pages - render header with tabs\n const tabs: PageLayoutTab[] = inputs.pages.map(page => {\n const path = page.get(coreExtensionData.routePath);\n const tabTitle = page.get(coreExtensionData.title);\n const tabIcon = page.get(coreExtensionData.icon);\n return {\n id: path,\n label: tabTitle || path,\n icon: tabIcon,\n href: path,\n };\n });\n\n const PageContent = () => {\n const firstPagePath = inputs.pages[0]?.get(coreExtensionData.routePath);\n const routeResolutionApi = useApi(routeResolutionApiRef);\n const titleLink = resolveTitleLink(routeResolutionApi, titleRouteRef);\n\n const headerActionsApi = useApi(pluginHeaderActionsApiRef);\n const headerActions = headerActionsApi.getPluginHeaderActions(pluginId);\n\n return (\n <PageLayout\n title={resolvedTitle}\n icon={resolvedIcon}\n tabs={tabs}\n titleLink={titleLink}\n headerActions={headerActions}\n >\n <Routes>\n {firstPagePath && (\n <Route\n index\n element={<Navigate to={firstPagePath} replace />}\n />\n )}\n {inputs.pages.map((page, index) => {\n const path = page.get(coreExtensionData.routePath);\n const element = page.get(coreExtensionData.reactElement);\n return (\n <Route key={index} path={`${path}/*`} element={element} />\n );\n })}\n </Routes>\n </PageLayout>\n );\n };\n\n yield coreExtensionData.reactElement(<PageContent />);\n } else {\n const PageContent = () => {\n const routeResolutionApi = useApi(routeResolutionApiRef);\n const titleLink = resolveTitleLink(routeResolutionApi, titleRouteRef);\n const headerActionsApi = useApi(pluginHeaderActionsApiRef);\n const headerActions = headerActionsApi.getPluginHeaderActions(pluginId);\n return (\n <PageLayout\n title={resolvedTitle}\n icon={resolvedIcon}\n titleLink={titleLink}\n headerActions={headerActions}\n />\n );\n };\n yield coreExtensionData.reactElement(<PageContent />);\n }\n if (params.routeRef) {\n yield coreExtensionData.routeRef(params.routeRef);\n }\n if (title) {\n yield coreExtensionData.title(title);\n }\n if (icon) {\n yield coreExtensionData.icon(icon);\n }\n },\n});\n"],"names":[],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ import { z } from 'zod/v4';
1
2
  import { coreExtensionData } from '../wiring/coreExtensionData.esm.js';
2
3
  import 'zod/v3';
3
4
  import 'zod-to-json-schema';
@@ -43,11 +44,9 @@ const SubPageBlueprint = createExtensionBlueprint({
43
44
  coreExtensionData.routeRef.optional(),
44
45
  coreExtensionData.icon.optional()
45
46
  ],
46
- config: {
47
- schema: {
48
- path: (z) => z.string().optional(),
49
- title: (z) => z.string().optional()
50
- }
47
+ configSchema: {
48
+ path: z.string().optional(),
49
+ title: z.string().optional()
51
50
  },
52
51
  *factory(params, { config, node }) {
53
52
  yield coreExtensionData.routePath(config.path ?? params.path);
@@ -1 +1 @@
1
- {"version":3,"file":"SubPageBlueprint.esm.js","sources":["../../src/blueprints/SubPageBlueprint.tsx"],"sourcesContent":["/*\n * Copyright 2026 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 { IconElement } from '../icons/types';\nimport { RouteRef } from '../routing';\nimport { coreExtensionData, createExtensionBlueprint } from '../wiring';\nimport { ExtensionBoundary } from '../components';\n\n/**\n * Creates extensions that are sub-page React components attached to a parent page.\n * Sub-pages are rendered as tabs within the parent page's header.\n *\n * @public\n * @example\n * ```tsx\n * const overviewRouteRef = createRouteRef();\n *\n * const mySubPage = SubPageBlueprint.make({\n * attachTo: { id: 'page:my-plugin', input: 'pages' },\n * name: 'overview',\n * params: {\n * path: 'overview',\n * title: 'Overview',\n * routeRef: overviewRouteRef,\n * loader: () => import('./components/Overview').then(m => <m.Overview />),\n * },\n * });\n * ```\n */\nexport const SubPageBlueprint = createExtensionBlueprint({\n kind: 'sub-page',\n attachTo: { relative: { kind: 'page' }, input: 'pages' },\n output: [\n coreExtensionData.routePath,\n coreExtensionData.reactElement,\n coreExtensionData.title,\n coreExtensionData.routeRef.optional(),\n coreExtensionData.icon.optional(),\n ],\n config: {\n schema: {\n path: z => z.string().optional(),\n title: z => z.string().optional(),\n },\n },\n *factory(\n params: {\n /**\n * The path for this sub-page, relative to the parent page. Must **not** start with '/'.\n *\n * @example 'overview', 'settings', 'details'\n */\n path: string;\n /**\n * The title displayed in the tab for this sub-page.\n */\n title: string;\n /**\n * Optional icon for this sub-page, displayed in the tab.\n */\n icon?: IconElement;\n /**\n * A function that returns a promise resolving to the React element to render.\n * This enables lazy loading of the sub-page content.\n */\n loader: () => Promise<JSX.Element>;\n /**\n * Optional route reference for this sub-page.\n */\n routeRef?: RouteRef;\n },\n { config, node },\n ) {\n yield coreExtensionData.routePath(config.path ?? params.path);\n yield coreExtensionData.title(config.title ?? params.title);\n yield coreExtensionData.reactElement(\n ExtensionBoundary.lazy(node, params.loader),\n );\n if (params.routeRef) {\n yield coreExtensionData.routeRef(params.routeRef);\n }\n if (params.icon) {\n yield coreExtensionData.icon(params.icon);\n }\n },\n});\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0CO,MAAM,mBAAmB,wBAAA,CAAyB;AAAA,EACvD,IAAA,EAAM,UAAA;AAAA,EACN,QAAA,EAAU,EAAE,QAAA,EAAU,EAAE,MAAM,MAAA,EAAO,EAAG,OAAO,OAAA,EAAQ;AAAA,EACvD,MAAA,EAAQ;AAAA,IACN,iBAAA,CAAkB,SAAA;AAAA,IAClB,iBAAA,CAAkB,YAAA;AAAA,IAClB,iBAAA,CAAkB,KAAA;AAAA,IAClB,iBAAA,CAAkB,SAAS,QAAA,EAAS;AAAA,IACpC,iBAAA,CAAkB,KAAK,QAAA;AAAS,GAClC;AAAA,EACA,MAAA,EAAQ;AAAA,IACN,MAAA,EAAQ;AAAA,MACN,IAAA,EAAM,CAAA,CAAA,KAAK,CAAA,CAAE,MAAA,GAAS,QAAA,EAAS;AAAA,MAC/B,KAAA,EAAO,CAAA,CAAA,KAAK,CAAA,CAAE,MAAA,GAAS,QAAA;AAAS;AAClC,GACF;AAAA,EACA,CAAC,OAAA,CACC,MAAA,EAyBA,EAAE,MAAA,EAAQ,MAAK,EACf;AACA,IAAA,MAAM,iBAAA,CAAkB,SAAA,CAAU,MAAA,CAAO,IAAA,IAAQ,OAAO,IAAI,CAAA;AAC5D,IAAA,MAAM,iBAAA,CAAkB,KAAA,CAAM,MAAA,CAAO,KAAA,IAAS,OAAO,KAAK,CAAA;AAC1D,IAAA,MAAM,iBAAA,CAAkB,YAAA;AAAA,MACtB,iBAAA,CAAkB,IAAA,CAAK,IAAA,EAAM,MAAA,CAAO,MAAM;AAAA,KAC5C;AACA,IAAA,IAAI,OAAO,QAAA,EAAU;AACnB,MAAA,MAAM,iBAAA,CAAkB,QAAA,CAAS,MAAA,CAAO,QAAQ,CAAA;AAAA,IAClD;AACA,IAAA,IAAI,OAAO,IAAA,EAAM;AACf,MAAA,MAAM,iBAAA,CAAkB,IAAA,CAAK,MAAA,CAAO,IAAI,CAAA;AAAA,IAC1C;AAAA,EACF;AACF,CAAC;;;;"}
1
+ {"version":3,"file":"SubPageBlueprint.esm.js","sources":["../../src/blueprints/SubPageBlueprint.tsx"],"sourcesContent":["/*\n * Copyright 2026 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 { z } from 'zod/v4';\nimport { IconElement } from '../icons/types';\nimport { RouteRef } from '../routing';\nimport { coreExtensionData, createExtensionBlueprint } from '../wiring';\nimport { ExtensionBoundary } from '../components';\n\n/**\n * Creates extensions that are sub-page React components attached to a parent page.\n * Sub-pages are rendered as tabs within the parent page's header.\n *\n * @public\n * @example\n * ```tsx\n * const overviewRouteRef = createRouteRef();\n *\n * const mySubPage = SubPageBlueprint.make({\n * attachTo: { id: 'page:my-plugin', input: 'pages' },\n * name: 'overview',\n * params: {\n * path: 'overview',\n * title: 'Overview',\n * routeRef: overviewRouteRef,\n * loader: () => import('./components/Overview').then(m => <m.Overview />),\n * },\n * });\n * ```\n */\nexport const SubPageBlueprint = createExtensionBlueprint({\n kind: 'sub-page',\n attachTo: { relative: { kind: 'page' }, input: 'pages' },\n output: [\n coreExtensionData.routePath,\n coreExtensionData.reactElement,\n coreExtensionData.title,\n coreExtensionData.routeRef.optional(),\n coreExtensionData.icon.optional(),\n ],\n configSchema: {\n path: z.string().optional(),\n title: z.string().optional(),\n },\n *factory(\n params: {\n /**\n * The path for this sub-page, relative to the parent page. Must **not** start with '/'.\n *\n * @example 'overview', 'settings', 'details'\n */\n path: string;\n /**\n * The title displayed in the tab for this sub-page.\n */\n title: string;\n /**\n * Optional icon for this sub-page, displayed in the tab.\n */\n icon?: IconElement;\n /**\n * A function that returns a promise resolving to the React element to render.\n * This enables lazy loading of the sub-page content.\n */\n loader: () => Promise<JSX.Element>;\n /**\n * Optional route reference for this sub-page.\n */\n routeRef?: RouteRef;\n },\n { config, node },\n ) {\n yield coreExtensionData.routePath(config.path ?? params.path);\n yield coreExtensionData.title(config.title ?? params.title);\n yield coreExtensionData.reactElement(\n ExtensionBoundary.lazy(node, params.loader),\n );\n if (params.routeRef) {\n yield coreExtensionData.routeRef(params.routeRef);\n }\n if (params.icon) {\n yield coreExtensionData.icon(params.icon);\n }\n },\n});\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2CO,MAAM,mBAAmB,wBAAA,CAAyB;AAAA,EACvD,IAAA,EAAM,UAAA;AAAA,EACN,QAAA,EAAU,EAAE,QAAA,EAAU,EAAE,MAAM,MAAA,EAAO,EAAG,OAAO,OAAA,EAAQ;AAAA,EACvD,MAAA,EAAQ;AAAA,IACN,iBAAA,CAAkB,SAAA;AAAA,IAClB,iBAAA,CAAkB,YAAA;AAAA,IAClB,iBAAA,CAAkB,KAAA;AAAA,IAClB,iBAAA,CAAkB,SAAS,QAAA,EAAS;AAAA,IACpC,iBAAA,CAAkB,KAAK,QAAA;AAAS,GAClC;AAAA,EACA,YAAA,EAAc;AAAA,IACZ,IAAA,EAAM,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,IAC1B,KAAA,EAAO,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA;AAAS,GAC7B;AAAA,EACA,CAAC,OAAA,CACC,MAAA,EAyBA,EAAE,MAAA,EAAQ,MAAK,EACf;AACA,IAAA,MAAM,iBAAA,CAAkB,SAAA,CAAU,MAAA,CAAO,IAAA,IAAQ,OAAO,IAAI,CAAA;AAC5D,IAAA,MAAM,iBAAA,CAAkB,KAAA,CAAM,MAAA,CAAO,KAAA,IAAS,OAAO,KAAK,CAAA;AAC1D,IAAA,MAAM,iBAAA,CAAkB,YAAA;AAAA,MACtB,iBAAA,CAAkB,IAAA,CAAK,IAAA,EAAM,MAAA,CAAO,MAAM;AAAA,KAC5C;AACA,IAAA,IAAI,OAAO,QAAA,EAAU;AACnB,MAAA,MAAM,iBAAA,CAAkB,QAAA,CAAS,MAAA,CAAO,QAAQ,CAAA;AAAA,IAClD;AACA,IAAA,IAAI,OAAO,IAAA,EAAM;AACf,MAAA,MAAM,iBAAA,CAAkB,IAAA,CAAK,MAAA,CAAO,IAAI,CAAA;AAAA,IAC1C;AAAA,EACF;AACF,CAAC;;;;"}
package/dist/index.d.ts CHANGED
@@ -2268,8 +2268,12 @@ declare const NavItemBlueprint: _backstage_frontend_plugin_api.ExtensionBlueprin
2268
2268
  routeRef: RouteRef<undefined>;
2269
2269
  }, "core.nav-item.target", {}>;
2270
2270
  inputs: {};
2271
- config: {};
2272
- configInput: {};
2271
+ config: {
2272
+ title: string | undefined;
2273
+ };
2274
+ configInput: {
2275
+ title?: string | undefined;
2276
+ };
2273
2277
  dataRefs: {
2274
2278
  target: _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<{
2275
2279
  title: string;
@@ -2322,8 +2326,8 @@ declare const PageBlueprint: _backstage_frontend_plugin_api.ExtensionBlueprint<{
2322
2326
  title: string | undefined;
2323
2327
  };
2324
2328
  configInput: {
2325
- title?: string | undefined;
2326
2329
  path?: string | undefined;
2330
+ title?: string | undefined;
2327
2331
  };
2328
2332
  dataRefs: never;
2329
2333
  }>;
@@ -2387,8 +2391,8 @@ declare const SubPageBlueprint: _backstage_frontend_plugin_api.ExtensionBlueprin
2387
2391
  title: string | undefined;
2388
2392
  };
2389
2393
  configInput: {
2390
- title?: string | undefined;
2391
2394
  path?: string | undefined;
2395
+ title?: string | undefined;
2392
2396
  };
2393
2397
  dataRefs: never;
2394
2398
  }>;
@@ -79,7 +79,7 @@ function buildPortableSchema(fields) {
79
79
  function resolveField(key, schema) {
80
80
  if (isZodV3Type(schema)) {
81
81
  throw new Error(
82
- `Config schema for field '${key}' uses a Zod v3 schema, which is not supported by the \`configSchema\` option. Either use \`import { z } from 'zod/v4'\` from the zod v3 package, or upgrade to zod v4.`
82
+ `Config schema for field '${key}' uses a Zod v3 schema, which is not supported by the \`configSchema\` option. Upgrade to the \`zod\` v4 package (\`zod@^4.0.0\`). Note that the \`zod/v4\` subpath export from the zod v3 package is also not supported, as it does not include JSON Schema conversion.`
83
83
  );
84
84
  }
85
85
  if (isStandardSchema(schema)) {
@@ -199,7 +199,7 @@ function formatStandardIssue(fieldKey, issue) {
199
199
  }
200
200
  function warnConfigSchemaPropDeprecation(callSite) {
201
201
  console.warn(
202
- `DEPRECATION WARNING: The \`config.schema\` option for extension config is deprecated. Use the \`configSchema\` option instead with Standard Schema values, for example \`configSchema: { title: z.string() }\` using zod v4 (or \`import { z } from 'zod/v4'\` from the zod v3 package). Declared at ${callSite}`
202
+ `DEPRECATION WARNING: The \`config.schema\` option for extension config is deprecated. Use the \`configSchema\` option instead with Standard Schema values, for example \`configSchema: { title: z.string() }\` using the \`zod\` v4 package (\`zod@^4.0.0\`). Declared at ${callSite}`
203
203
  );
204
204
  }
205
205
 
@@ -1 +1 @@
1
- {"version":3,"file":"createPortableSchema.esm.js","sources":["../../src/schema/createPortableSchema.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 { JsonObject } from '@backstage/types';\nimport { z as zodV3, type ZodType } from 'zod/v3';\nimport zodToJsonSchema from 'zod-to-json-schema';\nimport { PortableSchema } from './types';\n\n/**\n * The Standard Schema interface.\n * @public\n */\nexport type { StandardSchemaV1 } from '@standard-schema/spec';\nimport { type StandardSchemaV1 } from '@standard-schema/spec';\n\n/** @internal */\nexport function createDeprecatedConfigSchema(\n fields: Record<string, (zImpl: typeof zodV3) => ZodType>,\n): MergeablePortableSchema {\n const resolved: Record<string, ResolvedField> = {};\n\n for (const [key, field] of Object.entries(fields)) {\n resolved[key] = resolveZodField(key, field(zodV3));\n }\n\n return buildPortableSchema(resolved);\n}\n\n/**\n * Per-field resolved schema — validation is eager, JSON Schema is lazy.\n * @internal\n */\ninterface ResolvedField {\n validate(value: unknown): { value: unknown } | { errors: string[] };\n toJsonSchema(): JsonObject;\n required: boolean;\n}\n\n/**\n * Internal representation that carries per-field resolvers alongside the\n * public PortableSchema surface, enabling schema merging.\n * @internal\n */\nexport interface MergeablePortableSchema<TOutput = any, TInput = any>\n extends PortableSchema<TOutput, TInput> {\n /** @internal */\n readonly _fields: Record<string, ResolvedField>;\n}\n\n/**\n * Resolves each field, eagerly validates JSON Schema support, and returns\n * a PortableSchema whose JSON Schema conversion is lazy.\n * @internal\n */\nexport function createConfigSchema(\n fields: Record<string, StandardSchemaV1>,\n): MergeablePortableSchema {\n const resolved: Record<string, ResolvedField> = {};\n\n for (const [key, field] of Object.entries(fields)) {\n resolved[key] = resolveField(key, field);\n }\n\n return buildPortableSchema(resolved);\n}\n\n/**\n * Combines schemas from different sources for blueprint + override\n * composition. Each source may use a completely different schema library.\n * Because we track per-field resolvers, merging is just combining the\n * field maps.\n * @internal\n */\nexport function mergePortableSchemas<A, B>(\n a: MergeablePortableSchema<A> | undefined,\n b: MergeablePortableSchema<B> | undefined,\n): MergeablePortableSchema<A & B> | undefined {\n if (!a && !b) {\n return undefined;\n }\n if (!a) {\n return b as MergeablePortableSchema<A & B>;\n }\n if (!b) {\n return a as MergeablePortableSchema<A & B>;\n }\n\n return buildPortableSchema<A & B>({\n ...a._fields,\n ...b._fields,\n });\n}\n\n/**\n * Assembles resolved fields into a PortableSchema with per-field\n * validation (eager) and lazy JSON Schema generation.\n */\nfunction buildPortableSchema<TOutput = unknown>(\n fields: Record<string, ResolvedField>,\n): MergeablePortableSchema<TOutput> {\n function parse(input: unknown) {\n if (\n input !== undefined &&\n input !== null &&\n (typeof input !== 'object' || Array.isArray(input))\n ) {\n throw new Error(\n `Invalid config input, expected object but got ${\n Array.isArray(input) ? 'array' : typeof input\n }`,\n );\n }\n const inputObj = (input ?? {}) as Record<string, unknown>;\n const result: Record<string, unknown> = {};\n const errors: string[] = [];\n\n for (const [key, field] of Object.entries(fields)) {\n const validated = field.validate(inputObj[key]);\n if ('errors' in validated) {\n errors.push(...validated.errors);\n } else if (validated.value !== undefined || key in inputObj) {\n result[key] = validated.value;\n }\n }\n\n if (errors.length > 0) {\n throw new Error(errors.join('; '));\n }\n\n return result as TOutput;\n }\n\n const result: MergeablePortableSchema<TOutput> = {\n parse,\n schema: undefined as any,\n _fields: fields,\n };\n\n // Lazy getter — computes JSON Schema on first access, then caches it.\n let cached: PortableSchema['schema'] | undefined;\n Object.defineProperty(result, 'schema', {\n get() {\n if (!cached) {\n const jsonSchema = buildObjectJsonSchema(fields);\n const callable = Object.assign(\n () => ({ schema: jsonSchema }),\n jsonSchema,\n );\n cached = callable as PortableSchema['schema'];\n }\n return cached;\n },\n configurable: true,\n enumerable: false,\n });\n\n return result;\n}\n\n/**\n * Wraps a single schema into a ResolvedField. Eagerly validates that\n * JSON Schema conversion will be possible, but defers the actual\n * conversion until toJsonSchema() is called.\n */\nfunction resolveField(key: string, schema: unknown): ResolvedField {\n if (isZodV3Type(schema)) {\n throw new Error(\n `Config schema for field '${key}' uses a Zod v3 schema, which is ` +\n `not supported by the \\`configSchema\\` option. Either use ` +\n `\\`import { z } from 'zod/v4'\\` from the zod v3 package, or ` +\n `upgrade to zod v4.`,\n );\n }\n if (isStandardSchema(schema)) {\n if (!hasJsonSchemaConverter(schema)) {\n throw new Error(\n `Config schema for field '${key}' does not support JSON Schema ` +\n `conversion. Use a schema library that implements the Standard ` +\n `JSON Schema interface (like zod v4+).`,\n );\n }\n return resolveStandardField(key, schema);\n }\n throw new Error(\n `Config schema for field '${key}' is not a valid Standard Schema`,\n );\n}\n\nfunction resolveZodField(key: string, schema: ZodType): ResolvedField {\n const wrapper = zodV3.object({ [key]: schema });\n\n return {\n validate(value) {\n const result = wrapper.safeParse({ [key]: value });\n if (result.success) {\n return { value: result.data[key] };\n }\n return { errors: result.error.issues.map(formatZodIssue) };\n },\n toJsonSchema() {\n const wholeJsonSchema = zodToJsonSchema(wrapper) as Record<string, any>;\n return (wholeJsonSchema.properties?.[key] ?? {}) as JsonObject;\n },\n required: !schema.isOptional(),\n };\n}\n\nfunction resolveStandardField(\n key: string,\n schema: StandardSchemaV1 & {\n '~standard': { jsonSchema: { input: Function } };\n },\n): ResolvedField {\n const required = isFieldRequired(schema);\n\n return {\n validate(value) {\n const result = schema['~standard'].validate(value);\n if (result instanceof Promise) {\n throw new Error(\n `Config schema for '${key}' returned a Promise — async schemas are not supported`,\n );\n }\n if (result.issues) {\n return {\n errors: Array.from(result.issues).map(issue =>\n formatStandardIssue(key, issue),\n ),\n };\n }\n return { value: result.value };\n },\n toJsonSchema() {\n const raw = schema['~standard'].jsonSchema.input({ target: 'draft-07' });\n const { $schema: _, ...rest } = raw;\n return rest as JsonObject;\n },\n required,\n };\n}\n\n/** Assembles per-field JSON Schemas into a single object-level JSON Schema. */\nfunction buildObjectJsonSchema(\n fields: Record<string, ResolvedField>,\n): JsonObject {\n const properties: Record<string, JsonObject> = {};\n const required: string[] = [];\n\n for (const [key, field] of Object.entries(fields)) {\n properties[key] = field.toJsonSchema();\n if (field.required) {\n required.push(key);\n }\n }\n\n const schema: Record<string, unknown> = {\n type: 'object',\n properties,\n additionalProperties: false,\n };\n\n if (required.length > 0) {\n schema.required = required;\n }\n\n return schema as JsonObject;\n}\n\nfunction isZodV3Type(value: unknown): value is ZodType {\n return (\n typeof value === 'object' &&\n value !== null &&\n typeof (value as any)._parse === 'function' &&\n '_def' in value\n );\n}\n\nfunction isStandardSchema(value: unknown): value is StandardSchemaV1 {\n return (\n typeof value === 'object' &&\n value !== null &&\n '~standard' in value &&\n typeof (value as any)['~standard']?.validate === 'function'\n );\n}\n\nfunction hasJsonSchemaConverter(\n schema: StandardSchemaV1,\n): schema is StandardSchemaV1 & {\n '~standard': { jsonSchema: { input: Function } };\n} {\n const std = schema['~standard'] as any;\n return typeof std?.jsonSchema?.input === 'function';\n}\n\nfunction isFieldRequired(schema: StandardSchemaV1): boolean {\n const result = schema['~standard'].validate(undefined);\n if (result instanceof Promise) {\n return true;\n }\n return (result.issues?.length ?? 0) > 0;\n}\n\nfunction formatZodIssue(issue: {\n code: string;\n message: string;\n path: Array<string | number>;\n unionErrors?: Array<{ issues: Array<any> }>;\n}): string {\n if (issue.code === 'invalid_union' && issue.unionErrors?.[0]?.issues?.[0]) {\n return formatZodIssue(issue.unionErrors[0].issues[0]);\n }\n let message = issue.message;\n if (message === 'Required') {\n message = 'Missing required value';\n }\n if (issue.path.length) {\n message += ` at '${issue.path.join('.')}'`;\n }\n return message;\n}\n\nfunction formatStandardIssue(\n fieldKey: string,\n issue: StandardSchemaV1.Issue,\n): string {\n let message = issue.message;\n if (message === 'Required') {\n message = 'Missing required value';\n }\n const path = issue.path?.length\n ? `${fieldKey}.${issue.path\n .map((p: PropertyKey | StandardSchemaV1.PathSegment) =>\n typeof p === 'object' ? p.key : p,\n )\n .join('.')}`\n : fieldKey;\n return `${message} at '${path}'`;\n}\n\n/** @internal */\nexport function warnConfigSchemaPropDeprecation(callSite: string) {\n // eslint-disable-next-line no-console\n console.warn(\n `DEPRECATION WARNING: The \\`config.schema\\` option for extension config is deprecated. ` +\n `Use the \\`configSchema\\` option instead with Standard Schema values, for example ` +\n `\\`configSchema: { title: z.string() }\\` using zod v4 ` +\n `(or \\`import { z } from 'zod/v4'\\` from the zod v3 package). ` +\n `Declared at ${callSite}`,\n );\n}\n"],"names":["zodV3","result"],"mappings":"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"}
1
+ {"version":3,"file":"createPortableSchema.esm.js","sources":["../../src/schema/createPortableSchema.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 { JsonObject } from '@backstage/types';\nimport { z as zodV3, type ZodType } from 'zod/v3';\nimport zodToJsonSchema from 'zod-to-json-schema';\nimport { PortableSchema } from './types';\n\n/**\n * The Standard Schema interface.\n * @public\n */\nexport type { StandardSchemaV1 } from '@standard-schema/spec';\nimport { type StandardSchemaV1 } from '@standard-schema/spec';\n\n/** @internal */\nexport function createDeprecatedConfigSchema(\n fields: Record<string, (zImpl: typeof zodV3) => ZodType>,\n): MergeablePortableSchema {\n const resolved: Record<string, ResolvedField> = {};\n\n for (const [key, field] of Object.entries(fields)) {\n resolved[key] = resolveZodField(key, field(zodV3));\n }\n\n return buildPortableSchema(resolved);\n}\n\n/**\n * Per-field resolved schema — validation is eager, JSON Schema is lazy.\n * @internal\n */\ninterface ResolvedField {\n validate(value: unknown): { value: unknown } | { errors: string[] };\n toJsonSchema(): JsonObject;\n required: boolean;\n}\n\n/**\n * Internal representation that carries per-field resolvers alongside the\n * public PortableSchema surface, enabling schema merging.\n * @internal\n */\nexport interface MergeablePortableSchema<TOutput = any, TInput = any>\n extends PortableSchema<TOutput, TInput> {\n /** @internal */\n readonly _fields: Record<string, ResolvedField>;\n}\n\n/**\n * Resolves each field, eagerly validates JSON Schema support, and returns\n * a PortableSchema whose JSON Schema conversion is lazy.\n * @internal\n */\nexport function createConfigSchema(\n fields: Record<string, StandardSchemaV1>,\n): MergeablePortableSchema {\n const resolved: Record<string, ResolvedField> = {};\n\n for (const [key, field] of Object.entries(fields)) {\n resolved[key] = resolveField(key, field);\n }\n\n return buildPortableSchema(resolved);\n}\n\n/**\n * Combines schemas from different sources for blueprint + override\n * composition. Each source may use a completely different schema library.\n * Because we track per-field resolvers, merging is just combining the\n * field maps.\n * @internal\n */\nexport function mergePortableSchemas<A, B>(\n a: MergeablePortableSchema<A> | undefined,\n b: MergeablePortableSchema<B> | undefined,\n): MergeablePortableSchema<A & B> | undefined {\n if (!a && !b) {\n return undefined;\n }\n if (!a) {\n return b as MergeablePortableSchema<A & B>;\n }\n if (!b) {\n return a as MergeablePortableSchema<A & B>;\n }\n\n return buildPortableSchema<A & B>({\n ...a._fields,\n ...b._fields,\n });\n}\n\n/**\n * Assembles resolved fields into a PortableSchema with per-field\n * validation (eager) and lazy JSON Schema generation.\n */\nfunction buildPortableSchema<TOutput = unknown>(\n fields: Record<string, ResolvedField>,\n): MergeablePortableSchema<TOutput> {\n function parse(input: unknown) {\n if (\n input !== undefined &&\n input !== null &&\n (typeof input !== 'object' || Array.isArray(input))\n ) {\n throw new Error(\n `Invalid config input, expected object but got ${\n Array.isArray(input) ? 'array' : typeof input\n }`,\n );\n }\n const inputObj = (input ?? {}) as Record<string, unknown>;\n const result: Record<string, unknown> = {};\n const errors: string[] = [];\n\n for (const [key, field] of Object.entries(fields)) {\n const validated = field.validate(inputObj[key]);\n if ('errors' in validated) {\n errors.push(...validated.errors);\n } else if (validated.value !== undefined || key in inputObj) {\n result[key] = validated.value;\n }\n }\n\n if (errors.length > 0) {\n throw new Error(errors.join('; '));\n }\n\n return result as TOutput;\n }\n\n const result: MergeablePortableSchema<TOutput> = {\n parse,\n schema: undefined as any,\n _fields: fields,\n };\n\n // Lazy getter — computes JSON Schema on first access, then caches it.\n let cached: PortableSchema['schema'] | undefined;\n Object.defineProperty(result, 'schema', {\n get() {\n if (!cached) {\n const jsonSchema = buildObjectJsonSchema(fields);\n const callable = Object.assign(\n () => ({ schema: jsonSchema }),\n jsonSchema,\n );\n cached = callable as PortableSchema['schema'];\n }\n return cached;\n },\n configurable: true,\n enumerable: false,\n });\n\n return result;\n}\n\n/**\n * Wraps a single schema into a ResolvedField. Eagerly validates that\n * JSON Schema conversion will be possible, but defers the actual\n * conversion until toJsonSchema() is called.\n */\nfunction resolveField(key: string, schema: unknown): ResolvedField {\n if (isZodV3Type(schema)) {\n throw new Error(\n `Config schema for field '${key}' uses a Zod v3 schema, which is ` +\n `not supported by the \\`configSchema\\` option. Upgrade to the ` +\n `\\`zod\\` v4 package (\\`zod@^4.0.0\\`). Note that the \\`zod/v4\\` ` +\n `subpath export from the zod v3 package is also not supported, ` +\n `as it does not include JSON Schema conversion.`,\n );\n }\n if (isStandardSchema(schema)) {\n if (!hasJsonSchemaConverter(schema)) {\n throw new Error(\n `Config schema for field '${key}' does not support JSON Schema ` +\n `conversion. Use a schema library that implements the Standard ` +\n `JSON Schema interface (like zod v4+).`,\n );\n }\n return resolveStandardField(key, schema);\n }\n throw new Error(\n `Config schema for field '${key}' is not a valid Standard Schema`,\n );\n}\n\nfunction resolveZodField(key: string, schema: ZodType): ResolvedField {\n const wrapper = zodV3.object({ [key]: schema });\n\n return {\n validate(value) {\n const result = wrapper.safeParse({ [key]: value });\n if (result.success) {\n return { value: result.data[key] };\n }\n return { errors: result.error.issues.map(formatZodIssue) };\n },\n toJsonSchema() {\n const wholeJsonSchema = zodToJsonSchema(wrapper) as Record<string, any>;\n return (wholeJsonSchema.properties?.[key] ?? {}) as JsonObject;\n },\n required: !schema.isOptional(),\n };\n}\n\nfunction resolveStandardField(\n key: string,\n schema: StandardSchemaV1 & {\n '~standard': { jsonSchema: { input: Function } };\n },\n): ResolvedField {\n const required = isFieldRequired(schema);\n\n return {\n validate(value) {\n const result = schema['~standard'].validate(value);\n if (result instanceof Promise) {\n throw new Error(\n `Config schema for '${key}' returned a Promise — async schemas are not supported`,\n );\n }\n if (result.issues) {\n return {\n errors: Array.from(result.issues).map(issue =>\n formatStandardIssue(key, issue),\n ),\n };\n }\n return { value: result.value };\n },\n toJsonSchema() {\n const raw = schema['~standard'].jsonSchema.input({ target: 'draft-07' });\n const { $schema: _, ...rest } = raw;\n return rest as JsonObject;\n },\n required,\n };\n}\n\n/** Assembles per-field JSON Schemas into a single object-level JSON Schema. */\nfunction buildObjectJsonSchema(\n fields: Record<string, ResolvedField>,\n): JsonObject {\n const properties: Record<string, JsonObject> = {};\n const required: string[] = [];\n\n for (const [key, field] of Object.entries(fields)) {\n properties[key] = field.toJsonSchema();\n if (field.required) {\n required.push(key);\n }\n }\n\n const schema: Record<string, unknown> = {\n type: 'object',\n properties,\n additionalProperties: false,\n };\n\n if (required.length > 0) {\n schema.required = required;\n }\n\n return schema as JsonObject;\n}\n\nfunction isZodV3Type(value: unknown): value is ZodType {\n return (\n typeof value === 'object' &&\n value !== null &&\n typeof (value as any)._parse === 'function' &&\n '_def' in value\n );\n}\n\nfunction isStandardSchema(value: unknown): value is StandardSchemaV1 {\n return (\n typeof value === 'object' &&\n value !== null &&\n '~standard' in value &&\n typeof (value as any)['~standard']?.validate === 'function'\n );\n}\n\nfunction hasJsonSchemaConverter(\n schema: StandardSchemaV1,\n): schema is StandardSchemaV1 & {\n '~standard': { jsonSchema: { input: Function } };\n} {\n const std = schema['~standard'] as any;\n return typeof std?.jsonSchema?.input === 'function';\n}\n\nfunction isFieldRequired(schema: StandardSchemaV1): boolean {\n const result = schema['~standard'].validate(undefined);\n if (result instanceof Promise) {\n return true;\n }\n return (result.issues?.length ?? 0) > 0;\n}\n\nfunction formatZodIssue(issue: {\n code: string;\n message: string;\n path: Array<string | number>;\n unionErrors?: Array<{ issues: Array<any> }>;\n}): string {\n if (issue.code === 'invalid_union' && issue.unionErrors?.[0]?.issues?.[0]) {\n return formatZodIssue(issue.unionErrors[0].issues[0]);\n }\n let message = issue.message;\n if (message === 'Required') {\n message = 'Missing required value';\n }\n if (issue.path.length) {\n message += ` at '${issue.path.join('.')}'`;\n }\n return message;\n}\n\nfunction formatStandardIssue(\n fieldKey: string,\n issue: StandardSchemaV1.Issue,\n): string {\n let message = issue.message;\n if (message === 'Required') {\n message = 'Missing required value';\n }\n const path = issue.path?.length\n ? `${fieldKey}.${issue.path\n .map((p: PropertyKey | StandardSchemaV1.PathSegment) =>\n typeof p === 'object' ? p.key : p,\n )\n .join('.')}`\n : fieldKey;\n return `${message} at '${path}'`;\n}\n\n/** @internal */\nexport function warnConfigSchemaPropDeprecation(callSite: string) {\n // eslint-disable-next-line no-console\n console.warn(\n `DEPRECATION WARNING: The \\`config.schema\\` option for extension config is deprecated. ` +\n `Use the \\`configSchema\\` option instead with Standard Schema values, for example ` +\n `\\`configSchema: { title: z.string() }\\` using the \\`zod\\` v4 package ` +\n `(\\`zod@^4.0.0\\`). Declared at ${callSite}`,\n );\n}\n"],"names":["zodV3","result"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/frontend-plugin-api",
3
- "version": "0.16.0",
3
+ "version": "0.16.2",
4
4
  "backstage": {
5
5
  "role": "web-library"
6
6
  },
@@ -57,7 +57,7 @@
57
57
  "@backstage/types": "^1.2.2",
58
58
  "@backstage/version-bridge": "^1.0.12",
59
59
  "@standard-schema/spec": "^1.1.0",
60
- "zod": "^3.25.76 || ^4.0.0",
60
+ "zod": "^4.0.0",
61
61
  "zod-to-json-schema": "^3.25.1"
62
62
  },
63
63
  "devDependencies": {