diff --git a/.changeset/bitter-pants-watch.md b/.changeset/bitter-pants-watch.md deleted file mode 100644 index 3accf45826..0000000000 --- a/.changeset/bitter-pants-watch.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/canon': minor ---- - -We are updating the default size of the Button component in Canon to be small instead of medium. diff --git a/.changeset/brave-facts-pay.md b/.changeset/brave-facts-pay.md deleted file mode 100644 index 1f8e9663bf..0000000000 --- a/.changeset/brave-facts-pay.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend-module-confluence-to-markdown': patch ---- - -Migrate actions to new format diff --git a/.changeset/chatty-clowns-dream.md b/.changeset/chatty-clowns-dream.md deleted file mode 100644 index d601f7a40d..0000000000 --- a/.changeset/chatty-clowns-dream.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core-components': patch ---- - -table actions header support i18n diff --git a/.changeset/cold-meals-like.md b/.changeset/cold-meals-like.md deleted file mode 100644 index 7feb978337..0000000000 --- a/.changeset/cold-meals-like.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/catalog-client': patch ---- - -Fixed `CatalogClient` error responses for `refreshEntity` and `addLocation`. diff --git a/.changeset/create-app-1748956288.md b/.changeset/create-app-1748956288.md deleted file mode 100644 index b50d431d4b..0000000000 --- a/.changeset/create-app-1748956288.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/create-app': patch ---- - -Bumped create-app version. diff --git a/.changeset/cuddly-camels-lose.md b/.changeset/cuddly-camels-lose.md deleted file mode 100644 index 23162bfdc5..0000000000 --- a/.changeset/cuddly-camels-lose.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend-module-gitlab': patch ---- - -Migrate to new action format diff --git a/.changeset/curvy-peaches-relate.md b/.changeset/curvy-peaches-relate.md deleted file mode 100644 index 9fafc77abb..0000000000 --- a/.changeset/curvy-peaches-relate.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend-module-azure': patch ---- - -Migrating `azure` actions to using the new `zod` schema format diff --git a/.changeset/deep-moments-love.md b/.changeset/deep-moments-love.md deleted file mode 100644 index 89b3174275..0000000000 --- a/.changeset/deep-moments-love.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/canon': patch ---- - -Add min-width: 0; by default on every Flex components in Canon to help support truncated texts inside flex elements. diff --git a/.changeset/dull-buttons-press.md b/.changeset/dull-buttons-press.md deleted file mode 100644 index 1c8f8fc13c..0000000000 --- a/.changeset/dull-buttons-press.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend-module-bitbucket-cloud': patch ---- - -Migrate `bitbucket-cloud` to new actions format diff --git a/.changeset/dull-cars-shout.md b/.changeset/dull-cars-shout.md deleted file mode 100644 index be213a167c..0000000000 --- a/.changeset/dull-cars-shout.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend-module-github': patch ---- - -Migrate to using new actions diff --git a/.changeset/eight-pigs-post.md b/.changeset/eight-pigs-post.md deleted file mode 100644 index 8e50cc7707..0000000000 --- a/.changeset/eight-pigs-post.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/canon': minor ---- - -We set the default size for IconButton in Canon to be small instead of medium. diff --git a/.changeset/eight-planets-see.md b/.changeset/eight-planets-see.md deleted file mode 100644 index 20adcac7ef..0000000000 --- a/.changeset/eight-planets-see.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder': patch ---- - -render details for composite property schemas diff --git a/.changeset/eighty-showers-hide.md b/.changeset/eighty-showers-hide.md deleted file mode 100644 index 0871fea4bb..0000000000 --- a/.changeset/eighty-showers-hide.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -'@backstage/plugin-scaffolder-node-test-utils': minor ---- - -**BREAKING CHANGES** - -Because of the removal of the `logStream` property to the `ActionsContext` this has been removed from the `createMockActionContext` method. - -You can remove this as it's no longer supported in the scaffolder actions. diff --git a/.changeset/evil-cooks-watch.md b/.changeset/evil-cooks-watch.md deleted file mode 100644 index 0982f24634..0000000000 --- a/.changeset/evil-cooks-watch.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -'@backstage/plugin-catalog-unprocessed-entities': patch -'@backstage/plugin-app-visualizer': patch -'@backstage/plugin-catalog-import': patch -'@backstage/plugin-catalog-graph': patch -'@backstage/plugin-notifications': patch -'@backstage/plugin-user-settings': patch -'@backstage/plugin-kubernetes': patch -'@backstage/plugin-scaffolder': patch -'@backstage/plugin-api-docs': patch -'@backstage/plugin-devtools': patch -'@backstage/plugin-techdocs': patch -'@backstage/plugin-catalog': patch -'@backstage/plugin-signals': patch -'@backstage/plugin-search': patch -'@backstage/plugin-home': patch -'@backstage/plugin-app': patch -'@backstage/plugin-org': patch ---- - -Added the `info.packageJson` option to the plugin instance for the new frontend system. diff --git a/.changeset/fair-doors-bathe.md b/.changeset/fair-doors-bathe.md deleted file mode 100644 index bbb5f238ee..0000000000 --- a/.changeset/fair-doors-bathe.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/repo-tools': patch ---- - -Fixed a bug where linting would fail with the generated clients when defining top-level `enum` schema values. diff --git a/.changeset/famous-streets-stay.md b/.changeset/famous-streets-stay.md deleted file mode 100644 index d517b889c5..0000000000 --- a/.changeset/famous-streets-stay.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-node': patch ---- - -Use `LoggerService` instead of `Logger`. This is a non-breaking change, as the `LoggerService` is a subset of the `Logger` interface. diff --git a/.changeset/few-streets-accept.md b/.changeset/few-streets-accept.md deleted file mode 100644 index 4b82cc03e4..0000000000 --- a/.changeset/few-streets-accept.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend-module-bitbucket-server': patch ---- - -Migrate the actions to the new format diff --git a/.changeset/fix-cli-config-docs-feedback.md b/.changeset/fix-cli-config-docs-feedback.md deleted file mode 100644 index 1e7298bafa..0000000000 --- a/.changeset/fix-cli-config-docs-feedback.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Added user feedback when opening config docs in browser. The command now clearly indicates what it's doing and provides fallback instructions if the browser fails to open. diff --git a/.changeset/forty-seas-worry.md b/.changeset/forty-seas-worry.md deleted file mode 100644 index a88c15df53..0000000000 --- a/.changeset/forty-seas-worry.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/canon': patch ---- - -Fix styling for the title4 prop on the Heading component in Canon. diff --git a/.changeset/fresh-brooms-follow.md b/.changeset/fresh-brooms-follow.md deleted file mode 100644 index f2858779bf..0000000000 --- a/.changeset/fresh-brooms-follow.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -The `BACKSTAGE_CLI_EXPERIMENTAL_BUILD_CACHE` flag has been removed. Existing users are encouraged to switch to `EXPERIMENTAL_RSPACK` instead. diff --git a/.changeset/fresh-otters-say.md b/.changeset/fresh-otters-say.md deleted file mode 100644 index ed91c9fb8d..0000000000 --- a/.changeset/fresh-otters-say.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend': patch ---- - -Migrating to latest action format diff --git a/.changeset/good-paths-act.md b/.changeset/good-paths-act.md deleted file mode 100644 index dc33b43766..0000000000 --- a/.changeset/good-paths-act.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/repo-tools': patch ---- - -Fix an issue where errors were not printed to console when running `backstage-repo-tools schema openapi generate` without the `--watch` flag. diff --git a/.changeset/green-schools-live.md b/.changeset/green-schools-live.md deleted file mode 100644 index 9863021a28..0000000000 --- a/.changeset/green-schools-live.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend-module-yeoman': patch ---- - -Migrate to new actions format diff --git a/.changeset/grumpy-dryers-act.md b/.changeset/grumpy-dryers-act.md deleted file mode 100644 index caaeac5fa8..0000000000 --- a/.changeset/grumpy-dryers-act.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/repo-tools': patch ---- - -Add missing highlight language for the `package-docs` command. diff --git a/.changeset/honest-moles-bet.md b/.changeset/honest-moles-bet.md deleted file mode 100644 index 22e0cb4533..0000000000 --- a/.changeset/honest-moles-bet.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend-module-bitbucket-server': patch -'@backstage/plugin-scaffolder-backend-module-bitbucket-cloud': patch -'@backstage/plugin-scaffolder-node': patch ---- - -Update pull request creation filter to include .gitignore files in the created pull request diff --git a/.changeset/itchy-mirrors-juggle.md b/.changeset/itchy-mirrors-juggle.md deleted file mode 100644 index 6fd7c7543a..0000000000 --- a/.changeset/itchy-mirrors-juggle.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-notifications': patch -'@backstage/plugin-scaffolder': patch ---- - -Remove React import form notification and scaffolder plugin diff --git a/.changeset/khaki-horses-chew.md b/.changeset/khaki-horses-chew.md deleted file mode 100644 index b9f5dfda5e..0000000000 --- a/.changeset/khaki-horses-chew.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-techdocs-module-addons-contrib': patch -'@backstage/plugin-techdocs': patch ---- - -Improved Keyboard accessibility in techdocs. diff --git a/.changeset/khaki-swans-invite.md b/.changeset/khaki-swans-invite.md deleted file mode 100644 index 4e768a1978..0000000000 --- a/.changeset/khaki-swans-invite.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-notifications-backend-module-email': patch -'@backstage/plugin-notifications-backend': patch ---- - -Internal changes to switch to the non-alpha `catalogServiceRef` diff --git a/.changeset/kind-houses-feel.md b/.changeset/kind-houses-feel.md deleted file mode 100644 index a4b3ac0d14..0000000000 --- a/.changeset/kind-houses-feel.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/canon': patch ---- - -Added a render prop to the Button component in Canon to use it as a link. diff --git a/.changeset/large-baboons-prove.md b/.changeset/large-baboons-prove.md deleted file mode 100644 index 072d57de4c..0000000000 --- a/.changeset/large-baboons-prove.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -'@backstage/plugin-catalog': minor ---- - -Add support to customize the about card icon links via `EntityIconLinkBlueprint` and provide a default catalog view catalog source, launch scaffolder template and read techdocs docs icon links extensions. - -**BREAKING ALPHA** - -The `Scaffolder` launch template and `TechDocs` read documentation icons have been extracted from the default `Catalog` about card links and are now provided respectively by the `Scaffolder` and `TechDocs` plugins in the new frontend system. It means that they will not be available unless you install the `TechDocs` and `Scaffolder` plugins. Also If you are using translation for these icon link titles other than the default, you should now translate them using the scaffolder translation reference or the TechDocs translation reference (the translation keys are still the same, `aboutCard.viewTechdocs` and `aboutCard.launchTemplate`). diff --git a/.changeset/late-buttons-strive.md b/.changeset/late-buttons-strive.md deleted file mode 100644 index 23e1045ba0..0000000000 --- a/.changeset/late-buttons-strive.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-org': patch ---- - -Org plugin support i18n diff --git a/.changeset/lazy-rice-dream.md b/.changeset/lazy-rice-dream.md deleted file mode 100644 index fe91f85b2e..0000000000 --- a/.changeset/lazy-rice-dream.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend-module-gerrit': patch ---- - -Migrating to use new format for actions diff --git a/.changeset/long-suits-obey.md b/.changeset/long-suits-obey.md deleted file mode 100644 index 996bba6026..0000000000 --- a/.changeset/long-suits-obey.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-user-settings': patch ---- - -Add some translation to user-setting plugin diff --git a/.changeset/loose-ants-learn.md b/.changeset/loose-ants-learn.md deleted file mode 100644 index 29f357966c..0000000000 --- a/.changeset/loose-ants-learn.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-techdocs': minor ---- - -**New Frontend System Only:** -The `TechDocs` plugin is now responsible for providing an entity icon link extension to read documentation from the catalog entity page. diff --git a/.changeset/major-heads-scream.md b/.changeset/major-heads-scream.md deleted file mode 100644 index 24caa6e4bb..0000000000 --- a/.changeset/major-heads-scream.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-gitlab': minor ---- - -**BREAKING CHANGE**: User and Group discovery will default to ingesting all users in sub groups that belong to the specified root group in config. Disable by setting `restrictUsersToGroup: true` in app-config under your module settings. diff --git a/.changeset/mean-tigers-rush.md b/.changeset/mean-tigers-rush.md deleted file mode 100644 index e15b01cedc..0000000000 --- a/.changeset/mean-tigers-rush.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Switched to using the `ModuleFederationPlugin` from `@module-federation/enhanced/rspack` for Rspack, rather than the built-in one. diff --git a/.changeset/mighty-windows-boil.md b/.changeset/mighty-windows-boil.md deleted file mode 100644 index 52eb024db1..0000000000 --- a/.changeset/mighty-windows-boil.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend-module-sentry': patch ---- - -Migrate to new actions format diff --git a/.changeset/mira-flygande-spoons.md b/.changeset/mira-flygande-spoons.md deleted file mode 100644 index c4c50f117a..0000000000 --- a/.changeset/mira-flygande-spoons.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend': patch ---- - -You can now specify an optional value when applying the `HAS_LABEL` permission rule, similar to the `HAS_ANNOTATION` permission rule. diff --git a/.changeset/new-beers-sell.md b/.changeset/new-beers-sell.md deleted file mode 100644 index fd7407007d..0000000000 --- a/.changeset/new-beers-sell.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend-module-notifications': patch -'@backstage/plugin-notifications-backend': patch -'@backstage/plugin-notifications-common': patch -'@backstage/plugin-notifications': patch ---- - -Adds ability for user to turn on/off notifications for specific topics within an origin. diff --git a/.changeset/olive-buses-serve.md b/.changeset/olive-buses-serve.md deleted file mode 100644 index d4e1798360..0000000000 --- a/.changeset/olive-buses-serve.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-search-backend-module-techdocs': patch ---- - -Exports the default document collator for use in document transformation during search indexing. diff --git a/.changeset/open-bottles-attack.md b/.changeset/open-bottles-attack.md deleted file mode 100644 index e57607b55c..0000000000 --- a/.changeset/open-bottles-attack.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend-module-notifications': patch ---- - -Removed `octokit` dependency as it was not being used diff --git a/.changeset/open-eyes-learn.md b/.changeset/open-eyes-learn.md deleted file mode 100644 index 3a0299aafb..0000000000 --- a/.changeset/open-eyes-learn.md +++ /dev/null @@ -1,49 +0,0 @@ ---- -'@backstage/plugin-catalog-react': minor ---- - -Introduces a new `EntityIconLinkBlueprint` that customizes the `About` card icon links on the `Catalog` entity page. - -The blueprint currently accepts a `useProps` hook as `param` and this function returns the following props that will be passed to the icon link component: - -| Name | Description | Type | Default Value | -| ---------- | --------------------------------------------------- | ------------- | ------------- | -| `icon` | The icon to display. | `JSX.Element` | N/A | -| `label` | The label for the element. | `string` | N/A | -| `title` | The title for the element. | `string` | N/A | -| `disabled` | Whether the element is disabled. | `boolean` | `false` | -| `href` | The URL to navigate to when the element is clicked. | `string` | N/A | -| `onClick` | A function to call when the element is clicked. | `() => void` | N/A | - -Here is an usage example: - -```tsx -import { EntityIconLinkBlueprint } from '@backstage/plugin-catalog-react/alpha'; -//... - -EntityIconLinkBlueprint.make({ - name: 'my-icon-link', - params: { - useProps() { - const { t } = useTranslationRef(myIconLinkTranslationRef); - return { - label: t('myIconLink.label'), - icon: , - href: '/my-plugin', - }; - }, - }, -}); -``` - -Additionally, the `app-config.yaml` file allows you to override some of the default icon link parameters, including `label` and `title` values. Here's how to set them: - -```yaml -app: - extensions: - - entity-icon-link:my-plugin/my-icon-link: - config: - label: 'My Custom Icon Link label' -``` - -Finally, you can disable all links if you want to hide the About card header completely (useful, for example, when links are displayed on separate cards). The header is hidden when no icon links extensions are enabled. diff --git a/.changeset/orange-masks-decide.md b/.changeset/orange-masks-decide.md deleted file mode 100644 index 0ddb7a7e48..0000000000 --- a/.changeset/orange-masks-decide.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend-module-rails': patch ---- - -Migrate to new actions format diff --git a/.changeset/petite-candies-tan.md b/.changeset/petite-candies-tan.md deleted file mode 100644 index 6ec5c9c813..0000000000 --- a/.changeset/petite-candies-tan.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -'@backstage/frontend-plugin-api': patch ---- - -Added a new optional `info` option to `createFrontendPlugin` that lets you provide a loaders for different sources of metadata information about the plugin. - -There are two available loaders. The first one is `info.packageJson`, which can be used to point to a `package.json` file for the plugin. This is recommended for any plugin that is defined within its own package, especially all plugins that are published to a package registry. Typical usage looks like this: - -```ts -export default createFrontendPlugin({ - pluginId: '...', - info: { - packageJson: () => import('../package.json'), - }, -}); -``` - -The second loader is `info.manifest`, which can be used to point to an opaque plugin manifest. This **MUST ONLY** be used by plugins that are intended for use within a single organization. Plugins that are published to an open package registry should **NOT** use this loader. The loader is useful for adding additional internal metadata associated with the plugin, and it is up to the Backstage app to decide how these manifests are parsed and used. The default manifest parser in an app created with `createApp` from `@backstage/frontend-defaults` is able to parse the default `catalog-info.yaml` format and built-in fields such as `spec.owner`. - -Typical usage looks like this: - -```ts -export default createFrontendPlugin({ - pluginId: '...', - info: { - manifest: () => import('../catalog-info.yaml'), - }, -}); -``` diff --git a/.changeset/pre.json b/.changeset/pre.json deleted file mode 100644 index 2f88c82873..0000000000 --- a/.changeset/pre.json +++ /dev/null @@ -1,255 +0,0 @@ -{ - "mode": "pre", - "tag": "next", - "initialVersions": { - "example-app": "0.2.109", - "@backstage/app-defaults": "1.6.2", - "example-app-next": "0.0.23", - "app-next-example-plugin": "0.0.23", - "example-backend": "0.0.38", - "@backstage/backend-app-api": "1.2.3", - "@backstage/backend-defaults": "0.10.0", - "@backstage/backend-dev-utils": "0.1.5", - "@backstage/backend-dynamic-feature-service": "0.7.0", - "@backstage/backend-openapi-utils": "0.5.3", - "@backstage/backend-plugin-api": "1.3.1", - "@backstage/backend-test-utils": "1.5.0", - "@backstage/canon": "0.4.0", - "@backstage/catalog-client": "1.10.0", - "@backstage/catalog-model": "1.7.4", - "@backstage/cli": "0.32.1", - "@backstage/cli-common": "0.1.15", - "@backstage/cli-node": "0.2.13", - "@backstage/codemods": "0.1.52", - "@backstage/config": "1.3.2", - "@backstage/config-loader": "1.10.1", - "@backstage/core-app-api": "1.17.0", - "@backstage/core-compat-api": "0.4.2", - "@backstage/core-components": "0.17.2", - "@backstage/core-plugin-api": "1.10.7", - "@backstage/create-app": "0.6.2", - "@backstage/dev-utils": "1.1.10", - "e2e-test": "0.2.28", - "@backstage/e2e-test-utils": "0.1.1", - "@backstage/errors": "1.2.7", - "@backstage/eslint-plugin": "0.1.10", - "@backstage/frontend-app-api": "0.11.2", - "@backstage/frontend-defaults": "0.2.2", - "@backstage/frontend-dynamic-feature-loader": "0.1.1", - "@internal/frontend": "0.0.9", - "@backstage/frontend-plugin-api": "0.10.2", - "@backstage/frontend-test-utils": "0.3.2", - "@backstage/integration": "1.17.0", - "@backstage/integration-aws-node": "0.1.16", - "@backstage/integration-react": "1.2.7", - "@internal/opaque": "0.0.1", - "@backstage/release-manifests": "0.0.13", - "@backstage/repo-tools": "0.13.3", - "@internal/scaffolder": "0.0.9", - "@techdocs/cli": "1.9.3", - "techdocs-cli-embedded-app": "0.2.108", - "@backstage/test-utils": "1.7.8", - "@backstage/theme": "0.6.6", - "@backstage/types": "1.2.1", - "@backstage/version-bridge": "1.0.11", - "yarn-plugin-backstage": "0.0.5", - "@backstage/plugin-api-docs": "0.12.7", - "@backstage/plugin-api-docs-module-protoc-gen-doc": "0.1.10", - "@backstage/plugin-app": "0.1.9", - "@backstage/plugin-app-backend": "0.5.2", - "@backstage/plugin-app-node": "0.1.33", - "@backstage/plugin-app-visualizer": "0.1.19", - "@backstage/plugin-auth-backend": "0.25.0", - "@backstage/plugin-auth-backend-module-atlassian-provider": "0.4.3", - "@backstage/plugin-auth-backend-module-auth0-provider": "0.2.3", - "@backstage/plugin-auth-backend-module-aws-alb-provider": "0.4.3", - "@backstage/plugin-auth-backend-module-azure-easyauth-provider": "0.2.8", - "@backstage/plugin-auth-backend-module-bitbucket-provider": "0.3.3", - "@backstage/plugin-auth-backend-module-bitbucket-server-provider": "0.2.3", - "@backstage/plugin-auth-backend-module-cloudflare-access-provider": "0.4.3", - "@backstage/plugin-auth-backend-module-gcp-iap-provider": "0.4.3", - "@backstage/plugin-auth-backend-module-github-provider": "0.3.3", - "@backstage/plugin-auth-backend-module-gitlab-provider": "0.3.3", - "@backstage/plugin-auth-backend-module-google-provider": "0.3.3", - "@backstage/plugin-auth-backend-module-guest-provider": "0.2.8", - "@backstage/plugin-auth-backend-module-microsoft-provider": "0.3.3", - "@backstage/plugin-auth-backend-module-oauth2-provider": "0.4.3", - "@backstage/plugin-auth-backend-module-oauth2-proxy-provider": "0.2.8", - "@backstage/plugin-auth-backend-module-oidc-provider": "0.4.3", - "@backstage/plugin-auth-backend-module-okta-provider": "0.2.3", - "@backstage/plugin-auth-backend-module-onelogin-provider": "0.3.3", - "@backstage/plugin-auth-backend-module-pinniped-provider": "0.3.3", - "@backstage/plugin-auth-backend-module-vmware-cloud-provider": "0.5.3", - "@backstage/plugin-auth-node": "0.6.3", - "@backstage/plugin-auth-react": "0.1.15", - "@backstage/plugin-bitbucket-cloud-common": "0.3.0", - "@backstage/plugin-catalog": "1.30.0", - "@backstage/plugin-catalog-backend": "2.0.0", - "@backstage/plugin-catalog-backend-module-aws": "0.4.11", - "@backstage/plugin-catalog-backend-module-azure": "0.3.5", - "@backstage/plugin-catalog-backend-module-backstage-openapi": "0.5.2", - "@backstage/plugin-catalog-backend-module-bitbucket-cloud": "0.4.8", - "@backstage/plugin-catalog-backend-module-bitbucket-server": "0.4.1", - "@backstage/plugin-catalog-backend-module-gcp": "0.3.8", - "@backstage/plugin-catalog-backend-module-gerrit": "0.3.2", - "@backstage/plugin-catalog-backend-module-gitea": "0.1.0", - "@backstage/plugin-catalog-backend-module-github": "0.9.0", - "@backstage/plugin-catalog-backend-module-github-org": "0.3.10", - "@backstage/plugin-catalog-backend-module-gitlab": "0.6.6", - "@backstage/plugin-catalog-backend-module-gitlab-org": "0.2.9", - "@backstage/plugin-catalog-backend-module-incremental-ingestion": "0.7.0", - "@backstage/plugin-catalog-backend-module-ldap": "0.11.5", - "@backstage/plugin-catalog-backend-module-logs": "0.1.10", - "@backstage/plugin-catalog-backend-module-msgraph": "0.7.0", - "@backstage/plugin-catalog-backend-module-openapi": "0.2.10", - "@backstage/plugin-catalog-backend-module-puppetdb": "0.2.10", - "@backstage/plugin-catalog-backend-module-scaffolder-entity-model": "0.2.8", - "@backstage/plugin-catalog-backend-module-unprocessed": "0.6.0", - "@backstage/plugin-catalog-common": "1.1.4", - "@backstage/plugin-catalog-graph": "0.4.19", - "@backstage/plugin-catalog-import": "0.13.0", - "@backstage/plugin-catalog-node": "1.17.0", - "@backstage/plugin-catalog-react": "1.18.0", - "@backstage/plugin-catalog-unprocessed-entities": "0.2.17", - "@backstage/plugin-catalog-unprocessed-entities-common": "0.0.8", - "@backstage/plugin-config-schema": "0.1.68", - "@backstage/plugin-devtools": "0.1.27", - "@backstage/plugin-devtools-backend": "0.5.5", - "@backstage/plugin-devtools-common": "0.1.16", - "@backstage/plugin-events-backend": "0.5.2", - "@backstage/plugin-events-backend-module-aws-sqs": "0.4.11", - "@backstage/plugin-events-backend-module-azure": "0.2.20", - "@backstage/plugin-events-backend-module-bitbucket-cloud": "0.2.20", - "@backstage/plugin-events-backend-module-bitbucket-server": "0.1.1", - "@backstage/plugin-events-backend-module-gerrit": "0.2.20", - "@backstage/plugin-events-backend-module-github": "0.4.0", - "@backstage/plugin-events-backend-module-gitlab": "0.3.1", - "@backstage/plugin-events-backend-module-google-pubsub": "0.1.0", - "@backstage/plugin-events-backend-test-utils": "0.1.44", - "@backstage/plugin-events-node": "0.4.11", - "@internal/plugin-todo-list": "1.0.39", - "@internal/plugin-todo-list-backend": "1.0.39", - "@internal/plugin-todo-list-common": "1.0.25", - "@backstage/plugin-gateway-backend": "1.0.1", - "@backstage/plugin-home": "0.8.8", - "@backstage/plugin-home-react": "0.1.26", - "@backstage/plugin-kubernetes": "0.12.7", - "@backstage/plugin-kubernetes-backend": "0.19.6", - "@backstage/plugin-kubernetes-cluster": "0.0.25", - "@backstage/plugin-kubernetes-common": "0.9.5", - "@backstage/plugin-kubernetes-node": "0.3.0", - "@backstage/plugin-kubernetes-react": "0.5.7", - "@backstage/plugin-notifications": "0.5.5", - "@backstage/plugin-notifications-backend": "0.5.6", - "@backstage/plugin-notifications-backend-module-email": "0.3.9", - "@backstage/plugin-notifications-backend-module-slack": "0.1.1", - "@backstage/plugin-notifications-common": "0.0.8", - "@backstage/plugin-notifications-node": "0.2.15", - "@backstage/plugin-org": "0.6.39", - "@backstage/plugin-org-react": "0.1.38", - "@backstage/plugin-permission-backend": "0.7.0", - "@backstage/plugin-permission-backend-module-allow-all-policy": "0.2.8", - "@backstage/plugin-permission-common": "0.9.0", - "@backstage/plugin-permission-node": "0.10.0", - "@backstage/plugin-permission-react": "0.4.34", - "@backstage/plugin-proxy-backend": "0.6.2", - "@backstage/plugin-proxy-node": "0.1.4", - "@backstage/plugin-scaffolder": "1.31.0", - "@backstage/plugin-scaffolder-backend": "1.33.0", - "@backstage/plugin-scaffolder-backend-module-azure": "0.2.9", - "@backstage/plugin-scaffolder-backend-module-bitbucket": "0.3.10", - "@backstage/plugin-scaffolder-backend-module-bitbucket-cloud": "0.2.9", - "@backstage/plugin-scaffolder-backend-module-bitbucket-server": "0.2.9", - "@backstage/plugin-scaffolder-backend-module-confluence-to-markdown": "0.3.9", - "@backstage/plugin-scaffolder-backend-module-cookiecutter": "0.3.10", - "@backstage/plugin-scaffolder-backend-module-gcp": "0.2.9", - "@backstage/plugin-scaffolder-backend-module-gerrit": "0.2.9", - "@backstage/plugin-scaffolder-backend-module-gitea": "0.2.9", - "@backstage/plugin-scaffolder-backend-module-github": "0.7.1", - "@backstage/plugin-scaffolder-backend-module-gitlab": "0.9.1", - "@backstage/plugin-scaffolder-backend-module-notifications": "0.1.10", - "@backstage/plugin-scaffolder-backend-module-rails": "0.5.9", - "@backstage/plugin-scaffolder-backend-module-sentry": "0.2.9", - "@backstage/plugin-scaffolder-backend-module-yeoman": "0.4.10", - "@backstage/plugin-scaffolder-common": "1.5.11", - "@backstage/plugin-scaffolder-node": "0.8.2", - "@backstage/plugin-scaffolder-node-test-utils": "0.2.2", - "@backstage/plugin-scaffolder-react": "1.16.0", - "@backstage/plugin-search": "1.4.26", - "@backstage/plugin-search-backend": "2.0.2", - "@backstage/plugin-search-backend-module-catalog": "0.3.4", - "@backstage/plugin-search-backend-module-elasticsearch": "1.7.2", - "@backstage/plugin-search-backend-module-explore": "0.3.2", - "@backstage/plugin-search-backend-module-pg": "0.5.44", - "@backstage/plugin-search-backend-module-stack-overflow-collator": "0.3.9", - "@backstage/plugin-search-backend-module-techdocs": "0.4.2", - "@backstage/plugin-search-backend-node": "1.3.11", - "@backstage/plugin-search-common": "1.2.18", - "@backstage/plugin-search-react": "1.9.0", - "@backstage/plugin-signals": "0.0.19", - "@backstage/plugin-signals-backend": "0.3.4", - "@backstage/plugin-signals-node": "0.1.20", - "@backstage/plugin-signals-react": "0.0.13", - "@backstage/plugin-techdocs": "1.12.6", - "@backstage/plugin-techdocs-addons-test-utils": "1.0.48", - "@backstage/plugin-techdocs-backend": "2.0.2", - "@backstage/plugin-techdocs-common": "0.1.0", - "@backstage/plugin-techdocs-module-addons-contrib": "1.1.24", - "@backstage/plugin-techdocs-node": "1.13.3", - "@backstage/plugin-techdocs-react": "1.2.17", - "@backstage/plugin-user-settings": "0.8.22", - "@backstage/plugin-user-settings-backend": "0.3.2", - "@backstage/plugin-user-settings-common": "0.0.1" - }, - "changesets": [ - "bitter-pants-watch", - "brave-facts-pay", - "cold-meals-like", - "create-app-1748956288", - "curvy-peaches-relate", - "dull-buttons-press", - "eight-pigs-post", - "eight-planets-see", - "evil-cooks-watch", - "famous-streets-stay", - "few-streets-accept", - "fresh-brooms-follow", - "good-paths-act", - "grumpy-dryers-act", - "honest-moles-bet", - "khaki-horses-chew", - "late-buttons-strive", - "lazy-rice-dream", - "long-suits-obey", - "mean-tigers-rush", - "new-beers-sell", - "olive-buses-serve", - "petite-candies-tan", - "puny-pillows-wave", - "red-vans-march", - "ripe-squids-sink", - "salty-worlds-float", - "scaffolder-breakages-1", - "scaffolder-breakages-2", - "scaffolder-breakages-3", - "scaffolder-deprecations-1", - "seven-beans-appear", - "shiny-bags-bet", - "six-mangos-yell", - "slow-impalas-wear", - "small-dots-march", - "smooth-eels-think", - "spotty-cases-show", - "stupid-flies-speak", - "stupid-pens-serve", - "sweet-ducks-wait", - "sweet-squids-dig", - "three-boats-sort", - "tough-heads-knock", - "true-tools-play", - "warm-taxes-show", - "wet-bars-report", - "wet-bars-reporting", - "yummy-donuts-peel" - ] -} diff --git a/.changeset/puny-pillows-wave.md b/.changeset/puny-pillows-wave.md deleted file mode 100644 index 813e603007..0000000000 --- a/.changeset/puny-pillows-wave.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/frontend-plugin-api': patch ---- - -Added a new `useAppNode` hook, which can be used to get a reference to the `AppNode` from by the closest `ExtensionBoundary`. diff --git a/.changeset/purple-times-deny.md b/.changeset/purple-times-deny.md deleted file mode 100644 index 7cf4d2c3c3..0000000000 --- a/.changeset/purple-times-deny.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder': patch ---- - -Added appropriate message when global templating function metadata is absent. diff --git a/.changeset/rare-rules-move.md b/.changeset/rare-rules-move.md deleted file mode 100644 index 6abc778941..0000000000 --- a/.changeset/rare-rules-move.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-scaffolder': minor ---- - -**New Frontend System Only:** -The `Scaffolder` plugin is now responsible for providing an entity icon link extension to launch templates from the catalog entity page. diff --git a/.changeset/red-vans-march.md b/.changeset/red-vans-march.md deleted file mode 100644 index a168e89884..0000000000 --- a/.changeset/red-vans-march.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend-module-gitea': patch ---- - -Migrate to new actions format diff --git a/.changeset/ripe-squids-sink.md b/.changeset/ripe-squids-sink.md deleted file mode 100644 index 27d5d043b6..0000000000 --- a/.changeset/ripe-squids-sink.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -The experimental `FORCE_REACT_DEVELOPMENT` flag has been removed. diff --git a/.changeset/salty-worlds-float.md b/.changeset/salty-worlds-float.md deleted file mode 100644 index a21d0b2e7c..0000000000 --- a/.changeset/salty-worlds-float.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/create-app': minor ---- - -Add .cache directory to shipped gitignore. diff --git a/.changeset/scaffolder-breakages-1.md b/.changeset/scaffolder-breakages-1.md deleted file mode 100644 index 53a7ba9d6a..0000000000 --- a/.changeset/scaffolder-breakages-1.md +++ /dev/null @@ -1,27 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend': major ---- - -**BREAKING CHANGES** - -Removal of deprecated re-exports from module packages. - -The following functions have been re-exported from the `scaffolder-backend` plugin for quite some time, and now it's time to clean them up. They've been moved as follows: - -- `createPublishAzureAction` should be imported from `@backstage/plugin-scaffolder-backend-module-azure` instead. - -- `createPublishBitbucketCloudAction` should be imported from `@backstage/plugin-scaffolder-backend-module-bitbucket-cloud` instead. - -- `createPublishBitbucketServerAction` and `createPublishBitbucketServerPullRequestAction` can be imported from `@backstage/plugin-scaffolder-backend-module-bitbucket-server` instead. - -- `createPublishBitbucketAction` should be imported from `@backstage/plugin-scaffolder-backend-module-bitbucket` instead. - -- `createPublishGerritAction` and `createPublishGerritReviewAction` can be imported from `@backstage/plugin-scaffolder-backend-module-gerrit` instead. - -- `createGithubActionsDispatchAction`, `createGithubDeployKeyAction`, `createGithubEnvironmentAction`, `createGithubIssuesLabelAction`, `CreateGithubPullRequestActionOptions`, `createGithubRepoCreateAction`, `createGithubRepoPushAction`, `createGithubWebhookAction`, and `createPublishGithubAction` can be imported from `@backstage/plugin-scaffolder-backend-module-github` instead. - -- `createPublishGitlabAction` should be imported from `@backstage/plugin-scaffolder-backend-module-gitlab` instead. - -- `ActionContext`. `createTemplateAction`, `executeShellCommand`, `ExecuteShellCommandOptions`, `fetchContents`, `TaskSecrets`, and `TemplateAction` should be imported from `@backstage/plugin-scaffolder-node` instead. - -- `ScaffolderEntitiesProcessor` should be imported from `@backstage/plugin-catalog-backend-module-scaffolder-entity-model` instead. diff --git a/.changeset/scaffolder-breakages-2.md b/.changeset/scaffolder-breakages-2.md deleted file mode 100644 index 77ffe5fc42..0000000000 --- a/.changeset/scaffolder-breakages-2.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend': major ---- - -**BREAKING ALPHA**: The `/alpha` export no longer exports the plugin. Please use `import('@backstage/plugin-scaffolder-backend')` instead as this has been removed. - -**BREAKING CHANGES**: The old `createRouter` function which was used in the old backend system has been removed along with the `RouterOptions` type. diff --git a/.changeset/scaffolder-breakages-3.md b/.changeset/scaffolder-breakages-3.md deleted file mode 100644 index f6dca6416f..0000000000 --- a/.changeset/scaffolder-breakages-3.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend': major ---- - -**BREAKING CHANGES** - -The following functions have been re-exported from the `scaffolder-backend` plugin for quite some time, and now it's time to clean them up. They've been moved as follows: - -- `SerializedTask`, `SerializedTaskEvent`, `TaskBroker`, `TaskBrokerDispatchOptions`, `TaskBrokerDispatchResult`, `TaskCompletionState`, `TaskContext`, `TaskEventType`, `TaskStatus`, `TemplateFilter`, and `TemplateGlobal` should be imported from `@backstage/plugin-scaffolder-node` instead. - -- The deprecated `copyWithoutRender` option has been removed from `fetch:template` action. You should rename the option to `copyWithoutTemplating` instead. diff --git a/.changeset/scaffolder-breakages-4.md b/.changeset/scaffolder-breakages-4.md deleted file mode 100644 index e9f0c81256..0000000000 --- a/.changeset/scaffolder-breakages-4.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -'@backstage/plugin-scaffolder-node': minor ---- - -**BREAKING CHANGES** - -The legacy methods to define `createTemplateActions` have been replaced with the new native `zod` approaches for defining input and output schemas. - -You can migrate actions that look like the following with the below examples: - -```ts -// really old legacy json schema -createTemplateAction<{ repoUrl: string }, { repoOutput: string }>({ - id: 'test', - schema: { - input: { - type: 'object' - required: ['repoUrl'] - properties: { - repoUrl: { - type: 'string', - description: 'repository url description' - } - } - } - } -}); - -// old zod method -createTemplateAction({ - id: 'test' - schema: { - input: { - repoUrl: z.string({ description: 'repository url description' }) - } - } -}) - -// new method: -createTemplateAction({ - id: 'test', - schema: { - input: { - repoUrl: z => z.string({ description: 'repository url description' }) - } - } -}) - -// or for more complex zod types like unions -createTemplateAction({ - id: 'test', - schema: { - input: z => z.object({ - repoUrl: z.string({ description: 'repository url description' }) - }) - } -}) -``` - -This breaking change also means that `logStream` has been removed entirely from `ActionsContext`, and that the `logger` is now just a `LoggerService` implementation instead. There is no replacement for the `logStream`, if you wish to still keep using a `logStream` we recommend that you create your own stream that writes to `ctx.logger` instead. diff --git a/.changeset/scaffolder-breakages-5.md b/.changeset/scaffolder-breakages-5.md deleted file mode 100644 index 8047ec3dc3..0000000000 --- a/.changeset/scaffolder-breakages-5.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend-module-github': minor ---- - -**BREAKING CHANGES** - -The `createGithubEnvironmentAction` action no longer requires an `AuthService`, and now accepts a `CatalogService` instead of `CatalogClient`. - -Unless you're providing your own override action to the default, this should be a non-breaking change. - -You can migrate using the following if you're getting typescript errors: - -```ts -import { catalogServiceRef } from '@backstage/plugin-catalog-node'; -import { scaffolderActionsExtensionPoint } from '@backstage/plugin-scaffolder-node/alpha'; - -export const myModule = createBackendModule({ - pluginId: 'scaffolder', - moduleId: 'test', - register({ registerInit }) { - registerInit({ - deps: { - scaffolder: scaffolderActionsExtensionPoint, - catalog: catalogServiceRef, - }, - async init({ scaffolder, catalog }) { - scaffolder.addActions( - createGithubEnvironmentAction({ - catalog, - }), - ); - }, - }); - }, -}); -``` diff --git a/.changeset/scaffolder-breakages-6.md b/.changeset/scaffolder-breakages-6.md deleted file mode 100644 index 74ff76c27d..0000000000 --- a/.changeset/scaffolder-breakages-6.md +++ /dev/null @@ -1,42 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend': major ---- - -**BREAKING CHANGES** - -- The `createBuiltinActions` method has been removed, as this should no longer be needed with the new backend system route, and was only useful when passing the default list of actions again in the old backend system. You should be able to rely on the default behaviour of the new backend system which is to merge the actions. - -- The `createCatalogRegisterAction` and `createFetchCatalogEntityAction` actions no longer require an `AuthService`, and now accepts a `CatalogService` instead of `CatalogClient`. - -Unless you're providing your own override action to the default, this should be a non-breaking change. - -You can migrate using the following if you're getting typescript errors: - -```ts -import { catalogServiceRef } from '@backstage/plugin-catalog-node'; -import { scaffolderActionsExtensionPoint } from '@backstage/plugin-scaffolder-node/alpha'; - -export const myModule = createBackendModule({ - pluginId: 'scaffolder', - moduleId: 'test', - register({ registerInit }) { - registerInit({ - deps: { - scaffolder: scaffolderActionsExtensionPoint, - catalog: catalogServiceRef, - }, - async init({ scaffolder, catalog }) { - scaffolder.addActions( - createCatalogRegisterAction({ - catalog, - }), - createFetchCatalogEntityAction({ - catalog, - integrations, - }), - ); - }, - }); - }, -}); -``` diff --git a/.changeset/scaffolder-deprecations-1.md b/.changeset/scaffolder-deprecations-1.md deleted file mode 100644 index 7d87013536..0000000000 --- a/.changeset/scaffolder-deprecations-1.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend': minor ---- - -**DEPRECATIONS** - -The following types and implementations have been deprecated, either because they're no longer relevant, or because upcoming changes to the `scaffolder-backend` after `2.0.0` will influence the changes to these API surfaces. - -- `CreateWorkerOptions` -- `DatabaseTaskStore` -- `DatabaseTaskStoreOptions` -- `TaskManager` -- `TaskStoreCreateTaskOptions` -- `TaskStoreCreateTaskResult` -- `TaskStoreEmitOptions` -- `TaskStoreListEventsOptions` -- `TaskStoreRecoverTaskOptions` -- `TaskStoreShutDownTaskOptions` - -There is no current path off deprecation, these types are going to be removed and rethought with a better way to define workers in the new backend system. diff --git a/.changeset/seven-beans-appear.md b/.changeset/seven-beans-appear.md deleted file mode 100644 index 82fe9f9889..0000000000 --- a/.changeset/seven-beans-appear.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-gitlab': patch ---- - -Implement retry for GitLab API calls to handle rate limiting diff --git a/.changeset/shiny-bags-bet.md b/.changeset/shiny-bags-bet.md deleted file mode 100644 index 0d9f2c0f30..0000000000 --- a/.changeset/shiny-bags-bet.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend-module-bitbucket': patch ---- - -Migrating `bitbucket` actions to use the new `zod` format diff --git a/.changeset/six-mangos-yell.md b/.changeset/six-mangos-yell.md deleted file mode 100644 index 65ddae86f8..0000000000 --- a/.changeset/six-mangos-yell.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/repo-tools': minor ---- - -Add support for caching the per-package output from the `package-docs` command. diff --git a/.changeset/slimy-cups-shake.md b/.changeset/slimy-cups-shake.md deleted file mode 100644 index 164b741499..0000000000 --- a/.changeset/slimy-cups-shake.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-import': patch ---- - -Catalog import plugin full support i18n diff --git a/.changeset/slow-impalas-wear.md b/.changeset/slow-impalas-wear.md deleted file mode 100644 index b5151a6ed4..0000000000 --- a/.changeset/slow-impalas-wear.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Only use the caching Jest module loader for frontend packages in order to avoid breaking real ESM module imports. diff --git a/.changeset/small-dots-march.md b/.changeset/small-dots-march.md deleted file mode 100644 index 0796ef68bb..0000000000 --- a/.changeset/small-dots-march.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend-module-gitlab': patch ---- - -Support merge request labels in publish:gitlab:merge-request diff --git a/.changeset/smooth-eels-think.md b/.changeset/smooth-eels-think.md deleted file mode 100644 index c5e2fe0c85..0000000000 --- a/.changeset/smooth-eels-think.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -'@backstage/plugin-techdocs': minor -'@backstage/plugin-techdocs-react': minor -'@backstage/plugin-catalog': minor -'@backstage/plugin-techdocs-common': patch ---- - -Introduced `backstage.io/techdocs-entity-path` annotation which allows deep linking into another entities TechDocs in conjunction with `backstage.io/techdocs-entity`. diff --git a/.changeset/some-llamas-go.md b/.changeset/some-llamas-go.md deleted file mode 100644 index d07b6a6c75..0000000000 --- a/.changeset/some-llamas-go.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-bitbucket-cloud': minor ---- - -**BREAKING**: `BitbucketCloudEntityProvider` now accepts a `CatalogService` instead of a `CatalogApi`. diff --git a/.changeset/spicy-rivers-notice.md b/.changeset/spicy-rivers-notice.md deleted file mode 100644 index 941f2d257d..0000000000 --- a/.changeset/spicy-rivers-notice.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-home': patch ---- - -Fixed the `WelcomeTitle` to properly default to the previous value of `inherit` diff --git a/.changeset/spotty-cases-show.md b/.changeset/spotty-cases-show.md deleted file mode 100644 index 3e9a607733..0000000000 --- a/.changeset/spotty-cases-show.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/frontend-defaults': patch ---- - -Forwarded the new `pluginInfoResolver` option for `createApp`. diff --git a/.changeset/strong-trams-joke.md b/.changeset/strong-trams-joke.md deleted file mode 100644 index 8b6a831d7d..0000000000 --- a/.changeset/strong-trams-joke.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Updating the scaffolder action boilerplate to use new `zod` schema diff --git a/.changeset/stupid-flies-speak.md b/.changeset/stupid-flies-speak.md deleted file mode 100644 index 5156a5b8b6..0000000000 --- a/.changeset/stupid-flies-speak.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/frontend-app-api': patch ---- - -Implemented support for the `plugin.info()` method in specialized apps with a default resolved for `package.json` and `catalog-info.yaml`. The default resolution logic can be overridden via the `pluginInfoResolver` option to `createSpecializedApp`, and plugin-specific overrides can be applied via the new `app.pluginOverrides` key in static configuration. diff --git a/.changeset/stupid-goats-teach.md b/.changeset/stupid-goats-teach.md deleted file mode 100644 index f90d9373e7..0000000000 --- a/.changeset/stupid-goats-teach.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Added `backstage.pluginId` field in `package.json` to all default plugin package templates for the `new` command. diff --git a/.changeset/stupid-pens-serve.md b/.changeset/stupid-pens-serve.md deleted file mode 100644 index f7fe733254..0000000000 --- a/.changeset/stupid-pens-serve.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Internal refactor to combine alpha `build` and `start` modules. diff --git a/.changeset/sweet-ducks-wait.md b/.changeset/sweet-ducks-wait.md deleted file mode 100644 index 4792fafe84..0000000000 --- a/.changeset/sweet-ducks-wait.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-test-utils': minor ---- - -Added mock implementations for `ActionsService` and `ActionsRegistryService` diff --git a/.changeset/sweet-squids-dig.md b/.changeset/sweet-squids-dig.md deleted file mode 100644 index 78a388ec52..0000000000 --- a/.changeset/sweet-squids-dig.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend-module-cookiecutter': patch ---- - -Migrate using new actions format diff --git a/.changeset/three-boats-sort.md b/.changeset/three-boats-sort.md deleted file mode 100644 index 180a4e236c..0000000000 --- a/.changeset/three-boats-sort.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -fix: merge eslint reports when using json format diff --git a/.changeset/tough-heads-knock.md b/.changeset/tough-heads-knock.md deleted file mode 100644 index da2e2c1163..0000000000 --- a/.changeset/tough-heads-knock.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend': patch ---- - -Update `refresh_state_references.id` to be a big int diff --git a/.changeset/true-tools-play.md b/.changeset/true-tools-play.md deleted file mode 100644 index 4d1ae4d4e8..0000000000 --- a/.changeset/true-tools-play.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend-module-bitbucket-cloud': patch ---- - -Fix `bitbucketCloudBranchRestrictions` API calls to accept null to prevent 400 errors for some branch restriction kinds defined. diff --git a/.changeset/warm-hornets-unite.md b/.changeset/warm-hornets-unite.md deleted file mode 100644 index 65a56233cb..0000000000 --- a/.changeset/warm-hornets-unite.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-search-react': patch ---- - -SearchBar clear button support i18n diff --git a/.changeset/warm-taxes-show.md b/.changeset/warm-taxes-show.md deleted file mode 100644 index edebd0048e..0000000000 --- a/.changeset/warm-taxes-show.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/canon': minor ---- - -Fixes spacing props on layout components and aligned on naming for the Grid component. You should now call the Grid root component using instead of just . diff --git a/.changeset/wet-bars-report.md b/.changeset/wet-bars-report.md deleted file mode 100644 index d556f6cc61..0000000000 --- a/.changeset/wet-bars-report.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-plugin-api': minor ---- - -Added `coreServices.actionsRegistry` and `coreServices.actions` to allow registration of distributed actions from plugins, and the ability to invoke these actions diff --git a/.changeset/wet-bars-reporting.md b/.changeset/wet-bars-reporting.md deleted file mode 100644 index 7dc66cb280..0000000000 --- a/.changeset/wet-bars-reporting.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-defaults': patch ---- - -Added some default implementations for the `ActionsService` and `ActionsRegistryService` that allow registration of actions for a particular plugin. diff --git a/.changeset/yummy-donuts-peel.md b/.changeset/yummy-donuts-peel.md deleted file mode 100644 index 6c66573025..0000000000 --- a/.changeset/yummy-donuts-peel.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/canon': patch ---- - -Remove leftover console.log from Container component. diff --git a/.eslintrc.js b/.eslintrc.js index 409b820783..54f9e69576 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -18,8 +18,26 @@ var path = require('path'); module.exports = { root: true, - plugins: ['@spotify', 'notice', 'react', 'testing-library'], + plugins: ['@spotify', 'notice', 'react', 'testing-library', '@backstage'], rules: { + '@backstage/no-mixed-plugin-imports': [ + 'error', + { + // TODO: Fix these either by right role or by moving things to new packages + excludedTargetPackages: [ + '@backstage/plugin-catalog', + '@backstage/plugin-techdocs', + '@backstage/plugin-app', + '@backstage/plugin-catalog-backend', + '@backstage/test-utils', + '@backstage/plugin-auth-backend', + '@backstage/plugin-permission-backend', + '@backstage/plugin-kubernetes-backend', + '@backstage/config-loader', + '@backstage/plugin-app-backend' + ], + } + ], 'react/react-in-jsx-scope': 'off', 'notice/notice': [ 'error', diff --git a/.github/renovate.json5 b/.github/renovate.json5 index 77faa9354f..4716f1363f 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -35,6 +35,11 @@ rangeStrategy: 'replace', matchSourceUrls: ['https://github.com/gregberge/svgr{/,}**'], }, + { + groupName: 'Module-federation monorepo packages', + rangeStrategy: 'replace', + matchSourceUrls: ['https://github.com/module-federation/core{/,}**'], + }, // We update yarn packages manually as it's gzip'd and we don't want to pollute the repository too much. { matchSourceUrls: ['https://github.com/yarnpkg/berry'], diff --git a/.github/vale/config/vocabularies/Backstage/accept.txt b/.github/vale/config/vocabularies/Backstage/accept.txt index 36f9335b1f..92c7a293f5 100644 --- a/.github/vale/config/vocabularies/Backstage/accept.txt +++ b/.github/vale/config/vocabularies/Backstage/accept.txt @@ -433,6 +433,7 @@ statefulsets stdout storable storages +Streamable stringified stringify subcommand diff --git a/.github/workflows/deploy_docker-image.yml b/.github/workflows/deploy_docker-image.yml index e1547801ef..21913eb428 100644 --- a/.github/workflows/deploy_docker-image.yml +++ b/.github/workflows/deploy_docker-image.yml @@ -62,7 +62,7 @@ jobs: uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0 - name: Build and push - uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # v6.15.0 + uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0 with: context: './example-app' file: ./example-app/packages/backend/Dockerfile diff --git a/.github/workflows/deploy_microsite.yml b/.github/workflows/deploy_microsite.yml index 67fcc5d709..a5e89d6103 100644 --- a/.github/workflows/deploy_microsite.yml +++ b/.github/workflows/deploy_microsite.yml @@ -321,12 +321,12 @@ jobs: name: storybook path: microsite/build/storybook - - uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4 + - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4 with: name: stable-reference-beta path: microsite/build/api/stable/ - - uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4 + - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4 with: name: next-reference-beta path: microsite/build/api/next/ diff --git a/.github/workflows/sync_code-formatting.yml b/.github/workflows/sync_code-formatting.yml index ee97f3fef3..18ec62c7bf 100644 --- a/.github/workflows/sync_code-formatting.yml +++ b/.github/workflows/sync_code-formatting.yml @@ -30,7 +30,7 @@ jobs: cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }} - name: Run Prettier on ADOPTERS.md - uses: creyD/prettier_action@31355f8eef017f8aeba2e0bc09d8502b13dbbad1 # v4.3 + uses: creyD/prettier_action@8c18391fdc98ed0d884c6345f03975edac71b8f0 # v4.6 with: # Modifies commit only if prettier autofixed the ADOPTERS.md prettier_options: --config docs/prettier.config.js --write ADOPTERS.md diff --git a/.github/workflows/verify_microsite.yml b/.github/workflows/verify_microsite.yml index df68cff2cf..38900074d6 100644 --- a/.github/workflows/verify_microsite.yml +++ b/.github/workflows/verify_microsite.yml @@ -325,13 +325,13 @@ jobs: working-directory: microsite - name: download stable reference (beta) - uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4 with: name: stable-reference-beta path: api/stable/ - name: download next reference (beta) - uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4 with: name: next-reference-beta path: api/next/ diff --git a/.github/workflows/verify_storybook.yml b/.github/workflows/verify_storybook.yml index 3cc846a706..6c1ceb4c52 100644 --- a/.github/workflows/verify_storybook.yml +++ b/.github/workflows/verify_storybook.yml @@ -54,7 +54,7 @@ jobs: - run: yarn --cwd packages/canon build-storybook - - uses: chromaui/action@e8cc4c31775280b175a3c440076c00d19a9014d7 # v11 + - uses: chromaui/action@1cfa065cbdab28f6ca3afaeb3d761383076a35aa # v11 with: token: ${{ secrets.GITHUB_TOKEN }} # projectToken intentionally shared to allow collaborators to run Chromatic on forks diff --git a/OWNERS.md b/OWNERS.md index 44d7c7784f..d4ee3c6400 100644 --- a/OWNERS.md +++ b/OWNERS.md @@ -56,6 +56,18 @@ Scope: The Backstage design system, component library, as well as surrounding to | Charles de Dreuille | Spotify | | [cdedreuille](https://github.com/cdedreuille) | `cdedreuille` | | Patrik Oldsberg | Spotify | Cubic Belugas | [Rugvip](https://github.com/Rugvip) | `Rugvip` | +### Documentation + +Team: @backstage/documentation-maintainers + +Scope: The Backstage Documentation and Microsite, excluding the plugins listing + +| Name | Organization | GitHub | Discord | +| --------------- | ------------- | ----------------------------------------------------- | ------------- | +| Andre Wanlin | Spotify | [awanlin](https://github.com/awanlin) | `ahhhndre` | +| Aramis Sennyey | DoorDash | [aramissennyeydd](https://github.com/aramissennyeydd) | `Aramis#7984` | +| Peter Macdonald | VodafoneZiggo | [Parsifal-M](https://github.com/Parsifal-M) | `parsifal` | + ### Framework Team: @backstage/framework-maintainers @@ -208,18 +220,6 @@ Scope: Tooling and Community Repo Maintainers for the Backstage [Community Plugi | Vincenzo Scamporlino | Spotify | [vinzscam](https://github.com/vinzscam) | `vinzscam` | | Peter Macdonald | VodafoneZiggo | [Parsifal-M](https://github.com/Parsifal-M) | `parsifal` | -### Documentation - -Team: @backstage/documentation-maintainers - -Scope: The Backstage Documentation and Microsite, excluding the plugins listing - -| Name | Organization | GitHub | Discord | -| --------------- | ------------- | ----------------------------------------------------- | ------------- | -| Andre Wanlin | Spotify | [awanlin](https://github.com/awanlin) | `ahhhndre` | -| Aramis Sennyey | DoorDash | [aramissennyeydd](https://github.com/aramissennyeydd) | `Aramis#7984` | -| Peter Macdonald | VodafoneZiggo | [Parsifal-M](https://github.com/Parsifal-M) | `parsifal` | - ### Events Team: @backstage/events-maintainers diff --git a/app-config.yaml b/app-config.yaml index eaee401d09..89926357c2 100644 --- a/app-config.yaml +++ b/app-config.yaml @@ -36,6 +36,12 @@ backend: # keys: # - secret: ${BACKEND_SECRET} + # Used for testing rate limiting locally + # rateLimit: + # windowMs: 1m + # incomingRequestLimit: 1 + # ipAllowList: [] + auth: # TODO: once plugins have been migrated we can remove this, but right now it # is require for the backend-next to work in this repo diff --git a/canon-docs/next.config.mjs b/canon-docs/next.config.mjs index ca221d9a8c..8e6ed8fdc0 100644 --- a/canon-docs/next.config.mjs +++ b/canon-docs/next.config.mjs @@ -8,6 +8,11 @@ const nextConfig = { images: { unoptimized: true, }, + typescript: { + // Ignore TypeScript errors during build - safe for React 18/19 compatibility issues + // These are type-level conflicts that don't affect runtime behavior + ignoreBuildErrors: true, + }, }; const withMDX = createMDX({}); diff --git a/canon-docs/package.json b/canon-docs/package.json index 5a4affc45b..c9bc1ae96b 100644 --- a/canon-docs/package.json +++ b/canon-docs/package.json @@ -8,19 +8,25 @@ "lint": "next lint", "start": "npm run build:css && next dev" }, + "resolutions": { + "@types/react": "19.1.8", + "@types/react-dom": "19.1.6" + }, "dependencies": { "@codemirror/lang-sass": "^6.0.2", "@lezer/highlight": "^1.2.1", "@mdx-js/loader": "^3.1.0", "@mdx-js/react": "^3.1.0", - "@next/mdx": "^15.1.4", + "@next/mdx": "15.3.3", "@storybook/react": "^8.6.8", "@uiw/codemirror-themes": "^4.23.7", "@uiw/react-codemirror": "^4.23.7", + "html-react-parser": "^5.2.5", "motion": "^12.4.1", - "next": "14.2.26", - "react": "^18.0.2", - "react-dom": "^18.0.2", + "next": "15.3.3", + "next-mdx-remote-client": "^2.1.2", + "react": "19.1.0", + "react-dom": "19.1.0", "react-frame-component": "^5.2.7", "shiki": "^1.26.1", "storybook": "^8.6.8" @@ -28,10 +34,10 @@ "devDependencies": { "@types/mdx": "^2.0.13", "@types/node": "^20", - "@types/react": "^18.0.0", - "@types/react-dom": "^18.0.0", + "@types/react": "19.1.8", + "@types/react-dom": "19.1.6", "eslint": "^8", - "eslint-config-next": "14.2.23", + "eslint-config-next": "15.3.3", "lightningcss": "^1.28.2", "typescript": "^5" } diff --git a/canon-docs/public/header.png b/canon-docs/public/header.png index 507bd05ca7..8d11151a3e 100644 Binary files a/canon-docs/public/header.png and b/canon-docs/public/header.png differ diff --git a/canon-docs/src/app/(docs)/changelog/page.mdx b/canon-docs/src/app/(docs)/changelog/page.mdx new file mode 100644 index 0000000000..7cc0b2bf3e --- /dev/null +++ b/canon-docs/src/app/(docs)/changelog/page.mdx @@ -0,0 +1,13 @@ +import { Changelog } from '@/components/Changelog'; + +# Changelog + + + +## Version 0.1.0 + +We're excited to share the initial release of Canon 💚 In this first alpha version, +you'll find the foundation of our design system: a set of versatile layout components +and a handful of essential atomic elements to help you get started. While Canon is +still in its early stages, it's ready for exploration and we'd love for you to give +it a try and share your feedback. diff --git a/canon-docs/src/app/(docs)/components/[slug]/page.tsx b/canon-docs/src/app/(docs)/components/[slug]/page.tsx new file mode 100644 index 0000000000..d6f98c8f93 --- /dev/null +++ b/canon-docs/src/app/(docs)/components/[slug]/page.tsx @@ -0,0 +1,25 @@ +import { components, layoutComponents } from '@/utils/data'; + +export default async function Page({ + params, +}: { + params: Promise<{ slug: string }>; +}) { + const { slug } = await params; + + const { default: Component } = await import( + `@/content/components/${slug}.mdx` + ); + + return ; +} + +export function generateStaticParams() { + const list = [...components, ...layoutComponents]; + + return list.map(component => ({ + slug: component.slug, + })); +} + +export const dynamicParams = false; diff --git a/canon-docs/src/app/(docs)/components/avatar/page.mdx b/canon-docs/src/app/(docs)/components/avatar/page.mdx deleted file mode 100644 index b46caf8d62..0000000000 --- a/canon-docs/src/app/(docs)/components/avatar/page.mdx +++ /dev/null @@ -1,75 +0,0 @@ -import { PropsTable } from '@/components/PropsTable'; -import { Snippet } from '@/components/Snippet'; -import { Tabs } from '@/components/Tabs'; -import { CodeBlock } from '@/components/CodeBlock'; -import { AvatarSnippet } from '@/snippets/stories-snippets'; -import { avatarPropDefs } from './props'; - -# Avatar - -An avatar component with a fallback for initials. - -} - code={``} -/> - - - - Usage - Theming - - - `} - /> - - - We recommend starting with our [global tokens](/theme/theming) to customize the library and align it with - your brand. For additional flexibility, you can use the provided class names for each element listed below. - - `canon-AvatarRoot` - - `canon-AvatarRoot[data-size='small']` - - `canon-AvatarRoot[data-size='medium']` - - `canon-AvatarRoot[data-size='large']` - - `canon-AvatarImage` - - `canon-AvatarFallback` - - - -## API reference - - - -## Examples - -### Sizes - -Avatar sizes can be set using the `size` prop. - -} - code={` - - - - `} -/> - -### Fallback - -If the image is not available, the avatar will show the initials of the name. - -} - code={``} -/> diff --git a/canon-docs/src/app/(docs)/components/avatar/props.ts b/canon-docs/src/app/(docs)/components/avatar/props.ts deleted file mode 100644 index e86c67a41e..0000000000 --- a/canon-docs/src/app/(docs)/components/avatar/props.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { classNamePropDefs, stylePropDefs } from '@/utils/propDefs'; -import type { PropDef } from '@/utils/propDefs'; - -export const avatarPropDefs: Record = { - src: { - type: 'string', - }, - name: { - type: 'string', - }, - size: { - type: 'enum', - values: ['small', 'medium', 'large'], - default: 'medium', - responsive: true, - }, - ...classNamePropDefs, - ...stylePropDefs, -}; diff --git a/canon-docs/src/app/(docs)/components/box/props.ts b/canon-docs/src/app/(docs)/components/box/props.ts deleted file mode 100644 index f3e38984dd..0000000000 --- a/canon-docs/src/app/(docs)/components/box/props.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { - classNamePropDefs, - displayPropDefs, - heightPropDefs, - positionPropDefs, - stylePropDefs, - widthPropDefs, -} from '../../../../utils/propDefs'; -import type { PropDef } from '../../../../utils/propDefs'; - -export const boxPropDefs: Record = { - as: { - type: 'enum', - values: ['div', 'span'], - default: 'div', - responsive: true, - }, - ...widthPropDefs, - ...heightPropDefs, - ...positionPropDefs, - ...displayPropDefs, - ...classNamePropDefs, - ...stylePropDefs, -}; diff --git a/canon-docs/src/app/(docs)/components/button/page.mdx b/canon-docs/src/app/(docs)/components/button/page.mdx deleted file mode 100644 index 3554ee39f9..0000000000 --- a/canon-docs/src/app/(docs)/components/button/page.mdx +++ /dev/null @@ -1,150 +0,0 @@ -import { PropsTable } from '@/components/PropsTable'; -import { Snippet } from '@/components/Snippet'; -import { Tabs } from '@/components/Tabs'; -import { CodeBlock } from '@/components/CodeBlock'; -import { ButtonSnippet } from '@/snippets/stories-snippets'; -import { buttonVariants } from '@/snippets/code-snippets'; -import { buttonPropDefs } from './props'; - -# Button - -A button component that can be used to trigger actions. - -} - code={` - - - -`} -/> - - - - Usage - Theming - - - -`} - /> - - - We recommend starting with our [global tokens](/theme/theming) to customize the library and align it with - your brand. For additional flexibility, you can use the provided class names for each element listed below. - `} - /> - - - - -## API reference - - - -## Examples - -### Variants - -Here's a view when buttons have different variants. - -} - code={buttonVariants} -/> - -### Sizes - -Here's a view when buttons have different sizes. - -} - code={` - - -`} -/> - -### With Icons - -Here's a view when buttons have icons. - -} - code={` - - - -`} -/> - -### Full width - -Here's a view when buttons are full width. - -} - code={` - -`} -/> - -### Disabled - -Here's a view when buttons are disabled. - -} - code={``} -/> - -### As Link - -Here's a view when buttons are rendered as a link. - -} - code={``} -/> - -### Responsive - -Here's a view when buttons are responsive. - - - Responsive Button - `} -/> diff --git a/canon-docs/src/app/(docs)/components/button/props.ts b/canon-docs/src/app/(docs)/components/button/props.ts deleted file mode 100644 index 36b0f73066..0000000000 --- a/canon-docs/src/app/(docs)/components/button/props.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { classNamePropDefs, stylePropDefs } from '../../../../utils/propDefs'; -import type { PropDef } from '../../../../utils/propDefs'; - -export const buttonPropDefs: Record = { - variant: { - type: 'enum', - values: ['primary', 'secondary'], - default: 'primary', - responsive: true, - }, - size: { - type: 'enum', - values: ['small', 'medium'], - default: 'medium', - responsive: true, - }, - render: { - type: 'enum', - values: ['ReactNode'], - responsive: false, - default: ' - )} /> - - - It's the edge of the world and all of Western civilization - The sun may rise in the East, at least it settled in a final location - It's understood that Hollywood sells Californication - - -`} -/> - - - - Usage - Theming - - - - ( - - )} /> - Your content -`} - /> - - - We recommend starting with our [global tokens](/theme/theming) to customize the library and align it with - your brand. For additional flexibility, you can use the provided class names for each element listed below. - - `canon-CollapsibleRoot` - - `canon-CollapsibleTrigger` - - `canon-CollapsiblePanel` - - - -## API reference - -### Collapsible.Root - -Groups all parts of the collapsible. Renders a `
` element. - - - -### Collapsible.Trigger - -The trigger by default render a simple unstyled button. Because menus can be rendered in different ways, we recommend -using the `render` prop to render a custom trigger. - - - )} /> - - - It's the edge of the world and all of Western civilization - The sun may rise in the East, at least it settled in a final location - It's understood that Hollywood sells Californication - - -`} -/> diff --git a/canon-docs/src/app/(docs)/components/collapsible/props.ts b/canon-docs/src/app/(docs)/components/collapsible/props.ts deleted file mode 100644 index 02c62dc89e..0000000000 --- a/canon-docs/src/app/(docs)/components/collapsible/props.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { - classNamePropDefs, - stylePropDefs, - renderPropDefs, -} from '@/utils/propDefs'; -import type { PropDef } from '@/utils/propDefs'; - -export const collapsibleRootPropDefs: Record = { - defaultOpen: { - type: 'boolean', - default: 'false', - }, - open: { - type: 'boolean', - }, - onOpenChange: { - type: 'enum', - values: ['(open) => void'], - }, - ...renderPropDefs, - ...classNamePropDefs, - ...stylePropDefs, -}; - -export const collapsibleTriggerPropDefs: Record = { - ...renderPropDefs, - ...classNamePropDefs, - ...stylePropDefs, -}; - -export const collapsiblePanelPropDefs: Record = { - hiddenUntilFound: { - type: 'boolean', - default: 'false', - }, - keepMounted: { - type: 'boolean', - default: 'false', - }, - ...renderPropDefs, - ...classNamePropDefs, - ...stylePropDefs, -}; diff --git a/canon-docs/src/app/(docs)/components/container/props.ts b/canon-docs/src/app/(docs)/components/container/props.ts deleted file mode 100644 index 4a3410ec12..0000000000 --- a/canon-docs/src/app/(docs)/components/container/props.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { - classNamePropDefs, - stylePropDefs, - gapPropDefs, -} from '../../../../utils/propDefs'; -import type { PropDef } from '../../../../utils/propDefs'; - -export const containerPropDefs: Record = { - ...gapPropDefs, - ...classNamePropDefs, - ...stylePropDefs, -}; diff --git a/canon-docs/src/app/(docs)/components/flex/page.mdx b/canon-docs/src/app/(docs)/components/flex/page.mdx deleted file mode 100644 index 8150f3e3c5..0000000000 --- a/canon-docs/src/app/(docs)/components/flex/page.mdx +++ /dev/null @@ -1,83 +0,0 @@ -import { PropsTable } from '@/components/PropsTable'; -import { Tabs } from '@/components/Tabs'; -import { CodeBlock } from '@/components/CodeBlock'; -import { - flexFAQ1, - flexSimple, - flexResponsive, - flexAlign, -} from '@/snippets/code-snippets'; -import { Snippet } from '@/components/Snippet'; -import { FlexSnippet } from '@/snippets/stories-snippets'; -import { flexPropDefs } from './props'; -import { spacingPropDefs } from '../../../../utils/propDefs'; - -# Flex - -This is the flex container component. It will help to define the number of -columns that will be used in the grid. You can also define the gap between the -columns. All values are responsive. - -} - code={` - - - -`} -/> - - - - Usage - - - -`} - /> - - - -## API reference - - - -The grid component also accepts all the spacing props from the Box component. - - - -## Common questions - -### Can I stack horizontally? - -The Flex component only allows for stacking elements vertically. If you want -to create a column layout, please use the Grid component. - - - -## Examples - -### Simple - -A simple example of how to use the Flex component. - - - -### Responsive - -The Flex component also supports responsive values, making it easy to create -responsive designs. - - - -### Align - -The Flex component also supports responsive alignment, making it easy to -create responsive designs. - - diff --git a/canon-docs/src/app/(docs)/components/flex/props.ts b/canon-docs/src/app/(docs)/components/flex/props.ts deleted file mode 100644 index 2268a6909d..0000000000 --- a/canon-docs/src/app/(docs)/components/flex/props.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { - PropDef, - childrenPropDefs, - classNamePropDefs, - stylePropDefs, -} from '../../../../utils/propDefs'; - -export const flexPropDefs: Record = { - align: { - type: 'enum', - values: ['start', 'center', 'end', 'baseline', 'stretch'], - responsive: true, - }, - direction: { - type: 'enum', - values: ['row', 'column', 'row-reverse', 'column-reverse'], - responsive: true, - }, - justify: { - type: 'enum', - values: ['start', 'center', 'end', 'between'], - responsive: true, - }, - ...childrenPropDefs, - ...classNamePropDefs, - ...stylePropDefs, -}; diff --git a/canon-docs/src/app/(docs)/components/grid/props.ts b/canon-docs/src/app/(docs)/components/grid/props.ts deleted file mode 100644 index a9e8717fa1..0000000000 --- a/canon-docs/src/app/(docs)/components/grid/props.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { - PropDef, - childrenPropDefs, - classNamePropDefs, - stylePropDefs, -} from '../../../../utils/propDefs'; - -const columnsValues = [ - '1', - '2', - '3', - '4', - '5', - '6', - '7', - '8', - '9', - '10', - '11', - '12', -]; - -export const gridPropDefs: Record = { - columns: { - type: 'enum | string', - values: [...columnsValues, 'auto'], - responsive: true, - default: 'auto', - }, - ...childrenPropDefs, - ...classNamePropDefs, - ...stylePropDefs, -}; - -export const gridItemPropDefs: Record = { - colSpan: { - type: 'enum | string', - values: [...columnsValues, 'full'], - responsive: true, - }, - rowSpan: { - type: 'enum | string', - values: [...columnsValues, 'full'], - responsive: true, - }, - start: { - type: 'enum | string', - values: [...columnsValues, 'auto'], - responsive: true, - }, - end: { - type: 'enum | string', - values: [...columnsValues, 'auto'], - responsive: true, - }, - ...childrenPropDefs, - ...classNamePropDefs, - ...stylePropDefs, -}; diff --git a/canon-docs/src/app/(docs)/components/heading/page.mdx b/canon-docs/src/app/(docs)/components/heading/page.mdx deleted file mode 100644 index a5eb488411..0000000000 --- a/canon-docs/src/app/(docs)/components/heading/page.mdx +++ /dev/null @@ -1,102 +0,0 @@ -import { PropsTable } from '@/components/PropsTable'; -import { HeadingSnippet } from '@/snippets/stories-snippets'; -import { Snippet } from '@/components/Snippet'; -import { Tabs } from '@/components/Tabs'; -import { CodeBlock } from '@/components/CodeBlock'; -import { headingPropDefs } from './props'; - -# Heading - -Headings are used to structure the content of your page. - -} - code={`Hello World!`} -/> - - - - Usage - Theming - - - -`} - /> - - - We recommend starting with our [global tokens](/theme/theming) to customize the library and align it with - your brand. For additional flexibility, you can use the provided class names for each element listed below. - `} - /> - - - - -## API reference - - - -## Examples - -### All variants - -The `Heading` component has a `variant` prop that can be used to change the -appearance of the heading. - -} - code={` - Display - Title 1 - Title 2 - Title 3 - Title 4 - Title 5 -`} -/> - -### Truncate - -The `Heading` component has a `truncate` prop that can be used to truncate the -heading. - -} - code={` - A man looks at a painting in a museum and says, “Brothers and sisters I - have none, but that man's father is my father's son.” Who is - in the painting? - `} -/> - -### Custom render - -You can also use the `render` prop to render the heading as a different element. - -} - code={`}>Custom render`} -/> - -### Responsive - -You can also use the `variant` prop to change the appearance of the text based -on the screen size. - - - Responsive heading - `} -/> diff --git a/canon-docs/src/app/(docs)/components/heading/props.ts b/canon-docs/src/app/(docs)/components/heading/props.ts deleted file mode 100644 index 6d62d2dee1..0000000000 --- a/canon-docs/src/app/(docs)/components/heading/props.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { classNamePropDefs, stylePropDefs } from '../../../../utils/propDefs'; -import type { PropDef } from '../../../../utils/propDefs'; - -export const headingPropDefs: Record = { - variant: { - type: 'enum', - values: ['display', 'title1', 'title2', 'title3', 'title4', 'title5'], - responsive: true, - }, - children: { - type: 'enum', - values: ['ReactNode'], - responsive: false, - }, - truncate: { - type: 'boolean', - default: 'false', - }, - ...classNamePropDefs, - ...stylePropDefs, -}; diff --git a/canon-docs/src/app/(docs)/components/icon-button/page.mdx b/canon-docs/src/app/(docs)/components/icon-button/page.mdx deleted file mode 100644 index 60530ec9ea..0000000000 --- a/canon-docs/src/app/(docs)/components/icon-button/page.mdx +++ /dev/null @@ -1,97 +0,0 @@ -import { PropsTable } from '@/components/PropsTable'; -import { Snippet } from '@/components/Snippet'; -import { Tabs } from '@/components/Tabs'; -import { CodeBlock } from '@/components/CodeBlock'; -import { IconButtonSnippet } from '@/snippets/stories-snippets'; -import { iconButtonVariants } from '@/snippets/code-snippets'; -import { iconButtonPropDefs } from './props'; - -# Icon Button - -A button component with a single icon that can be used to trigger actions. - -} - code={` - - - `} -/> - - - - Usage - Theming - - - -`} - /> - - - We recommend starting with our [global tokens](/theme/theming) to customize the library and align it with - your brand. For additional flexibility, you can use the provided class names for each element listed below. - `} - /> - - - - -## API reference - - - -## Examples - -### Variants - -Here's a view when buttons have different variants. - -} - code={iconButtonVariants} -/> - -### Sizes - -Here's a view when buttons have different sizes. - -} - code={` - - -`} -/> - -### Disabled - -Here's a view when buttons are disabled. - -} - code={``} -/> - -### Responsive - -Here's a view when buttons are responsive. - -`} -/> diff --git a/canon-docs/src/app/(docs)/components/icon-button/props.ts b/canon-docs/src/app/(docs)/components/icon-button/props.ts deleted file mode 100644 index bcb1580247..0000000000 --- a/canon-docs/src/app/(docs)/components/icon-button/props.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { classNamePropDefs, stylePropDefs } from '../../../../utils/propDefs'; -import type { PropDef } from '../../../../utils/propDefs'; - -export const iconButtonPropDefs: Record = { - variant: { - type: 'enum', - values: ['primary', 'secondary'], - default: 'primary', - responsive: true, - }, - size: { - type: 'enum', - values: ['small', 'medium'], - default: 'medium', - responsive: true, - }, - icon: { type: 'enum', values: 'icon', responsive: false }, - ...classNamePropDefs, - ...stylePropDefs, -}; diff --git a/canon-docs/src/app/(docs)/components/icon/page.mdx b/canon-docs/src/app/(docs)/components/icon/page.mdx deleted file mode 100644 index 66be460d13..0000000000 --- a/canon-docs/src/app/(docs)/components/icon/page.mdx +++ /dev/null @@ -1,44 +0,0 @@ -import { PropsTable } from '@/components/PropsTable'; -import { IconSnippet } from '@/snippets/stories-snippets'; -import { Snippet } from '@/components/Snippet'; -import { Tabs } from '@/components/Tabs'; -import { CodeBlock } from '@/components/CodeBlock'; -import { iconPropDefs } from './props'; - -# Icon - -Icons are used to represent an action or a state. - -} - code={``} -/> - - - - Usage - Theming - - - -`} - /> - - - We recommend starting with our [global tokens](/theme/theming) to customize the library and align it with - your brand. For additional flexibility, you can use the provided class names for each element listed below. - `} - /> - - - - -## API reference - - diff --git a/canon-docs/src/app/(docs)/components/link/page.mdx b/canon-docs/src/app/(docs)/components/link/page.mdx deleted file mode 100644 index 64a3261590..0000000000 --- a/canon-docs/src/app/(docs)/components/link/page.mdx +++ /dev/null @@ -1,84 +0,0 @@ -import { PropsTable } from '@/components/PropsTable'; -import { Snippet } from '@/components/Snippet'; -import { Tabs } from '@/components/Tabs'; -import { CodeBlock } from '@/components/CodeBlock'; -import { - MenuSnippet, - ButtonSnippet, - LinkSnippet, -} from '@/snippets/stories-snippets'; -import { linkPropDefs } from './props'; - -# Link - -A link component that renders a `` element. - -} - code={`Sign up for Backstage`} -/> - - - - Usage - Theming - - - Sign up for Backstage`} - /> - - - We recommend starting with our [global tokens](/theme/theming) to customize the library and align it with - your brand. For additional flexibility, you can use the provided class names for each element listed below. - - `canon-Link` - - `canon-Link[data-variant='body']` - - `canon-Link[data-variant='subtitle']` - - `canon-Link[data-variant='caption']` - - `canon-Link[data-variant='label']` - - `canon-Link[data-weight='regular']` - - `canon-Link[data-weight='bold']` - - - -## API reference - - - -## Examples - -### Variants - -Here's a view when links have different variants. - -} - code={` - - - - - `} -/> - -### Weights - -Here's a view when links have different weights. - -} - code={` - - - `} -/> diff --git a/canon-docs/src/app/(docs)/components/link/props.ts b/canon-docs/src/app/(docs)/components/link/props.ts deleted file mode 100644 index 83507c5594..0000000000 --- a/canon-docs/src/app/(docs)/components/link/props.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { classNamePropDefs, stylePropDefs } from '@/utils/propDefs'; -import type { PropDef } from '@/utils/propDefs'; - -export const linkPropDefs: Record = { - to: { - type: 'string', - }, - variant: { - type: 'enum', - values: ['subtitle', 'body', 'caption', 'label'], - default: 'body', - responsive: true, - }, - weight: { - type: 'enum', - values: ['regular', 'bold'], - default: 'regular', - responsive: true, - }, - ...classNamePropDefs, - ...stylePropDefs, -}; diff --git a/canon-docs/src/app/(docs)/components/menu/page.mdx b/canon-docs/src/app/(docs)/components/menu/page.mdx deleted file mode 100644 index 524db26cd1..0000000000 --- a/canon-docs/src/app/(docs)/components/menu/page.mdx +++ /dev/null @@ -1,202 +0,0 @@ -import { PropsTable } from '@/components/PropsTable'; -import { Snippet } from '@/components/Snippet'; -import { Tabs } from '@/components/Tabs'; -import { CodeBlock } from '@/components/CodeBlock'; -import { MenuSnippet } from '@/snippets/stories-snippets'; -import { BaseUI } from '@/components/HeadlessBanners/BaseUI'; -import { - menuRootPropDefs, - menuTriggerPropDefs, - menuPositionerPropDefs, - menuItemPropDefs, -} from './props'; - -# Menu - -A list of actions in a dropdown, enhanced with keyboard navigation. - -} - code={` - ( - - )} - /> - - - - Settings - Invite new members - Download app - Log out - - - - `} -/> - - - - Usage - Theming - - - - - - - - - - - - `} - /> - - - We recommend starting with our [global tokens](/theme/theming) to customize the library and align it with - your brand. For additional flexibility, you can use the provided class names for each element listed below. - - `canon-MenuTrigger` - - `canon-MenuBackdrop` - - `canon-MenuPositioner` - - `canon-MenuPopup` - - `canon-MenuArrow` - - `canon-MenuItem` - - `canon-MenuGroup` - - `canon-MenuGroupLabel` - - `canon-MenuRadioGroup` - - `canon-MenuRadioItem` - - `canon-MenuRadioItemIndicator` - - `canon-MenuCheckboxItem` - - `canon-MenuCheckboxItemIndicator` - - `canon-MenuSubmenuTrigger` - - `canon-MenuSeparator` - - - -## API reference - - - -### Menu.Root - -Groups all parts of the menu. Doesn't render its own HTML element. - - - -### Menu.Trigger - -The trigger by default render a simple unstyled button. Because menus can be rendered in different ways, we recommend -using the `render` prop to render a custom trigger. - - - )} - /> - - - - Settings - Invite new members - Download app - Log out - - - - `} -/> - -### Nested navigation - -You can nest menus to create a more complex navigation structure. - -} - code={` ( - - )} - /> - - - - Settings - Invite new members - Download app - Log out - - Submenu - - - - Submenu Item 1 - Submenu Item 2 - Submenu Item 3 - - - - - - - `} -/> diff --git a/canon-docs/src/app/(docs)/components/select/page.mdx b/canon-docs/src/app/(docs)/components/select/page.mdx deleted file mode 100644 index 4399f62235..0000000000 --- a/canon-docs/src/app/(docs)/components/select/page.mdx +++ /dev/null @@ -1,128 +0,0 @@ -import { PropsTable } from '@/components/PropsTable'; -import { Snippet } from '@/components/Snippet'; -import { Tabs } from '@/components/Tabs'; -import { CodeBlock } from '@/components/CodeBlock'; -import { SelectSnippet } from '@/snippets/stories-snippets'; -import { selectPropDefs } from './props'; - -# Select - -A common form component for choosing a predefined value in a dropdown menu. - -} - code={``} -/> - -### Sizes - -Here's a view when the selects have different sizes. - -} - code={` - - `} -/> - -### Disabled - -Here's a view when the select is disabled. - -} - code={``; + +export const selectDefaultSnippet = ``; + +export const selectSizesSnippet = ` + +`; + +export const selectDisabledSnippet = ``; diff --git a/canon-docs/src/content/components/switch.mdx b/canon-docs/src/content/components/switch.mdx new file mode 100644 index 0000000000..068ec96217 --- /dev/null +++ b/canon-docs/src/content/components/switch.mdx @@ -0,0 +1,41 @@ +import { PropsTable } from '@/components/PropsTable'; +import { Snippet } from '@/components/Snippet'; +import { CodeBlock } from '@/components/CodeBlock'; +import { SwitchSnippet } from '@/snippets/stories-snippets'; +import { switchPropDefs, snippetUsage } from './switch.props'; +import { ComponentInfos } from '@/components/ComponentInfos'; + +# Switch + +A control that indicates whether a setting is on or off. + +} + code={``} +/> + + + +## API reference + + + +## Examples + +### Disabled + +A switch can be disabled using the `isDisabled` prop. + +} + code={``} +/> diff --git a/canon-docs/src/content/components/switch.props.ts b/canon-docs/src/content/components/switch.props.ts new file mode 100644 index 0000000000..ddbca4e049 --- /dev/null +++ b/canon-docs/src/content/components/switch.props.ts @@ -0,0 +1,71 @@ +import { classNamePropDefs, stylePropDefs } from '@/utils/propDefs'; +import type { PropDef } from '@/utils/propDefs'; + +export const switchPropDefs: Record = { + autoFocus: { + type: 'boolean', + }, + defaultSelected: { + type: 'boolean', + }, + ...classNamePropDefs, + isDisabled: { + type: 'boolean', + }, + isReadOnly: { + type: 'boolean', + }, + isSelected: { + type: 'boolean', + }, + label: { + type: 'string', + }, + name: { + type: 'string', + }, + onChange: { + type: 'enum', + values: ['(isSelected: boolean) => void'], + }, + onFocus: { + type: 'enum', + values: ['(e: FocusEvent) => void'], + }, + onBlur: { + type: 'enum', + values: ['(e: FocusEvent) => void'], + }, + onFocusChange: { + type: 'enum', + values: ['(isFocused: boolean) => void'], + }, + onKeyDown: { + type: 'enum', + values: ['(e: KeyboardEvent) => void'], + }, + onKeyUp: { + type: 'enum', + values: ['(e: KeyboardEvent) => void'], + }, + onHoverStart: { + type: 'enum', + values: ['(e: HoverEvent) => void'], + }, + onHoverEnd: { + type: 'enum', + values: ['(e: HoverEvent) => void'], + }, + onHoverChange: { + type: 'enum', + values: ['(isHovered: boolean) => void'], + }, + ...stylePropDefs, + value: { + type: 'string', + }, +}; + +export const snippetUsage = `import { Switch } from '@backstage/canon'; + +`; diff --git a/canon-docs/src/app/(docs)/components/table/page.mdx b/canon-docs/src/content/components/table.mdx similarity index 100% rename from canon-docs/src/app/(docs)/components/table/page.mdx rename to canon-docs/src/content/components/table.mdx diff --git a/canon-docs/src/content/components/tabs.mdx b/canon-docs/src/content/components/tabs.mdx new file mode 100644 index 0000000000..85cfa34af2 --- /dev/null +++ b/canon-docs/src/content/components/tabs.mdx @@ -0,0 +1,61 @@ +import { PropsTable } from '@/components/PropsTable'; +import { TabsSnippet } from '@/snippets/stories-snippets'; +import { Snippet } from '@/components/Snippet'; +import { CodeBlock } from '@/components/CodeBlock'; +import { + tabsRootPropDefs, + tabsListPropDefs, + tabsTabPropDefs, + tabsPanelPropDefs, + tabsUsageSnippet, + tabsDefaultSnippet, +} from './tabs.props'; +import { ComponentInfos } from '@/components/ComponentInfos'; + +# Tabs + +A component for toggling between related panels on the same page. + +} + code={tabsDefaultSnippet} +/> + + + +## API reference + +### Tabs.Root + +Groups the tabs and the corresponding panels. Renders a `
` element. + + + +### Tabs.List + +Groups the individual tab buttons. Renders a `
` element. + + + +### Tabs.Tab + +An individual interactive tab button that toggles the corresponding panel. Renders a ` - - - -`; - -export const iconButtonVariants = ` - - - -`; - -export const flexFAQ1 = ` - Hello World - Hello World - Hello World -`; - -export const flexSimple = ` - Hello World - Hello World - Hello World -`; - -export const flexResponsive = ` - Hello World - Hello World - Hello World -`; - -export const flexAlign = ` - Hello World - Hello World - Hello World -`; diff --git a/canon-docs/src/snippets/stories-snippets.tsx b/canon-docs/src/snippets/stories-snippets.tsx index 64047ebde9..95738a6330 100644 --- a/canon-docs/src/snippets/stories-snippets.tsx +++ b/canon-docs/src/snippets/stories-snippets.tsx @@ -18,6 +18,7 @@ import * as LinkStories from '../../../packages/canon/src/components/Link/Link.s import * as AvatarStories from '../../../packages/canon/src/components/Avatar/Avatar.stories'; import * as CollapsibleStories from '../../../packages/canon/src/components/Collapsible/Collapsible.stories'; import * as TabsStories from '../../../packages/canon/src/components/Tabs/Tabs.stories'; +import * as SwitchStories from '../../../packages/canon/src/components/Switch/Switch.stories'; export const BoxSnippet = ({ story }: { story: keyof typeof BoxStories }) => { const stories = composeStories(BoxStories); @@ -173,3 +174,14 @@ export const TabsSnippet = ({ story }: { story: keyof typeof TabsStories }) => { return StoryComponent ? : null; }; + +export const SwitchSnippet = ({ + story, +}: { + story: keyof typeof SwitchStories; +}) => { + const stories = composeStories(SwitchStories); + const StoryComponent = stories[story as keyof typeof stories]; + + return StoryComponent ? : null; +}; diff --git a/canon-docs/src/utils/changelog.ts b/canon-docs/src/utils/changelog.ts new file mode 100644 index 0000000000..94317ab78b --- /dev/null +++ b/canon-docs/src/utils/changelog.ts @@ -0,0 +1,386 @@ +export type Component = + | 'avatar' + | 'box' + | 'button' + | 'heading' + | 'text' + | 'icon-button' + | 'icon' + | 'tabs' + | 'menu' + | 'textfield' + | 'datatable' + | 'select' + | 'collapsible' + | 'checkbox' + | 'container' + | 'link' + | 'tooltip' + | 'scrollarea' + | 'flex' + | 'switch'; + +export type Version = `${number}.${number}.${number}`; + +export interface ChangelogProps { + components: Component[]; + description: string; + version: Version; + platform: 'oss' | 'portal'; + prs: string[]; +} + +export const changelog: ChangelogProps[] = [ + { + components: ['switch'], + version: '0.5.0', + description: '✨ Add new `Switch` component', + platform: 'portal', + prs: ['30251'], + }, + { + components: ['tabs'], + version: '0.4.0', + description: '✨ Add new `Tabs` component', + platform: 'portal', + prs: ['29996'], + }, + { + components: ['text', 'heading'], + version: '0.4.0', + description: '✨ Add `truncate` prop to `Text` and `Heading`', + platform: 'portal', + prs: ['29988'], + }, + { + components: ['menu'], + version: '0.4.0', + description: '✨ Add combobox option to `Menu`', + platform: 'portal', + prs: ['29986'], + }, + { + components: ['textfield'], + version: '0.4.0', + description: '✨ Add icon prop on `TextField`', + platform: 'portal', + prs: ['29820'], + }, + { + components: ['button', 'icon-button'], + version: '0.4.0', + description: 'Improve icon props on `Button` and `IconButton`', + platform: 'portal', + prs: ['29667'], + }, + { + components: ['text', 'heading'], + version: '0.4.0', + description: + 'Improve the way we treat custom render on `Text` and `Heading`', + platform: 'portal', + prs: ['29989'], + }, + { + components: ['menu'], + version: '0.4.0', + description: 'Improve `Menu` styles', + platform: 'portal', + prs: ['29986'], + }, + { + components: ['textfield'], + version: '0.4.0', + description: 'Improve `TextField` styles', + platform: 'portal', + prs: ['29974'], + }, + { + components: ['textfield'], + version: '0.4.0', + description: 'Improve clear button on `TextField`', + platform: 'portal', + prs: ['29878'], + }, + { + components: ['flex'], + version: '0.4.0', + description: 'Fix spacing props on all layout components', + platform: 'portal', + prs: ['30013'], + }, + { + components: [], + version: '0.4.0', + description: 'Fix - Pin Base UI version', + platform: 'portal', + prs: ['29782'], + }, + { + components: ['select'], + version: '0.4.0', + description: 'Fix - Clicking `Select` label moves focus to trigger', + platform: 'portal', + prs: ['29755'], + }, + { + components: ['datatable'], + version: '0.4.0', + description: 'Fix `DataTable.Pagination` count issue', + platform: 'portal', + prs: ['29688'], + }, + { + components: ['datatable'], + version: '0.3.0', + description: 'Add `DataTable` component', + platform: 'portal', + prs: ['29484', '29603'], + }, + { + components: ['select'], + version: '0.3.0', + description: 'Add `Select` component', + platform: 'portal', + prs: ['29440'], + }, + { + components: ['avatar'], + version: '0.3.0', + description: 'Add `Avatar` component', + platform: 'portal', + prs: ['29594'], + }, + { + components: ['collapsible'], + version: '0.3.0', + description: 'Add `Collapsible` component', + platform: 'portal', + prs: ['29617'], + }, + { + components: ['textfield'], + version: '0.3.0', + description: 'Add `TextField` component instead of `Field` + `Input`', + platform: 'portal', + prs: ['29364'], + }, + { + components: ['datatable'], + version: '0.3.0', + description: 'Add `TableCellProfile`', + platform: 'portal', + prs: ['29600'], + }, + { + components: [], + version: '0.3.0', + description: 'Add breakpoint hooks - `up()` and `down()`', + platform: 'portal', + prs: ['29564'], + }, + { + components: [], + version: '0.3.0', + description: 'Add gray scale css tokens', + platform: 'portal', + prs: ['29543'], + }, + { + components: [], + version: '0.3.0', + description: + 'Update CSS styling API using `[data-___]` instead of class names for props', + platform: 'portal', + prs: ['29560'], + }, + { + components: ['checkbox'], + version: '0.3.0', + description: 'Update `Checkbox` dark mode', + platform: 'portal', + prs: ['29544'], + }, + { + components: ['container'], + version: '0.3.0', + description: 'Update `Container` styles', + platform: 'portal', + prs: ['29475'], + }, + { + components: ['menu'], + version: '0.3.0', + description: 'Update `Menu` styles', + platform: 'portal', + prs: ['29351'], + }, + { + components: ['select'], + version: '0.3.0', + description: 'Fix `Select` styles on small sizes + with long option names', + platform: 'portal', + prs: ['29545'], + }, + { + components: ['link'], + version: '0.3.0', + description: 'Fix render prop on `Link`', + platform: 'portal', + prs: ['29247'], + }, + { + components: ['textfield', 'select'], + version: '0.3.0', + description: 'Remove `Field` from `TextField` + `Select`', + platform: 'portal', + prs: ['29482'], + }, + { + components: ['text', 'heading'], + version: '0.3.0', + description: 'Update `textDecoration` to `none` on `Text` / `Heading`', + platform: 'portal', + prs: ['29357'], + }, + { + components: ['text', 'heading'], + version: '0.3.0', + description: 'Update `textDecoration` to `none` on `Text` / `Heading`', + platform: 'portal', + prs: ['29357'], + }, + { + components: [], + version: '0.3.0', + description: 'Docs - Use stories from Storybook for all examples in Nextjs', + platform: 'portal', + prs: ['29306'], + }, + { + components: [], + version: '0.3.0', + description: 'Docs - Add release page (this one 🤗)', + platform: 'portal', + prs: ['29461'], + }, + { + components: [], + version: '0.3.0', + description: 'Docs - Add docs for Menu, Link', + platform: 'portal', + prs: ['29576'], + }, + { + components: [], + version: '0.3.0', + description: 'Fix CSS watch mode', + platform: 'portal', + prs: ['29352'], + }, + { + components: ['menu'], + version: '0.2.0', + description: 'New `Menu` component', + platform: 'portal', + prs: ['29151'], + }, + { + components: ['icon-button'], + version: '0.2.0', + description: 'New `IconButton` component', + platform: 'portal', + prs: ['29239'], + }, + { + components: ['scrollarea'], + version: '0.2.0', + description: 'New `ScrollArea` component', + platform: 'portal', + prs: ['29240'], + }, + { + components: ['button', 'checkbox'], + version: '0.2.0', + description: 'Improve `Button` & `Checkbox` styles', + platform: 'portal', + prs: ['29127', '28789'], + }, + { + components: ['text'], + version: '0.2.0', + description: 'Improve `Text` styles', + platform: 'portal', + prs: ['29200'], + }, + { + components: ['icon'], + version: '0.2.0', + description: 'Renamed `CanonProvider` to `IconProvider`', + platform: 'portal', + prs: ['29002'], + }, + { + components: ['icon'], + version: '0.2.0', + description: 'Added about 40+ new icons', + platform: 'portal', + prs: ['29264'], + }, + { + components: [], + version: '0.2.0', + description: 'Simplified styling into a unique styles.css file', + platform: 'portal', + prs: ['29199'], + }, + { + components: [], + version: '0.2.0', + description: 'Added Canon styles to Backstage', + platform: 'portal', + prs: ['29137'], + }, + { + components: [], + version: '0.2.0', + description: 'Update global CSS tokens', + platform: 'portal', + prs: ['28804'], + }, + { + components: ['flex'], + version: '0.2.0', + description: 'Merge Stack + Inline into Flex', + platform: 'portal', + prs: ['28634'], + }, + { + components: ['button'], + version: '0.2.0', + description: 'Improve `Button` types', + platform: 'portal', + prs: ['29205'], + }, + { + components: [], + version: '0.2.0', + description: 'Move font weight and family back to each components', + platform: 'portal', + prs: ['28972'], + }, + { + components: [], + version: '0.2.0', + description: 'Fix custom values in spacing props', + platform: 'portal', + prs: ['28770'], + }, + { + components: [], + version: '0.2.0', + description: 'Multiple updates on the Canon Docs site', + platform: 'portal', + prs: ['28760'], + }, +]; diff --git a/canon-docs/src/utils/data.ts b/canon-docs/src/utils/data.ts index ba4fd5e432..20ff9146a7 100644 --- a/canon-docs/src/utils/data.ts +++ b/canon-docs/src/utils/data.ts @@ -14,8 +14,8 @@ export const overview: Page[] = [ slug: 'about', }, { - title: 'Releases', - slug: 'releases', + title: 'Changelog', + slug: 'changelog', }, ]; @@ -116,6 +116,11 @@ export const components: Page[] = [ slug: 'select', status: 'alpha', }, + { + title: 'Switch', + slug: 'switch', + status: 'alpha', + }, { title: 'Table', slug: 'table', diff --git a/canon-docs/tsconfig.json b/canon-docs/tsconfig.json index 2baa7cde8f..e1b3951aa8 100644 --- a/canon-docs/tsconfig.json +++ b/canon-docs/tsconfig.json @@ -3,7 +3,7 @@ "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, "skipLibCheck": true, - "strict": true, + "strict": false, "noEmit": true, "esModuleInterop": true, "module": "esnext", @@ -12,6 +12,7 @@ "isolatedModules": true, "jsx": "preserve", "incremental": true, + "noImplicitAny": false, "plugins": [ { "name": "next" @@ -19,14 +20,16 @@ ], "paths": { "@/*": ["./src/*"] - } + }, + "target": "ES2017" }, "include": [ "next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", - "dist/types/**/*.ts" + "dist/types/**/*.ts", + "src/types/**/*.d.ts" ], "exclude": ["node_modules"] } diff --git a/canon-docs/yarn.lock b/canon-docs/yarn.lock index decb4e7efe..9232edb7af 100644 --- a/canon-docs/yarn.lock +++ b/canon-docs/yarn.lock @@ -5,36 +5,52 @@ __metadata: version: 8 cacheKey: 10 -"@babel/runtime@npm:^7.18.6": - version: 7.26.10 - resolution: "@babel/runtime@npm:7.26.10" +"@babel/code-frame@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/code-frame@npm:7.27.1" dependencies: - regenerator-runtime: "npm:^0.14.0" - checksum: 10/9d7ff8e96abe3791047c1138789c742411e3ef19c4d7ca18ce916f83cec92c06ec5dc64401759f6dd1e377cf8a01bbd2c62e033eb7550f435cf6579768d0d4a5 + "@babel/helper-validator-identifier": "npm:^7.27.1" + js-tokens: "npm:^4.0.0" + picocolors: "npm:^1.1.1" + checksum: 10/721b8a6e360a1fa0f1c9fe7351ae6c874828e119183688b533c477aa378f1010f37cc9afbfc4722c686d1f5cdd00da02eab4ba7278a0c504fa0d7a321dcd4fdf + languageName: node + linkType: hard + +"@babel/helper-validator-identifier@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/helper-validator-identifier@npm:7.27.1" + checksum: 10/75041904d21bdc0cd3b07a8ac90b11d64cd3c881e89cb936fa80edd734bf23c35e6bd1312611e8574c4eab1f3af0f63e8a5894f4699e9cfdf70c06fcf4252320 + languageName: node + linkType: hard + +"@babel/runtime@npm:^7.18.6": + version: 7.27.6 + resolution: "@babel/runtime@npm:7.27.6" + checksum: 10/cc957a12ba3781241b83d528eb69ddeb86ca5ac43179a825e83aa81263a6b3eb88c57bed8a937cdeacfc3192e07ec24c73acdfea4507d0c0428c8e23d6322bfe languageName: node linkType: hard "@codemirror/autocomplete@npm:^6.0.0": - version: 6.18.4 - resolution: "@codemirror/autocomplete@npm:6.18.4" + version: 6.18.6 + resolution: "@codemirror/autocomplete@npm:6.18.6" dependencies: "@codemirror/language": "npm:^6.0.0" "@codemirror/state": "npm:^6.0.0" "@codemirror/view": "npm:^6.17.0" "@lezer/common": "npm:^1.0.0" - checksum: 10/7cd62db2ee87d6cb3936ced4f211bdcd9ce75515f64922119370c303a8bdbf5640e640a8d802c30d01cb55fb6c9b5299426ff799f04cff0bef8d0c3450fe2528 + checksum: 10/0574d96fd04ccf2d3b7ae3c4efe0a72f423fa81658876ec50865ce3371cea038aeddf026976ec0d0ccbee72ac66bdf7deec9106dee251ad49019ae7e1a871663 languageName: node linkType: hard "@codemirror/commands@npm:^6.0.0, @codemirror/commands@npm:^6.1.0": - version: 6.8.0 - resolution: "@codemirror/commands@npm:6.8.0" + version: 6.8.1 + resolution: "@codemirror/commands@npm:6.8.1" dependencies: "@codemirror/language": "npm:^6.0.0" "@codemirror/state": "npm:^6.4.0" "@codemirror/view": "npm:^6.27.0" "@lezer/common": "npm:^1.1.0" - checksum: 10/0c7991736bc84d0a7f8e49c311c78a78def84fca36ff61c2f9887067e2c06b1b232711cb99282cd410527ddbe0671d2b9aff93e0848fa731a2014c3691c737ea + checksum: 10/72b6343777d4fe4af1bcc91331eb64705b33e871c9f8e2a0cd177269478a6f3282bf25aeaecdbb55fd5e031b67aabfede068e919fe69e473d07e5090dd76b381 languageName: node linkType: hard @@ -65,8 +81,8 @@ __metadata: linkType: hard "@codemirror/language@npm:^6.0.0": - version: 6.10.8 - resolution: "@codemirror/language@npm:6.10.8" + version: 6.11.1 + resolution: "@codemirror/language@npm:6.11.1" dependencies: "@codemirror/state": "npm:^6.0.0" "@codemirror/view": "npm:^6.23.0" @@ -74,38 +90,38 @@ __metadata: "@lezer/highlight": "npm:^1.0.0" "@lezer/lr": "npm:^1.0.0" style-mod: "npm:^4.0.0" - checksum: 10/63b83b41d9f8475f757144cc204df08834bb14411c484aa265ffa3e93b7d8f696a21110df72101159a8675eda29018c6d08f864965bd4651b607a39f10ad32ed + checksum: 10/024969113d61ccb5d497b75a8a9875d43e1bfc8466de2819bb5db23f01b200937366800a812e8d33eb5e34e3a5d2aa22d0ff8205f34a5e8aeb4cd1d221bcaa78 languageName: node linkType: hard "@codemirror/lint@npm:^6.0.0": - version: 6.8.4 - resolution: "@codemirror/lint@npm:6.8.4" + version: 6.8.5 + resolution: "@codemirror/lint@npm:6.8.5" dependencies: "@codemirror/state": "npm:^6.0.0" "@codemirror/view": "npm:^6.35.0" crelt: "npm:^1.0.5" - checksum: 10/401ead0591d88d31d1bf6527d4caba26e0deb7b49382dfbb8c712037d858047b0699fa2c15831a07db928194549eea9b942004fee42f334b34ff5973c7dbec58 + checksum: 10/9eddfea1dd0615431d57687c2a0d4de510d725aac6f6bbc2eba4bc934963371304dfa4c49398b3043372ef34cead3ebc0ec3f652632a87f5d8a458fa911a309a languageName: node linkType: hard "@codemirror/search@npm:^6.0.0": - version: 6.5.8 - resolution: "@codemirror/search@npm:6.5.8" + version: 6.5.11 + resolution: "@codemirror/search@npm:6.5.11" dependencies: "@codemirror/state": "npm:^6.0.0" "@codemirror/view": "npm:^6.0.0" crelt: "npm:^1.0.5" - checksum: 10/1389fa4e05da72b621ae10ff00d4ef0d23b08a3a7ac48f6e0b867429da7b80036bd7a6feef1a54f5b4c4af9fc4277f754a313a858fbfc12ccdfa48e9bf300cef + checksum: 10/d057f37cb369460b25625d7eb72f40636bf78ecd140608da53010cf3660f982a9e613826e38d85d87c9c2ff11e45c9482429987bfd4f29cbbd192f1ee3fd2695 languageName: node linkType: hard "@codemirror/state@npm:^6.0.0, @codemirror/state@npm:^6.1.1, @codemirror/state@npm:^6.4.0, @codemirror/state@npm:^6.5.0": - version: 6.5.1 - resolution: "@codemirror/state@npm:6.5.1" + version: 6.5.2 + resolution: "@codemirror/state@npm:6.5.2" dependencies: "@marijn/find-cluster-break": "npm:^1.0.0" - checksum: 10/117f21ba2ff5bc9f9b946ca9943279a29bb9461ec77fc2313cfd8908ed6eb7df2950d7c5b0ba0a0a23c3e0633c6bba56f8c105f97875665e0376a9e110d10a48 + checksum: 10/5ccd3acb0c0a5b88e83fb91be39099fceb9f44a5047cc41a75d53f160e736851f65c8de40950b90c6519e6d2828e12f468db0af658dde30e938896f1c39eec91 languageName: node linkType: hard @@ -122,199 +138,228 @@ __metadata: linkType: hard "@codemirror/view@npm:^6.0.0, @codemirror/view@npm:^6.17.0, @codemirror/view@npm:^6.23.0, @codemirror/view@npm:^6.27.0, @codemirror/view@npm:^6.35.0": - version: 6.36.2 - resolution: "@codemirror/view@npm:6.36.2" + version: 6.37.1 + resolution: "@codemirror/view@npm:6.37.1" dependencies: "@codemirror/state": "npm:^6.5.0" + crelt: "npm:^1.0.6" style-mod: "npm:^4.1.0" w3c-keyname: "npm:^2.2.4" - checksum: 10/9ef7fcf4f9d9b6e66645ae65da1bf0c90e08f6ba786de0373b9f3644632066b91b8ea20faf67bb81eb9adf310ae76888cc7fd0901e2bb4821193f5427455c137 + checksum: 10/04594b0bad98036c57ef0fb962b0e09186de404e26f1068fd98191edae51f2c5b476938d42239c8c7f0b70deead837f925a9d671b7cc8f9f336bdbb01630bbf9 languageName: node linkType: hard -"@esbuild/aix-ppc64@npm:0.25.0": - version: 0.25.0 - resolution: "@esbuild/aix-ppc64@npm:0.25.0" +"@emnapi/core@npm:^1.4.3": + version: 1.4.3 + resolution: "@emnapi/core@npm:1.4.3" + dependencies: + "@emnapi/wasi-threads": "npm:1.0.2" + tslib: "npm:^2.4.0" + checksum: 10/b511f66b897d2019835391544fdf11f4fa0ce06cc1181abfa17c7d4cf03aaaa4fc8a64fcd30bb3f901de488d0a6f370b53a8de2215a898f5a4ac98015265b3b7 + languageName: node + linkType: hard + +"@emnapi/runtime@npm:^1.4.3": + version: 1.4.3 + resolution: "@emnapi/runtime@npm:1.4.3" + dependencies: + tslib: "npm:^2.4.0" + checksum: 10/4f90852a1a5912982cc4e176b6420556971bcf6a85ee23e379e2455066d616219751367dcf43e6a6eaf41ea7e95ba9dc830665a52b5d979dfe074237d19578f8 + languageName: node + linkType: hard + +"@emnapi/wasi-threads@npm:1.0.2": + version: 1.0.2 + resolution: "@emnapi/wasi-threads@npm:1.0.2" + dependencies: + tslib: "npm:^2.4.0" + checksum: 10/e82941776665eb958c2084728191d6b15a94383449975c4621b67a1c8217e1c0ec11056a693906c76863cb96f782f8be500510ecec6874e3f5da35a8e7968cfd + languageName: node + linkType: hard + +"@esbuild/aix-ppc64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/aix-ppc64@npm:0.25.5" conditions: os=aix & cpu=ppc64 languageName: node linkType: hard -"@esbuild/android-arm64@npm:0.25.0": - version: 0.25.0 - resolution: "@esbuild/android-arm64@npm:0.25.0" +"@esbuild/android-arm64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/android-arm64@npm:0.25.5" conditions: os=android & cpu=arm64 languageName: node linkType: hard -"@esbuild/android-arm@npm:0.25.0": - version: 0.25.0 - resolution: "@esbuild/android-arm@npm:0.25.0" +"@esbuild/android-arm@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/android-arm@npm:0.25.5" conditions: os=android & cpu=arm languageName: node linkType: hard -"@esbuild/android-x64@npm:0.25.0": - version: 0.25.0 - resolution: "@esbuild/android-x64@npm:0.25.0" +"@esbuild/android-x64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/android-x64@npm:0.25.5" conditions: os=android & cpu=x64 languageName: node linkType: hard -"@esbuild/darwin-arm64@npm:0.25.0": - version: 0.25.0 - resolution: "@esbuild/darwin-arm64@npm:0.25.0" +"@esbuild/darwin-arm64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/darwin-arm64@npm:0.25.5" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@esbuild/darwin-x64@npm:0.25.0": - version: 0.25.0 - resolution: "@esbuild/darwin-x64@npm:0.25.0" +"@esbuild/darwin-x64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/darwin-x64@npm:0.25.5" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@esbuild/freebsd-arm64@npm:0.25.0": - version: 0.25.0 - resolution: "@esbuild/freebsd-arm64@npm:0.25.0" +"@esbuild/freebsd-arm64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/freebsd-arm64@npm:0.25.5" conditions: os=freebsd & cpu=arm64 languageName: node linkType: hard -"@esbuild/freebsd-x64@npm:0.25.0": - version: 0.25.0 - resolution: "@esbuild/freebsd-x64@npm:0.25.0" +"@esbuild/freebsd-x64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/freebsd-x64@npm:0.25.5" conditions: os=freebsd & cpu=x64 languageName: node linkType: hard -"@esbuild/linux-arm64@npm:0.25.0": - version: 0.25.0 - resolution: "@esbuild/linux-arm64@npm:0.25.0" +"@esbuild/linux-arm64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/linux-arm64@npm:0.25.5" conditions: os=linux & cpu=arm64 languageName: node linkType: hard -"@esbuild/linux-arm@npm:0.25.0": - version: 0.25.0 - resolution: "@esbuild/linux-arm@npm:0.25.0" +"@esbuild/linux-arm@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/linux-arm@npm:0.25.5" conditions: os=linux & cpu=arm languageName: node linkType: hard -"@esbuild/linux-ia32@npm:0.25.0": - version: 0.25.0 - resolution: "@esbuild/linux-ia32@npm:0.25.0" +"@esbuild/linux-ia32@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/linux-ia32@npm:0.25.5" conditions: os=linux & cpu=ia32 languageName: node linkType: hard -"@esbuild/linux-loong64@npm:0.25.0": - version: 0.25.0 - resolution: "@esbuild/linux-loong64@npm:0.25.0" +"@esbuild/linux-loong64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/linux-loong64@npm:0.25.5" conditions: os=linux & cpu=loong64 languageName: node linkType: hard -"@esbuild/linux-mips64el@npm:0.25.0": - version: 0.25.0 - resolution: "@esbuild/linux-mips64el@npm:0.25.0" +"@esbuild/linux-mips64el@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/linux-mips64el@npm:0.25.5" conditions: os=linux & cpu=mips64el languageName: node linkType: hard -"@esbuild/linux-ppc64@npm:0.25.0": - version: 0.25.0 - resolution: "@esbuild/linux-ppc64@npm:0.25.0" +"@esbuild/linux-ppc64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/linux-ppc64@npm:0.25.5" conditions: os=linux & cpu=ppc64 languageName: node linkType: hard -"@esbuild/linux-riscv64@npm:0.25.0": - version: 0.25.0 - resolution: "@esbuild/linux-riscv64@npm:0.25.0" +"@esbuild/linux-riscv64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/linux-riscv64@npm:0.25.5" conditions: os=linux & cpu=riscv64 languageName: node linkType: hard -"@esbuild/linux-s390x@npm:0.25.0": - version: 0.25.0 - resolution: "@esbuild/linux-s390x@npm:0.25.0" +"@esbuild/linux-s390x@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/linux-s390x@npm:0.25.5" conditions: os=linux & cpu=s390x languageName: node linkType: hard -"@esbuild/linux-x64@npm:0.25.0": - version: 0.25.0 - resolution: "@esbuild/linux-x64@npm:0.25.0" +"@esbuild/linux-x64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/linux-x64@npm:0.25.5" conditions: os=linux & cpu=x64 languageName: node linkType: hard -"@esbuild/netbsd-arm64@npm:0.25.0": - version: 0.25.0 - resolution: "@esbuild/netbsd-arm64@npm:0.25.0" +"@esbuild/netbsd-arm64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/netbsd-arm64@npm:0.25.5" conditions: os=netbsd & cpu=arm64 languageName: node linkType: hard -"@esbuild/netbsd-x64@npm:0.25.0": - version: 0.25.0 - resolution: "@esbuild/netbsd-x64@npm:0.25.0" +"@esbuild/netbsd-x64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/netbsd-x64@npm:0.25.5" conditions: os=netbsd & cpu=x64 languageName: node linkType: hard -"@esbuild/openbsd-arm64@npm:0.25.0": - version: 0.25.0 - resolution: "@esbuild/openbsd-arm64@npm:0.25.0" +"@esbuild/openbsd-arm64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/openbsd-arm64@npm:0.25.5" conditions: os=openbsd & cpu=arm64 languageName: node linkType: hard -"@esbuild/openbsd-x64@npm:0.25.0": - version: 0.25.0 - resolution: "@esbuild/openbsd-x64@npm:0.25.0" +"@esbuild/openbsd-x64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/openbsd-x64@npm:0.25.5" conditions: os=openbsd & cpu=x64 languageName: node linkType: hard -"@esbuild/sunos-x64@npm:0.25.0": - version: 0.25.0 - resolution: "@esbuild/sunos-x64@npm:0.25.0" +"@esbuild/sunos-x64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/sunos-x64@npm:0.25.5" conditions: os=sunos & cpu=x64 languageName: node linkType: hard -"@esbuild/win32-arm64@npm:0.25.0": - version: 0.25.0 - resolution: "@esbuild/win32-arm64@npm:0.25.0" +"@esbuild/win32-arm64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/win32-arm64@npm:0.25.5" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@esbuild/win32-ia32@npm:0.25.0": - version: 0.25.0 - resolution: "@esbuild/win32-ia32@npm:0.25.0" +"@esbuild/win32-ia32@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/win32-ia32@npm:0.25.5" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@esbuild/win32-x64@npm:0.25.0": - version: 0.25.0 - resolution: "@esbuild/win32-x64@npm:0.25.0" +"@esbuild/win32-x64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/win32-x64@npm:0.25.5" conditions: os=win32 & cpu=x64 languageName: node linkType: hard -"@eslint-community/eslint-utils@npm:^4.2.0, @eslint-community/eslint-utils@npm:^4.4.0": - version: 4.4.1 - resolution: "@eslint-community/eslint-utils@npm:4.4.1" +"@eslint-community/eslint-utils@npm:^4.2.0, @eslint-community/eslint-utils@npm:^4.7.0": + version: 4.7.0 + resolution: "@eslint-community/eslint-utils@npm:4.7.0" dependencies: eslint-visitor-keys: "npm:^3.4.3" peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - checksum: 10/ae92a11412674329b4bd38422518601ec9ceae28e251104d1cad83715da9d38e321f68c817c39b64e66d0af7d98df6f9a10ad2dc638911254b47fb8932df00ef + checksum: 10/43ed5d391526d9f5bbe452aef336389a473026fca92057cf97c576db11401ce9bcf8ef0bf72625bbaf6207ed8ba6bf0dcf4d7e809c24f08faa68a28533c491a7 languageName: node linkType: hard @@ -374,17 +419,192 @@ __metadata: languageName: node linkType: hard -"@isaacs/cliui@npm:^8.0.2": - version: 8.0.2 - resolution: "@isaacs/cliui@npm:8.0.2" +"@img/sharp-darwin-arm64@npm:0.34.2": + version: 0.34.2 + resolution: "@img/sharp-darwin-arm64@npm:0.34.2" dependencies: - string-width: "npm:^5.1.2" - string-width-cjs: "npm:string-width@^4.2.0" - strip-ansi: "npm:^7.0.1" - strip-ansi-cjs: "npm:strip-ansi@^6.0.1" - wrap-ansi: "npm:^8.1.0" - wrap-ansi-cjs: "npm:wrap-ansi@^7.0.0" - checksum: 10/e9ed5fd27c3aec1095e3a16e0c0cf148d1fee55a38665c35f7b3f86a9b5d00d042ddaabc98e8a1cb7463b9378c15f22a94eb35e99469c201453eb8375191f243 + "@img/sharp-libvips-darwin-arm64": "npm:1.1.0" + dependenciesMeta: + "@img/sharp-libvips-darwin-arm64": + optional: true + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@img/sharp-darwin-x64@npm:0.34.2": + version: 0.34.2 + resolution: "@img/sharp-darwin-x64@npm:0.34.2" + dependencies: + "@img/sharp-libvips-darwin-x64": "npm:1.1.0" + dependenciesMeta: + "@img/sharp-libvips-darwin-x64": + optional: true + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@img/sharp-libvips-darwin-arm64@npm:1.1.0": + version: 1.1.0 + resolution: "@img/sharp-libvips-darwin-arm64@npm:1.1.0" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@img/sharp-libvips-darwin-x64@npm:1.1.0": + version: 1.1.0 + resolution: "@img/sharp-libvips-darwin-x64@npm:1.1.0" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@img/sharp-libvips-linux-arm64@npm:1.1.0": + version: 1.1.0 + resolution: "@img/sharp-libvips-linux-arm64@npm:1.1.0" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + +"@img/sharp-libvips-linux-arm@npm:1.1.0": + version: 1.1.0 + resolution: "@img/sharp-libvips-linux-arm@npm:1.1.0" + conditions: os=linux & cpu=arm & libc=glibc + languageName: node + linkType: hard + +"@img/sharp-libvips-linux-ppc64@npm:1.1.0": + version: 1.1.0 + resolution: "@img/sharp-libvips-linux-ppc64@npm:1.1.0" + conditions: os=linux & cpu=ppc64 & libc=glibc + languageName: node + linkType: hard + +"@img/sharp-libvips-linux-s390x@npm:1.1.0": + version: 1.1.0 + resolution: "@img/sharp-libvips-linux-s390x@npm:1.1.0" + conditions: os=linux & cpu=s390x & libc=glibc + languageName: node + linkType: hard + +"@img/sharp-libvips-linux-x64@npm:1.1.0": + version: 1.1.0 + resolution: "@img/sharp-libvips-linux-x64@npm:1.1.0" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + +"@img/sharp-libvips-linuxmusl-arm64@npm:1.1.0": + version: 1.1.0 + resolution: "@img/sharp-libvips-linuxmusl-arm64@npm:1.1.0" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + +"@img/sharp-libvips-linuxmusl-x64@npm:1.1.0": + version: 1.1.0 + resolution: "@img/sharp-libvips-linuxmusl-x64@npm:1.1.0" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + +"@img/sharp-linux-arm64@npm:0.34.2": + version: 0.34.2 + resolution: "@img/sharp-linux-arm64@npm:0.34.2" + dependencies: + "@img/sharp-libvips-linux-arm64": "npm:1.1.0" + dependenciesMeta: + "@img/sharp-libvips-linux-arm64": + optional: true + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + +"@img/sharp-linux-arm@npm:0.34.2": + version: 0.34.2 + resolution: "@img/sharp-linux-arm@npm:0.34.2" + dependencies: + "@img/sharp-libvips-linux-arm": "npm:1.1.0" + dependenciesMeta: + "@img/sharp-libvips-linux-arm": + optional: true + conditions: os=linux & cpu=arm & libc=glibc + languageName: node + linkType: hard + +"@img/sharp-linux-s390x@npm:0.34.2": + version: 0.34.2 + resolution: "@img/sharp-linux-s390x@npm:0.34.2" + dependencies: + "@img/sharp-libvips-linux-s390x": "npm:1.1.0" + dependenciesMeta: + "@img/sharp-libvips-linux-s390x": + optional: true + conditions: os=linux & cpu=s390x & libc=glibc + languageName: node + linkType: hard + +"@img/sharp-linux-x64@npm:0.34.2": + version: 0.34.2 + resolution: "@img/sharp-linux-x64@npm:0.34.2" + dependencies: + "@img/sharp-libvips-linux-x64": "npm:1.1.0" + dependenciesMeta: + "@img/sharp-libvips-linux-x64": + optional: true + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + +"@img/sharp-linuxmusl-arm64@npm:0.34.2": + version: 0.34.2 + resolution: "@img/sharp-linuxmusl-arm64@npm:0.34.2" + dependencies: + "@img/sharp-libvips-linuxmusl-arm64": "npm:1.1.0" + dependenciesMeta: + "@img/sharp-libvips-linuxmusl-arm64": + optional: true + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + +"@img/sharp-linuxmusl-x64@npm:0.34.2": + version: 0.34.2 + resolution: "@img/sharp-linuxmusl-x64@npm:0.34.2" + dependencies: + "@img/sharp-libvips-linuxmusl-x64": "npm:1.1.0" + dependenciesMeta: + "@img/sharp-libvips-linuxmusl-x64": + optional: true + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + +"@img/sharp-wasm32@npm:0.34.2": + version: 0.34.2 + resolution: "@img/sharp-wasm32@npm:0.34.2" + dependencies: + "@emnapi/runtime": "npm:^1.4.3" + conditions: cpu=wasm32 + languageName: node + linkType: hard + +"@img/sharp-win32-arm64@npm:0.34.2": + version: 0.34.2 + resolution: "@img/sharp-win32-arm64@npm:0.34.2" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@img/sharp-win32-ia32@npm:0.34.2": + version: 0.34.2 + resolution: "@img/sharp-win32-ia32@npm:0.34.2" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + +"@img/sharp-win32-x64@npm:0.34.2": + version: 0.34.2 + resolution: "@img/sharp-win32-x64@npm:0.34.2" + conditions: os=win32 & cpu=x64 languageName: node linkType: hard @@ -396,13 +616,13 @@ __metadata: linkType: hard "@lezer/css@npm:^1.1.7": - version: 1.1.9 - resolution: "@lezer/css@npm:1.1.9" + version: 1.2.1 + resolution: "@lezer/css@npm:1.2.1" dependencies: "@lezer/common": "npm:^1.2.0" "@lezer/highlight": "npm:^1.0.0" - "@lezer/lr": "npm:^1.0.0" - checksum: 10/bcc277bb6b806961ebfd03e98faf8e5870dd7da2eb565c43922ac378d926b49f479309b28cc824fd4e17baac2c8952966807d06fbe2a45d53e9a3f1518134729 + "@lezer/lr": "npm:^1.3.0" + checksum: 10/726ea0e0b4d10c0326cc62d562a63c0d74970dde2002fab8172681c63e3210ff39d0f629370ad498b70e503ab2e9f74dd342d7c9e402b98f315b556116c3551a languageName: node linkType: hard @@ -415,7 +635,7 @@ __metadata: languageName: node linkType: hard -"@lezer/lr@npm:^1.0.0": +"@lezer/lr@npm:^1.0.0, @lezer/lr@npm:^1.3.0": version: 1.4.2 resolution: "@lezer/lr@npm:1.4.2" dependencies: @@ -425,13 +645,13 @@ __metadata: linkType: hard "@lezer/sass@npm:^1.0.0": - version: 1.0.7 - resolution: "@lezer/sass@npm:1.0.7" + version: 1.1.0 + resolution: "@lezer/sass@npm:1.1.0" dependencies: "@lezer/common": "npm:^1.2.0" "@lezer/highlight": "npm:^1.0.0" "@lezer/lr": "npm:^1.0.0" - checksum: 10/a7531cbf0766d3875480c24ae8929dd56053d71f9eaef8815e6f468e2252e66e38236a3f89395463e4cee43230dc35351386bedc6138cf1a19a44a64ce58a372 + checksum: 10/2f42dfaf5a328d4626a0a8ff8cd5973b7f52e8112541281cf1cbb1970acdc52c7c9f55c71f635bcff75a6151a55f7653d277306a15494b23b652e87d16df9ce3 languageName: node linkType: hard @@ -457,7 +677,7 @@ __metadata: languageName: node linkType: hard -"@mdx-js/mdx@npm:^3.0.0": +"@mdx-js/mdx@npm:^3.0.0, @mdx-js/mdx@npm:^3.1.0": version: 3.1.0 resolution: "@mdx-js/mdx@npm:3.1.0" dependencies: @@ -501,25 +721,36 @@ __metadata: languageName: node linkType: hard -"@next/env@npm:14.2.26": - version: 14.2.26 - resolution: "@next/env@npm:14.2.26" - checksum: 10/0caa679cdf9367501daf1bff0e762b720613a3ee1689e5585bfb7c792fdd07c251bc1f7488919a296047eb1f2b82ceb13955b673143468cad338a87b7d98c196 - languageName: node - linkType: hard - -"@next/eslint-plugin-next@npm:14.2.23": - version: 14.2.23 - resolution: "@next/eslint-plugin-next@npm:14.2.23" +"@napi-rs/wasm-runtime@npm:^0.2.11": + version: 0.2.11 + resolution: "@napi-rs/wasm-runtime@npm:0.2.11" dependencies: - glob: "npm:10.3.10" - checksum: 10/e46513a7601bf682f1e60cc668188cf2c9f0471be73ffbbac69da240e9f91c6b9c3aad3e83a8da54c0ba8bce37cc6368bbafb04b74b385d5df0c36dde09a3217 + "@emnapi/core": "npm:^1.4.3" + "@emnapi/runtime": "npm:^1.4.3" + "@tybys/wasm-util": "npm:^0.9.0" + checksum: 10/e30fe3060474c5018e160231df0531d62b5e22f4736ecd49c04ca6cadacb2acf59b9205435794cd5b898e41e2e3ddb6523e93b97799bd1f4d0751557de6e38e4 languageName: node linkType: hard -"@next/mdx@npm:^15.1.4": - version: 15.1.6 - resolution: "@next/mdx@npm:15.1.6" +"@next/env@npm:15.3.3": + version: 15.3.3 + resolution: "@next/env@npm:15.3.3" + checksum: 10/f71fd8b397c60b80ee2ba836152d2c8bc772f4f840b976bfd82ca0c1452539b4832a1ce6702a90da1d4edb874383944ea2662add5c0729423cd4d1cb2e58fc3d + languageName: node + linkType: hard + +"@next/eslint-plugin-next@npm:15.3.3": + version: 15.3.3 + resolution: "@next/eslint-plugin-next@npm:15.3.3" + dependencies: + fast-glob: "npm:3.3.1" + checksum: 10/08b19a39fa01ac69c7b117a29ebdb193353a29cb3d51b2e3f72fabd7f2b014d08e37d819aed8e440a8a0a6e1acd9053dbf939b5f76603e6a87de0042fbf0bd4b + languageName: node + linkType: hard + +"@next/mdx@npm:15.3.3": + version: 15.3.3 + resolution: "@next/mdx@npm:15.3.3" dependencies: source-map: "npm:^0.7.0" peerDependencies: @@ -530,69 +761,62 @@ __metadata: optional: true "@mdx-js/react": optional: true - checksum: 10/3b46e99934543df94bcb335dddab794db4fcaff09223343e9e00597d3df1e094f16dd619c433fb2fa7fff38c3da57b3118cbc010cdeb9790d0cf01e6c37016e8 + checksum: 10/5583f01e986322bee6eae1052fce27964b33796b8fbd2ea360340a65ccf60cd348c614524bcbf8323be178cace1da5c74f45f8a111cf9e62682aad3a0a9d12e3 languageName: node linkType: hard -"@next/swc-darwin-arm64@npm:14.2.26": - version: 14.2.26 - resolution: "@next/swc-darwin-arm64@npm:14.2.26" +"@next/swc-darwin-arm64@npm:15.3.3": + version: 15.3.3 + resolution: "@next/swc-darwin-arm64@npm:15.3.3" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@next/swc-darwin-x64@npm:14.2.26": - version: 14.2.26 - resolution: "@next/swc-darwin-x64@npm:14.2.26" +"@next/swc-darwin-x64@npm:15.3.3": + version: 15.3.3 + resolution: "@next/swc-darwin-x64@npm:15.3.3" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@next/swc-linux-arm64-gnu@npm:14.2.26": - version: 14.2.26 - resolution: "@next/swc-linux-arm64-gnu@npm:14.2.26" +"@next/swc-linux-arm64-gnu@npm:15.3.3": + version: 15.3.3 + resolution: "@next/swc-linux-arm64-gnu@npm:15.3.3" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"@next/swc-linux-arm64-musl@npm:14.2.26": - version: 14.2.26 - resolution: "@next/swc-linux-arm64-musl@npm:14.2.26" +"@next/swc-linux-arm64-musl@npm:15.3.3": + version: 15.3.3 + resolution: "@next/swc-linux-arm64-musl@npm:15.3.3" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"@next/swc-linux-x64-gnu@npm:14.2.26": - version: 14.2.26 - resolution: "@next/swc-linux-x64-gnu@npm:14.2.26" +"@next/swc-linux-x64-gnu@npm:15.3.3": + version: 15.3.3 + resolution: "@next/swc-linux-x64-gnu@npm:15.3.3" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"@next/swc-linux-x64-musl@npm:14.2.26": - version: 14.2.26 - resolution: "@next/swc-linux-x64-musl@npm:14.2.26" +"@next/swc-linux-x64-musl@npm:15.3.3": + version: 15.3.3 + resolution: "@next/swc-linux-x64-musl@npm:15.3.3" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"@next/swc-win32-arm64-msvc@npm:14.2.26": - version: 14.2.26 - resolution: "@next/swc-win32-arm64-msvc@npm:14.2.26" +"@next/swc-win32-arm64-msvc@npm:15.3.3": + version: 15.3.3 + resolution: "@next/swc-win32-arm64-msvc@npm:15.3.3" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@next/swc-win32-ia32-msvc@npm:14.2.26": - version: 14.2.26 - resolution: "@next/swc-win32-ia32-msvc@npm:14.2.26" - conditions: os=win32 & cpu=ia32 - languageName: node - linkType: hard - -"@next/swc-win32-x64-msvc@npm:14.2.26": - version: 14.2.26 - resolution: "@next/swc-win32-x64-msvc@npm:14.2.26" +"@next/swc-win32-x64-msvc@npm:15.3.3": + version: 15.3.3 + resolution: "@next/swc-win32-x64-msvc@npm:15.3.3" conditions: os=win32 & cpu=x64 languageName: node linkType: hard @@ -631,13 +855,6 @@ __metadata: languageName: node linkType: hard -"@pkgjs/parseargs@npm:^0.11.0": - version: 0.11.0 - resolution: "@pkgjs/parseargs@npm:0.11.0" - checksum: 10/115e8ceeec6bc69dff2048b35c0ab4f8bbee12d8bb6c1f4af758604586d802b6e669dcb02dda61d078de42c2b4ddce41b3d9e726d7daa6b4b850f4adbf7333ff - languageName: node - linkType: hard - "@rtsao/scc@npm:^1.1.0": version: 1.1.0 resolution: "@rtsao/scc@npm:1.1.0" @@ -645,97 +862,97 @@ __metadata: languageName: node linkType: hard -"@rushstack/eslint-patch@npm:^1.3.3": - version: 1.10.5 - resolution: "@rushstack/eslint-patch@npm:1.10.5" - checksum: 10/769d130dfb088c21e7ce72b552ea58c0d6d790cfe9fcadc4cd66e1282a0213a2c6b570d679723e0d3792a6b6ebfcbdeb5e785261d196017840853b8a5c57dfea +"@rushstack/eslint-patch@npm:^1.10.3": + version: 1.11.0 + resolution: "@rushstack/eslint-patch@npm:1.11.0" + checksum: 10/9bb3eb4a48a9a55e31d302b8b99f405e0f3e436fc3cda8c869fdd3fefd3ac398f5a353cceaa6c8cc5e5baf03ccd88d7965fbd25eb111f1f334415f95fa0f996d languageName: node linkType: hard -"@shikijs/core@npm:1.26.1": - version: 1.26.1 - resolution: "@shikijs/core@npm:1.26.1" +"@shikijs/core@npm:1.29.2": + version: 1.29.2 + resolution: "@shikijs/core@npm:1.29.2" dependencies: - "@shikijs/engine-javascript": "npm:1.26.1" - "@shikijs/engine-oniguruma": "npm:1.26.1" - "@shikijs/types": "npm:1.26.1" + "@shikijs/engine-javascript": "npm:1.29.2" + "@shikijs/engine-oniguruma": "npm:1.29.2" + "@shikijs/types": "npm:1.29.2" "@shikijs/vscode-textmate": "npm:^10.0.1" "@types/hast": "npm:^3.0.4" hast-util-to-html: "npm:^9.0.4" - checksum: 10/d70dd7e267da624bdc098f9f0295699d30d6bb0873a0c7f239f0664f253532af395208efe10cb0ad6f96b8c63fee439ce7ddbf5bd60b41149e2911fc3c55fc8f + checksum: 10/83dc5e86efc587d513268175ff43e8273567d2c6616d725bff15b08cf243d90f9371d6fa76ba49bb0e9823fc9947c8d8c650c81cfb19c3eb726178326f639a55 languageName: node linkType: hard -"@shikijs/engine-javascript@npm:1.26.1": - version: 1.26.1 - resolution: "@shikijs/engine-javascript@npm:1.26.1" +"@shikijs/engine-javascript@npm:1.29.2": + version: 1.29.2 + resolution: "@shikijs/engine-javascript@npm:1.29.2" dependencies: - "@shikijs/types": "npm:1.26.1" + "@shikijs/types": "npm:1.29.2" "@shikijs/vscode-textmate": "npm:^10.0.1" - oniguruma-to-es: "npm:0.10.0" - checksum: 10/fd7dac25fe4310bcd055af5163044fa598a65ec54376938f2ee70b8ab864a4d2f4bba2e76353d739ffcf071ffbc57b16147f47e5c9f950bf82f826cf88d3dd85 + oniguruma-to-es: "npm:^2.2.0" + checksum: 10/b49461ff7152650ffdbd77332d1c70e24a2ff1abe869e1038694b410194c6403fe5e8fce104fdd305d10c18702a50c1edbdb87172aa09f11340bc1203ed38488 languageName: node linkType: hard -"@shikijs/engine-oniguruma@npm:1.26.1": - version: 1.26.1 - resolution: "@shikijs/engine-oniguruma@npm:1.26.1" +"@shikijs/engine-oniguruma@npm:1.29.2": + version: 1.29.2 + resolution: "@shikijs/engine-oniguruma@npm:1.29.2" dependencies: - "@shikijs/types": "npm:1.26.1" + "@shikijs/types": "npm:1.29.2" "@shikijs/vscode-textmate": "npm:^10.0.1" - checksum: 10/17b3355fc226f58ef67d419c9e64a4dc99a63481c66f7ec55fdfb5035363605359414211e40ac8260db9c10c507e587dfac1061c0f57f111050e921e38cd58ef + checksum: 10/bb3e2c01da84d573251ebc289b1ecf815261024dea5bddb93ad56c3504a71cde3630db070be401ed3bbcd23a8a839ec78984a82317f9c9d0bba58daed935b781 languageName: node linkType: hard -"@shikijs/langs@npm:1.26.1": - version: 1.26.1 - resolution: "@shikijs/langs@npm:1.26.1" +"@shikijs/langs@npm:1.29.2": + version: 1.29.2 + resolution: "@shikijs/langs@npm:1.29.2" dependencies: - "@shikijs/types": "npm:1.26.1" - checksum: 10/b3909ffa30a89aa81e21da3c0af9388dfadab4f5ce9ce6f5a1cc3f7728e46702c02720123bad49dcd3f02e823c0ce9d533534164b0feb57856d2f8ee9504bce2 + "@shikijs/types": "npm:1.29.2" + checksum: 10/01f62d31c653c718a992918357e54d2d312c8da407997565fc19056fbf47f0fadc0f9f4b5fe1e1ba7b7d08e3984fb1f962159503ef0edd81fab5ee8bfdbf9080 languageName: node linkType: hard -"@shikijs/themes@npm:1.26.1": - version: 1.26.1 - resolution: "@shikijs/themes@npm:1.26.1" +"@shikijs/themes@npm:1.29.2": + version: 1.29.2 + resolution: "@shikijs/themes@npm:1.29.2" dependencies: - "@shikijs/types": "npm:1.26.1" - checksum: 10/5e2f5fe828f1b74dcc4027239768b3fe91567a5e07c3d014747627a7bd8a5ecf22460c59c20924172a96d99f4deed3e81e6f377e5f81239d6c6666d09e12fbd6 + "@shikijs/types": "npm:1.29.2" + checksum: 10/b81606dd882136e3fd751d0829133b5e66b10b8e32bd52ce16e7eac8755891c23e43f3ce06e65b97a75d2bc3b17e7fdb9115e9812679bb820ab163915868fd8b languageName: node linkType: hard -"@shikijs/types@npm:1.26.1": - version: 1.26.1 - resolution: "@shikijs/types@npm:1.26.1" +"@shikijs/types@npm:1.29.2": + version: 1.29.2 + resolution: "@shikijs/types@npm:1.29.2" dependencies: "@shikijs/vscode-textmate": "npm:^10.0.1" "@types/hast": "npm:^3.0.4" - checksum: 10/68ad9307424012cb833c02b7e0db4f0792d6ff9b633591318c76edb5a4ffb84da0de56dbe33b9b62ae810a878fdfd4f9ff6655a067997c664d9b0436266bcb16 + checksum: 10/579e64b6e8cb83023232b8060b08f51cff3909b199d0d1a0c58ed500c898dd34b74bf0457336fa2e6bee1005889e198d7d924347ad616eee30c6ae4c89a67ab8 languageName: node linkType: hard "@shikijs/vscode-textmate@npm:^10.0.1": - version: 10.0.1 - resolution: "@shikijs/vscode-textmate@npm:10.0.1" - checksum: 10/8bb005efbf472a9cac19bb5fb0bb1a2b612e128122e5a9d7b2bb2af674c29912db0e59c547ec458e5333f8f7ac7a8f054a24cb653f11dc20951e299933b416e4 + version: 10.0.2 + resolution: "@shikijs/vscode-textmate@npm:10.0.2" + checksum: 10/d924cba8a01cd9ca12f56ba097d628fdb81455abb85884c8d8a5ae85b628a37dd5907e7691019b97107bd6608c866adf91ba04a1c3bba391281c88e386c044ea languageName: node linkType: hard -"@storybook/components@npm:8.6.12": - version: 8.6.12 - resolution: "@storybook/components@npm:8.6.12" +"@storybook/components@npm:8.6.14": + version: 8.6.14 + resolution: "@storybook/components@npm:8.6.14" peerDependencies: storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 - checksum: 10/ccc6af275bdfbc66de8afb272f59b2b4b6b76bb2961903335cb62e7defae4a2368bd8f5a2008f8598dd8417e5368d824bce836ca96c3c6ff659dbf2f081ec0dd + checksum: 10/d3647505510313aa3c32fd1f8f202eda723ad99bd353b20aa929c5ecab4edc3c86ad06d0eac02f3c6d948e88f13f65ca5fa35ef27c079ef1b92abe8692f23699 languageName: node linkType: hard -"@storybook/core@npm:8.6.12": - version: 8.6.12 - resolution: "@storybook/core@npm:8.6.12" +"@storybook/core@npm:8.6.14": + version: 8.6.14 + resolution: "@storybook/core@npm:8.6.14" dependencies: - "@storybook/theming": "npm:8.6.12" + "@storybook/theming": "npm:8.6.14" better-opn: "npm:^3.0.2" browser-assert: "npm:^1.2.1" esbuild: "npm:^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0 || ^0.24.0 || ^0.25.0" @@ -751,7 +968,7 @@ __metadata: peerDependenciesMeta: prettier: optional: true - checksum: 10/78776f51b9eae00f9387421b33b646b1dc67ef833fd6272de03399daa7f0ffa248c65b5f24d5d2a9af923a029d06d84d5425e3455302ece542bf47c7a9ec0df6 + checksum: 10/8f8c811edd4ea8dcedcc63a79b3168dc83aa0401e3760990cb5995ea6beaac4026c6ccc1046182f41eed7c09333005f3348d8b42f89fc5dd5b2ce011a9d2a48f languageName: node linkType: hard @@ -762,92 +979,91 @@ __metadata: languageName: node linkType: hard -"@storybook/manager-api@npm:8.6.12": - version: 8.6.12 - resolution: "@storybook/manager-api@npm:8.6.12" +"@storybook/manager-api@npm:8.6.14": + version: 8.6.14 + resolution: "@storybook/manager-api@npm:8.6.14" peerDependencies: storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 - checksum: 10/d1c44c6649a024c4007461c12a15337f5d13532dbaccc4c02f71bd99599fb973e2574eb8f1bc2d93e05da24e4ae43fa47ec637a7c4cccf5ffc67045cafbf087c + checksum: 10/4544b317050b81574f1cd6f911dcb99ee2adbd7190555209171a7dd2233cd331165fa11c16a5977ebe58eeaf26c86bbfcb23f701cfd79a10f0d034dae65197bd languageName: node linkType: hard -"@storybook/preview-api@npm:8.6.12": - version: 8.6.12 - resolution: "@storybook/preview-api@npm:8.6.12" +"@storybook/preview-api@npm:8.6.14": + version: 8.6.14 + resolution: "@storybook/preview-api@npm:8.6.14" peerDependencies: storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 - checksum: 10/d24f11e4e54e9e51297b0f87e1d462b3f14a974b4681f31d93b62b0706ce5b5ed4ffaaac521ec049dcb0e08e7aa7590f2e039aee4bbe9f85033d69474d982f23 + checksum: 10/9b77288f2f627a7c70cfd3e88bdc4348c1425fab6b333ed77efb913e45881bcdf2ca67f1174e47fe978a7993c2a653fb8accf518ba51441cfb9450145101e9d8 languageName: node linkType: hard -"@storybook/react-dom-shim@npm:8.6.12": - version: 8.6.12 - resolution: "@storybook/react-dom-shim@npm:8.6.12" +"@storybook/react-dom-shim@npm:8.6.14": + version: 8.6.14 + resolution: "@storybook/react-dom-shim@npm:8.6.14" peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta - storybook: ^8.6.12 - checksum: 10/7677b4fae978209af239471f9eb609db4318815bd4249a0f48b9875482d9ae910b93fbe4db5d7f794ecc2a1249edf40da26af9de673c941c48fccc4007819c96 + storybook: ^8.6.14 + checksum: 10/d14d970b98dc8266d4df80225538fb537449c15877f0f54465dfe52242f0c3f041c975824cc2894f72a3a8023fdffa0a281d90325b95297858e3684913b3cc15 languageName: node linkType: hard "@storybook/react@npm:^8.6.8": - version: 8.6.12 - resolution: "@storybook/react@npm:8.6.12" + version: 8.6.14 + resolution: "@storybook/react@npm:8.6.14" dependencies: - "@storybook/components": "npm:8.6.12" + "@storybook/components": "npm:8.6.14" "@storybook/global": "npm:^5.0.0" - "@storybook/manager-api": "npm:8.6.12" - "@storybook/preview-api": "npm:8.6.12" - "@storybook/react-dom-shim": "npm:8.6.12" - "@storybook/theming": "npm:8.6.12" + "@storybook/manager-api": "npm:8.6.14" + "@storybook/preview-api": "npm:8.6.14" + "@storybook/react-dom-shim": "npm:8.6.14" + "@storybook/theming": "npm:8.6.14" peerDependencies: - "@storybook/test": 8.6.12 + "@storybook/test": 8.6.14 react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta - storybook: ^8.6.12 + storybook: ^8.6.14 typescript: ">= 4.2.x" peerDependenciesMeta: "@storybook/test": optional: true typescript: optional: true - checksum: 10/d8258c82743906f48a872a781f3e5a63e9ce3fda2ba3b911e959cf62ebda43989b23746257d97905addb7142ac7e53d0089dc178bcbeea48ed4d37d025dd047b + checksum: 10/a8710dcb80da9df4a78cfb3560a8c0c31c6f6c04902aa95446d4e40f6a9179770ead6f9a0a06fa44d00677cd1cd92eb60fdc57f433035ec722275847139671a4 languageName: node linkType: hard -"@storybook/theming@npm:8.6.12": - version: 8.6.12 - resolution: "@storybook/theming@npm:8.6.12" +"@storybook/theming@npm:8.6.14": + version: 8.6.14 + resolution: "@storybook/theming@npm:8.6.14" peerDependencies: storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 - checksum: 10/c811d9dbb9eaaa680b922111fca126a2985f2238dfb01c1cd23184323eea12899dc9f079063ac42c5e63b0c83de326bd9cc17241e4060ff04e860c57a55fb8b9 + checksum: 10/6936ea3348968fe598ad47421c11a78c6ee2ce62336ea1ce9cb8257e9faa2553d3ac3e443f8a36d35a41b0d60eb169231516649c710582ec68fdead4f23ffc0e languageName: node linkType: hard -"@swc/counter@npm:^0.1.3": +"@swc/counter@npm:0.1.3": version: 0.1.3 resolution: "@swc/counter@npm:0.1.3" checksum: 10/df8f9cfba9904d3d60f511664c70d23bb323b3a0803ec9890f60133954173047ba9bdeabce28cd70ba89ccd3fd6c71c7b0bd58be85f611e1ffbe5d5c18616598 languageName: node linkType: hard -"@swc/helpers@npm:0.5.5": - version: 0.5.5 - resolution: "@swc/helpers@npm:0.5.5" +"@swc/helpers@npm:0.5.15": + version: 0.5.15 + resolution: "@swc/helpers@npm:0.5.15" dependencies: - "@swc/counter": "npm:^0.1.3" - tslib: "npm:^2.4.0" - checksum: 10/1c5ef04f642542212df28c669438f3e0f459dcde7b448a5b1fcafb2e9e4f13e76d8428535a270e91ed123dd2a21189dbed34086b88a8cf68baf84984d6d0e39b + tslib: "npm:^2.8.0" + checksum: 10/e3f32c6deeecfb0fa3f22edff03a7b358e7ce16d27b0f1c8b5cdc3042c5c4ce4da6eac0b781ab7cc4f54696ece657467d56734fb26883439fb00017385364c4c languageName: node linkType: hard -"@types/acorn@npm:^4.0.0": - version: 4.0.6 - resolution: "@types/acorn@npm:4.0.6" +"@tybys/wasm-util@npm:^0.9.0": + version: 0.9.0 + resolution: "@tybys/wasm-util@npm:0.9.0" dependencies: - "@types/estree": "npm:*" - checksum: 10/e00671d5055d06b07feccb8c2841467a4bdd1ab95a29e191d51cacc08c496e1ba1f54edeefab274bb2ba51cb45b0aaaa662a63897650e9d02e9997ad82124ae4 + tslib: "npm:^2.4.0" + checksum: 10/aa58e64753a420ad1eefaf7bacef3dda61d74f9336925943d9244132d5b48d9242f734f1e707fd5ccfa6dd1d8ec8e6debc234b4dedb3a5b0d8486d1f373350b2 languageName: node linkType: hard @@ -870,9 +1086,9 @@ __metadata: linkType: hard "@types/estree@npm:*, @types/estree@npm:^1.0.0": - version: 1.0.6 - resolution: "@types/estree@npm:1.0.6" - checksum: 10/9d35d475095199c23e05b431bcdd1f6fec7380612aed068b14b2a08aa70494de8a9026765a5a91b1073f636fb0368f6d8973f518a31391d519e20c59388ed88d + version: 1.0.8 + resolution: "@types/estree@npm:1.0.8" + checksum: 10/25a4c16a6752538ffde2826c2cc0c6491d90e69cd6187bef4a006dd2c3c45469f049e643d7e516c515f21484dc3d48fd5c870be158a5beb72f5baf3dc43e4099 languageName: node linkType: hard @@ -892,7 +1108,7 @@ __metadata: languageName: node linkType: hard -"@types/mdast@npm:^4.0.0": +"@types/mdast@npm:^4.0.0, @types/mdast@npm:^4.0.4": version: 4.0.4 resolution: "@types/mdast@npm:4.0.4" dependencies: @@ -909,44 +1125,36 @@ __metadata: linkType: hard "@types/ms@npm:*": - version: 0.7.34 - resolution: "@types/ms@npm:0.7.34" - checksum: 10/f38d36e7b6edecd9badc9cf50474159e9da5fa6965a75186cceaf883278611b9df6669dc3a3cc122b7938d317b68a9e3d573d316fcb35d1be47ec9e468c6bd8a + version: 2.1.0 + resolution: "@types/ms@npm:2.1.0" + checksum: 10/532d2ebb91937ccc4a89389715e5b47d4c66e708d15942fe6cc25add6dc37b2be058230a327dd50f43f89b8b6d5d52b74685a9e8f70516edfc9bdd6be910eff4 languageName: node linkType: hard "@types/node@npm:^20": - version: 20.17.30 - resolution: "@types/node@npm:20.17.30" + version: 20.19.0 + resolution: "@types/node@npm:20.19.0" dependencies: - undici-types: "npm:~6.19.2" - checksum: 10/69fd3b177417be77b459e8f1dd4e78c85c686167086920fbf35a9fda301709bbeee6a87ad2591fb1ddd96c65e725ec6bb527a06496626a1c94367d1361048f8d + undici-types: "npm:~6.21.0" + checksum: 10/76cc44487faa0bf5302c84e5317de4b9727ea4e4b86d59d18d25435f4ccd7e6c584614dea061256f24a097c25a1d82dac1cd134357b42ae28006ba113c97f490 languageName: node linkType: hard -"@types/prop-types@npm:*": - version: 15.7.14 - resolution: "@types/prop-types@npm:15.7.14" - checksum: 10/d0c5407b9ccc3dd5fae0ccf9b1007e7622ba5e6f1c18399b4f24dff33619d469da4b9fa918a374f19dc0d9fe6a013362aab0b844b606cfc10676efba3f5f736d - languageName: node - linkType: hard - -"@types/react-dom@npm:^18.0.0": - version: 18.3.7 - resolution: "@types/react-dom@npm:18.3.7" +"@types/react-dom@npm:19.1.6": + version: 19.1.6 + resolution: "@types/react-dom@npm:19.1.6" peerDependencies: - "@types/react": ^18.0.0 - checksum: 10/317569219366d487a3103ba1e5e47154e95a002915fdcf73a44162c48fe49c3a57fcf7f57fc6979e70d447112681e6b13c6c3c1df289db8b544df4aab2d318f3 + "@types/react": ^19.0.0 + checksum: 10/b5b20b7f0797f34c5a11915b74dcf8b3b7a9da9fea90279975ce6f150ca5d31bb069dbb0838638a5e9e168098aa4bb4a6f61d078efa1bbb55d7f0bdfe47bb142 languageName: node linkType: hard -"@types/react@npm:^18.0.0": - version: 18.3.21 - resolution: "@types/react@npm:18.3.21" +"@types/react@npm:19.1.8": + version: 19.1.8 + resolution: "@types/react@npm:19.1.8" dependencies: - "@types/prop-types": "npm:*" csstype: "npm:^3.0.2" - checksum: 10/89adc2fe391fd63b620db0aaa10b2be89fad338039415fd748e60c962e47bf2b0f1897cb5226f181eda963f37a1c8ac1bf0b3b29a0e35313bacd0355e5d6c736 + checksum: 10/a3e6fe0f60f22828ef887f30993aa147b71532d7b1219dd00d246277eb7a9ca01ec533096237fa21ca1bccb3653373b4e8e59e5ae59f9c793058384bbc1f4d5c languageName: node linkType: hard @@ -965,120 +1173,144 @@ __metadata: linkType: hard "@typescript-eslint/eslint-plugin@npm:^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0": - version: 8.19.1 - resolution: "@typescript-eslint/eslint-plugin@npm:8.19.1" + version: 8.34.0 + resolution: "@typescript-eslint/eslint-plugin@npm:8.34.0" dependencies: "@eslint-community/regexpp": "npm:^4.10.0" - "@typescript-eslint/scope-manager": "npm:8.19.1" - "@typescript-eslint/type-utils": "npm:8.19.1" - "@typescript-eslint/utils": "npm:8.19.1" - "@typescript-eslint/visitor-keys": "npm:8.19.1" + "@typescript-eslint/scope-manager": "npm:8.34.0" + "@typescript-eslint/type-utils": "npm:8.34.0" + "@typescript-eslint/utils": "npm:8.34.0" + "@typescript-eslint/visitor-keys": "npm:8.34.0" graphemer: "npm:^1.4.0" - ignore: "npm:^5.3.1" + ignore: "npm:^7.0.0" natural-compare: "npm:^1.4.0" - ts-api-utils: "npm:^2.0.0" + ts-api-utils: "npm:^2.1.0" peerDependencies: - "@typescript-eslint/parser": ^8.0.0 || ^8.0.0-alpha.0 + "@typescript-eslint/parser": ^8.34.0 eslint: ^8.57.0 || ^9.0.0 - typescript: ">=4.8.4 <5.8.0" - checksum: 10/c9a6d3181ec01068075b85ad3ac454910b4452281d60c775cc7229827f6d6a076b7336f5f07a7ad89bf08b3224f6a49aa20342b9438702393bee0aa7315d23b2 + typescript: ">=4.8.4 <5.9.0" + checksum: 10/224f9e8a596e3c37fade2f2a1a9efce2fad652a768710693458e2b7c7f88c3a0e7bbbbc46d34d839c9373861fac542de6b9a7e132e36e2819b63840b9529e605 languageName: node linkType: hard "@typescript-eslint/parser@npm:^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0": - version: 8.19.1 - resolution: "@typescript-eslint/parser@npm:8.19.1" + version: 8.34.0 + resolution: "@typescript-eslint/parser@npm:8.34.0" dependencies: - "@typescript-eslint/scope-manager": "npm:8.19.1" - "@typescript-eslint/types": "npm:8.19.1" - "@typescript-eslint/typescript-estree": "npm:8.19.1" - "@typescript-eslint/visitor-keys": "npm:8.19.1" + "@typescript-eslint/scope-manager": "npm:8.34.0" + "@typescript-eslint/types": "npm:8.34.0" + "@typescript-eslint/typescript-estree": "npm:8.34.0" + "@typescript-eslint/visitor-keys": "npm:8.34.0" debug: "npm:^4.3.4" peerDependencies: eslint: ^8.57.0 || ^9.0.0 - typescript: ">=4.8.4 <5.8.0" - checksum: 10/da3db63ff655cf0fb91745ba8e52d853386f601cf6106d36f4541efcb9e2c6c3b82c6743b15680eff9eafeccaf31c9b26191a955e66ae19de9172f67335463ab + typescript: ">=4.8.4 <5.9.0" + checksum: 10/b4c03ff2f09fd800a8f28c24289d24e2f4bfb4745c122f5f496bf832b06f0f37b1ab31ce8d7590ff1f83253de3306d145ef7b3c7b853a4ae716cb7ff443d1c27 languageName: node linkType: hard -"@typescript-eslint/scope-manager@npm:8.19.1": - version: 8.19.1 - resolution: "@typescript-eslint/scope-manager@npm:8.19.1" +"@typescript-eslint/project-service@npm:8.34.0": + version: 8.34.0 + resolution: "@typescript-eslint/project-service@npm:8.34.0" dependencies: - "@typescript-eslint/types": "npm:8.19.1" - "@typescript-eslint/visitor-keys": "npm:8.19.1" - checksum: 10/6ffc78b15367f211eb6650459ca2bb6bfe4c1fa95a3474adc08ee9a20c250b2e0e02fd99be36bd3dad74967ecd9349e792b5d818d85735cba40f1b5c236074d1 - languageName: node - linkType: hard - -"@typescript-eslint/type-utils@npm:8.19.1": - version: 8.19.1 - resolution: "@typescript-eslint/type-utils@npm:8.19.1" - dependencies: - "@typescript-eslint/typescript-estree": "npm:8.19.1" - "@typescript-eslint/utils": "npm:8.19.1" + "@typescript-eslint/tsconfig-utils": "npm:^8.34.0" + "@typescript-eslint/types": "npm:^8.34.0" debug: "npm:^4.3.4" - ts-api-utils: "npm:^2.0.0" + peerDependencies: + typescript: ">=4.8.4 <5.9.0" + checksum: 10/04763896215c208c6b29e0b4f66ee0621878cd88fb6d9008c543db57f1d6b5d7fcc88f048c9a66ba2ed797f68e563c350e1b65403349ef75a4bc419072cef3c8 + languageName: node + linkType: hard + +"@typescript-eslint/scope-manager@npm:8.34.0": + version: 8.34.0 + resolution: "@typescript-eslint/scope-manager@npm:8.34.0" + dependencies: + "@typescript-eslint/types": "npm:8.34.0" + "@typescript-eslint/visitor-keys": "npm:8.34.0" + checksum: 10/fec7bb94fb3848bdf5ab9cfaf634e56aec3ed9bc4d546f65d83bb6511452e5a4b9eed5d09f54efceb9fa3b23a451d409735359237e8c0d51233d6537e5449fa7 + languageName: node + linkType: hard + +"@typescript-eslint/tsconfig-utils@npm:8.34.0, @typescript-eslint/tsconfig-utils@npm:^8.34.0": + version: 8.34.0 + resolution: "@typescript-eslint/tsconfig-utils@npm:8.34.0" + peerDependencies: + typescript: ">=4.8.4 <5.9.0" + checksum: 10/cbbca9526bd9c0309c77f9436f68c2c06712779a593a17757f1f7558ece27d9f40db2b37ebf12bd9e19cf227479083b7973c502436a0954a08406d8a598910ba + languageName: node + linkType: hard + +"@typescript-eslint/type-utils@npm:8.34.0": + version: 8.34.0 + resolution: "@typescript-eslint/type-utils@npm:8.34.0" + dependencies: + "@typescript-eslint/typescript-estree": "npm:8.34.0" + "@typescript-eslint/utils": "npm:8.34.0" + debug: "npm:^4.3.4" + ts-api-utils: "npm:^2.1.0" peerDependencies: eslint: ^8.57.0 || ^9.0.0 - typescript: ">=4.8.4 <5.8.0" - checksum: 10/123ecda88b057d6a4b68226701f435661440a420fda88cba60b49d7fb3e4f49483164ff174f259e28c0beabb0ed04500462a20faefd78331ba202bf54b01e3ef + typescript: ">=4.8.4 <5.9.0" + checksum: 10/e7c565868b18d66ce5de016455c5ba2dc625a845e05ad563bfdf08b1753faa11d9aef22b9dc5071c57b6e73932748505715e7b47993757f1bc244d4d6f70d688 languageName: node linkType: hard -"@typescript-eslint/types@npm:8.19.1": - version: 8.19.1 - resolution: "@typescript-eslint/types@npm:8.19.1" - checksum: 10/5833a5f8fdac4a490dd3906a0243a0713fbf138fabb451870c70b0b089c539a9624b467b0913ddc0a225a8284342e7fd31cd506dec53c1a6d8f3c8c8902b9cae +"@typescript-eslint/types@npm:8.34.0, @typescript-eslint/types@npm:^8.34.0": + version: 8.34.0 + resolution: "@typescript-eslint/types@npm:8.34.0" + checksum: 10/da4dcee51e78139bdeb5832df836528c519a22c2e39b7737ae660afe024576030165424079f423a131ad56e2dca8f033943d6b48a54b4f4d296a6f7f83f5b494 languageName: node linkType: hard -"@typescript-eslint/typescript-estree@npm:8.19.1": - version: 8.19.1 - resolution: "@typescript-eslint/typescript-estree@npm:8.19.1" +"@typescript-eslint/typescript-estree@npm:8.34.0": + version: 8.34.0 + resolution: "@typescript-eslint/typescript-estree@npm:8.34.0" dependencies: - "@typescript-eslint/types": "npm:8.19.1" - "@typescript-eslint/visitor-keys": "npm:8.19.1" + "@typescript-eslint/project-service": "npm:8.34.0" + "@typescript-eslint/tsconfig-utils": "npm:8.34.0" + "@typescript-eslint/types": "npm:8.34.0" + "@typescript-eslint/visitor-keys": "npm:8.34.0" debug: "npm:^4.3.4" fast-glob: "npm:^3.3.2" is-glob: "npm:^4.0.3" minimatch: "npm:^9.0.4" semver: "npm:^7.6.0" - ts-api-utils: "npm:^2.0.0" + ts-api-utils: "npm:^2.1.0" peerDependencies: - typescript: ">=4.8.4 <5.8.0" - checksum: 10/5de467452d5ef1a380d441b06cd0134652a0c98cdb4ce31b93eb589f7dc75ef60364d03fd80ca0a48d0c8b268f7258d4f6528b16fe1b89442d60a4bc960fe5f5 + typescript: ">=4.8.4 <5.9.0" + checksum: 10/26817d4c948253eb6a8f49fcd7a8f74c4ffeae7943aef9e1cb90d1b7adbc8e0f66605b0b318dc6eee3eda212882e278a300776b26fe4e2319712cd9822a3a4e4 languageName: node linkType: hard -"@typescript-eslint/utils@npm:8.19.1": - version: 8.19.1 - resolution: "@typescript-eslint/utils@npm:8.19.1" +"@typescript-eslint/utils@npm:8.34.0": + version: 8.34.0 + resolution: "@typescript-eslint/utils@npm:8.34.0" dependencies: - "@eslint-community/eslint-utils": "npm:^4.4.0" - "@typescript-eslint/scope-manager": "npm:8.19.1" - "@typescript-eslint/types": "npm:8.19.1" - "@typescript-eslint/typescript-estree": "npm:8.19.1" + "@eslint-community/eslint-utils": "npm:^4.7.0" + "@typescript-eslint/scope-manager": "npm:8.34.0" + "@typescript-eslint/types": "npm:8.34.0" + "@typescript-eslint/typescript-estree": "npm:8.34.0" peerDependencies: eslint: ^8.57.0 || ^9.0.0 - typescript: ">=4.8.4 <5.8.0" - checksum: 10/bb92116a53fe143ee87e830941afb21d4222a64ca3f2b6dac5c2d9984f981408e60e52b04c32d95208896075ac222fb4ee631c5b0c4826b87d4bd8091c421ab1 + typescript: ">=4.8.4 <5.9.0" + checksum: 10/c51d2015e8076dd2a9d8255746889130aaf298cf9ff8f73114dcf7148f34536d47d883880eec7e3d89ec3f746c2d3f2b749e8fef5e8ad9914132deb5c013efbd languageName: node linkType: hard -"@typescript-eslint/visitor-keys@npm:8.19.1": - version: 8.19.1 - resolution: "@typescript-eslint/visitor-keys@npm:8.19.1" +"@typescript-eslint/visitor-keys@npm:8.34.0": + version: 8.34.0 + resolution: "@typescript-eslint/visitor-keys@npm:8.34.0" dependencies: - "@typescript-eslint/types": "npm:8.19.1" + "@typescript-eslint/types": "npm:8.34.0" eslint-visitor-keys: "npm:^4.2.0" - checksum: 10/510eb196e7b7d59d3981d672a75454615159e931fe78e2a64b09607c3cfa45110709b0eb5ac3dd271d757a0d98cf4868ad2f45bf9193f96e9efec3efa92a19c1 + checksum: 10/8a591cb9f922b6fd92107ebdf255425cf7ecd56281d032d944fb38e6be319e6cca7dc49bab6ad1d46390d2ca023c3413c03775e638ec5fd70172150debf7636a languageName: node linkType: hard -"@uiw/codemirror-extensions-basic-setup@npm:4.23.7": - version: 4.23.7 - resolution: "@uiw/codemirror-extensions-basic-setup@npm:4.23.7" +"@uiw/codemirror-extensions-basic-setup@npm:4.23.13": + version: 4.23.13 + resolution: "@uiw/codemirror-extensions-basic-setup@npm:4.23.13" dependencies: "@codemirror/autocomplete": "npm:^6.0.0" "@codemirror/commands": "npm:^6.0.0" @@ -1095,13 +1327,13 @@ __metadata: "@codemirror/search": ">=6.0.0" "@codemirror/state": ">=6.0.0" "@codemirror/view": ">=6.0.0" - checksum: 10/7b8cbb9ccc931bc1a6909d009e653f78797e4b851aa9fb8e11f90ae1cea233e643a1951ad4ad9e10123ef166808acee1acff24732ea9fc15cd77164f6b179b91 + checksum: 10/35fd1894f9f7da8f94fa077a70821f92118597e2e2b12782b254b0844f06c1855508421c4cb47de7099a972ef706218c08203116aa93da4e8e1585c8d234015d languageName: node linkType: hard "@uiw/codemirror-themes@npm:^4.23.7": - version: 4.23.12 - resolution: "@uiw/codemirror-themes@npm:4.23.12" + version: 4.23.13 + resolution: "@uiw/codemirror-themes@npm:4.23.13" dependencies: "@codemirror/language": "npm:^6.0.0" "@codemirror/state": "npm:^6.0.0" @@ -1110,19 +1342,19 @@ __metadata: "@codemirror/language": ">=6.0.0" "@codemirror/state": ">=6.0.0" "@codemirror/view": ">=6.0.0" - checksum: 10/472121efadf2b9eb110030f06d657cb9693861e1ca360c81c7b0d7aa4533e6e6791737dfd14bcbe496bcb818d33f4cf6a18caf504ec628807e273441f969ef83 + checksum: 10/8c168ed1aa6185c4cc92b66f873e38f6bb50778f1ccadcc99db04cbe97c928e7b924a2f41cb40c4b26328489038d986fe9360605e1668e6c0af2ba931b79523e languageName: node linkType: hard "@uiw/react-codemirror@npm:^4.23.7": - version: 4.23.7 - resolution: "@uiw/react-codemirror@npm:4.23.7" + version: 4.23.13 + resolution: "@uiw/react-codemirror@npm:4.23.13" dependencies: "@babel/runtime": "npm:^7.18.6" "@codemirror/commands": "npm:^6.1.0" "@codemirror/state": "npm:^6.1.1" "@codemirror/theme-one-dark": "npm:^6.0.0" - "@uiw/codemirror-extensions-basic-setup": "npm:4.23.7" + "@uiw/codemirror-extensions-basic-setup": "npm:4.23.13" codemirror: "npm:^6.0.0" peerDependencies: "@babel/runtime": ">=7.11.0" @@ -1132,14 +1364,135 @@ __metadata: codemirror: ">=6.0.0" react: ">=16.8.0" react-dom: ">=16.8.0" - checksum: 10/dc6f1fd2f1863120e29ea331b2e279054bf508f00656d3fed97779f17818ae00b6cf9d74d3b0996800174d444b59702da74ca88c303db563daad85c0824fc952 + checksum: 10/51777d7eb313be0716d3597f829e6ee9982ab2dc3e36dc5219f25cdf680b82a6c0a0951d9adaca85b9c829da92f7971aa6e65bdd50e7610972d89463fe2587a1 languageName: node linkType: hard "@ungap/structured-clone@npm:^1.0.0, @ungap/structured-clone@npm:^1.2.0": - version: 1.2.1 - resolution: "@ungap/structured-clone@npm:1.2.1" - checksum: 10/6770f71e8183311b2871601ddb02d62a26373be7cf2950cb546a345a2305c75b502e36ce80166120aa2f5f1ea1562141684651ebbfcc711c58acd32035d3e545 + version: 1.3.0 + resolution: "@ungap/structured-clone@npm:1.3.0" + checksum: 10/80d6910946f2b1552a2406650051c91bbd1f24a6bf854354203d84fe2714b3e8ce4618f49cc3410494173a1c1e8e9777372fe68dce74bd45faf0a7a1a6ccf448 + languageName: node + linkType: hard + +"@unrs/resolver-binding-darwin-arm64@npm:1.7.13": + version: 1.7.13 + resolution: "@unrs/resolver-binding-darwin-arm64@npm:1.7.13" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@unrs/resolver-binding-darwin-x64@npm:1.7.13": + version: 1.7.13 + resolution: "@unrs/resolver-binding-darwin-x64@npm:1.7.13" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@unrs/resolver-binding-freebsd-x64@npm:1.7.13": + version: 1.7.13 + resolution: "@unrs/resolver-binding-freebsd-x64@npm:1.7.13" + conditions: os=freebsd & cpu=x64 + languageName: node + linkType: hard + +"@unrs/resolver-binding-linux-arm-gnueabihf@npm:1.7.13": + version: 1.7.13 + resolution: "@unrs/resolver-binding-linux-arm-gnueabihf@npm:1.7.13" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + +"@unrs/resolver-binding-linux-arm-musleabihf@npm:1.7.13": + version: 1.7.13 + resolution: "@unrs/resolver-binding-linux-arm-musleabihf@npm:1.7.13" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + +"@unrs/resolver-binding-linux-arm64-gnu@npm:1.7.13": + version: 1.7.13 + resolution: "@unrs/resolver-binding-linux-arm64-gnu@npm:1.7.13" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + +"@unrs/resolver-binding-linux-arm64-musl@npm:1.7.13": + version: 1.7.13 + resolution: "@unrs/resolver-binding-linux-arm64-musl@npm:1.7.13" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + +"@unrs/resolver-binding-linux-ppc64-gnu@npm:1.7.13": + version: 1.7.13 + resolution: "@unrs/resolver-binding-linux-ppc64-gnu@npm:1.7.13" + conditions: os=linux & cpu=ppc64 & libc=glibc + languageName: node + linkType: hard + +"@unrs/resolver-binding-linux-riscv64-gnu@npm:1.7.13": + version: 1.7.13 + resolution: "@unrs/resolver-binding-linux-riscv64-gnu@npm:1.7.13" + conditions: os=linux & cpu=riscv64 & libc=glibc + languageName: node + linkType: hard + +"@unrs/resolver-binding-linux-riscv64-musl@npm:1.7.13": + version: 1.7.13 + resolution: "@unrs/resolver-binding-linux-riscv64-musl@npm:1.7.13" + conditions: os=linux & cpu=riscv64 & libc=musl + languageName: node + linkType: hard + +"@unrs/resolver-binding-linux-s390x-gnu@npm:1.7.13": + version: 1.7.13 + resolution: "@unrs/resolver-binding-linux-s390x-gnu@npm:1.7.13" + conditions: os=linux & cpu=s390x & libc=glibc + languageName: node + linkType: hard + +"@unrs/resolver-binding-linux-x64-gnu@npm:1.7.13": + version: 1.7.13 + resolution: "@unrs/resolver-binding-linux-x64-gnu@npm:1.7.13" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + +"@unrs/resolver-binding-linux-x64-musl@npm:1.7.13": + version: 1.7.13 + resolution: "@unrs/resolver-binding-linux-x64-musl@npm:1.7.13" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + +"@unrs/resolver-binding-wasm32-wasi@npm:1.7.13": + version: 1.7.13 + resolution: "@unrs/resolver-binding-wasm32-wasi@npm:1.7.13" + dependencies: + "@napi-rs/wasm-runtime": "npm:^0.2.11" + conditions: cpu=wasm32 + languageName: node + linkType: hard + +"@unrs/resolver-binding-win32-arm64-msvc@npm:1.7.13": + version: 1.7.13 + resolution: "@unrs/resolver-binding-win32-arm64-msvc@npm:1.7.13" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@unrs/resolver-binding-win32-ia32-msvc@npm:1.7.13": + version: 1.7.13 + resolution: "@unrs/resolver-binding-win32-ia32-msvc@npm:1.7.13" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + +"@unrs/resolver-binding-win32-x64-msvc@npm:1.7.13": + version: 1.7.13 + resolution: "@unrs/resolver-binding-win32-x64-msvc@npm:1.7.13" + conditions: os=win32 & cpu=x64 languageName: node linkType: hard @@ -1153,11 +1506,11 @@ __metadata: linkType: hard "acorn@npm:^8.0.0, acorn@npm:^8.9.0": - version: 8.14.0 - resolution: "acorn@npm:8.14.0" + version: 8.15.0 + resolution: "acorn@npm:8.15.0" bin: acorn: bin/acorn - checksum: 10/6df29c35556782ca9e632db461a7f97947772c6c1d5438a81f0c873a3da3a792487e83e404d1c6c25f70513e91aa18745f6eafb1fcc3a43ecd1920b21dd173d2 + checksum: 10/77f2de5051a631cf1729c090e5759148459cdb76b5f5c70f890503d629cf5052357b0ce783c0f976dd8a93c5150f59f6d18df1def3f502396a20f81282482fa4 languageName: node linkType: hard @@ -1180,14 +1533,7 @@ __metadata: languageName: node linkType: hard -"ansi-regex@npm:^6.0.1": - version: 6.1.0 - resolution: "ansi-regex@npm:6.1.0" - checksum: 10/495834a53b0856c02acd40446f7130cb0f8284f4a39afdab20d5dc42b2e198b1196119fe887beed8f9055c4ff2055e3b2f6d4641d0be018cdfb64fedf6fc1aac - languageName: node - linkType: hard - -"ansi-styles@npm:^4.0.0, ansi-styles@npm:^4.1.0": +"ansi-styles@npm:^4.1.0": version: 4.3.0 resolution: "ansi-styles@npm:4.3.0" dependencies: @@ -1196,13 +1542,6 @@ __metadata: languageName: node linkType: hard -"ansi-styles@npm:^6.1.0": - version: 6.2.1 - resolution: "ansi-styles@npm:6.2.1" - checksum: 10/70fdf883b704d17a5dfc9cde206e698c16bcd74e7f196ab821511651aee4f9f76c9514bdfa6ca3a27b5e49138b89cb222a28caf3afe4567570139577f991df32 - languageName: node - linkType: hard - "argparse@npm:^2.0.1": version: 2.0.1 resolution: "argparse@npm:2.0.1" @@ -1228,16 +1567,18 @@ __metadata: linkType: hard "array-includes@npm:^3.1.6, array-includes@npm:^3.1.8": - version: 3.1.8 - resolution: "array-includes@npm:3.1.8" + version: 3.1.9 + resolution: "array-includes@npm:3.1.9" dependencies: - call-bind: "npm:^1.0.7" + call-bind: "npm:^1.0.8" + call-bound: "npm:^1.0.4" define-properties: "npm:^1.2.1" - es-abstract: "npm:^1.23.2" - es-object-atoms: "npm:^1.0.0" - get-intrinsic: "npm:^1.2.4" - is-string: "npm:^1.0.7" - checksum: 10/290b206c9451f181fb2b1f79a3bf1c0b66bb259791290ffbada760c79b284eef6f5ae2aeb4bcff450ebc9690edd25732c4c73a3c2b340fcc0f4563aed83bf488 + es-abstract: "npm:^1.24.0" + es-object-atoms: "npm:^1.1.1" + get-intrinsic: "npm:^1.3.0" + is-string: "npm:^1.1.1" + math-intrinsics: "npm:^1.1.0" + checksum: 10/8bfe9a58df74f326b4a76b04ee05c13d871759e888b4ee8f013145297cf5eb3c02cfa216067ebdaac5d74eb9763ac5cad77cdf2773b8ab475833701e032173aa languageName: node linkType: hard @@ -1256,16 +1597,17 @@ __metadata: linkType: hard "array.prototype.findlastindex@npm:^1.2.5": - version: 1.2.5 - resolution: "array.prototype.findlastindex@npm:1.2.5" + version: 1.2.6 + resolution: "array.prototype.findlastindex@npm:1.2.6" dependencies: - call-bind: "npm:^1.0.7" + call-bind: "npm:^1.0.8" + call-bound: "npm:^1.0.4" define-properties: "npm:^1.2.1" - es-abstract: "npm:^1.23.2" + es-abstract: "npm:^1.23.9" es-errors: "npm:^1.3.0" - es-object-atoms: "npm:^1.0.0" - es-shim-unscopables: "npm:^1.0.2" - checksum: 10/7c5c821f357cd53ab6cc305de8086430dd8d7a2485db87b13f843e868055e9582b1fd338f02338f67fc3a1603ceaf9610dd2a470b0b506f9d18934780f95b246 + es-object-atoms: "npm:^1.1.1" + es-shim-unscopables: "npm:^1.1.0" + checksum: 10/5ddb6420e820bef6ddfdcc08ce780d0fd5e627e97457919c27e32359916de5a11ce12f7c55073555e503856618eaaa70845d6ca11dcba724766f38eb1c22f7a2 languageName: node linkType: hard @@ -1346,6 +1688,13 @@ __metadata: languageName: node linkType: hard +"async-function@npm:^1.0.0": + version: 1.0.0 + resolution: "async-function@npm:1.0.0" + checksum: 10/1a09379937d846f0ce7614e75071c12826945d4e417db634156bf0e4673c495989302f52186dfa9767a1d9181794554717badd193ca2bbab046ef1da741d8efd + languageName: node + linkType: hard + "available-typed-arrays@npm:^1.0.7": version: 1.0.7 resolution: "available-typed-arrays@npm:1.0.7" @@ -1356,9 +1705,9 @@ __metadata: linkType: hard "axe-core@npm:^4.10.0": - version: 4.10.2 - resolution: "axe-core@npm:4.10.2" - checksum: 10/a69423b2ff16c15922c4ea7cf9cc5112728a2817bbe0f2cc212248d648885ffd1ba554e3a341dfc289cd9e67fc0d06f333b5c6837c5c38ca6652507381216fc1 + version: 4.10.3 + resolution: "axe-core@npm:4.10.3" + checksum: 10/9ff51ad0fd0fdec5c0247ea74e8ace5990b54c7f01f8fa3e5cd8ba98b0db24d8ebd7bab4a9bd4d75c28c4edcd1eac455b44c8c6c258c6a98f3d2f88bc60af4cc languageName: node linkType: hard @@ -1393,21 +1742,21 @@ __metadata: linkType: hard "brace-expansion@npm:^1.1.7": - version: 1.1.11 - resolution: "brace-expansion@npm:1.1.11" + version: 1.1.12 + resolution: "brace-expansion@npm:1.1.12" dependencies: balanced-match: "npm:^1.0.0" concat-map: "npm:0.0.1" - checksum: 10/faf34a7bb0c3fcf4b59c7808bc5d2a96a40988addf2e7e09dfbb67a2251800e0d14cd2bfc1aa79174f2f5095c54ff27f46fb1289fe2d77dac755b5eb3434cc07 + checksum: 10/12cb6d6310629e3048cadb003e1aca4d8c9bb5c67c3c321bafdd7e7a50155de081f78ea3e0ed92ecc75a9015e784f301efc8132383132f4f7904ad1ac529c562 languageName: node linkType: hard "brace-expansion@npm:^2.0.1": - version: 2.0.1 - resolution: "brace-expansion@npm:2.0.1" + version: 2.0.2 + resolution: "brace-expansion@npm:2.0.2" dependencies: balanced-match: "npm:^1.0.0" - checksum: 10/a61e7cd2e8a8505e9f0036b3b6108ba5e926b4b55089eeb5550cd04a471fe216c96d4fe7e4c7f995c728c554ae20ddfc4244cad10aef255e72b62930afd233d1 + checksum: 10/01dff195e3646bc4b0d27b63d9bab84d2ebc06121ff5013ad6e5356daa5a9d6b60fa26cf73c74797f2dc3fbec112af13578d51f75228c1112b26c790a87b0488 languageName: node linkType: hard @@ -1476,9 +1825,9 @@ __metadata: linkType: hard "caniuse-lite@npm:^1.0.30001579": - version: 1.0.30001690 - resolution: "caniuse-lite@npm:1.0.30001690" - checksum: 10/9fb4659eb09a298601b9593739072c481e2f5cc524bd0530e5e0f002e66246da5e866669854dfc0d53195ee36b201dab02f7933a7cdf60ccba7adb2d4a304caf + version: 1.0.30001722 + resolution: "caniuse-lite@npm:1.0.30001722" + checksum: 10/60ad52c891221c894085d450c7308f94768702bed4f0b4b99199e3c3c5926b22d7c7c05f474fcdb484befbd43d1975f8529c8ad8f66770f5c32c5342716ecd0b languageName: node linkType: hard @@ -1490,21 +1839,23 @@ __metadata: "@lezer/highlight": "npm:^1.2.1" "@mdx-js/loader": "npm:^3.1.0" "@mdx-js/react": "npm:^3.1.0" - "@next/mdx": "npm:^15.1.4" + "@next/mdx": "npm:15.3.3" "@storybook/react": "npm:^8.6.8" "@types/mdx": "npm:^2.0.13" "@types/node": "npm:^20" - "@types/react": "npm:^18.0.0" - "@types/react-dom": "npm:^18.0.0" + "@types/react": "npm:19.1.8" + "@types/react-dom": "npm:19.1.6" "@uiw/codemirror-themes": "npm:^4.23.7" "@uiw/react-codemirror": "npm:^4.23.7" eslint: "npm:^8" - eslint-config-next: "npm:14.2.23" + eslint-config-next: "npm:15.3.3" + html-react-parser: "npm:^5.2.5" lightningcss: "npm:^1.28.2" motion: "npm:^12.4.1" - next: "npm:14.2.26" - react: "npm:^18.0.2" - react-dom: "npm:^18.0.2" + next: "npm:15.3.3" + next-mdx-remote-client: "npm:^2.1.2" + react: "npm:19.1.0" + react-dom: "npm:19.1.0" react-frame-component: "npm:^5.2.7" shiki: "npm:^1.26.1" storybook: "npm:^8.6.8" @@ -1595,13 +1946,33 @@ __metadata: languageName: node linkType: hard -"color-name@npm:~1.1.4": +"color-name@npm:^1.0.0, color-name@npm:~1.1.4": version: 1.1.4 resolution: "color-name@npm:1.1.4" checksum: 10/b0445859521eb4021cd0fb0cc1a75cecf67fceecae89b63f62b201cca8d345baf8b952c966862a9d9a2632987d4f6581f0ec8d957dfacece86f0a7919316f610 languageName: node linkType: hard +"color-string@npm:^1.9.0": + version: 1.9.1 + resolution: "color-string@npm:1.9.1" + dependencies: + color-name: "npm:^1.0.0" + simple-swizzle: "npm:^0.2.2" + checksum: 10/72aa0b81ee71b3f4fb1ac9cd839cdbd7a011a7d318ef58e6cb13b3708dca75c7e45029697260488709f1b1c7ac4e35489a87e528156c1e365917d1c4ccb9b9cd + languageName: node + linkType: hard + +"color@npm:^4.2.3": + version: 4.2.3 + resolution: "color@npm:4.2.3" + dependencies: + color-convert: "npm:^2.0.1" + color-string: "npm:^1.9.0" + checksum: 10/b23f5e500a79ea22428db43d1a70642d983405c0dd1f95ef59dbdb9ba66afbb4773b334fa0b75bb10b0552fd7534c6b28d4db0a8b528f91975976e70973c0152 + languageName: node + linkType: hard + "comma-separated-tokens@npm:^2.0.0": version: 2.0.3 resolution: "comma-separated-tokens@npm:2.0.3" @@ -1616,14 +1987,14 @@ __metadata: languageName: node linkType: hard -"crelt@npm:^1.0.5": +"crelt@npm:^1.0.5, crelt@npm:^1.0.6": version: 1.0.6 resolution: "crelt@npm:1.0.6" checksum: 10/5ed326ca6bd243b1dba6b943f665b21c2c04be03271824bc48f20dba324b0f8233e221f8c67312526d24af2b1243c023dc05a41bd8bd05d1a479fd2c72fb39c3 languageName: node linkType: hard -"cross-spawn@npm:^7.0.0, cross-spawn@npm:^7.0.2": +"cross-spawn@npm:^7.0.2": version: 7.0.6 resolution: "cross-spawn@npm:7.0.6" dependencies: @@ -1690,24 +2061,24 @@ __metadata: languageName: node linkType: hard -"debug@npm:^4.0.0, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.4, debug@npm:^4.3.7": - version: 4.4.0 - resolution: "debug@npm:4.4.0" +"debug@npm:^4.0.0, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.4, debug@npm:^4.4.0": + version: 4.4.1 + resolution: "debug@npm:4.4.1" dependencies: ms: "npm:^2.1.3" peerDependenciesMeta: supports-color: optional: true - checksum: 10/1847944c2e3c2c732514b93d11886575625686056cd765336212dc15de2d2b29612b6cd80e1afba767bb8e1803b778caf9973e98169ef1a24a7a7009e1820367 + checksum: 10/8e2709b2144f03c7950f8804d01ccb3786373df01e406a0f66928e47001cf2d336cbed9ee137261d4f90d68d8679468c755e3548ed83ddacdc82b194d2468afe languageName: node linkType: hard "decode-named-character-reference@npm:^1.0.0": - version: 1.0.2 - resolution: "decode-named-character-reference@npm:1.0.2" + version: 1.1.0 + resolution: "decode-named-character-reference@npm:1.1.0" dependencies: character-entities: "npm:^2.0.0" - checksum: 10/f4c71d3b93105f20076052f9cb1523a22a9c796b8296cd35eef1ca54239c78d182c136a848b83ff8da2071e3ae2b1d300bf29d00650a6d6e675438cc31b11d78 + checksum: 10/102970fde2d011f307d3789776e68defd75ba4ade1a34951affd1fabb86cd32026fd809f2658c2b600d839a57b6b6a84e2b3a45166d38c8625d66ca11cd702b8 languageName: node linkType: hard @@ -1754,10 +2125,10 @@ __metadata: languageName: node linkType: hard -"detect-libc@npm:^2.0.3": - version: 2.0.3 - resolution: "detect-libc@npm:2.0.3" - checksum: 10/b4ea018d623e077bd395f168a9e81db77370dde36a5b01d067f2ad7989924a81d31cb547ff764acb2aa25d50bb7fdde0b0a93bec02212b0cb430621623246d39 +"detect-libc@npm:^2.0.3, detect-libc@npm:^2.0.4": + version: 2.0.4 + resolution: "detect-libc@npm:2.0.4" + checksum: 10/136e995f8c5ffbc515955b0175d441b967defd3d5f2268e89fa695e9c7170d8bed17993e31a34b04f0fad33d844a3a598e0fd519a8e9be3cad5f67662d96fee0 languageName: node linkType: hard @@ -1788,6 +2159,44 @@ __metadata: languageName: node linkType: hard +"dom-serializer@npm:^2.0.0": + version: 2.0.0 + resolution: "dom-serializer@npm:2.0.0" + dependencies: + domelementtype: "npm:^2.3.0" + domhandler: "npm:^5.0.2" + entities: "npm:^4.2.0" + checksum: 10/e3bf9027a64450bca0a72297ecdc1e3abb7a2912268a9f3f5d33a2e29c1e2c3502c6e9f860fc6625940bfe0cfb57a44953262b9e94df76872fdfb8151097eeb3 + languageName: node + linkType: hard + +"domelementtype@npm:^2.3.0": + version: 2.3.0 + resolution: "domelementtype@npm:2.3.0" + checksum: 10/ee837a318ff702622f383409d1f5b25dd1024b692ef64d3096ff702e26339f8e345820f29a68bcdcea8cfee3531776b3382651232fbeae95612d6f0a75efb4f6 + languageName: node + linkType: hard + +"domhandler@npm:5.0.3, domhandler@npm:^5.0.2, domhandler@npm:^5.0.3": + version: 5.0.3 + resolution: "domhandler@npm:5.0.3" + dependencies: + domelementtype: "npm:^2.3.0" + checksum: 10/809b805a50a9c6884a29f38aec0a4e1b4537f40e1c861950ed47d10b049febe6b79ab72adaeeebb3cc8fc1cd33f34e97048a72a9265103426d93efafa78d3e96 + languageName: node + linkType: hard + +"domutils@npm:^3.2.1": + version: 3.2.2 + resolution: "domutils@npm:3.2.2" + dependencies: + dom-serializer: "npm:^2.0.0" + domelementtype: "npm:^2.3.0" + domhandler: "npm:^5.0.3" + checksum: 10/2e08842151aa406f50fe5e6d494f4ec73c2373199fa00d1f77b56ec604e566b7f226312ae35ab8160bb7f27a27c7285d574c8044779053e499282ca9198be210 + languageName: node + linkType: hard + "dunder-proto@npm:^1.0.0, dunder-proto@npm:^1.0.1": version: 1.0.1 resolution: "dunder-proto@npm:1.0.1" @@ -1799,13 +2208,6 @@ __metadata: languageName: node linkType: hard -"eastasianwidth@npm:^0.2.0": - version: 0.2.0 - resolution: "eastasianwidth@npm:0.2.0" - checksum: 10/9b1d3e1baefeaf7d70799db8774149cef33b97183a6addceeba0cf6b85ba23ee2686f302f14482006df32df75d32b17c509c143a3689627929e4a8efaf483952 - languageName: node - linkType: hard - "emoji-regex-xs@npm:^1.0.0": version: 1.0.0 resolution: "emoji-regex-xs@npm:1.0.0" @@ -1813,13 +2215,6 @@ __metadata: languageName: node linkType: hard -"emoji-regex@npm:^8.0.0": - version: 8.0.0 - resolution: "emoji-regex@npm:8.0.0" - checksum: 10/c72d67a6821be15ec11997877c437491c313d924306b8da5d87d2a2bcc2cec9903cb5b04ee1a088460501d8e5b44f10df82fdc93c444101a7610b80c8b6938e1 - languageName: node - linkType: hard - "emoji-regex@npm:^9.2.2": version: 9.2.2 resolution: "emoji-regex@npm:9.2.2" @@ -1827,36 +2222,40 @@ __metadata: languageName: node linkType: hard -"enhanced-resolve@npm:^5.15.0": - version: 5.18.0 - resolution: "enhanced-resolve@npm:5.18.0" - dependencies: - graceful-fs: "npm:^4.2.4" - tapable: "npm:^2.2.0" - checksum: 10/e88463ef97b68d40d0da0cd0c572e23f43dba0be622d6d44eae5cafed05f0c5dac43e463a83a86c4f70186d029357f82b56d9e1e47e8fc91dce3d6602f8bd6ce +"entities@npm:^4.2.0": + version: 4.5.0 + resolution: "entities@npm:4.5.0" + checksum: 10/ede2a35c9bce1aeccd055a1b445d41c75a14a2bb1cd22e242f20cf04d236cdcd7f9c859eb83f76885327bfae0c25bf03303665ee1ce3d47c5927b98b0e3e3d48 languageName: node linkType: hard -"es-abstract@npm:^1.17.5, es-abstract@npm:^1.23.2, es-abstract@npm:^1.23.3, es-abstract@npm:^1.23.5, es-abstract@npm:^1.23.6, es-abstract@npm:^1.23.9": - version: 1.23.9 - resolution: "es-abstract@npm:1.23.9" +"entities@npm:^6.0.0": + version: 6.0.1 + resolution: "entities@npm:6.0.1" + checksum: 10/62af1307202884349d2867f0aac5c60d8b57102ea0b0e768b16246099512c28e239254ad772d6834e7e14cb1b6f153fc3d0c031934e3183b086c86d3838d874a + languageName: node + linkType: hard + +"es-abstract@npm:^1.17.5, es-abstract@npm:^1.23.2, es-abstract@npm:^1.23.3, es-abstract@npm:^1.23.5, es-abstract@npm:^1.23.6, es-abstract@npm:^1.23.9, es-abstract@npm:^1.24.0": + version: 1.24.0 + resolution: "es-abstract@npm:1.24.0" dependencies: array-buffer-byte-length: "npm:^1.0.2" arraybuffer.prototype.slice: "npm:^1.0.4" available-typed-arrays: "npm:^1.0.7" call-bind: "npm:^1.0.8" - call-bound: "npm:^1.0.3" + call-bound: "npm:^1.0.4" data-view-buffer: "npm:^1.0.2" data-view-byte-length: "npm:^1.0.2" data-view-byte-offset: "npm:^1.0.1" es-define-property: "npm:^1.0.1" es-errors: "npm:^1.3.0" - es-object-atoms: "npm:^1.0.0" + es-object-atoms: "npm:^1.1.1" es-set-tostringtag: "npm:^2.1.0" es-to-primitive: "npm:^1.3.0" function.prototype.name: "npm:^1.1.8" - get-intrinsic: "npm:^1.2.7" - get-proto: "npm:^1.0.0" + get-intrinsic: "npm:^1.3.0" + get-proto: "npm:^1.0.1" get-symbol-description: "npm:^1.1.0" globalthis: "npm:^1.0.4" gopd: "npm:^1.2.0" @@ -1868,21 +2267,24 @@ __metadata: is-array-buffer: "npm:^3.0.5" is-callable: "npm:^1.2.7" is-data-view: "npm:^1.0.2" + is-negative-zero: "npm:^2.0.3" is-regex: "npm:^1.2.1" + is-set: "npm:^2.0.3" is-shared-array-buffer: "npm:^1.0.4" is-string: "npm:^1.1.1" is-typed-array: "npm:^1.1.15" - is-weakref: "npm:^1.1.0" + is-weakref: "npm:^1.1.1" math-intrinsics: "npm:^1.1.0" - object-inspect: "npm:^1.13.3" + object-inspect: "npm:^1.13.4" object-keys: "npm:^1.1.1" object.assign: "npm:^4.1.7" own-keys: "npm:^1.0.1" - regexp.prototype.flags: "npm:^1.5.3" + regexp.prototype.flags: "npm:^1.5.4" safe-array-concat: "npm:^1.1.3" safe-push-apply: "npm:^1.0.0" safe-regex-test: "npm:^1.1.0" set-proto: "npm:^1.0.0" + stop-iteration-iterator: "npm:^1.1.0" string.prototype.trim: "npm:^1.2.10" string.prototype.trimend: "npm:^1.0.9" string.prototype.trimstart: "npm:^1.0.8" @@ -1891,8 +2293,8 @@ __metadata: typed-array-byte-offset: "npm:^1.0.4" typed-array-length: "npm:^1.0.7" unbox-primitive: "npm:^1.1.0" - which-typed-array: "npm:^1.1.18" - checksum: 10/31a321966d760d88fc2ed984104841b42f4f24fc322b246002b9be0af162e03803ee41fcc3cf8be89e07a27ba3033168f877dd983703cb81422ffe5322a27582 + which-typed-array: "npm:^1.1.19" + checksum: 10/64e07a886f7439cf5ccfc100f9716e6173e10af6071a50a5031afbdde474a3dbc9619d5965da54e55f8908746a9134a46be02af8c732d574b7b81ed3124e2daf languageName: node linkType: hard @@ -1955,12 +2357,12 @@ __metadata: languageName: node linkType: hard -"es-shim-unscopables@npm:^1.0.2": - version: 1.0.2 - resolution: "es-shim-unscopables@npm:1.0.2" +"es-shim-unscopables@npm:^1.0.2, es-shim-unscopables@npm:^1.1.0": + version: 1.1.0 + resolution: "es-shim-unscopables@npm:1.1.0" dependencies: - hasown: "npm:^2.0.0" - checksum: 10/6d3bf91f658a27cc7217cd32b407a0d714393a84d125ad576319b9e83a893bea165cf41270c29e9ceaa56d3cf41608945d7e2a2c31fd51c0009b0c31402b91c7 + hasown: "npm:^2.0.2" + checksum: 10/c351f586c30bbabc62355be49564b2435468b52c3532b8a1663672e3d10dc300197e69c247869dd173e56d86423ab95fc0c10b0939cdae597094e0fdca078cba languageName: node linkType: hard @@ -2011,34 +2413,34 @@ __metadata: linkType: hard "esbuild@npm:^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0 || ^0.24.0 || ^0.25.0": - version: 0.25.0 - resolution: "esbuild@npm:0.25.0" + version: 0.25.5 + resolution: "esbuild@npm:0.25.5" dependencies: - "@esbuild/aix-ppc64": "npm:0.25.0" - "@esbuild/android-arm": "npm:0.25.0" - "@esbuild/android-arm64": "npm:0.25.0" - "@esbuild/android-x64": "npm:0.25.0" - "@esbuild/darwin-arm64": "npm:0.25.0" - "@esbuild/darwin-x64": "npm:0.25.0" - "@esbuild/freebsd-arm64": "npm:0.25.0" - "@esbuild/freebsd-x64": "npm:0.25.0" - "@esbuild/linux-arm": "npm:0.25.0" - "@esbuild/linux-arm64": "npm:0.25.0" - "@esbuild/linux-ia32": "npm:0.25.0" - "@esbuild/linux-loong64": "npm:0.25.0" - "@esbuild/linux-mips64el": "npm:0.25.0" - "@esbuild/linux-ppc64": "npm:0.25.0" - "@esbuild/linux-riscv64": "npm:0.25.0" - "@esbuild/linux-s390x": "npm:0.25.0" - "@esbuild/linux-x64": "npm:0.25.0" - "@esbuild/netbsd-arm64": "npm:0.25.0" - "@esbuild/netbsd-x64": "npm:0.25.0" - "@esbuild/openbsd-arm64": "npm:0.25.0" - "@esbuild/openbsd-x64": "npm:0.25.0" - "@esbuild/sunos-x64": "npm:0.25.0" - "@esbuild/win32-arm64": "npm:0.25.0" - "@esbuild/win32-ia32": "npm:0.25.0" - "@esbuild/win32-x64": "npm:0.25.0" + "@esbuild/aix-ppc64": "npm:0.25.5" + "@esbuild/android-arm": "npm:0.25.5" + "@esbuild/android-arm64": "npm:0.25.5" + "@esbuild/android-x64": "npm:0.25.5" + "@esbuild/darwin-arm64": "npm:0.25.5" + "@esbuild/darwin-x64": "npm:0.25.5" + "@esbuild/freebsd-arm64": "npm:0.25.5" + "@esbuild/freebsd-x64": "npm:0.25.5" + "@esbuild/linux-arm": "npm:0.25.5" + "@esbuild/linux-arm64": "npm:0.25.5" + "@esbuild/linux-ia32": "npm:0.25.5" + "@esbuild/linux-loong64": "npm:0.25.5" + "@esbuild/linux-mips64el": "npm:0.25.5" + "@esbuild/linux-ppc64": "npm:0.25.5" + "@esbuild/linux-riscv64": "npm:0.25.5" + "@esbuild/linux-s390x": "npm:0.25.5" + "@esbuild/linux-x64": "npm:0.25.5" + "@esbuild/netbsd-arm64": "npm:0.25.5" + "@esbuild/netbsd-x64": "npm:0.25.5" + "@esbuild/openbsd-arm64": "npm:0.25.5" + "@esbuild/openbsd-x64": "npm:0.25.5" + "@esbuild/sunos-x64": "npm:0.25.5" + "@esbuild/win32-arm64": "npm:0.25.5" + "@esbuild/win32-ia32": "npm:0.25.5" + "@esbuild/win32-x64": "npm:0.25.5" dependenciesMeta: "@esbuild/aix-ppc64": optional: true @@ -2092,7 +2494,7 @@ __metadata: optional: true bin: esbuild: bin/esbuild - checksum: 10/451daf6a442df29ec5d528587caa4ce783d41ff4acb93252da5a852b8d36c22e9f84d17f6721d4fbef9a1ba9855bc9fe1f167dd732c11665fe53032f2b89f114 + checksum: 10/0fa4c3b42c6ddf1a008e75a4bb3dcab08ce22ac0b31dd59dc01f7fe8e21380bfaec07a2fe3730a7cf430da5a30142d016714b358666325a4733547afa42be405 languageName: node linkType: hard @@ -2103,27 +2505,27 @@ __metadata: languageName: node linkType: hard -"eslint-config-next@npm:14.2.23": - version: 14.2.23 - resolution: "eslint-config-next@npm:14.2.23" +"eslint-config-next@npm:15.3.3": + version: 15.3.3 + resolution: "eslint-config-next@npm:15.3.3" dependencies: - "@next/eslint-plugin-next": "npm:14.2.23" - "@rushstack/eslint-patch": "npm:^1.3.3" + "@next/eslint-plugin-next": "npm:15.3.3" + "@rushstack/eslint-patch": "npm:^1.10.3" "@typescript-eslint/eslint-plugin": "npm:^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0" "@typescript-eslint/parser": "npm:^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0" eslint-import-resolver-node: "npm:^0.3.6" eslint-import-resolver-typescript: "npm:^3.5.2" - eslint-plugin-import: "npm:^2.28.1" - eslint-plugin-jsx-a11y: "npm:^6.7.1" - eslint-plugin-react: "npm:^7.33.2" - eslint-plugin-react-hooks: "npm:^4.5.0 || 5.0.0-canary-7118f5dd7-20230705" + eslint-plugin-import: "npm:^2.31.0" + eslint-plugin-jsx-a11y: "npm:^6.10.0" + eslint-plugin-react: "npm:^7.37.0" + eslint-plugin-react-hooks: "npm:^5.0.0" peerDependencies: - eslint: ^7.23.0 || ^8.0.0 + eslint: ^7.23.0 || ^8.0.0 || ^9.0.0 typescript: ">=3.3.1" peerDependenciesMeta: typescript: optional: true - checksum: 10/ee23822e91c155cb0531c786cf11573b8914bc7dfa3b506c45c1d13d4b0c1b515764bd2744daa9c36bddf3bb7cfff434fa6bd169540a2fb933a336df78e7d850 + checksum: 10/63c51a9e4cc3f54073d15aff85b1088459439169721c379af1202df62c3a757c3849a194f46d4ec95a9c202322aa25d1ddab24159addcca290532a09afda3532 languageName: node linkType: hard @@ -2139,17 +2541,16 @@ __metadata: linkType: hard "eslint-import-resolver-typescript@npm:^3.5.2": - version: 3.7.0 - resolution: "eslint-import-resolver-typescript@npm:3.7.0" + version: 3.10.1 + resolution: "eslint-import-resolver-typescript@npm:3.10.1" dependencies: "@nolyfill/is-core-module": "npm:1.0.39" - debug: "npm:^4.3.7" - enhanced-resolve: "npm:^5.15.0" - fast-glob: "npm:^3.3.2" - get-tsconfig: "npm:^4.7.5" - is-bun-module: "npm:^1.0.2" - is-glob: "npm:^4.0.3" - stable-hash: "npm:^0.0.4" + debug: "npm:^4.4.0" + get-tsconfig: "npm:^4.10.0" + is-bun-module: "npm:^2.0.0" + stable-hash: "npm:^0.0.5" + tinyglobby: "npm:^0.2.13" + unrs-resolver: "npm:^1.6.2" peerDependencies: eslint: "*" eslint-plugin-import: "*" @@ -2159,7 +2560,7 @@ __metadata: optional: true eslint-plugin-import-x: optional: true - checksum: 10/8158730c11e562c56ed9bf7236dc75bce35b6992dc32c39ac2f4177ab77fca97b95999850204a6458054243607b54aee88c028a61fed4184f24f425fa1afff01 + checksum: 10/b8d6a9b2045c70f043f722f78c9e65bc0283126f0ad92c8f07473f7647d77f7b1562f765a472f17e06b81897b407091c0ec9f2e4592b158c9fd92d0b0c33de89 languageName: node linkType: hard @@ -2175,7 +2576,7 @@ __metadata: languageName: node linkType: hard -"eslint-plugin-import@npm:^2.28.1": +"eslint-plugin-import@npm:^2.31.0": version: 2.31.0 resolution: "eslint-plugin-import@npm:2.31.0" dependencies: @@ -2204,7 +2605,7 @@ __metadata: languageName: node linkType: hard -"eslint-plugin-jsx-a11y@npm:^6.7.1": +"eslint-plugin-jsx-a11y@npm:^6.10.0": version: 6.10.2 resolution: "eslint-plugin-jsx-a11y@npm:6.10.2" dependencies: @@ -2229,18 +2630,18 @@ __metadata: languageName: node linkType: hard -"eslint-plugin-react-hooks@npm:^4.5.0 || 5.0.0-canary-7118f5dd7-20230705": - version: 5.0.0-canary-7118f5dd7-20230705 - resolution: "eslint-plugin-react-hooks@npm:5.0.0-canary-7118f5dd7-20230705" +"eslint-plugin-react-hooks@npm:^5.0.0": + version: 5.2.0 + resolution: "eslint-plugin-react-hooks@npm:5.2.0" peerDependencies: - eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 - checksum: 10/0e0e80c21552998b7af2b92a74aec5e862b33f6f16c3e1303d42b5821d68b7ba11c2037bd73e3581fc7d97d9a2e64dd19e202d47d6885f53e33aac87c048d641 + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 + checksum: 10/ebb79e9cf69ae06e3a7876536653c5e556b5fd8cd9dc49577f10a6e728360e7b6f5ce91f4339b33e93b26e3bb23805418f8b5e75db80baddd617b1dffe73bed1 languageName: node linkType: hard -"eslint-plugin-react@npm:^7.33.2": - version: 7.37.3 - resolution: "eslint-plugin-react@npm:7.37.3" +"eslint-plugin-react@npm:^7.37.0": + version: 7.37.5 + resolution: "eslint-plugin-react@npm:7.37.5" dependencies: array-includes: "npm:^3.1.8" array.prototype.findlast: "npm:^1.2.5" @@ -2252,7 +2653,7 @@ __metadata: hasown: "npm:^2.0.2" jsx-ast-utils: "npm:^2.4.1 || ^3.0.0" minimatch: "npm:^3.1.2" - object.entries: "npm:^1.1.8" + object.entries: "npm:^1.1.9" object.fromentries: "npm:^2.0.8" object.values: "npm:^1.2.1" prop-types: "npm:^15.8.1" @@ -2262,7 +2663,7 @@ __metadata: string.prototype.repeat: "npm:^1.0.0" peerDependencies: eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 - checksum: 10/30042b95c440a962157192f67369d8c9171f7c73e992695e5674c9d28c3cfe4098488eca86dfa7c433d4c8a91243cbafdc80c7e42d2c1720a427ddb36e65457e + checksum: 10/ee1bd4e0ec64f29109d5a625bb703d179c82e0159c86c3f1b52fc1209d2994625a137dae303c333fb308a2e38315e44066d5204998177e31974382f9fda25d5c languageName: node linkType: hard @@ -2284,9 +2685,9 @@ __metadata: linkType: hard "eslint-visitor-keys@npm:^4.2.0": - version: 4.2.0 - resolution: "eslint-visitor-keys@npm:4.2.0" - checksum: 10/9651b3356b01760e586b4c631c5268c0e1a85236e3292bf754f0472f465bf9a856c0ddc261fceace155334118c0151778effafbab981413dbf9288349343fa25 + version: 4.2.1 + resolution: "eslint-visitor-keys@npm:4.2.1" + checksum: 10/3ee00fc6a7002d4b0ffd9dc99e13a6a7882c557329e6c25ab254220d71e5c9c4f89dca4695352949ea678eb1f3ba912a18ef8aac0a7fe094196fd92f441bfce2 languageName: node linkType: hard @@ -2473,6 +2874,19 @@ __metadata: languageName: node linkType: hard +"fast-glob@npm:3.3.1": + version: 3.3.1 + resolution: "fast-glob@npm:3.3.1" + dependencies: + "@nodelib/fs.stat": "npm:^2.0.2" + "@nodelib/fs.walk": "npm:^1.2.3" + glob-parent: "npm:^5.1.2" + merge2: "npm:^1.3.0" + micromatch: "npm:^4.0.4" + checksum: 10/51bcd15472879dfe51d4b01c5b70bbc7652724d39cdd082ba11276dbd7d84db0f6b33757e1938af8b2768a4bf485d9be0c89153beae24ee8331d6dcc7550379f + languageName: node + linkType: hard + "fast-glob@npm:^3.3.2": version: 3.3.3 resolution: "fast-glob@npm:3.3.3" @@ -2501,11 +2915,23 @@ __metadata: linkType: hard "fastq@npm:^1.6.0": - version: 1.18.0 - resolution: "fastq@npm:1.18.0" + version: 1.19.1 + resolution: "fastq@npm:1.19.1" dependencies: reusify: "npm:^1.0.4" - checksum: 10/c5b501333dc8f5d188d828ea162aad03ff5a81aed185b6d4a5078aaeae0a42babc34296d7af13ebce86401cccd93c9b7b3cbf61280821c5f20af233378b42fbb + checksum: 10/75679dc226316341c4f2a6b618571f51eac96779906faecd8921b984e844d6ae42fabb2df69b1071327d398d5716693ea9c9c8941f64ac9e89ec2032ce59d730 + languageName: node + linkType: hard + +"fdir@npm:^6.4.4": + version: 6.4.6 + resolution: "fdir@npm:6.4.6" + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + checksum: 10/c186ba387e7b75ccf874a098d9bc5fe0af0e9c52fc56f8eac8e80aa4edb65532684bf2bf769894ff90f53bf221d6136692052d31f07a9952807acae6cbe7ee50 languageName: node linkType: hard @@ -2549,9 +2975,9 @@ __metadata: linkType: hard "flatted@npm:^3.2.9": - version: 3.3.2 - resolution: "flatted@npm:3.3.2" - checksum: 10/ac3c159742e01d0e860a861164bcfd35bb567ccbebb8a0dd041e61cf3c64a435b917dd1e7ed1c380c2ebca85735fb16644485ec33665bc6aafc3b316aa1eed44 + version: 3.3.3 + resolution: "flatted@npm:3.3.3" + checksum: 10/8c96c02fbeadcf4e8ffd0fa24983241e27698b0781295622591fc13585e2f226609d95e422bcf2ef044146ffacb6b68b1f20871454eddf75ab3caa6ee5f4a1fe languageName: node linkType: hard @@ -2564,22 +2990,12 @@ __metadata: languageName: node linkType: hard -"foreground-child@npm:^3.1.0": - version: 3.3.0 - resolution: "foreground-child@npm:3.3.0" +"framer-motion@npm:^12.17.0": + version: 12.17.0 + resolution: "framer-motion@npm:12.17.0" dependencies: - cross-spawn: "npm:^7.0.0" - signal-exit: "npm:^4.0.1" - checksum: 10/e3a60480f3a09b12273ce2c5fcb9514d98dd0e528f58656a1b04680225f918d60a2f81f6a368f2f3b937fcee9cfc0cbf16f1ad9a0bc6a3a6e103a84c9a90087e - languageName: node - linkType: hard - -"framer-motion@npm:^12.5.0": - version: 12.5.0 - resolution: "framer-motion@npm:12.5.0" - dependencies: - motion-dom: "npm:^12.5.0" - motion-utils: "npm:^12.5.0" + motion-dom: "npm:^12.17.0" + motion-utils: "npm:^12.12.1" tslib: "npm:^2.4.0" peerDependencies: "@emotion/is-prop-valid": "*" @@ -2592,7 +3008,7 @@ __metadata: optional: true react-dom: optional: true - checksum: 10/6659e0b704d3216dafdcb11175e3c5f55d536469ddd8ad62b37d00bc7e893d914989791c018cfdfa17b3142b655f0d85226adc94ed390c1524312c3653b8c75f + checksum: 10/803b57cb7ec7200938c9425392a66839c96bf5a800ff14b38d9e689a47341678c53ce54765f68f0a186cfad6c1270b2ad46a75aeff67b2a2e2f3b846852d792c languageName: node linkType: hard @@ -2670,12 +3086,12 @@ __metadata: languageName: node linkType: hard -"get-tsconfig@npm:^4.7.5": - version: 4.8.1 - resolution: "get-tsconfig@npm:4.8.1" +"get-tsconfig@npm:^4.10.0": + version: 4.10.1 + resolution: "get-tsconfig@npm:4.10.1" dependencies: resolve-pkg-maps: "npm:^1.0.0" - checksum: 10/3fb5a8ad57b9633eaea085d81661e9e5c9f78b35d8f8689eaf8b8b45a2a3ebf3b3422266d4d7df765e308cc1e6231648d114803ab3d018332e29916f2c1de036 + checksum: 10/04d63f47fdecaefbd1f73ec02949be4ec4db7d6d9fbc8d4e81f9a4bb1c6f876e48943712f2f9236643d3e4d61d9a7b06da08564d08b034631ebe3f5605bef237 languageName: node linkType: hard @@ -2697,21 +3113,6 @@ __metadata: languageName: node linkType: hard -"glob@npm:10.3.10": - version: 10.3.10 - resolution: "glob@npm:10.3.10" - dependencies: - foreground-child: "npm:^3.1.0" - jackspeak: "npm:^2.3.5" - minimatch: "npm:^9.0.1" - minipass: "npm:^5.0.0 || ^6.0.2 || ^7.0.0" - path-scurry: "npm:^1.10.1" - bin: - glob: dist/esm/bin.mjs - checksum: 10/38bdb2c9ce75eb5ed168f309d4ed05b0798f640b637034800a6bf306f39d35409bf278b0eaaffaec07591085d3acb7184a201eae791468f0f617771c2486a6a8 - languageName: node - linkType: hard - "glob@npm:^7.1.3": version: 7.2.3 resolution: "glob@npm:7.2.3" @@ -2752,13 +3153,6 @@ __metadata: languageName: node linkType: hard -"graceful-fs@npm:^4.2.11, graceful-fs@npm:^4.2.4": - version: 4.2.11 - resolution: "graceful-fs@npm:4.2.11" - checksum: 10/bf152d0ed1dc159239db1ba1f74fdbc40cb02f626770dcd5815c427ce0688c2635a06ed69af364396da4636d0408fcf7d4afdf7881724c3307e46aff30ca49e2 - languageName: node - linkType: hard - "graphemer@npm:^1.4.0": version: 1.4.0 resolution: "graphemer@npm:1.4.0" @@ -2814,7 +3208,7 @@ __metadata: languageName: node linkType: hard -"hasown@npm:^2.0.0, hasown@npm:^2.0.2": +"hasown@npm:^2.0.2": version: 2.0.2 resolution: "hasown@npm:2.0.2" dependencies: @@ -2824,8 +3218,8 @@ __metadata: linkType: hard "hast-util-to-estree@npm:^3.0.0": - version: 3.1.1 - resolution: "hast-util-to-estree@npm:3.1.1" + version: 3.1.3 + resolution: "hast-util-to-estree@npm:3.1.3" dependencies: "@types/estree": "npm:^1.0.0" "@types/estree-jsx": "npm:^1.0.0" @@ -2838,18 +3232,18 @@ __metadata: mdast-util-mdx-expression: "npm:^2.0.0" mdast-util-mdx-jsx: "npm:^3.0.0" mdast-util-mdxjs-esm: "npm:^2.0.0" - property-information: "npm:^6.0.0" + property-information: "npm:^7.0.0" space-separated-tokens: "npm:^2.0.0" - style-to-object: "npm:^1.0.0" + style-to-js: "npm:^1.0.0" unist-util-position: "npm:^5.0.0" zwitch: "npm:^2.0.0" - checksum: 10/f72b0d72d6f3e1d55a876e175716b78bf93b8246fac8dd6db6b46c03b0288d03f40644606f36c00e8f12829a6bef0e7a73b405825b651a94b41f0bc5b53b92b4 + checksum: 10/efe69c8af68f021d853e70916c6e940765be519aec8703765898c1c3814424b0470f70c0272cf4ac06dcaf6d6f3cc781ebf034701ed240a33ac691d1f5eaf65b languageName: node linkType: hard "hast-util-to-html@npm:^9.0.4": - version: 9.0.4 - resolution: "hast-util-to-html@npm:9.0.4" + version: 9.0.5 + resolution: "hast-util-to-html@npm:9.0.5" dependencies: "@types/hast": "npm:^3.0.0" "@types/unist": "npm:^3.0.0" @@ -2858,17 +3252,17 @@ __metadata: hast-util-whitespace: "npm:^3.0.0" html-void-elements: "npm:^3.0.0" mdast-util-to-hast: "npm:^13.0.0" - property-information: "npm:^6.0.0" + property-information: "npm:^7.0.0" space-separated-tokens: "npm:^2.0.0" stringify-entities: "npm:^4.0.0" zwitch: "npm:^2.0.4" - checksum: 10/a0b4ed9058e57fa2ca010d10c077fda78d2ab2af99f5bd09fe4b9948970025ac4a2a1a03ec7e2e0f3b0444066b1b35d602fa3e9fbd9b7fc9cdd35d0cafa909ca + checksum: 10/4278e5246f43adf7a30bf3b87db4a4e628b5362b8c149eb4360bf7e0f731f81fa31e4e844e8090d1dd5f739d0884678f8165b28f97c14139e4da4f945f9ff5f7 languageName: node linkType: hard "hast-util-to-jsx-runtime@npm:^2.0.0": - version: 2.3.2 - resolution: "hast-util-to-jsx-runtime@npm:2.3.2" + version: 2.3.6 + resolution: "hast-util-to-jsx-runtime@npm:2.3.6" dependencies: "@types/estree": "npm:^1.0.0" "@types/hast": "npm:^3.0.0" @@ -2880,12 +3274,12 @@ __metadata: mdast-util-mdx-expression: "npm:^2.0.0" mdast-util-mdx-jsx: "npm:^3.0.0" mdast-util-mdxjs-esm: "npm:^2.0.0" - property-information: "npm:^6.0.0" + property-information: "npm:^7.0.0" space-separated-tokens: "npm:^2.0.0" - style-to-object: "npm:^1.0.0" + style-to-js: "npm:^1.0.0" unist-util-position: "npm:^5.0.0" vfile-message: "npm:^4.0.0" - checksum: 10/3d72f83e2d8c29adc6576d2c6b41479902fd51fac8cfb2b67c35fd68fcb9c25c274699442e4dee901a7ab926a0ff6851713ed5d92448ac09ae0f10daf293476c + checksum: 10/111bd69f482952c7591cb4e1d3face25f1c18849b310a4d6cacc91e2d2cbc965d455fad35c059b8f0cfd762e933b826a7090b6f3098dece08307a6569de8f1d8 languageName: node linkType: hard @@ -2898,6 +3292,34 @@ __metadata: languageName: node linkType: hard +"html-dom-parser@npm:5.1.1": + version: 5.1.1 + resolution: "html-dom-parser@npm:5.1.1" + dependencies: + domhandler: "npm:5.0.3" + htmlparser2: "npm:10.0.0" + checksum: 10/85bbaa8699d40d54fd64f5472088199178a6c3dd6a907358ac476d9c511cb8ab10bff1469a785411e8b831a73ac08348392e56076eab6d100a3ec19dccc722ad + languageName: node + linkType: hard + +"html-react-parser@npm:^5.2.5": + version: 5.2.5 + resolution: "html-react-parser@npm:5.2.5" + dependencies: + domhandler: "npm:5.0.3" + html-dom-parser: "npm:5.1.1" + react-property: "npm:2.0.2" + style-to-js: "npm:1.1.16" + peerDependencies: + "@types/react": 0.14 || 15 || 16 || 17 || 18 || 19 + react: 0.14 || 15 || 16 || 17 || 18 || 19 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10/22852dc4826d3be9506e238e37a05c23b432675aac33f22bd5741caa195a32e99de99d2b99037fda532f198afbcdeacfc0b27627d6e529143a98c8f191e99c52 + languageName: node + linkType: hard + "html-void-elements@npm:^3.0.0": version: 3.0.0 resolution: "html-void-elements@npm:3.0.0" @@ -2905,20 +3327,39 @@ __metadata: languageName: node linkType: hard -"ignore@npm:^5.2.0, ignore@npm:^5.3.1": +"htmlparser2@npm:10.0.0": + version: 10.0.0 + resolution: "htmlparser2@npm:10.0.0" + dependencies: + domelementtype: "npm:^2.3.0" + domhandler: "npm:^5.0.3" + domutils: "npm:^3.2.1" + entities: "npm:^6.0.0" + checksum: 10/768870f0e020dca19dc45df206cb6ac466c5dba6566c8fca4ca880347eed409f9977028d08644ac516bca8628ac9c7ded5a3847dc3ee1c043f049abf9e817154 + languageName: node + linkType: hard + +"ignore@npm:^5.2.0": version: 5.3.2 resolution: "ignore@npm:5.3.2" checksum: 10/cceb6a457000f8f6a50e1196429750d782afce5680dd878aa4221bd79972d68b3a55b4b1458fc682be978f4d3c6a249046aa0880637367216444ab7b014cfc98 languageName: node linkType: hard +"ignore@npm:^7.0.0": + version: 7.0.5 + resolution: "ignore@npm:7.0.5" + checksum: 10/f134b96a4de0af419196f52c529d5c6120c4456ff8a6b5a14ceaaa399f883e15d58d2ce651c9b69b9388491d4669dda47285d307e827de9304a53a1824801bc6 + languageName: node + linkType: hard + "import-fresh@npm:^3.2.1": - version: 3.3.0 - resolution: "import-fresh@npm:3.3.0" + version: 3.3.1 + resolution: "import-fresh@npm:3.3.1" dependencies: parent-module: "npm:^1.0.0" resolve-from: "npm:^4.0.0" - checksum: 10/2cacfad06e652b1edc50be650f7ec3be08c5e5a6f6d12d035c440a42a8cc028e60a5b99ca08a77ab4d6b1346da7d971915828f33cdab730d3d42f08242d09baa + checksum: 10/a06b19461b4879cc654d46f8a6244eb55eb053437afd4cbb6613cad6be203811849ed3e4ea038783092879487299fda24af932b86bdfff67c9055ba3612b8c87 languageName: node linkType: hard @@ -3002,15 +3443,23 @@ __metadata: languageName: node linkType: hard +"is-arrayish@npm:^0.3.1": + version: 0.3.2 + resolution: "is-arrayish@npm:0.3.2" + checksum: 10/81a78d518ebd8b834523e25d102684ee0f7e98637136d3bdc93fd09636350fa06f1d8ca997ea28143d4d13cb1b69c0824f082db0ac13e1ab3311c10ffea60ade + languageName: node + linkType: hard + "is-async-function@npm:^2.0.0": - version: 2.1.0 - resolution: "is-async-function@npm:2.1.0" + version: 2.1.1 + resolution: "is-async-function@npm:2.1.1" dependencies: + async-function: "npm:^1.0.0" call-bound: "npm:^1.0.3" get-proto: "npm:^1.0.1" has-tostringtag: "npm:^1.0.2" safe-regex-test: "npm:^1.1.0" - checksum: 10/865f0e915b7d9aa5577327e7550bf77a4bb2b7bca497d32564e1d32dbe0ccb7eca1c9c56dd679b6dd2bd7feddb91574e773922276871a5958e53ae8473db4742 + checksum: 10/7c2ac7efdf671e03265e74a043bcb1c0a32e226bc2a42dfc5ec8644667df668bbe14b91c08e6c1414f392f8cf86cd1d489b3af97756e2c7a49dd1ba63fd40ca6 languageName: node linkType: hard @@ -3024,21 +3473,21 @@ __metadata: linkType: hard "is-boolean-object@npm:^1.2.1": - version: 1.2.1 - resolution: "is-boolean-object@npm:1.2.1" + version: 1.2.2 + resolution: "is-boolean-object@npm:1.2.2" dependencies: - call-bound: "npm:^1.0.2" + call-bound: "npm:^1.0.3" has-tostringtag: "npm:^1.0.2" - checksum: 10/5a15524635c9334ebbd668f20a6cbf023adceed5725ec96a50056d21ae65f52759d04a8fa7d7febf00ff3bc4e6d3837638eb84be572f287bcfd15f8b8facde43 + checksum: 10/051fa95fdb99d7fbf653165a7e6b2cba5d2eb62f7ffa81e793a790f3fb5366c91c1b7b6af6820aa2937dd86c73aa3ca9d9ca98f500988457b1c59692c52ba911 languageName: node linkType: hard -"is-bun-module@npm:^1.0.2": - version: 1.3.0 - resolution: "is-bun-module@npm:1.3.0" +"is-bun-module@npm:^2.0.0": + version: 2.0.0 + resolution: "is-bun-module@npm:2.0.0" dependencies: - semver: "npm:^7.6.3" - checksum: 10/b23d9ec7b4d4bfd89e4e72b5cd52e1bc153facad59fdd7394c656f8859a78740ef35996a2066240a32f39cc9a9da4b4eb69e68df3c71755a61ebbaf56d3daef0 + semver: "npm:^7.7.1" + checksum: 10/cded5a1a58368b847872d08617975d620ad94426d76a932f3e08d55b4574d199e0a62a4fb024fa2dc444200b71719eb0bffc5d3d1e1cc82e29b293bb8d66a990 languageName: node linkType: hard @@ -3111,13 +3560,6 @@ __metadata: languageName: node linkType: hard -"is-fullwidth-code-point@npm:^3.0.0": - version: 3.0.0 - resolution: "is-fullwidth-code-point@npm:3.0.0" - checksum: 10/44a30c29457c7fb8f00297bce733f0a64cd22eca270f83e58c105e0d015e45c019491a4ab2faef91ab51d4738c670daff901c799f6a700e27f7314029e99e348 - languageName: node - linkType: hard - "is-generator-function@npm:^1.0.10, is-generator-function@npm:^1.0.7": version: 1.1.0 resolution: "is-generator-function@npm:1.1.0" @@ -3153,6 +3595,13 @@ __metadata: languageName: node linkType: hard +"is-negative-zero@npm:^2.0.3": + version: 2.0.3 + resolution: "is-negative-zero@npm:2.0.3" + checksum: 10/8fe5cffd8d4fb2ec7b49d657e1691889778d037494c6f40f4d1a524cadd658b4b53ad7b6b73a59bcb4b143ae9a3d15829af864b2c0f9d65ac1e678c4c80f17e5 + languageName: node + linkType: hard + "is-number-object@npm:^1.1.1": version: 1.1.1 resolution: "is-number-object@npm:1.1.1" @@ -3212,7 +3661,7 @@ __metadata: languageName: node linkType: hard -"is-string@npm:^1.0.7, is-string@npm:^1.1.1": +"is-string@npm:^1.1.1": version: 1.1.1 resolution: "is-string@npm:1.1.1" dependencies: @@ -3249,12 +3698,12 @@ __metadata: languageName: node linkType: hard -"is-weakref@npm:^1.0.2, is-weakref@npm:^1.1.0": - version: 1.1.0 - resolution: "is-weakref@npm:1.1.0" +"is-weakref@npm:^1.0.2, is-weakref@npm:^1.1.1": + version: 1.1.1 + resolution: "is-weakref@npm:1.1.1" dependencies: - call-bound: "npm:^1.0.2" - checksum: 10/89e627cc1763ea110574bb408fcf060ede47e70437d9278858bc939e3b3f7e4b7c558610b733da5f2ad6084d9f12b9c714b011ccf3fa771ec87e221c22bed910 + call-bound: "npm:^1.0.3" + checksum: 10/543506fd8259038b371bb083aac25b16cb4fd8b12fc58053aa3d45ac28dfd001cd5c6dffbba7aeea4213c74732d46b6cb2cfb5b412eed11f2db524f3f97d09a0 languageName: node linkType: hard @@ -3305,20 +3754,7 @@ __metadata: languageName: node linkType: hard -"jackspeak@npm:^2.3.5": - version: 2.3.6 - resolution: "jackspeak@npm:2.3.6" - dependencies: - "@isaacs/cliui": "npm:^8.0.2" - "@pkgjs/parseargs": "npm:^0.11.0" - dependenciesMeta: - "@pkgjs/parseargs": - optional: true - checksum: 10/6e6490d676af8c94a7b5b29b8fd5629f21346911ebe2e32931c2a54210134408171c24cee1a109df2ec19894ad04a429402a8438cbf5cc2794585d35428ace76 - languageName: node - linkType: hard - -"js-tokens@npm:^3.0.0 || ^4.0.0": +"js-tokens@npm:^3.0.0 || ^4.0.0, js-tokens@npm:^4.0.0": version: 4.0.0 resolution: "js-tokens@npm:4.0.0" checksum: 10/af37d0d913fb56aec6dc0074c163cc71cd23c0b8aad5c2350747b6721d37ba118af35abdd8b33c47ec2800de07dedb16a527ca9c530ee004093e04958bd0cbf2 @@ -3422,91 +3858,91 @@ __metadata: languageName: node linkType: hard -"lightningcss-darwin-arm64@npm:1.29.3": - version: 1.29.3 - resolution: "lightningcss-darwin-arm64@npm:1.29.3" +"lightningcss-darwin-arm64@npm:1.30.1": + version: 1.30.1 + resolution: "lightningcss-darwin-arm64@npm:1.30.1" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"lightningcss-darwin-x64@npm:1.29.3": - version: 1.29.3 - resolution: "lightningcss-darwin-x64@npm:1.29.3" +"lightningcss-darwin-x64@npm:1.30.1": + version: 1.30.1 + resolution: "lightningcss-darwin-x64@npm:1.30.1" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"lightningcss-freebsd-x64@npm:1.29.3": - version: 1.29.3 - resolution: "lightningcss-freebsd-x64@npm:1.29.3" +"lightningcss-freebsd-x64@npm:1.30.1": + version: 1.30.1 + resolution: "lightningcss-freebsd-x64@npm:1.30.1" conditions: os=freebsd & cpu=x64 languageName: node linkType: hard -"lightningcss-linux-arm-gnueabihf@npm:1.29.3": - version: 1.29.3 - resolution: "lightningcss-linux-arm-gnueabihf@npm:1.29.3" +"lightningcss-linux-arm-gnueabihf@npm:1.30.1": + version: 1.30.1 + resolution: "lightningcss-linux-arm-gnueabihf@npm:1.30.1" conditions: os=linux & cpu=arm languageName: node linkType: hard -"lightningcss-linux-arm64-gnu@npm:1.29.3": - version: 1.29.3 - resolution: "lightningcss-linux-arm64-gnu@npm:1.29.3" +"lightningcss-linux-arm64-gnu@npm:1.30.1": + version: 1.30.1 + resolution: "lightningcss-linux-arm64-gnu@npm:1.30.1" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"lightningcss-linux-arm64-musl@npm:1.29.3": - version: 1.29.3 - resolution: "lightningcss-linux-arm64-musl@npm:1.29.3" +"lightningcss-linux-arm64-musl@npm:1.30.1": + version: 1.30.1 + resolution: "lightningcss-linux-arm64-musl@npm:1.30.1" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"lightningcss-linux-x64-gnu@npm:1.29.3": - version: 1.29.3 - resolution: "lightningcss-linux-x64-gnu@npm:1.29.3" +"lightningcss-linux-x64-gnu@npm:1.30.1": + version: 1.30.1 + resolution: "lightningcss-linux-x64-gnu@npm:1.30.1" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"lightningcss-linux-x64-musl@npm:1.29.3": - version: 1.29.3 - resolution: "lightningcss-linux-x64-musl@npm:1.29.3" +"lightningcss-linux-x64-musl@npm:1.30.1": + version: 1.30.1 + resolution: "lightningcss-linux-x64-musl@npm:1.30.1" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"lightningcss-win32-arm64-msvc@npm:1.29.3": - version: 1.29.3 - resolution: "lightningcss-win32-arm64-msvc@npm:1.29.3" +"lightningcss-win32-arm64-msvc@npm:1.30.1": + version: 1.30.1 + resolution: "lightningcss-win32-arm64-msvc@npm:1.30.1" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"lightningcss-win32-x64-msvc@npm:1.29.3": - version: 1.29.3 - resolution: "lightningcss-win32-x64-msvc@npm:1.29.3" +"lightningcss-win32-x64-msvc@npm:1.30.1": + version: 1.30.1 + resolution: "lightningcss-win32-x64-msvc@npm:1.30.1" conditions: os=win32 & cpu=x64 languageName: node linkType: hard "lightningcss@npm:^1.28.2": - version: 1.29.3 - resolution: "lightningcss@npm:1.29.3" + version: 1.30.1 + resolution: "lightningcss@npm:1.30.1" dependencies: detect-libc: "npm:^2.0.3" - lightningcss-darwin-arm64: "npm:1.29.3" - lightningcss-darwin-x64: "npm:1.29.3" - lightningcss-freebsd-x64: "npm:1.29.3" - lightningcss-linux-arm-gnueabihf: "npm:1.29.3" - lightningcss-linux-arm64-gnu: "npm:1.29.3" - lightningcss-linux-arm64-musl: "npm:1.29.3" - lightningcss-linux-x64-gnu: "npm:1.29.3" - lightningcss-linux-x64-musl: "npm:1.29.3" - lightningcss-win32-arm64-msvc: "npm:1.29.3" - lightningcss-win32-x64-msvc: "npm:1.29.3" + lightningcss-darwin-arm64: "npm:1.30.1" + lightningcss-darwin-x64: "npm:1.30.1" + lightningcss-freebsd-x64: "npm:1.30.1" + lightningcss-linux-arm-gnueabihf: "npm:1.30.1" + lightningcss-linux-arm64-gnu: "npm:1.30.1" + lightningcss-linux-arm64-musl: "npm:1.30.1" + lightningcss-linux-x64-gnu: "npm:1.30.1" + lightningcss-linux-x64-musl: "npm:1.30.1" + lightningcss-win32-arm64-msvc: "npm:1.30.1" + lightningcss-win32-x64-msvc: "npm:1.30.1" dependenciesMeta: lightningcss-darwin-arm64: optional: true @@ -3528,7 +3964,7 @@ __metadata: optional: true lightningcss-win32-x64-msvc: optional: true - checksum: 10/90933a666975f8e4f2b1bed1ec698a0072f96d2cd118e358932456a46105d62b72b701e4a5da5bd66f0b6e3beac2c65d0be2306acdf3f30603d86143502cce88 + checksum: 10/6c921135216cc498dfcb87e35dffe8432e99306cbd58009c598b1daf20c81cc14535abbd4c1066e5d1faf4080ed44a2995e8ecc343633db4897a2d041b76fb05 languageName: node linkType: hard @@ -3555,7 +3991,7 @@ __metadata: languageName: node linkType: hard -"loose-envify@npm:^1.1.0, loose-envify@npm:^1.4.0": +"loose-envify@npm:^1.4.0": version: 1.4.0 resolution: "loose-envify@npm:1.4.0" dependencies: @@ -3566,13 +4002,6 @@ __metadata: languageName: node linkType: hard -"lru-cache@npm:^10.2.0": - version: 10.4.3 - resolution: "lru-cache@npm:10.4.3" - checksum: 10/e6e90267360476720fa8e83cc168aa2bf0311f3f2eea20a6ba78b90a885ae72071d9db132f40fda4129c803e7dcec3a6b6a6fbb44ca90b081630b810b5d6a41a - languageName: node - linkType: hard - "markdown-extensions@npm:^2.0.0": version: 2.0.0 resolution: "markdown-extensions@npm:2.0.0" @@ -3622,8 +4051,8 @@ __metadata: linkType: hard "mdast-util-mdx-jsx@npm:^3.0.0": - version: 3.1.3 - resolution: "mdast-util-mdx-jsx@npm:3.1.3" + version: 3.2.0 + resolution: "mdast-util-mdx-jsx@npm:3.2.0" dependencies: "@types/estree-jsx": "npm:^1.0.0" "@types/hast": "npm:^3.0.0" @@ -3637,7 +4066,7 @@ __metadata: stringify-entities: "npm:^4.0.0" unist-util-stringify-position: "npm:^4.0.0" vfile-message: "npm:^4.0.0" - checksum: 10/6c14f271f1380fd512038247f45887b7aa71bbf4acd8881651a317b61706b114f2582f62f7777d0eacd42c4a7b979802825c2a2fd8bb7c46a1ab931ccb1ddf3e + checksum: 10/62cd650a522e5d72ea6afd6d4a557fc86525b802d097a29a2fbe17d22e7b97c502a580611873e4d685777fe77c6ff8d39fb6e37d026b3acbc86c3b24927f4ad9 languageName: node linkType: hard @@ -3654,7 +4083,7 @@ __metadata: languageName: node linkType: hard -"mdast-util-mdxjs-esm@npm:^2.0.0": +"mdast-util-mdxjs-esm@npm:^2.0.0, mdast-util-mdxjs-esm@npm:^2.0.1": version: 2.0.1 resolution: "mdast-util-mdxjs-esm@npm:2.0.1" dependencies: @@ -3729,8 +4158,8 @@ __metadata: linkType: hard "micromark-core-commonmark@npm:^2.0.0": - version: 2.0.2 - resolution: "micromark-core-commonmark@npm:2.0.2" + version: 2.0.3 + resolution: "micromark-core-commonmark@npm:2.0.3" dependencies: decode-named-character-reference: "npm:^1.0.0" devlop: "npm:^1.0.0" @@ -3748,13 +4177,13 @@ __metadata: micromark-util-subtokenize: "npm:^2.0.0" micromark-util-symbol: "npm:^2.0.0" micromark-util-types: "npm:^2.0.0" - checksum: 10/eafa6b9cd6fd9f51efa7795824af9a765e24a4519855a5b6dfcb0f619a93d90599d39a261f626bfcc1dfa64f22430f7a677a83cb6ce4bd8e4eeabc892610c016 + checksum: 10/2b98b9eba1463850ebd8f338f966bd2113dafe764b490ebee3dccab3764d3c48b53fe67673297530e56bf54f58de27dfd1952ed79c5b4e32047cb7f29bd807f2 languageName: node linkType: hard "micromark-extension-mdx-expression@npm:^3.0.0": - version: 3.0.0 - resolution: "micromark-extension-mdx-expression@npm:3.0.0" + version: 3.0.1 + resolution: "micromark-extension-mdx-expression@npm:3.0.1" dependencies: "@types/estree": "npm:^1.0.0" devlop: "npm:^1.0.0" @@ -3764,15 +4193,14 @@ __metadata: micromark-util-events-to-acorn: "npm:^2.0.0" micromark-util-symbol: "npm:^2.0.0" micromark-util-types: "npm:^2.0.0" - checksum: 10/a5592160319d4617362f6b72a6fc44b5570466afa07419d44bcfdd9398a77a5693d7c5f8da7b3ff4682edf6209d4781835f5d2e3166fdf6bba37db456fd2d091 + checksum: 10/a185e1787fe6d49d0e435690affd4b83ce319f88a08c57d2460d37d5c0a75ea64aa49a4a116b6d37f91389dc04351e1826aa834519a9f25fc31e1424962c6eb7 languageName: node linkType: hard "micromark-extension-mdx-jsx@npm:^3.0.0": - version: 3.0.1 - resolution: "micromark-extension-mdx-jsx@npm:3.0.1" + version: 3.0.2 + resolution: "micromark-extension-mdx-jsx@npm:3.0.2" dependencies: - "@types/acorn": "npm:^4.0.0" "@types/estree": "npm:^1.0.0" devlop: "npm:^1.0.0" estree-util-is-identifier-name: "npm:^3.0.0" @@ -3783,7 +4211,7 @@ __metadata: micromark-util-symbol: "npm:^2.0.0" micromark-util-types: "npm:^2.0.0" vfile-message: "npm:^4.0.0" - checksum: 10/2cc0277d91c3c85d52e88755d17d021b5eab6fa03a578a9965f9d3d2c184dbc1accce63e7f8437a092ceeb602840ef451d4dce6dc9e8c13df0bc76e741080a89 + checksum: 10/a85cdb7c972fbb2cc8f0a64adc808b2b62bc2d79dbdd31fcd3208ff15aafa0198b002022840b2c65b5bff6f2a8c2c4a59a32a89f3482e6e183114b476e98e25c languageName: node linkType: hard @@ -3853,8 +4281,8 @@ __metadata: linkType: hard "micromark-factory-mdx-expression@npm:^2.0.0": - version: 2.0.2 - resolution: "micromark-factory-mdx-expression@npm:2.0.2" + version: 2.0.3 + resolution: "micromark-factory-mdx-expression@npm:2.0.3" dependencies: "@types/estree": "npm:^1.0.0" devlop: "npm:^1.0.0" @@ -3865,7 +4293,7 @@ __metadata: micromark-util-types: "npm:^2.0.0" unist-util-position-from-estree: "npm:^2.0.0" vfile-message: "npm:^4.0.0" - checksum: 10/d5285fa98018f14a058c7cd4a961aacedd2d3c4f4fddd4c58c16f1e640d1284a8f581f4d00fa3e18c06ed302ce23bca23f6a01edd66064c23c9057e65385a62d + checksum: 10/afadae88a18f31afa564747101e076011c56457454b30294ae55aeea7efee8626ddc3bad0f0f43649008f89b8784782b5adec143fdf477fb352354d76f08db55 languageName: node linkType: hard @@ -3972,10 +4400,9 @@ __metadata: linkType: hard "micromark-util-events-to-acorn@npm:^2.0.0": - version: 2.0.2 - resolution: "micromark-util-events-to-acorn@npm:2.0.2" + version: 2.0.3 + resolution: "micromark-util-events-to-acorn@npm:2.0.3" dependencies: - "@types/acorn": "npm:^4.0.0" "@types/estree": "npm:^1.0.0" "@types/unist": "npm:^3.0.0" devlop: "npm:^1.0.0" @@ -3983,7 +4410,7 @@ __metadata: micromark-util-symbol: "npm:^2.0.0" micromark-util-types: "npm:^2.0.0" vfile-message: "npm:^4.0.0" - checksum: 10/475367e716c4d24f2a57464a7f2c8aa507ae36c05b7767fd652895525f3f0a1179ea3219cabccc0f3038bb5e4f9cce5390d530dc56decaa5f1786bda42739810 + checksum: 10/0d87e49b897636dc0e84b4bd06b6fa9e6abcd40ab90c9431e36737c85c444d3db1e4f9b8f51433422b1bedc46f086890ce96671b5a795230c6b7b09cb53d9aba languageName: node linkType: hard @@ -4024,14 +4451,14 @@ __metadata: linkType: hard "micromark-util-subtokenize@npm:^2.0.0": - version: 2.0.3 - resolution: "micromark-util-subtokenize@npm:2.0.3" + version: 2.1.0 + resolution: "micromark-util-subtokenize@npm:2.1.0" dependencies: devlop: "npm:^1.0.0" micromark-util-chunked: "npm:^2.0.0" micromark-util-symbol: "npm:^2.0.0" micromark-util-types: "npm:^2.0.0" - checksum: 10/57b26f129f46424a4670bb47c50f13c7309bb1bc557c02150a788d1634337c1bb25a3523af3d6dffc29aaec873b3bd88fd931bfff34e64284e6436e23873ca22 + checksum: 10/5f18c70cb952a414a4d161f5d6a5254d33c7dfcd56577e592ef2e172a0414058d3531a3554f43538f14e243592fffbc2e68ddaf6a41c54577b3ba7beb555d3dc languageName: node linkType: hard @@ -4043,15 +4470,15 @@ __metadata: linkType: hard "micromark-util-types@npm:^2.0.0": - version: 2.0.1 - resolution: "micromark-util-types@npm:2.0.1" - checksum: 10/69c5e18e6ba4e12473d6fe5f1a7cc113ac1d4bfc23c7ad57b16a5e4bfd09ef48b7c17a40c39d43996f2078ad898efd3f1945007c14f395abd55f2af03d413acd + version: 2.0.2 + resolution: "micromark-util-types@npm:2.0.2" + checksum: 10/a9eb067bd9384eab61942285d53738aa22f3fef4819eaf20249bec6ec13f1e4da2800230fd0ceb7e705108987aa9062fe3e9a8e5e48aa60180db80b9489dc3e2 languageName: node linkType: hard "micromark@npm:^4.0.0": - version: 4.0.1 - resolution: "micromark@npm:4.0.1" + version: 4.0.2 + resolution: "micromark@npm:4.0.2" dependencies: "@types/debug": "npm:^4.0.0" debug: "npm:^4.0.0" @@ -4070,11 +4497,11 @@ __metadata: micromark-util-subtokenize: "npm:^2.0.0" micromark-util-symbol: "npm:^2.0.0" micromark-util-types: "npm:^2.0.0" - checksum: 10/b948b1b239e589826bdaf2835daa9e88873e23d4b9148cd22109a86d4af55b96345cf9fc9059b6b19ae828f64d55e66f376ca3aeb4af3d2b0241560125f5dae6 + checksum: 10/1b85e49c8f71013df2d07a59e477deb72cd325d41cc15f35b2aa52b8b7a93fed45498ce3e18ed34464a9afa9ba8a9210b2509454b2a2d16ac06c7429f562bfac languageName: node linkType: hard -"micromatch@npm:^4.0.8": +"micromatch@npm:^4.0.4, micromatch@npm:^4.0.8": version: 4.0.8 resolution: "micromatch@npm:4.0.8" dependencies: @@ -4093,7 +4520,7 @@ __metadata: languageName: node linkType: hard -"minimatch@npm:^9.0.1, minimatch@npm:^9.0.4": +"minimatch@npm:^9.0.4": version: 9.0.5 resolution: "minimatch@npm:9.0.5" dependencies: @@ -4109,34 +4536,27 @@ __metadata: languageName: node linkType: hard -"minipass@npm:^5.0.0 || ^6.0.2 || ^7.0.0": - version: 7.1.2 - resolution: "minipass@npm:7.1.2" - checksum: 10/c25f0ee8196d8e6036661104bacd743785b2599a21de5c516b32b3fa2b83113ac89a2358465bc04956baab37ffb956ae43be679b2262bf7be15fce467ccd7950 - languageName: node - linkType: hard - -"motion-dom@npm:^12.5.0": - version: 12.5.0 - resolution: "motion-dom@npm:12.5.0" +"motion-dom@npm:^12.17.0": + version: 12.17.0 + resolution: "motion-dom@npm:12.17.0" dependencies: - motion-utils: "npm:^12.5.0" - checksum: 10/289e3d5567053e9b84223df9b482bb9180732c0cb6276e7982a73ddad0f76e47f8e0f69e4cdf93d7a689ad021fce837fa8a19c8b61bf56d71bdfc0e590bc3e7e + motion-utils: "npm:^12.12.1" + checksum: 10/54b482d643ca12d895e8a0860809b2b53f2e7c2981d12f3d1230f5bd6154cb59df6ab81a690681df7a526da283aaf76acbf351b148e2b805ad5f8ce97156e061 languageName: node linkType: hard -"motion-utils@npm:^12.5.0": - version: 12.5.0 - resolution: "motion-utils@npm:12.5.0" - checksum: 10/f2d754a9e1c4cd829f0703ce47bbeb3e9967994a9cb35e759f34de16af6c520a4959b04ff6998211ca67dc7bfe0002d9b2465858167b1971b0403f63289f97fc +"motion-utils@npm:^12.12.1": + version: 12.12.1 + resolution: "motion-utils@npm:12.12.1" + checksum: 10/679503df10a1cd7ad58f9ed2f864acb5ecbadf380a668874f0cc6bdc1155278bac0cce73e3f703df19532f2bd922e3500fde179e8f76386e9651f8b1bd0cfe6d languageName: node linkType: hard "motion@npm:^12.4.1": - version: 12.5.0 - resolution: "motion@npm:12.5.0" + version: 12.17.0 + resolution: "motion@npm:12.17.0" dependencies: - framer-motion: "npm:^12.5.0" + framer-motion: "npm:^12.17.0" tslib: "npm:^2.4.0" peerDependencies: "@emotion/is-prop-valid": "*" @@ -4149,7 +4569,7 @@ __metadata: optional: true react-dom: optional: true - checksum: 10/15910d37a14b91236c27c8cc6d12ae157cd1e6b55700fc58a0d271954236fae8e676b1ac9f705cb770c235892925fc6bbdb1f612dfb4018a5d4c0171964f5b3a + checksum: 10/4fde3c4f39fa872cb27a41ddf39dcf20a9a066428ce07cf7455e2a4779d916a47cb3141e8c4c970f9d7b8e8818b822f3eeb86761d61904a18383b82426f5f3ca languageName: node linkType: hard @@ -4161,11 +4581,20 @@ __metadata: linkType: hard "nanoid@npm:^3.3.6": - version: 3.3.8 - resolution: "nanoid@npm:3.3.8" + version: 3.3.11 + resolution: "nanoid@npm:3.3.11" bin: nanoid: bin/nanoid.cjs - checksum: 10/2d1766606cf0d6f47b6f0fdab91761bb81609b2e3d367027aff45e6ee7006f660fb7e7781f4a34799fe6734f1268eeed2e37a5fdee809ade0c2d4eb11b0f9c40 + checksum: 10/73b5afe5975a307aaa3c95dfe3334c52cdf9ae71518176895229b8d65ab0d1c0417dd081426134eb7571c055720428ea5d57c645138161e7d10df80815527c48 + languageName: node + linkType: hard + +"napi-postinstall@npm:^0.2.2": + version: 0.2.4 + resolution: "napi-postinstall@npm:0.2.4" + bin: + napi-postinstall: lib/cli.js + checksum: 10/286785f884b872102fb284847ecc693101f70126b1fc7a97e19293929ce7f08802b41f89398015cce0797070ea3ce6871939a3c1e693c04cf594f7939dbe8cfb languageName: node linkType: hard @@ -4176,31 +4605,50 @@ __metadata: languageName: node linkType: hard -"next@npm:14.2.26": - version: 14.2.26 - resolution: "next@npm:14.2.26" +"next-mdx-remote-client@npm:^2.1.2": + version: 2.1.2 + resolution: "next-mdx-remote-client@npm:2.1.2" dependencies: - "@next/env": "npm:14.2.26" - "@next/swc-darwin-arm64": "npm:14.2.26" - "@next/swc-darwin-x64": "npm:14.2.26" - "@next/swc-linux-arm64-gnu": "npm:14.2.26" - "@next/swc-linux-arm64-musl": "npm:14.2.26" - "@next/swc-linux-x64-gnu": "npm:14.2.26" - "@next/swc-linux-x64-musl": "npm:14.2.26" - "@next/swc-win32-arm64-msvc": "npm:14.2.26" - "@next/swc-win32-ia32-msvc": "npm:14.2.26" - "@next/swc-win32-x64-msvc": "npm:14.2.26" - "@swc/helpers": "npm:0.5.5" + "@babel/code-frame": "npm:^7.27.1" + "@mdx-js/mdx": "npm:^3.1.0" + "@mdx-js/react": "npm:^3.1.0" + remark-mdx-remove-esm: "npm:^1.1.0" + serialize-error: "npm:^12.0.0" + vfile: "npm:^6.0.3" + vfile-matter: "npm:^5.0.1" + peerDependencies: + react: ^19.1.0 + react-dom: ^19.1.0 + checksum: 10/610e95bff6c1dcdb4d1fefc9333ac748f1899cbca1ea551e784cd1e8cfd077c14d6bb8ab27826886f354cc3b9cf700fe25810263f996c53f824a2cfdbc5a064f + languageName: node + linkType: hard + +"next@npm:15.3.3": + version: 15.3.3 + resolution: "next@npm:15.3.3" + dependencies: + "@next/env": "npm:15.3.3" + "@next/swc-darwin-arm64": "npm:15.3.3" + "@next/swc-darwin-x64": "npm:15.3.3" + "@next/swc-linux-arm64-gnu": "npm:15.3.3" + "@next/swc-linux-arm64-musl": "npm:15.3.3" + "@next/swc-linux-x64-gnu": "npm:15.3.3" + "@next/swc-linux-x64-musl": "npm:15.3.3" + "@next/swc-win32-arm64-msvc": "npm:15.3.3" + "@next/swc-win32-x64-msvc": "npm:15.3.3" + "@swc/counter": "npm:0.1.3" + "@swc/helpers": "npm:0.5.15" busboy: "npm:1.6.0" caniuse-lite: "npm:^1.0.30001579" - graceful-fs: "npm:^4.2.11" postcss: "npm:8.4.31" - styled-jsx: "npm:5.1.1" + sharp: "npm:^0.34.1" + styled-jsx: "npm:5.1.6" peerDependencies: "@opentelemetry/api": ^1.1.0 "@playwright/test": ^1.41.2 - react: ^18.2.0 - react-dom: ^18.2.0 + babel-plugin-react-compiler: "*" + react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 + react-dom: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 sass: ^1.3.0 dependenciesMeta: "@next/swc-darwin-arm64": @@ -4217,20 +4665,22 @@ __metadata: optional: true "@next/swc-win32-arm64-msvc": optional: true - "@next/swc-win32-ia32-msvc": - optional: true "@next/swc-win32-x64-msvc": optional: true + sharp: + optional: true peerDependenciesMeta: "@opentelemetry/api": optional: true "@playwright/test": optional: true + babel-plugin-react-compiler: + optional: true sass: optional: true bin: next: dist/bin/next - checksum: 10/9bd8b2ef40076b251d036c6d3a3b435095ff941bab7166ebc3c75bd832c1812eb368f8dae1e56ef4bf600a81d0ad8190d778d610aa062ffa7c4c4f126cae7f13 + checksum: 10/287e3b24aade1763b13f95246d7df0e23d5fdde2d8c4b170360b22fabfa38184e102eb64886260e0034f4fc6979a1d47929e423d7946f5da57d306034645f6c7 languageName: node linkType: hard @@ -4241,10 +4691,10 @@ __metadata: languageName: node linkType: hard -"object-inspect@npm:^1.13.3": - version: 1.13.3 - resolution: "object-inspect@npm:1.13.3" - checksum: 10/14cb973d8381c69e14d7f1c8c75044eb4caf04c6dabcf40ca5c2ce42dc2073ae0bb2a9939eeca142b0c05215afaa1cd5534adb7c8879c32cba2576e045ed8368 +"object-inspect@npm:^1.13.3, object-inspect@npm:^1.13.4": + version: 1.13.4 + resolution: "object-inspect@npm:1.13.4" + checksum: 10/aa13b1190ad3e366f6c83ad8a16ed37a19ed57d267385aa4bfdccda833d7b90465c057ff6c55d035a6b2e52c1a2295582b294217a0a3a1ae7abdd6877ef781fb languageName: node linkType: hard @@ -4269,14 +4719,15 @@ __metadata: languageName: node linkType: hard -"object.entries@npm:^1.1.8": - version: 1.1.8 - resolution: "object.entries@npm:1.1.8" +"object.entries@npm:^1.1.9": + version: 1.1.9 + resolution: "object.entries@npm:1.1.9" dependencies: - call-bind: "npm:^1.0.7" + call-bind: "npm:^1.0.8" + call-bound: "npm:^1.0.4" define-properties: "npm:^1.2.1" - es-object-atoms: "npm:^1.0.0" - checksum: 10/2301918fbd1ee697cf6ff7cd94f060c738c0a7d92b22fd24c7c250e9b593642c9707ad2c44d339303c1439c5967d8964251cdfc855f7f6ec55db2dd79e8dc2a7 + es-object-atoms: "npm:^1.1.1" + checksum: 10/24163ab1e1e013796693fc5f5d349e8b3ac0b6a34a7edb6c17d3dd45c6a8854145780c57d302a82512c1582f63720f4b4779d6c1cfba12cbb1420b978802d8a3 languageName: node linkType: hard @@ -4324,14 +4775,14 @@ __metadata: languageName: node linkType: hard -"oniguruma-to-es@npm:0.10.0": - version: 0.10.0 - resolution: "oniguruma-to-es@npm:0.10.0" +"oniguruma-to-es@npm:^2.2.0": + version: 2.3.0 + resolution: "oniguruma-to-es@npm:2.3.0" dependencies: emoji-regex-xs: "npm:^1.0.0" regex: "npm:^5.1.1" regex-recursion: "npm:^5.1.1" - checksum: 10/09756001a74218b26d18940bea3ebb00d1949aa7ac142def3a94a4d256371fea169f52088ea32a6a23ca21338be56427fd9f0264907cee663e7ab147152638f7 + checksum: 10/7ac89fe04791650c21a146e58c985de394597e0ab3eb7d7c46699d09f87d6aca63d9f2470f1473c5adfa16961c360df6858e6a24b2429ebd7c73620ca68aec98 languageName: node linkType: hard @@ -4441,17 +4892,7 @@ __metadata: languageName: node linkType: hard -"path-scurry@npm:^1.10.1": - version: 1.11.1 - resolution: "path-scurry@npm:1.11.1" - dependencies: - lru-cache: "npm:^10.2.0" - minipass: "npm:^5.0.0 || ^6.0.2 || ^7.0.0" - checksum: 10/5e8845c159261adda6f09814d7725683257fcc85a18f329880ab4d7cc1d12830967eae5d5894e453f341710d5484b8fdbbd4d75181b4d6e1eb2f4dc7aeadc434 - languageName: node - linkType: hard - -"picocolors@npm:^1.0.0": +"picocolors@npm:^1.0.0, picocolors@npm:^1.1.1": version: 1.1.1 resolution: "picocolors@npm:1.1.1" checksum: 10/e1cf46bf84886c79055fdfa9dcb3e4711ad259949e3565154b004b260cd356c5d54b31a1437ce9782624bf766272fe6b0154f5f0c744fb7af5d454d2b60db045 @@ -4465,10 +4906,17 @@ __metadata: languageName: node linkType: hard +"picomatch@npm:^4.0.2": + version: 4.0.2 + resolution: "picomatch@npm:4.0.2" + checksum: 10/ce617b8da36797d09c0baacb96ca8a44460452c89362d7cb8f70ca46b4158ba8bc3606912de7c818eb4a939f7f9015cef3c766ec8a0c6bfc725fdc078e39c717 + languageName: node + linkType: hard + "possible-typed-array-names@npm:^1.0.0": - version: 1.0.0 - resolution: "possible-typed-array-names@npm:1.0.0" - checksum: 10/8ed3e96dfeea1c5880c1f4c9cb707e5fb26e8be22f14f82ef92df20fd2004e635c62ba47fbe8f2bb63bfd80dac1474be2fb39798da8c2feba2815435d1f749af + version: 1.1.0 + resolution: "possible-typed-array-names@npm:1.1.0" + checksum: 10/2f44137b8d3dd35f4a7ba7469eec1cd9cfbb46ec164b93a5bc1f4c3d68599c9910ee3b91da1d28b4560e9cc8414c3cd56fedc07259c67e52cc774476270d3302 languageName: node linkType: hard @@ -4508,10 +4956,10 @@ __metadata: languageName: node linkType: hard -"property-information@npm:^6.0.0": - version: 6.5.0 - resolution: "property-information@npm:6.5.0" - checksum: 10/fced94f3a09bf651ad1824d1bdc8980428e3e480e6d01e98df6babe2cc9d45a1c52eee9a7736d2006958f9b394eb5964dedd37e23038086ddc143fc2fd5e426c +"property-information@npm:^7.0.0": + version: 7.1.0 + resolution: "property-information@npm:7.1.0" + checksum: 10/896d38a52ad7170de73f832d277c69e76a9605d941ebb3f0d6e56271414a7fdf95ff6d2819e68036b8a0c7d2d4d88bf1d4a5765c032cb19c2343567ee3a14b15 languageName: node linkType: hard @@ -4529,15 +4977,14 @@ __metadata: languageName: node linkType: hard -"react-dom@npm:^18.0.2": - version: 18.3.1 - resolution: "react-dom@npm:18.3.1" +"react-dom@npm:19.1.0": + version: 19.1.0 + resolution: "react-dom@npm:19.1.0" dependencies: - loose-envify: "npm:^1.1.0" - scheduler: "npm:^0.23.2" + scheduler: "npm:^0.26.0" peerDependencies: - react: ^18.3.1 - checksum: 10/3f4b73a3aa083091173b29812b10394dd06f4ac06aff410b74702cfb3aa29d7b0ced208aab92d5272919b612e5cda21aeb1d54191848cf6e46e9e354f3541f81 + react: ^19.1.0 + checksum: 10/c5b58605862c7b0bb044416b01c73647bb8e89717fb5d7a2c279b11815fb7b49b619fe685c404e59f55eb52c66831236cc565c25ee1c2d042739f4a2cc538aa2 languageName: node linkType: hard @@ -4559,25 +5006,30 @@ __metadata: languageName: node linkType: hard -"react@npm:^18.0.2": - version: 18.3.1 - resolution: "react@npm:18.3.1" - dependencies: - loose-envify: "npm:^1.1.0" - checksum: 10/261137d3f3993eaa2368a83110466fc0e558bc2c7f7ae7ca52d94f03aac945f45146bd85e5f481044db1758a1dbb57879e2fcdd33924e2dde1bdc550ce73f7bf +"react-property@npm:2.0.2": + version: 2.0.2 + resolution: "react-property@npm:2.0.2" + checksum: 10/3a4bc1951b2b7992cb8a2d3f12016dd0920d1c06eb58b456204a6ae1210401d62baece098d3200ed8a0513dde247a5d96ffdb24f354e32ce5a9b26fbd8552668 + languageName: node + linkType: hard + +"react@npm:19.1.0": + version: 19.1.0 + resolution: "react@npm:19.1.0" + checksum: 10/d0180689826fd9de87e839c365f6f361c561daea397d61d724687cae88f432a307d1c0f53a0ee95ddbe3352c10dac41d7ff1ad85530fb24951b27a39e5398db4 languageName: node linkType: hard "recast@npm:^0.23.5": - version: 0.23.9 - resolution: "recast@npm:0.23.9" + version: 0.23.11 + resolution: "recast@npm:0.23.11" dependencies: ast-types: "npm:^0.16.1" esprima: "npm:~4.0.0" source-map: "npm:~0.6.1" tiny-invariant: "npm:^1.3.3" tslib: "npm:^2.0.1" - checksum: 10/d60584be179d81a82fbe58b5bbe009aa42831ee114a21a3e3a22bda91334e0b8a1a4610dca8ecb7f9ea1426da4febc08134d3003085ad6ecee478d1808eb8796 + checksum: 10/a622b7848efe13a59a40c9a1a3a8178433eae1048780e04d7392406e2d67fc29e3efa84b3aa8cfda28fd58989f4b59fa968bed295b739987a666bd11cc57a5b2 languageName: node linkType: hard @@ -4645,13 +5097,6 @@ __metadata: languageName: node linkType: hard -"regenerator-runtime@npm:^0.14.0": - version: 0.14.1 - resolution: "regenerator-runtime@npm:0.14.1" - checksum: 10/5db3161abb311eef8c45bcf6565f4f378f785900ed3945acf740a9888c792f75b98ecb77f0775f3bf95502ff423529d23e94f41d80c8256e8fa05ed4b07cf471 - languageName: node - linkType: hard - "regex-recursion@npm:^5.1.1": version: 5.1.1 resolution: "regex-recursion@npm:5.1.1" @@ -4678,7 +5123,7 @@ __metadata: languageName: node linkType: hard -"regexp.prototype.flags@npm:^1.5.3": +"regexp.prototype.flags@npm:^1.5.3, regexp.prototype.flags@npm:^1.5.4": version: 1.5.4 resolution: "regexp.prototype.flags@npm:1.5.4" dependencies: @@ -4703,6 +5148,19 @@ __metadata: languageName: node linkType: hard +"remark-mdx-remove-esm@npm:^1.1.0": + version: 1.2.0 + resolution: "remark-mdx-remove-esm@npm:1.2.0" + dependencies: + "@types/mdast": "npm:^4.0.4" + mdast-util-mdxjs-esm: "npm:^2.0.1" + unist-util-remove: "npm:^4.0.0" + peerDependencies: + unified: ^11 + checksum: 10/0a1155e08395ab73f877948455fc04d7457864f7556617efabecae7ea1b441cec2ca7ee9672e16a6cd56f2a16c57a4778f901e77d19052d1dd245de5bdf4618f + languageName: node + linkType: hard + "remark-mdx@npm:^3.0.0": version: 3.1.0 resolution: "remark-mdx@npm:3.1.0" @@ -4726,15 +5184,15 @@ __metadata: linkType: hard "remark-rehype@npm:^11.0.0": - version: 11.1.1 - resolution: "remark-rehype@npm:11.1.1" + version: 11.1.2 + resolution: "remark-rehype@npm:11.1.2" dependencies: "@types/hast": "npm:^3.0.0" "@types/mdast": "npm:^4.0.0" mdast-util-to-hast: "npm:^13.0.0" unified: "npm:^11.0.0" vfile: "npm:^6.0.0" - checksum: 10/39404bd19c57b2b69660be7e3d587ddb2240495845d42fad3bcc506c9c132d07abacb0a20182b73c530857b2da0c463ad5658382b448243ce432152ab49af08d + checksum: 10/b5374a0bf08398431c92740d0cd9b20aea9df44cee12326820ddcc1b7ee642706604006461ea9799554c347e7caf31e7432132a03b97c508e1f77d29c423bd86 languageName: node linkType: hard @@ -4805,9 +5263,9 @@ __metadata: linkType: hard "reusify@npm:^1.0.4": - version: 1.0.4 - resolution: "reusify@npm:1.0.4" - checksum: 10/14222c9e1d3f9ae01480c50d96057228a8524706db79cdeb5a2ce5bb7070dd9f409a6f84a02cbef8cdc80d39aef86f2dd03d155188a1300c599b05437dcd2ffb + version: 1.1.0 + resolution: "reusify@npm:1.1.0" + checksum: 10/af47851b547e8a8dc89af144fceee17b80d5beaf5e6f57ed086432d79943434ff67ca526e92275be6f54b6189f6920a24eace75c2657eed32d02c400312b21ec languageName: node linkType: hard @@ -4865,12 +5323,10 @@ __metadata: languageName: node linkType: hard -"scheduler@npm:^0.23.2": - version: 0.23.2 - resolution: "scheduler@npm:0.23.2" - dependencies: - loose-envify: "npm:^1.1.0" - checksum: 10/e8d68b89d18d5b028223edf090092846868a765a591944760942b77ea1f69b17235f7e956696efbb62c8130ab90af7e0949bfb8eba7896335507317236966bc9 +"scheduler@npm:^0.26.0": + version: 0.26.0 + resolution: "scheduler@npm:0.26.0" + checksum: 10/1ecf2e5d7de1a7a132796834afe14a2d589ba7e437615bd8c06f3e0786a3ac3434655e67aac8755d9b14e05754c177e49c064261de2673aaa3c926bc98caa002 languageName: node linkType: hard @@ -4883,12 +5339,21 @@ __metadata: languageName: node linkType: hard -"semver@npm:^7.6.0, semver@npm:^7.6.2, semver@npm:^7.6.3": - version: 7.6.3 - resolution: "semver@npm:7.6.3" +"semver@npm:^7.6.0, semver@npm:^7.6.2, semver@npm:^7.7.1, semver@npm:^7.7.2": + version: 7.7.2 + resolution: "semver@npm:7.7.2" bin: semver: bin/semver.js - checksum: 10/36b1fbe1a2b6f873559cd57b238f1094a053dbfd997ceeb8757d79d1d2089c56d1321b9f1069ce263dc64cfa922fa1d2ad566b39426fe1ac6c723c1487589e10 + checksum: 10/7a24cffcaa13f53c09ce55e05efe25cd41328730b2308678624f8b9f5fc3093fc4d189f47950f0b811ff8f3c3039c24a2c36717ba7961615c682045bf03e1dda + languageName: node + linkType: hard + +"serialize-error@npm:^12.0.0": + version: 12.0.0 + resolution: "serialize-error@npm:12.0.0" + dependencies: + type-fest: "npm:^4.31.0" + checksum: 10/733ddb9a2bd86515d18ef43f6bcb1f55a9d9b900944420e5606725668e64b752e5da971071d8fe1562961a926796257d2edb9fad828ec90a35cc6c32a75449bb languageName: node linkType: hard @@ -4929,6 +5394,81 @@ __metadata: languageName: node linkType: hard +"sharp@npm:^0.34.1": + version: 0.34.2 + resolution: "sharp@npm:0.34.2" + dependencies: + "@img/sharp-darwin-arm64": "npm:0.34.2" + "@img/sharp-darwin-x64": "npm:0.34.2" + "@img/sharp-libvips-darwin-arm64": "npm:1.1.0" + "@img/sharp-libvips-darwin-x64": "npm:1.1.0" + "@img/sharp-libvips-linux-arm": "npm:1.1.0" + "@img/sharp-libvips-linux-arm64": "npm:1.1.0" + "@img/sharp-libvips-linux-ppc64": "npm:1.1.0" + "@img/sharp-libvips-linux-s390x": "npm:1.1.0" + "@img/sharp-libvips-linux-x64": "npm:1.1.0" + "@img/sharp-libvips-linuxmusl-arm64": "npm:1.1.0" + "@img/sharp-libvips-linuxmusl-x64": "npm:1.1.0" + "@img/sharp-linux-arm": "npm:0.34.2" + "@img/sharp-linux-arm64": "npm:0.34.2" + "@img/sharp-linux-s390x": "npm:0.34.2" + "@img/sharp-linux-x64": "npm:0.34.2" + "@img/sharp-linuxmusl-arm64": "npm:0.34.2" + "@img/sharp-linuxmusl-x64": "npm:0.34.2" + "@img/sharp-wasm32": "npm:0.34.2" + "@img/sharp-win32-arm64": "npm:0.34.2" + "@img/sharp-win32-ia32": "npm:0.34.2" + "@img/sharp-win32-x64": "npm:0.34.2" + color: "npm:^4.2.3" + detect-libc: "npm:^2.0.4" + semver: "npm:^7.7.2" + dependenciesMeta: + "@img/sharp-darwin-arm64": + optional: true + "@img/sharp-darwin-x64": + optional: true + "@img/sharp-libvips-darwin-arm64": + optional: true + "@img/sharp-libvips-darwin-x64": + optional: true + "@img/sharp-libvips-linux-arm": + optional: true + "@img/sharp-libvips-linux-arm64": + optional: true + "@img/sharp-libvips-linux-ppc64": + optional: true + "@img/sharp-libvips-linux-s390x": + optional: true + "@img/sharp-libvips-linux-x64": + optional: true + "@img/sharp-libvips-linuxmusl-arm64": + optional: true + "@img/sharp-libvips-linuxmusl-x64": + optional: true + "@img/sharp-linux-arm": + optional: true + "@img/sharp-linux-arm64": + optional: true + "@img/sharp-linux-s390x": + optional: true + "@img/sharp-linux-x64": + optional: true + "@img/sharp-linuxmusl-arm64": + optional: true + "@img/sharp-linuxmusl-x64": + optional: true + "@img/sharp-wasm32": + optional: true + "@img/sharp-win32-arm64": + optional: true + "@img/sharp-win32-ia32": + optional: true + "@img/sharp-win32-x64": + optional: true + checksum: 10/8c7a6f20d58849a6e33bc69c4525f471d57eb3dea0072331b55ab12bae4b8bd8b99b65264aeaec38e54d52d692db13e3261f6e7bc29430b39b507c409838cbb0 + languageName: node + linkType: hard + "shebang-command@npm:^2.0.0": version: 2.0.0 resolution: "shebang-command@npm:2.0.0" @@ -4946,18 +5486,18 @@ __metadata: linkType: hard "shiki@npm:^1.26.1": - version: 1.26.1 - resolution: "shiki@npm:1.26.1" + version: 1.29.2 + resolution: "shiki@npm:1.29.2" dependencies: - "@shikijs/core": "npm:1.26.1" - "@shikijs/engine-javascript": "npm:1.26.1" - "@shikijs/engine-oniguruma": "npm:1.26.1" - "@shikijs/langs": "npm:1.26.1" - "@shikijs/themes": "npm:1.26.1" - "@shikijs/types": "npm:1.26.1" + "@shikijs/core": "npm:1.29.2" + "@shikijs/engine-javascript": "npm:1.29.2" + "@shikijs/engine-oniguruma": "npm:1.29.2" + "@shikijs/langs": "npm:1.29.2" + "@shikijs/themes": "npm:1.29.2" + "@shikijs/types": "npm:1.29.2" "@shikijs/vscode-textmate": "npm:^10.0.1" "@types/hast": "npm:^3.0.4" - checksum: 10/10b54241b2c58b0af228dbd00ebf2f7f820ec3527933c7fcbe7c1b634893fe003703f660cbf3ab4d0bdf61d2062590d3c7af5be57cd3192ebb4e5f2900d32f58 + checksum: 10/93de1ebc768ff497ba36720f3b385bff65a853248fdfc0afcb2aea81a43560b1bdc7db9e8417df11a87e106b0de0943989c6301daf62a43d09bd9ac7bc776bf3 languageName: node linkType: hard @@ -5009,10 +5549,12 @@ __metadata: languageName: node linkType: hard -"signal-exit@npm:^4.0.1": - version: 4.1.0 - resolution: "signal-exit@npm:4.1.0" - checksum: 10/c9fa63bbbd7431066174a48ba2dd9986dfd930c3a8b59de9c29d7b6854ec1c12a80d15310869ea5166d413b99f041bfa3dd80a7947bcd44ea8e6eb3ffeabfa1f +"simple-swizzle@npm:^0.2.2": + version: 0.2.2 + resolution: "simple-swizzle@npm:0.2.2" + dependencies: + is-arrayish: "npm:^0.3.1" + checksum: 10/c6dffff17aaa383dae7e5c056fbf10cf9855a9f79949f20ee225c04f06ddde56323600e0f3d6797e82d08d006e93761122527438ee9531620031c08c9e0d73cc languageName: node linkType: hard @@ -5044,18 +5586,28 @@ __metadata: languageName: node linkType: hard -"stable-hash@npm:^0.0.4": - version: 0.0.4 - resolution: "stable-hash@npm:0.0.4" - checksum: 10/21c039d21c1cb739cf8342561753a5e007cb95ea682ccd452e76310bbb9c6987a89de8eda023e320b019f3e4691aabda75079cdbb7dadf7ab9013e931f2f23cd +"stable-hash@npm:^0.0.5": + version: 0.0.5 + resolution: "stable-hash@npm:0.0.5" + checksum: 10/9222ea2c558e37c4a576cb4e406966b9e6aa05b93f5c4f09ef4aaabe3577439b9b8fbff407b16840b63e2ae83de74290c7b1c2da7360d571e480e46a4aec0a56 + languageName: node + linkType: hard + +"stop-iteration-iterator@npm:^1.1.0": + version: 1.1.0 + resolution: "stop-iteration-iterator@npm:1.1.0" + dependencies: + es-errors: "npm:^1.3.0" + internal-slot: "npm:^1.1.0" + checksum: 10/ff36c4db171ee76c936ccfe9541946b77017f12703d4c446652017356816862d3aa029a64e7d4c4ceb484e00ed4a81789333896390d808458638f3a216aa1f41 languageName: node linkType: hard "storybook@npm:^8.6.8": - version: 8.6.12 - resolution: "storybook@npm:8.6.12" + version: 8.6.14 + resolution: "storybook@npm:8.6.14" dependencies: - "@storybook/core": "npm:8.6.12" + "@storybook/core": "npm:8.6.14" peerDependencies: prettier: ^2 || ^3 peerDependenciesMeta: @@ -5065,7 +5617,7 @@ __metadata: getstorybook: ./bin/index.cjs sb: ./bin/index.cjs storybook: ./bin/index.cjs - checksum: 10/babd1d086eb02ba25ee659e02e619f7797a6b91028ad74d2da0ab77e72021cd5c2ac4f239668f15156aabf00bd97066a774370dceadf178b1e649bf971160a26 + checksum: 10/104932fe29ebf49bef24c90285741cec964d1c36b3f0b38da1dace31ac664be457f2a510e41ba69fe8aa0d90c20e3446fec27d1ced41e5eefb3a9ca713d99e79 languageName: node linkType: hard @@ -5076,28 +5628,6 @@ __metadata: languageName: node linkType: hard -"string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^4.1.0": - version: 4.2.3 - resolution: "string-width@npm:4.2.3" - dependencies: - emoji-regex: "npm:^8.0.0" - is-fullwidth-code-point: "npm:^3.0.0" - strip-ansi: "npm:^6.0.1" - checksum: 10/e52c10dc3fbfcd6c3a15f159f54a90024241d0f149cf8aed2982a2d801d2e64df0bf1dc351cf8e95c3319323f9f220c16e740b06faecd53e2462df1d2b5443fb - languageName: node - linkType: hard - -"string-width@npm:^5.0.1, string-width@npm:^5.1.2": - version: 5.1.2 - resolution: "string-width@npm:5.1.2" - dependencies: - eastasianwidth: "npm:^0.2.0" - emoji-regex: "npm:^9.2.2" - strip-ansi: "npm:^7.0.1" - checksum: 10/7369deaa29f21dda9a438686154b62c2c5f661f8dda60449088f9f980196f7908fc39fdd1803e3e01541970287cf5deae336798337e9319a7055af89dafa7193 - languageName: node - linkType: hard - "string.prototype.includes@npm:^2.0.1": version: 2.0.1 resolution: "string.prototype.includes@npm:2.0.1" @@ -5188,7 +5718,7 @@ __metadata: languageName: node linkType: hard -"strip-ansi-cjs@npm:strip-ansi@^6.0.1, strip-ansi@npm:^6.0.0, strip-ansi@npm:^6.0.1": +"strip-ansi@npm:^6.0.1": version: 6.0.1 resolution: "strip-ansi@npm:6.0.1" dependencies: @@ -5197,15 +5727,6 @@ __metadata: languageName: node linkType: hard -"strip-ansi@npm:^7.0.1": - version: 7.1.0 - resolution: "strip-ansi@npm:7.1.0" - dependencies: - ansi-regex: "npm:^6.0.1" - checksum: 10/475f53e9c44375d6e72807284024ac5d668ee1d06010740dec0b9744f2ddf47de8d7151f80e5f6190fc8f384e802fdf9504b76a7e9020c9faee7103623338be2 - languageName: node - linkType: hard - "strip-bom@npm:^3.0.0": version: 3.0.0 resolution: "strip-bom@npm:3.0.0" @@ -5227,7 +5748,16 @@ __metadata: languageName: node linkType: hard -"style-to-object@npm:^1.0.0": +"style-to-js@npm:1.1.16, style-to-js@npm:^1.0.0": + version: 1.1.16 + resolution: "style-to-js@npm:1.1.16" + dependencies: + style-to-object: "npm:1.0.8" + checksum: 10/a876cc49a29ac90c7723b4d6f002ac6c1ac5ccc6b5bc963d9c607cfc74b15927b704c9324df6f824f576c65689fe4b4ff79caabcd44a13d8a02641f721f1b316 + languageName: node + linkType: hard + +"style-to-object@npm:1.0.8": version: 1.0.8 resolution: "style-to-object@npm:1.0.8" dependencies: @@ -5236,19 +5766,19 @@ __metadata: languageName: node linkType: hard -"styled-jsx@npm:5.1.1": - version: 5.1.1 - resolution: "styled-jsx@npm:5.1.1" +"styled-jsx@npm:5.1.6": + version: 5.1.6 + resolution: "styled-jsx@npm:5.1.6" dependencies: client-only: "npm:0.0.1" peerDependencies: - react: ">= 16.8.0 || 17.x.x || ^18.0.0-0" + react: ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" peerDependenciesMeta: "@babel/core": optional: true babel-plugin-macros: optional: true - checksum: 10/4f6a5d0010770fdeea1183d919d528fd46c484e23c0535ef3e1dd49488116f639c594f3bd4440e3bc8a8686c9f8d53c5761599870ff039ede11a5c3bfe08a4be + checksum: 10/ba01200e8227fe1441a719c2e7da96c8aa7ef61d14211d1500e1abce12efa118479bcb6e7e12beecb9e1db76432caad2f4e01bbc0c9be21c134b088a4ca5ffe0 languageName: node linkType: hard @@ -5268,13 +5798,6 @@ __metadata: languageName: node linkType: hard -"tapable@npm:^2.2.0": - version: 2.2.1 - resolution: "tapable@npm:2.2.1" - checksum: 10/1769336dd21481ae6347611ca5fca47add0962fd8e80466515032125eca0084a4f0ede11e65341b9c0018ef4e1cf1ad820adbb0fba7cc99865c6005734000b0a - languageName: node - linkType: hard - "text-table@npm:^0.2.0": version: 0.2.0 resolution: "text-table@npm:0.2.0" @@ -5289,6 +5812,16 @@ __metadata: languageName: node linkType: hard +"tinyglobby@npm:^0.2.13": + version: 0.2.14 + resolution: "tinyglobby@npm:0.2.14" + dependencies: + fdir: "npm:^6.4.4" + picomatch: "npm:^4.0.2" + checksum: 10/3d306d319718b7cc9d79fb3f29d8655237aa6a1f280860a217f93417039d0614891aee6fc47c5db315f4fcc6ac8d55eb8e23e2de73b2c51a431b42456d9e5764 + languageName: node + linkType: hard + "to-regex-range@npm:^5.0.1": version: 5.0.1 resolution: "to-regex-range@npm:5.0.1" @@ -5312,12 +5845,12 @@ __metadata: languageName: node linkType: hard -"ts-api-utils@npm:^2.0.0": - version: 2.0.0 - resolution: "ts-api-utils@npm:2.0.0" +"ts-api-utils@npm:^2.1.0": + version: 2.1.0 + resolution: "ts-api-utils@npm:2.1.0" peerDependencies: typescript: ">=4.8.4" - checksum: 10/485bdf8bbba98d58712243d958f4fd44742bbe49e559cd77882fb426d866eec6dd05c67ef91935dc4f8a3c776f235859735e1f05be399e4dc9e7ffd580120974 + checksum: 10/02e55b49d9617c6eebf8aadfa08d3ca03ca0cd2f0586ad34117fdfc7aa3cd25d95051843fde9df86665ad907f99baed179e7a117b11021417f379e4d2614eacd languageName: node linkType: hard @@ -5333,7 +5866,7 @@ __metadata: languageName: node linkType: hard -"tslib@npm:^2.0.1, tslib@npm:^2.4.0": +"tslib@npm:^2.0.1, tslib@npm:^2.4.0, tslib@npm:^2.8.0": version: 2.8.1 resolution: "tslib@npm:2.8.1" checksum: 10/3e2e043d5c2316461cb54e5c7fe02c30ef6dccb3384717ca22ae5c6b5bc95232a6241df19c622d9c73b809bea33b187f6dbc73030963e29950c2141bc32a79f7 @@ -5356,6 +5889,13 @@ __metadata: languageName: node linkType: hard +"type-fest@npm:^4.31.0": + version: 4.41.0 + resolution: "type-fest@npm:4.41.0" + checksum: 10/617ace794ac0893c2986912d28b3065ad1afb484cad59297835a0807dc63286c39e8675d65f7de08fafa339afcb8fe06a36e9a188b9857756ae1e92ee8bda212 + languageName: node + linkType: hard + "typed-array-buffer@npm:^1.0.3": version: 1.0.3 resolution: "typed-array-buffer@npm:1.0.3" @@ -5441,10 +5981,10 @@ __metadata: languageName: node linkType: hard -"undici-types@npm:~6.19.2": - version: 6.19.8 - resolution: "undici-types@npm:6.19.8" - checksum: 10/cf0b48ed4fc99baf56584afa91aaffa5010c268b8842f62e02f752df209e3dea138b372a60a963b3b2576ed932f32329ce7ddb9cb5f27a6c83040d8cd74b7a70 +"undici-types@npm:~6.21.0": + version: 6.21.0 + resolution: "undici-types@npm:6.21.0" + checksum: 10/ec8f41aa4359d50f9b59fa61fe3efce3477cc681908c8f84354d8567bb3701fafdddf36ef6bff307024d3feb42c837cf6f670314ba37fc8145e219560e473d14 languageName: node linkType: hard @@ -5490,6 +6030,17 @@ __metadata: languageName: node linkType: hard +"unist-util-remove@npm:^4.0.0": + version: 4.0.0 + resolution: "unist-util-remove@npm:4.0.0" + dependencies: + "@types/unist": "npm:^3.0.0" + unist-util-is: "npm:^6.0.0" + unist-util-visit-parents: "npm:^6.0.0" + checksum: 10/24a84224720f4c2d2ffce1d570c00b83ef545de80ec32a246698feff880446af6c410fc94deec4b4daafe09851d59f17cd1770e20f66d68092e3cd60c2147fb8 + languageName: node + linkType: hard + "unist-util-stringify-position@npm:^4.0.0": version: 4.0.0 resolution: "unist-util-stringify-position@npm:4.0.0" @@ -5520,6 +6071,67 @@ __metadata: languageName: node linkType: hard +"unrs-resolver@npm:^1.6.2": + version: 1.7.13 + resolution: "unrs-resolver@npm:1.7.13" + dependencies: + "@unrs/resolver-binding-darwin-arm64": "npm:1.7.13" + "@unrs/resolver-binding-darwin-x64": "npm:1.7.13" + "@unrs/resolver-binding-freebsd-x64": "npm:1.7.13" + "@unrs/resolver-binding-linux-arm-gnueabihf": "npm:1.7.13" + "@unrs/resolver-binding-linux-arm-musleabihf": "npm:1.7.13" + "@unrs/resolver-binding-linux-arm64-gnu": "npm:1.7.13" + "@unrs/resolver-binding-linux-arm64-musl": "npm:1.7.13" + "@unrs/resolver-binding-linux-ppc64-gnu": "npm:1.7.13" + "@unrs/resolver-binding-linux-riscv64-gnu": "npm:1.7.13" + "@unrs/resolver-binding-linux-riscv64-musl": "npm:1.7.13" + "@unrs/resolver-binding-linux-s390x-gnu": "npm:1.7.13" + "@unrs/resolver-binding-linux-x64-gnu": "npm:1.7.13" + "@unrs/resolver-binding-linux-x64-musl": "npm:1.7.13" + "@unrs/resolver-binding-wasm32-wasi": "npm:1.7.13" + "@unrs/resolver-binding-win32-arm64-msvc": "npm:1.7.13" + "@unrs/resolver-binding-win32-ia32-msvc": "npm:1.7.13" + "@unrs/resolver-binding-win32-x64-msvc": "npm:1.7.13" + napi-postinstall: "npm:^0.2.2" + dependenciesMeta: + "@unrs/resolver-binding-darwin-arm64": + optional: true + "@unrs/resolver-binding-darwin-x64": + optional: true + "@unrs/resolver-binding-freebsd-x64": + optional: true + "@unrs/resolver-binding-linux-arm-gnueabihf": + optional: true + "@unrs/resolver-binding-linux-arm-musleabihf": + optional: true + "@unrs/resolver-binding-linux-arm64-gnu": + optional: true + "@unrs/resolver-binding-linux-arm64-musl": + optional: true + "@unrs/resolver-binding-linux-ppc64-gnu": + optional: true + "@unrs/resolver-binding-linux-riscv64-gnu": + optional: true + "@unrs/resolver-binding-linux-riscv64-musl": + optional: true + "@unrs/resolver-binding-linux-s390x-gnu": + optional: true + "@unrs/resolver-binding-linux-x64-gnu": + optional: true + "@unrs/resolver-binding-linux-x64-musl": + optional: true + "@unrs/resolver-binding-wasm32-wasi": + optional: true + "@unrs/resolver-binding-win32-arm64-msvc": + optional: true + "@unrs/resolver-binding-win32-ia32-msvc": + optional: true + "@unrs/resolver-binding-win32-x64-msvc": + optional: true + checksum: 10/362aa31e5cd635cf5955a7eb3fe58230a1a32bd5daba4c71e7620e0a0fcd35fffb926655e32d4834a82d48b676cf8a2208cf1de30e30b4bc85c2dc67fa60acb8 + languageName: node + linkType: hard + "uri-js@npm:^4.2.2": version: 4.4.1 resolution: "uri-js@npm:4.4.1" @@ -5542,6 +6154,16 @@ __metadata: languageName: node linkType: hard +"vfile-matter@npm:^5.0.1": + version: 5.0.1 + resolution: "vfile-matter@npm:5.0.1" + dependencies: + vfile: "npm:^6.0.0" + yaml: "npm:^2.0.0" + checksum: 10/5eddf848617050df7b539b68c60f4850d4f87e848accb44eb541719cece48a170897fae759023d0f3a87bcfc65fc2183a9875f11c7b3dc9ceaab7b4d739f74d6 + languageName: node + linkType: hard + "vfile-message@npm:^4.0.0": version: 4.0.2 resolution: "vfile-message@npm:4.0.2" @@ -5552,7 +6174,7 @@ __metadata: languageName: node linkType: hard -"vfile@npm:^6.0.0": +"vfile@npm:^6.0.0, vfile@npm:^6.0.3": version: 6.0.3 resolution: "vfile@npm:6.0.3" dependencies: @@ -5615,7 +6237,7 @@ __metadata: languageName: node linkType: hard -"which-typed-array@npm:^1.1.16, which-typed-array@npm:^1.1.18, which-typed-array@npm:^1.1.2": +"which-typed-array@npm:^1.1.16, which-typed-array@npm:^1.1.19, which-typed-array@npm:^1.1.2": version: 1.1.19 resolution: "which-typed-array@npm:1.1.19" dependencies: @@ -5648,28 +6270,6 @@ __metadata: languageName: node linkType: hard -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": - version: 7.0.0 - resolution: "wrap-ansi@npm:7.0.0" - dependencies: - ansi-styles: "npm:^4.0.0" - string-width: "npm:^4.1.0" - strip-ansi: "npm:^6.0.0" - checksum: 10/cebdaeca3a6880da410f75209e68cd05428580de5ad24535f22696d7d9cab134d1f8498599f344c3cf0fb37c1715807a183778d8c648d6cc0cb5ff2bb4236540 - languageName: node - linkType: hard - -"wrap-ansi@npm:^8.1.0": - version: 8.1.0 - resolution: "wrap-ansi@npm:8.1.0" - dependencies: - ansi-styles: "npm:^6.1.0" - string-width: "npm:^5.0.1" - strip-ansi: "npm:^7.0.1" - checksum: 10/7b1e4b35e9bb2312d2ee9ee7dc95b8cb5f8b4b5a89f7dde5543fe66c1e3715663094defa50d75454ac900bd210f702d575f15f3f17fa9ec0291806d2578d1ddf - languageName: node - linkType: hard - "wrappy@npm:1": version: 1.0.2 resolution: "wrappy@npm:1.0.2" @@ -5678,8 +6278,8 @@ __metadata: linkType: hard "ws@npm:^8.2.3": - version: 8.18.1 - resolution: "ws@npm:8.18.1" + version: 8.18.2 + resolution: "ws@npm:8.18.2" peerDependencies: bufferutil: ^4.0.1 utf-8-validate: ">=5.0.2" @@ -5688,7 +6288,16 @@ __metadata: optional: true utf-8-validate: optional: true - checksum: 10/3f38e9594f2af5b6324138e86b74df7d77bbb8e310bf8188679dd80bac0d1f47e51536a1923ac3365f31f3d8b25ea0b03e4ade466aa8292a86cd5defca64b19b + checksum: 10/018e04ec95561d88248d53a2eaf094b4ae131e9b062f2679e6e8a62f04649bc543448f1e038125225ac6bbb25f54c1e65d7a2cc9dbc1e28b43e5e6b7162ad88e + languageName: node + linkType: hard + +"yaml@npm:^2.0.0": + version: 2.8.0 + resolution: "yaml@npm:2.8.0" + bin: + yaml: bin.mjs + checksum: 10/7d4bd9c10d0e467601f496193f2ac254140f8e36f96f5ff7f852b9ce37974168eb7354f4c36dc8837dde527a2043d004b6aff48818ec24a69ab2dd3c6b6c381c languageName: node linkType: hard diff --git a/docs/architecture-decisions/adr000-template.md b/docs/architecture-decisions/adr000-template.md index f16ae7d39f..267eceab44 100644 --- a/docs/architecture-decisions/adr000-template.md +++ b/docs/architecture-decisions/adr000-template.md @@ -1,7 +1,6 @@ --- id: adrs-adr000 title: 'ADR000: [TITLE]' -# prettier-ignore description: Architecture Decision Record (ADR) for [TITLE] [DESCRIPTION] --- diff --git a/docs/architecture-decisions/adr001-add-adr-log.md b/docs/architecture-decisions/adr001-add-adr-log.md index de4283319a..8ad0fa3748 100644 --- a/docs/architecture-decisions/adr001-add-adr-log.md +++ b/docs/architecture-decisions/adr001-add-adr-log.md @@ -1,7 +1,6 @@ --- id: adrs-adr001 title: 'ADR001: Architecture Decision Record (ADR) log' -# prettier-ignore description: Architecture Decision Record (ADR) logs as a reference point for the team --- diff --git a/docs/architecture-decisions/adr002-default-catalog-file-format.md b/docs/architecture-decisions/adr002-default-catalog-file-format.md index 3b606cf46b..eb84913313 100644 --- a/docs/architecture-decisions/adr002-default-catalog-file-format.md +++ b/docs/architecture-decisions/adr002-default-catalog-file-format.md @@ -1,7 +1,6 @@ --- id: adrs-adr002 title: 'ADR002: Default Software Catalog File Format' -# prettier-ignore description: Architecture Decision Record (ADR) log on Default Software Catalog File Format --- diff --git a/docs/architecture-decisions/adr003-avoid-default-exports.md b/docs/architecture-decisions/adr003-avoid-default-exports.md index 24445f0be1..8ba37914df 100644 --- a/docs/architecture-decisions/adr003-avoid-default-exports.md +++ b/docs/architecture-decisions/adr003-avoid-default-exports.md @@ -1,7 +1,6 @@ --- id: adrs-adr003 title: 'ADR003: Avoid Default Exports and Prefer Named Exports' -# prettier-ignore description: Architecture Decision Record (ADR) log on Avoid Default Exports and Prefer Named Exports --- diff --git a/docs/architecture-decisions/adr004-module-export-structure.md b/docs/architecture-decisions/adr004-module-export-structure.md index 95d0f27811..507859ef01 100644 --- a/docs/architecture-decisions/adr004-module-export-structure.md +++ b/docs/architecture-decisions/adr004-module-export-structure.md @@ -1,7 +1,6 @@ --- id: adrs-adr004 title: 'ADR004: Module Export Structure' -# prettier-ignore description: Architecture Decision Record (ADR) log on Module Export Structure --- diff --git a/docs/architecture-decisions/adr005-catalog-core-entities.md b/docs/architecture-decisions/adr005-catalog-core-entities.md index 1206d9e83d..ca65425645 100644 --- a/docs/architecture-decisions/adr005-catalog-core-entities.md +++ b/docs/architecture-decisions/adr005-catalog-core-entities.md @@ -1,7 +1,6 @@ --- id: adrs-adr005 title: 'ADR005: Catalog Core Entities' -# prettier-ignore description: Architecture Decision Record (ADR) log on Catalog Core Entities --- diff --git a/docs/architecture-decisions/adr006-avoid-react-fc.md b/docs/architecture-decisions/adr006-avoid-react-fc.md index 6a7c431655..0630718763 100644 --- a/docs/architecture-decisions/adr006-avoid-react-fc.md +++ b/docs/architecture-decisions/adr006-avoid-react-fc.md @@ -1,7 +1,6 @@ --- id: adrs-adr006 title: 'ADR006: Avoid React.FC and React.SFC' -# prettier-ignore description: Architecture Decision Record (ADR) log on Avoid React.FC and React.SFC --- diff --git a/docs/architecture-decisions/adr007-use-msw-to-mock-service-requests.md b/docs/architecture-decisions/adr007-use-msw-to-mock-service-requests.md index a61bb78787..535adea8cb 100644 --- a/docs/architecture-decisions/adr007-use-msw-to-mock-service-requests.md +++ b/docs/architecture-decisions/adr007-use-msw-to-mock-service-requests.md @@ -1,7 +1,6 @@ --- id: adrs-adr007 title: 'ADR007: Use MSW to mock http requests' -# prettier-ignore description: Architecture Decision Record (ADR) log on Use MSW to mock http requests --- diff --git a/docs/architecture-decisions/adr008-default-catalog-file-name.md b/docs/architecture-decisions/adr008-default-catalog-file-name.md index fca65c8355..1f00c19b7e 100644 --- a/docs/architecture-decisions/adr008-default-catalog-file-name.md +++ b/docs/architecture-decisions/adr008-default-catalog-file-name.md @@ -1,7 +1,6 @@ --- id: adrs-adr008 title: 'ADR008: Default Catalog File Name' -# prettier-ignore description: Architecture Decision Record (ADR) log on Default Catalog File Name --- diff --git a/docs/architecture-decisions/adr009-entity-references.md b/docs/architecture-decisions/adr009-entity-references.md index 7cac946388..5779503113 100644 --- a/docs/architecture-decisions/adr009-entity-references.md +++ b/docs/architecture-decisions/adr009-entity-references.md @@ -1,7 +1,6 @@ --- id: adrs-adr009 title: 'ADR009: Entity References' -# prettier-ignore description: Architecture Decision Record (ADR) log on Entity References --- diff --git a/docs/architecture-decisions/adr010-luxon-date-library.md b/docs/architecture-decisions/adr010-luxon-date-library.md index a7b287ae0d..262a468fa9 100644 --- a/docs/architecture-decisions/adr010-luxon-date-library.md +++ b/docs/architecture-decisions/adr010-luxon-date-library.md @@ -1,7 +1,6 @@ --- id: adrs-adr010 title: 'ADR010: Use the Luxon Date Library' -# prettier-ignore description: Architecture Decision Record (ADR) for Luxon Date Library --- diff --git a/docs/architecture-decisions/adr011-plugin-package-structure.md b/docs/architecture-decisions/adr011-plugin-package-structure.md index 8e4b5435f9..323483e2d9 100644 --- a/docs/architecture-decisions/adr011-plugin-package-structure.md +++ b/docs/architecture-decisions/adr011-plugin-package-structure.md @@ -1,7 +1,6 @@ --- id: adrs-adr011 title: 'ADR011: Plugin Package Structure' -# prettier-ignore description: Architecture Decision Record (ADR) for Plugin Package Structure --- diff --git a/docs/architecture-decisions/adr012-use-luxon-locale-and-date-presets.md b/docs/architecture-decisions/adr012-use-luxon-locale-and-date-presets.md index 25bb6c1833..423e2c58f6 100644 --- a/docs/architecture-decisions/adr012-use-luxon-locale-and-date-presets.md +++ b/docs/architecture-decisions/adr012-use-luxon-locale-and-date-presets.md @@ -1,7 +1,6 @@ --- id: adrs-adr012 title: 'ADR012: Use Luxon.toLocaleString and date/time presets' -# prettier-ignore description: Architecture Decision Record (ADR) for using Luxon's toLocaleString method and date/time presets for displaying dates and times --- diff --git a/docs/architecture-decisions/adr013-use-node-fetch.md b/docs/architecture-decisions/adr013-use-node-fetch.md index e65cf0a97b..664faed1db 100644 --- a/docs/architecture-decisions/adr013-use-node-fetch.md +++ b/docs/architecture-decisions/adr013-use-node-fetch.md @@ -1,7 +1,6 @@ --- id: adrs-adr013 title: 'ADR013: [superseded] Proper use of HTTP fetching libraries' -# prettier-ignore description: Architecture Decision Record (ADR) for the proper use of fetchApiRef, node-fetch, and cross-fetch for data fetching. --- diff --git a/docs/architecture-decisions/adr014-use-fetch.md b/docs/architecture-decisions/adr014-use-fetch.md index 8454e69e7c..9faa6c9ead 100644 --- a/docs/architecture-decisions/adr014-use-fetch.md +++ b/docs/architecture-decisions/adr014-use-fetch.md @@ -1,7 +1,6 @@ --- id: adrs-adr014 title: 'ADR014: Proper use of HTTP fetching libraries' -# prettier-ignore description: Architecture Decision Record (ADR) for the proper use of fetchApiRef, native fetch, and cross-fetch for data fetching. --- diff --git a/docs/architecture-decisions/index.md b/docs/architecture-decisions/index.md index 8bb854497a..eddbdbe81e 100644 --- a/docs/architecture-decisions/index.md +++ b/docs/architecture-decisions/index.md @@ -2,7 +2,6 @@ id: adrs-overview title: Architecture Decision Records (ADR) sidebar_label: Overview -# prettier-ignore description: Overview of Architecture Decision Records (ADR) --- diff --git a/docs/auth/autologout.md b/docs/auth/autologout.md index b85f6f486d..e2462522f4 100644 --- a/docs/auth/autologout.md +++ b/docs/auth/autologout.md @@ -1,7 +1,6 @@ --- id: autologout title: Auto Logout -# prettier-ignore description: This section describes how to setup the Auto Logout mechanism in Backstage --- @@ -69,7 +68,7 @@ These are the available settings: | Configuration Key | Component Property | Description | Allowed Values | Default Value | | ----------------------------------------- | ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------- | --------------------------- | | `auth.autologout.enabled` | `enabled` | Enable/disable the Auto Logout feature. | `true`/`false` | Default is enabled (`true`) | -| `auth.autologout.idleTimeoutMinutes` | `idleTimeoutMinutes` | Sets the idle time (in minutes) after which the user will be logged out. | `>= 0.5` minutes | `60` | +| `auth.autologout.idleTimeoutMinutes` | `idleTimeoutMinutes` | Sets the idle time (in minutes) after which the user will be logged out. | `>= 0.5` minutes | `0.5` | | `auth.autologout.promptBeforeIdleSeconds` | `promptBeforeIdleSeconds` | Determines the time (in seconds) prior to idle state when a prompt will appear. A value of 0 disables the prompt. This must be less than the value of `idleTimeoutMinutes`. | `>= 0` seconds | `10` | | `auth.autologout.useWorkerTimers` | `useWorkerTimers` | Enables or disables the use of Node's worker thread timers instead of main thread timers. This can be beneficial if the browser is terminating timers in inactive tabs, like those used by auto logout. In case of browser incompatibility, try setting this to false. | `true`/`false` | `true` | | `auth.autologout.logoutIfDisconnected` | `logoutIfDisconnected` | Enable/disable auto logout for disconnected users. Disconnected users are those who are logged in but do not have any active Backstage tabs open in their browsers. If enabled, such users will be automatically logged out after `idleTimeoutMinutes`. | `true`/`false` | `true` | diff --git a/docs/auth/google/gcp-iap-auth.md b/docs/auth/google/gcp-iap-auth.md index 6fe8b56d9e..386fab383f 100644 --- a/docs/auth/google/gcp-iap-auth.md +++ b/docs/auth/google/gcp-iap-auth.md @@ -2,7 +2,6 @@ id: gcp-iap-auth title: Google Identity-Aware Proxy Provider sidebar_label: Google IAP -# prettier-ignore description: Adding Google Identity-Aware Proxy as an authentication provider in Backstage --- diff --git a/docs/auth/oauth.md b/docs/auth/oauth.md index fbd87d653b..06b204fdaf 100644 --- a/docs/auth/oauth.md +++ b/docs/auth/oauth.md @@ -1,7 +1,6 @@ --- id: oauth title: OAuth and OpenID Connect -# prettier-ignore description: This section describes how Backstage allows plugins to request OAuth Access Tokens and OpenID Connect ID Tokens on behalf of the user, to be used for auth to various third party APIs --- diff --git a/docs/auth/service-to-service-auth.md b/docs/auth/service-to-service-auth.md index fecb3f5191..d35aed364d 100644 --- a/docs/auth/service-to-service-auth.md +++ b/docs/auth/service-to-service-auth.md @@ -1,7 +1,6 @@ --- id: service-to-service-auth title: Service to Service Auth -# prettier-ignore description: This section describes service to service authentication works, both internally within Backstage plugins and when external callers want to make requests. --- diff --git a/docs/backend-system/architecture/01-index.md b/docs/backend-system/architecture/01-index.md index 968ff2f001..293a46b7ca 100644 --- a/docs/backend-system/architecture/01-index.md +++ b/docs/backend-system/architecture/01-index.md @@ -2,7 +2,6 @@ id: index title: Backend System Architecture sidebar_label: Overview -# prettier-ignore description: The structure and architecture of the new Backend System and its component parts --- diff --git a/docs/backend-system/architecture/02-backends.md b/docs/backend-system/architecture/02-backends.md index 1310453a3f..8f903eb7a8 100644 --- a/docs/backend-system/architecture/02-backends.md +++ b/docs/backend-system/architecture/02-backends.md @@ -2,7 +2,6 @@ id: backends title: Backend Instances sidebar_label: Backend -# prettier-ignore description: Backend instances --- diff --git a/docs/backend-system/architecture/03-services.md b/docs/backend-system/architecture/03-services.md index ad437e471e..cfcd606d92 100644 --- a/docs/backend-system/architecture/03-services.md +++ b/docs/backend-system/architecture/03-services.md @@ -2,7 +2,6 @@ id: services title: Backend Services sidebar_label: Services -# prettier-ignore description: Services for backend plugins --- diff --git a/docs/backend-system/architecture/04-plugins.md b/docs/backend-system/architecture/04-plugins.md index f2a6b856b9..fdb5012569 100644 --- a/docs/backend-system/architecture/04-plugins.md +++ b/docs/backend-system/architecture/04-plugins.md @@ -2,7 +2,6 @@ id: plugins title: Backend Plugins sidebar_label: Plugins -# prettier-ignore description: Backend plugins --- diff --git a/docs/backend-system/architecture/05-extension-points.md b/docs/backend-system/architecture/05-extension-points.md index 12c4ec75f5..2e11d2763f 100644 --- a/docs/backend-system/architecture/05-extension-points.md +++ b/docs/backend-system/architecture/05-extension-points.md @@ -2,7 +2,6 @@ id: extension-points title: Backend Plugin Extension Points sidebar_label: Extension Points -# prettier-ignore description: Extension points of backend plugins --- diff --git a/docs/backend-system/architecture/06-modules.md b/docs/backend-system/architecture/06-modules.md index 010f36109c..e8905808ee 100644 --- a/docs/backend-system/architecture/06-modules.md +++ b/docs/backend-system/architecture/06-modules.md @@ -2,7 +2,6 @@ id: modules title: Plugin Modules sidebar_label: Modules -# prettier-ignore description: Modules for backend plugins --- diff --git a/docs/backend-system/architecture/07-feature-loaders.md b/docs/backend-system/architecture/07-feature-loaders.md index b2cc574bf9..0a2d611b7b 100644 --- a/docs/backend-system/architecture/07-feature-loaders.md +++ b/docs/backend-system/architecture/07-feature-loaders.md @@ -2,7 +2,6 @@ id: feature-loaders title: Backend Feature Loaders sidebar_label: Feature Loaders -# prettier-ignore description: Backend feature loaders --- diff --git a/docs/backend-system/architecture/08-naming-patterns.md b/docs/backend-system/architecture/08-naming-patterns.md index 32ed1d9035..585a9fe87c 100644 --- a/docs/backend-system/architecture/08-naming-patterns.md +++ b/docs/backend-system/architecture/08-naming-patterns.md @@ -2,7 +2,6 @@ id: naming-patterns title: Backend System Naming Patterns sidebar_label: Naming Patterns -# prettier-ignore description: Naming patterns in the backend system --- diff --git a/docs/backend-system/building-backends/01-index.md b/docs/backend-system/building-backends/01-index.md index ec95e57973..0f0a8e01ea 100644 --- a/docs/backend-system/building-backends/01-index.md +++ b/docs/backend-system/building-backends/01-index.md @@ -2,7 +2,6 @@ id: index title: Building Backends sidebar_label: Overview -# prettier-ignore description: Building backends using the new backend system --- diff --git a/docs/backend-system/building-backends/08-migrating.md b/docs/backend-system/building-backends/08-migrating.md index a827171ff7..c07862cc3c 100644 --- a/docs/backend-system/building-backends/08-migrating.md +++ b/docs/backend-system/building-backends/08-migrating.md @@ -2,7 +2,6 @@ id: migrating title: Migrating your Backend to the New Backend System sidebar_label: Migration Guide -# prettier-ignore description: How to migrate existing backends to the new backend system --- diff --git a/docs/backend-system/building-plugins-and-modules/01-index.md b/docs/backend-system/building-plugins-and-modules/01-index.md index db78faaced..53bf4af8ef 100644 --- a/docs/backend-system/building-plugins-and-modules/01-index.md +++ b/docs/backend-system/building-plugins-and-modules/01-index.md @@ -2,7 +2,6 @@ id: index title: Building Backend Plugins and Modules sidebar_label: Overview -# prettier-ignore description: Building backend plugins and modules using the new backend system --- diff --git a/docs/backend-system/building-plugins-and-modules/02-testing.md b/docs/backend-system/building-plugins-and-modules/02-testing.md index f72d2de49b..6000c14a45 100644 --- a/docs/backend-system/building-plugins-and-modules/02-testing.md +++ b/docs/backend-system/building-plugins-and-modules/02-testing.md @@ -2,7 +2,6 @@ id: testing title: Testing Backend Plugins and Modules sidebar_label: Testing -# prettier-ignore description: Learn how to test your backend plugins and modules --- diff --git a/docs/backend-system/building-plugins-and-modules/08-migrating.md b/docs/backend-system/building-plugins-and-modules/08-migrating.md index 5da443328c..f48c5579f6 100644 --- a/docs/backend-system/building-plugins-and-modules/08-migrating.md +++ b/docs/backend-system/building-plugins-and-modules/08-migrating.md @@ -2,7 +2,6 @@ id: migrating title: Migrating your Backend Plugin to the New Backend System sidebar_label: Migration Guide -# prettier-ignore description: How to migrate existing backend plugins to the new backend system --- diff --git a/docs/backend-system/core-services/01-index.md b/docs/backend-system/core-services/01-index.md index 3be12b2e26..50ebea0e4f 100644 --- a/docs/backend-system/core-services/01-index.md +++ b/docs/backend-system/core-services/01-index.md @@ -2,7 +2,6 @@ id: index title: Core Backend Service APIs sidebar_label: Overview -# prettier-ignore description: Core backend service APIs --- diff --git a/docs/backend-system/core-services/actions-registry.md b/docs/backend-system/core-services/actions-registry.md new file mode 100644 index 0000000000..02ccfd1481 --- /dev/null +++ b/docs/backend-system/core-services/actions-registry.md @@ -0,0 +1,176 @@ +--- +id: actions-registry +title: Actions Registry (alpha) +sidebar_label: Actions Registry (alpha) +description: Documentation for the Actions Registry Service +--- + +## Overview + +The Actions Registry Service is a core service designed to provide a distributed registry for actions that can be executed within Backstage backend plugins. This service allows plugins to register reusable actions with well-defined schemas and execution logic, promoting consistency and reusability across the Backstage ecosystem. + +## Action Structure + +Each action registered with the service must conform to the `ActionsRegistryActionOptions` type, which includes: + +### Required Properties + +- **`name`:** A unique identifier for the action (string) +- **`title`:** A human-readable title for the action (string) +- **`description`:** A detailed description of what the action does (string) +- **`schema`:** Object containing input and output schema definitions + - **`input`:** Function that returns a Zod schema for validating input + - **`output`:** Function that returns a Zod schema for validating output +- **`action`:** The async function that executes the action logic + +### Optional Properties + +- **`attributes`:** Object containing behavioral flags: + - **`destructive`:** Boolean indicating if the action modifies or deletes data + - **`idempotent`:** Boolean indicating if running the action multiple times produces the same result + - **`readOnly`:** Boolean indicating if the action only reads data without modifications + +### Action Context + +When an action is executed, it receives a context object (`ActionsRegistryActionContext`) containing: + +- **`input`:** The validated input data matching the defined input schema +- **`logger`:** A LoggerService instance for logging within the action +- **`credentials`:** BackstageCredentials for authentication and authorization + +## Using the Service + +### Registering an Action + +Here's an example of how to register an action with the Actions Registry Service: + +```typescript +import { ActionsRegistryService } from '@backstage/backend-plugin-api'; + +export function registerMyActions(actionsRegistry: ActionsRegistryService) { + // Register a simple read-only action + actionsRegistry.register({ + name: 'fetch-user-info', + title: 'Fetch User Information', + description: 'Retrieves user information from the catalog', + schema: { + input: z => + z.object({ + userRef: z.string(), + includeGroups: z.boolean().optional(), + }), + output: z => + z.object({ + user: z.object({ + name: z.string(), + email: z.string(), + groups: z.array(z.string()).optional(), + }), + }), + }, + attributes: { + readOnly: true, + idempotent: true, + }, + action: async ({ input, logger, credentials }) => { + logger.info(`Fetching user info for ${input.userRef}`); + + // Perform the action logic here + const user = await fetchUserFromCatalog(input.userRef, credentials); + + return { + output: { + user: { + name: user.name, + email: user.email, + groups: input.includeGroups ? user.groups : undefined, + }, + }, + }; + }, + }); + + // Register a destructive action + actionsRegistry.register({ + name: 'delete-entity', + title: 'Delete Entity', + description: 'Removes an entity from the catalog', + schema: { + input: z => + z.object({ + entityRef: z.string(), + force: z.boolean().optional(), + }), + output: z => + z.object({ + deletedEntities: z.array(z.string()), + }), + }, + attributes: { + destructive: true, + idempotent: false, + }, + action: async ({ input, logger, credentials }) => { + logger.warn(`Deleting entity ${input.entityRef}`); + + // Perform the deletion logic here + const { deletedEntities } = await deleteEntityFromCatalog( + input.entityRef, + input.force, + credentials, + ); + + return { + output: deletedEntities, + }; + }, + }); +} +``` + +### Accessing the Service in a Plugin + +To use the Actions Registry Service in your plugin, access it through dependency injection: + +```typescript +import { + createBackendPlugin, + coreServices, +} from '@backstage/backend-plugin-api'; + +export const myPlugin = createBackendPlugin({ + pluginId: 'my-plugin', + register(env) { + env.registerInit({ + deps: { + actionsRegistry: coreServices.actionsRegistry, + logger: coreServices.logger, + }, + async init({ actionsRegistry, logger }) { + logger.info('Registering actions...'); + registerMyActions(actionsRegistry); + logger.info('Actions registered successfully'); + }, + }); + }, +}); +``` + +## Best Practices + +### Naming Conventions + +- **Use kebab-case:** Action names should be in kebab-case (e.g., `fetch-user-info`, `create-repository`) +- **Be Descriptive:** Choose names that clearly describe what the action does +- **Avoid Redundancy:** Don't include plugin names in action names since the plugin context is separate +- **Use Verbs:** Start action names with verbs that describe the operation (e.g., `fetch`, `create`, `delete`, `update`) + +## Action Attributes Reference + +| Attribute | Type | Default | Description | +| ------------- | ------- | ------- | ------------------------------------------------------------------- | +| `destructive` | boolean | `true` | Indicates the action modifies or deletes data. Use with caution. | +| `idempotent` | boolean | `false` | Indicates the action can be run multiple times with the same result | +| `readOnly` | boolean | `false` | Indicates the action only reads data without making modifications | + +These attributes help consumers of actions understand their behavior and implement appropriate safeguards, retries, or optimizations based on the action's characteristics. diff --git a/docs/backend-system/core-services/actions.md b/docs/backend-system/core-services/actions.md new file mode 100644 index 0000000000..ddb28b4da7 --- /dev/null +++ b/docs/backend-system/core-services/actions.md @@ -0,0 +1,131 @@ +--- +id: actions +title: Actions (alpha) +sidebar_label: Actions (alpha) +description: Documentation for the Actions Service +--- + +## Overview + +The Actions Service is a core service that provides a standardized interface for discovering and executing registered actions within Backstage backend plugins. This service acts as the consumer-facing API for actions that have been registered through the Actions Registry Service, allowing plugins to list available actions and invoke them with proper authentication and input validation. + +## How it Works + +The Actions Service implements the `ActionsService` interface, which provides two primary methods: + +- **`list()`:** Retrieves all available actions with their complete metadata +- **`invoke()`:** Executes a specific action by ID with provided input data + +The service works in conjunction with the [Actions Registry Service](./actions-registry.md), where actions are registered by plugins and then made available for discovery and execution through this service. + +## Action Identification + +Actions are identified using a unique ID that follows a specific format: + +- All action IDs are prefixed with the plugin ID that registered them, following the pattern `pluginId:actionName` +- An action named `fetch-user-info` registered by the `catalog` plugin would have the ID `catalog:fetch-user-info` +- When using the `actionsRegistryServiceMock`, the plugin ID prefix will be `test:` + +This naming convention ensures that action names are globally unique across all plugins and provides clear ownership identification. + +## Configuration + +The Actions Service can be configured to control which plugins' actions are available: + +```yaml +backend: + actions: + pluginSources: + - catalog +``` + +## Using the Service + +### Listing Available Actions + +Here's an example of how to list all available actions: + +```typescript +import { ActionsService } from '@backstage/backend-plugin-api'; + +export async function listAvailableActions( + actionsService: ActionsService, + credentials: BackstageCredentials, +) { + try { + const { actions } = await actionsService.list({ credentials }); + + console.log(`Found ${actions.length} available actions:`); + + actions.forEach(action => { + console.log(`- ${action.id}: ${action.title}`); + console.log(` Description: ${action.description}`); + console.log(` Attributes: ${JSON.stringify(action.attributes)}`); + + if (action.schema.input) { + console.log( + ` Input Schema: ${JSON.stringify(action.schema.input, null, 2)}`, + ); + } + }); + + return actions; + } catch (error) { + console.error('Failed to list actions:', error); + throw error; + } +} +``` + +### Invoking an Action + +Here's an example of how to execute a specific action: + +```typescript +import { ActionsService } from '@backstage/backend-plugin-api'; + +export async function executeAction( + actionsService: ActionsService, + actionId: string, + input: JsonObject, + credentials: BackstageCredentials, +) { + try { + const { output } = await actionsService.invoke({ + id: actionId, + input, + credentials, + }); + + console.log(`Action ${actionId} executed successfully`); + console.log('Output:', JSON.stringify(output, null, 2)); + + return output; + } catch (error) { + console.error(`Failed to execute action ${actionId}:`, error); + throw error; + } +} + +// Example usage +async function fetchUserInfo( + actionsService: ActionsService, + credentials: BackstageCredentials, +) { + const output = await executeAction( + actionsService, + 'catalog:fetch-user-info', // Note: Action ID includes plugin prefix + { + userRef: 'user:default/john.doe', + includeGroups: true, + }, + credentials, + ); + + return output; +} +``` + +## Best Practices + +For comprehensive guidance on action design, naming conventions, and schema design, see the [Actions Registry Best Practices](./actions-registry.md#best-practices) documentation. diff --git a/docs/backend-system/core-services/http-router.md b/docs/backend-system/core-services/http-router.md index d7658d9a67..5e065152a0 100644 --- a/docs/backend-system/core-services/http-router.md +++ b/docs/backend-system/core-services/http-router.md @@ -68,6 +68,60 @@ For those routes you will also have to specify `allowLimitedAccess: true` when using the [`auth`](./auth.md) and [`httpAuth`](./http-auth.md) services to access the incoming credentials. +## Rate limiting + +Rate limiting allows you to limit the amount of requests users can send to you backend. +This is useful for blocking various network attacks, such as DDOS. + +To enable rate limiting, add the following to your config: + +```yaml +backend: + rateLimit: true +``` + +You can additionally configure the rate limiting parameters, also by plugin: + +```yaml +backend: + rateLimit: + global: true # Enables or disables rate limit for all plugins + window: 6s # Time window for rate limiting for single client + incomingRequestLimit: 100 # Number of requests to accept from one client during time window + ipAllowList: ['127.0.0.1'] # IPs to bypass rate limiting + skipSuccesfulRequests: false # Rate limit successful requests + skipFailedRequests: false # Rate limit failed requests + plugin: + # Plugin specific rate limiting + catalog: + window: 3s + incomingRequestLimit: 50 +``` + +By default, the rate limiting is per instance and the request counts are stored into memory. +If you want to share this information across all your backstage instances, you have to configure +the rate limiting store: + +```yaml +backend: + rateLimit: + global: true + store: + type: redis + connection: redis://127.0.0.1:16379 +``` + +If your instance is working behind a proxy, you have to configure the backend to trust the proxy +for the rate limiting being able to distinguish clients. + +```yaml +backend: + trustProxy: true +``` + +For more information about the trust proxy configuration and available options, +please refer to [express documentation](https://expressjs.com/en/guide/behind-proxies.html). + ## Configuring the service For more advanced customization, there are several APIs from the `@backstage/backend-defaults/httpRouter` package that allow you to customize the implementation of the config service. The default implementation uses all of the middleware exported from `@backstage/backend-defaults/httpRouter`, including `createLifecycleMiddleware`, `createAuthIntegrationRouter`, `createCredentialsBarrier` and `createCookieAuthRefreshMiddleware`. You can use these to create your own `httpRouter` service implementation, for example - here's how you would add a custom health check route to all plugins: @@ -78,6 +132,7 @@ import { createCookieAuthRefreshMiddleware, createCredentialsBarrier, createAuthIntegrationRouter, + createRateLimitMiddleware, } from '@backstage/backend-defaults/httpRouter'; import { createServiceFactory } from '@backstage/backend-plugin-api'; @@ -105,6 +160,11 @@ backend.add( }) { const router = PromiseRouter(); + // Optional rate limiting middleware + router.use( + createRateLimitMiddleware({ pluginId: plugin.getId(), config }), + ); + rootHttpRouter.use(`/api/${plugin.getId()}`, router); const credentialsBarrier = createCredentialsBarrier({ diff --git a/docs/backend-system/core-services/root-http-router.md b/docs/backend-system/core-services/root-http-router.md index 7a268e27fc..1e76fb1871 100644 --- a/docs/backend-system/core-services/root-http-router.md +++ b/docs/backend-system/core-services/root-http-router.md @@ -40,6 +40,10 @@ createBackendPlugin({ }); ``` +## Rate limiting + +Please refer to the [HTTP Router documentation](./http-router.md#rate-limiting). + ## Configuring the service ### Via `app-config.yaml` @@ -60,7 +64,7 @@ backend: # - A string in the format of '1d', '2 seconds' etc. as supported by the `ms` library. # - A standard ISO formatted duration string, e.g. 'P2DT6H' or 'PT1M'. # - An object with individual units (in plural) as keys, e.g. `{ days: 2, hours: 6 }`. - serverShutdownTimeout: { seconds: 20 } + serverShutdownDelay: { seconds: 20 } ``` ### Via Code @@ -121,6 +125,11 @@ backend.add( app.use(middleware.cors()); app.use(middleware.compression()); + // Optional rate limiting middleware + app.use(middleware.rateLimit()); + // If you are using rate limiting behind a proxy, you should set the `trust proxy` setting to true + app.set('trust proxy', true); + app.use(healthRouter); // you can add you your own middleware in here @@ -161,3 +170,52 @@ backend.add( }), ); ``` + +## Defining Content Security Policy (CSP) Configuration + +Content Security Policy (CSP) is a crucial security feature that helps protect your Backstage instance from various attacks, particularly Cross-Site Scripting (XSS). Backstage provides a flexible way to configure CSP directives through your `app-config.yaml` file. + +### Basic Configuration + +CSP directives can be defined under the `backend.csp` section in your configuration: + +```yaml +backend: + csp: + default-src: ["'self'"] + script-src: ["'self'", "'unsafe-inline'", 'example.com'] + connect-src: ["'self'", 'http:', 'https:'] + img-src: ["'self'", 'data:', 'https://backstage.io'] + style-src: ["'self'", "'unsafe-inline'"] + frame-src: ['https://some-analytics-provider.com'] +``` + +### Available Directives + +You can configure any CSP directive supported by modern browsers. Common directives include: + +- `default-src`: The fallback for other CSP directives +- `script-src`: Controls which scripts can be executed +- `style-src`: Controls which styles can be applied +- `img-src`: Controls which images can be loaded +- `connect-src`: Controls which URLs can be loaded using fetch, WebSocket, etc. +- `frame-src`: Controls which URLs can be embedded in iframes +- `font-src`: Controls which fonts can be loaded +- `object-src`: Controls which URLs can be loaded as plugins +- `media-src`: Controls which media (audio, video) can be loaded +- `upgrade-insecure-requests`: Instructs browsers to upgrade HTTP to HTTPS + +### Special Values + +- Common special values within directive arrays: + - `self`: Allows content from the same origin + - `unsafe-inline`: Allows inline scripts/styles + - `unsafe-eval`: Allows dynamic code evaluation + - `none`: Blocks all content for that directive + - `data:`: Allows data: URIs (commonly used for images) + - `https:`: Allows any content over HTTPS + +For more information on available CSP options, refer to: + +- [MDN Content Security Policy documentation](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) +- [Helmet Content Security Policy](https://helmetjs.github.io/#content-security-policy) diff --git a/docs/backend-system/index.md b/docs/backend-system/index.md index 9fcd7f0c9a..2eb7f158ef 100644 --- a/docs/backend-system/index.md +++ b/docs/backend-system/index.md @@ -2,7 +2,6 @@ id: index title: The Backend System sidebar_label: Introduction -# prettier-ignore description: Introduction to Backstage's backend system and its documentation --- diff --git a/docs/contribute/getting-involved.md b/docs/contribute/getting-involved.md index 4b8c4dfc6f..696b73b7d4 100644 --- a/docs/contribute/getting-involved.md +++ b/docs/contribute/getting-involved.md @@ -1,7 +1,6 @@ --- id: getting-involved title: Getting Involved -# prettier-ignore description: How can you help us build Backstage? We welcome contributions of all kinds, from documentation to code to design. --- diff --git a/docs/contribute/index.md b/docs/contribute/index.md index 627a2ff0d0..dbdf126b20 100644 --- a/docs/contribute/index.md +++ b/docs/contribute/index.md @@ -1,7 +1,6 @@ --- id: index title: Contributors -# prettier-ignore description: Documentation on how to get set up for doing development on the Backstage repository --- diff --git a/docs/contribute/project-structure.md b/docs/contribute/project-structure.md index 984cfe98d6..08e4379620 100644 --- a/docs/contribute/project-structure.md +++ b/docs/contribute/project-structure.md @@ -1,7 +1,6 @@ --- id: project-structure title: Backstage Project Structure -# prettier-ignore description: Introduction to files and folders in the Backstage Project repository --- diff --git a/docs/dls/figma.md b/docs/dls/figma.md index 21a05d2818..738d607439 100644 --- a/docs/dls/figma.md +++ b/docs/dls/figma.md @@ -1,7 +1,6 @@ --- id: figma title: Figma -# prettier-ignore description: Documentation on using Figma to build your own plugins for Backstage --- diff --git a/docs/features/kubernetes/configuration.md b/docs/features/kubernetes/configuration.md index aeba3fddbb..830027f53b 100644 --- a/docs/features/kubernetes/configuration.md +++ b/docs/features/kubernetes/configuration.md @@ -2,7 +2,6 @@ id: configuration title: Configuring Kubernetes integration sidebar_label: Configuration -# prettier-ignore description: Configuring the Kubernetes integration for Backstage expose your entity's objects --- @@ -699,6 +698,7 @@ rules: - '*' resources: - pods + - pods/log - configmaps - services - deployments diff --git a/docs/features/search/README.md b/docs/features/search/README.md index 93aa22ebe1..eb5d12080c 100644 --- a/docs/features/search/README.md +++ b/docs/features/search/README.md @@ -2,7 +2,6 @@ id: search-overview title: Search Documentation sidebar_label: Overview -# prettier-ignore description: Backstage Search lets you find the right information you are looking for in the Backstage ecosystem. --- diff --git a/docs/features/software-catalog/catalog-customization.md b/docs/features/software-catalog/catalog-customization.md index 1c36301605..1ef865039f 100644 --- a/docs/features/software-catalog/catalog-customization.md +++ b/docs/features/software-catalog/catalog-customization.md @@ -1,7 +1,6 @@ --- id: catalog-customization title: Catalog Customization -# prettier-ignore description: How to add custom filters or interface elements to the Backstage software catalog --- diff --git a/docs/features/software-catalog/descriptor-format.md b/docs/features/software-catalog/descriptor-format.md index 28ddfae282..0e54ba2690 100644 --- a/docs/features/software-catalog/descriptor-format.md +++ b/docs/features/software-catalog/descriptor-format.md @@ -2,7 +2,6 @@ id: descriptor-format title: Descriptor Format of Catalog Entities sidebar_label: YAML File Format -# prettier-ignore description: Documentation on Descriptor Format of Catalog Entities which describes the default data shape and semantics of catalog entities --- diff --git a/docs/features/software-catalog/extending-the-model--old.md b/docs/features/software-catalog/extending-the-model--old.md index 668d1d8311..00a6688352 100644 --- a/docs/features/software-catalog/extending-the-model--old.md +++ b/docs/features/software-catalog/extending-the-model--old.md @@ -1,7 +1,6 @@ --- id: extending-the-model--old title: Extending the model -# prettier-ignore description: Documentation on extending the catalog model --- diff --git a/docs/features/software-catalog/extending-the-model.md b/docs/features/software-catalog/extending-the-model.md index d289886a09..5d51a69e6b 100644 --- a/docs/features/software-catalog/extending-the-model.md +++ b/docs/features/software-catalog/extending-the-model.md @@ -1,7 +1,6 @@ --- id: extending-the-model title: Extending the model -# prettier-ignore description: Documentation on extending the catalog model --- diff --git a/docs/features/software-catalog/external-integrations.md b/docs/features/software-catalog/external-integrations.md index 8938fefdf6..0aef4565d9 100644 --- a/docs/features/software-catalog/external-integrations.md +++ b/docs/features/software-catalog/external-integrations.md @@ -1,7 +1,6 @@ --- id: external-integrations title: External integrations -# prettier-ignore description: Documentation on External integrations to integrate systems with Backstage --- diff --git a/docs/features/software-catalog/index.md b/docs/features/software-catalog/index.md index ac1d0ee8cd..1f374385a4 100644 --- a/docs/features/software-catalog/index.md +++ b/docs/features/software-catalog/index.md @@ -2,7 +2,6 @@ id: software-catalog-overview title: Backstage Software Catalog sidebar_label: Overview -# prettier-ignore description: The Backstage Software Catalog --- diff --git a/docs/features/software-catalog/life-of-an-entity.md b/docs/features/software-catalog/life-of-an-entity.md index 1489688720..9bb0604b82 100644 --- a/docs/features/software-catalog/life-of-an-entity.md +++ b/docs/features/software-catalog/life-of-an-entity.md @@ -2,7 +2,6 @@ id: life-of-an-entity title: The Life of an Entity sidebar_label: The Life of an Entity -# prettier-ignore description: The life cycle of entities, from being introduced into the catalog, through processing, to being removed again --- diff --git a/docs/features/software-catalog/well-known-annotations.md b/docs/features/software-catalog/well-known-annotations.md index 42cefd3adb..cdd93b50ac 100644 --- a/docs/features/software-catalog/well-known-annotations.md +++ b/docs/features/software-catalog/well-known-annotations.md @@ -2,7 +2,6 @@ id: well-known-annotations title: Well-known Annotations on Catalog Entities sidebar_label: Well-known Annotations -# prettier-ignore description: Documentation that lists a number of well known Annotations, that have defined semantics. They can be attached to catalog entities and consumed by plugins as needed. --- diff --git a/docs/features/software-catalog/well-known-relations.md b/docs/features/software-catalog/well-known-relations.md index 6d61847a15..740dbe0df2 100644 --- a/docs/features/software-catalog/well-known-relations.md +++ b/docs/features/software-catalog/well-known-relations.md @@ -2,7 +2,6 @@ id: well-known-relations title: Well-known Relations between Catalog Entities sidebar_label: Well-known Relations -# prettier-ignore description: Documentation that lists a number of well known Relations, that have defined semantics. They can be attached to catalog entities and consumed by plugins as needed. --- diff --git a/docs/features/software-catalog/well-known-statuses.md b/docs/features/software-catalog/well-known-statuses.md index d293ae5062..6829b1ccdf 100644 --- a/docs/features/software-catalog/well-known-statuses.md +++ b/docs/features/software-catalog/well-known-statuses.md @@ -2,7 +2,6 @@ id: well-known-statuses title: Well-known Status fields of Catalog Entities sidebar_label: Well-known Statuses -# prettier-ignore description: Lists a number of well known entity statuses, that have defined semantics. They can be attached to catalog entities and consumed by plugins as needed. --- diff --git a/docs/features/software-templates/experimental.md b/docs/features/software-templates/experimental.md index 929fe088cf..1df041d7a2 100644 --- a/docs/features/software-templates/experimental.md +++ b/docs/features/software-templates/experimental.md @@ -1,7 +1,6 @@ --- id: experimental title: Experimental Features -# prettier-ignore description: Information on Experimental Features that are currently available in the Scaffolder --- diff --git a/docs/features/software-templates/index.md b/docs/features/software-templates/index.md index 10550f7c01..16f7c3cbbd 100644 --- a/docs/features/software-templates/index.md +++ b/docs/features/software-templates/index.md @@ -2,7 +2,6 @@ id: software-templates-index title: Backstage Software Templates sidebar_label: Overview -# prettier-ignore description: The Software Templates part of Backstage is a tool that can help you create Components inside Backstage --- diff --git a/docs/features/software-templates/migrating-from-v1beta2-to-v1beta3.md b/docs/features/software-templates/migrating-from-v1beta2-to-v1beta3.md index bd8d4bdb72..830c343033 100644 --- a/docs/features/software-templates/migrating-from-v1beta2-to-v1beta3.md +++ b/docs/features/software-templates/migrating-from-v1beta2-to-v1beta3.md @@ -1,7 +1,6 @@ --- id: migrating-from-v1beta2-to-v1beta3 title: Migrating to v1beta3 templates -# prettier-ignore description: How to migrate your existing templates to beta3 syntax --- diff --git a/docs/features/software-templates/migrating-to-rjsf-v5.md b/docs/features/software-templates/migrating-to-rjsf-v5.md index 8357d7567b..d35eb166f0 100644 --- a/docs/features/software-templates/migrating-to-rjsf-v5.md +++ b/docs/features/software-templates/migrating-to-rjsf-v5.md @@ -1,7 +1,6 @@ --- id: migrating-to-rjsf-v5 title: 'Migrating to react-jsonschema-form@v5' -# prettier-ignore description: Docs on migrating to `react-jsonschema-form`@v5 and the new designs --- diff --git a/docs/features/software-templates/writing-templates.md b/docs/features/software-templates/writing-templates.md index eeaa4ad203..275d5c26b2 100644 --- a/docs/features/software-templates/writing-templates.md +++ b/docs/features/software-templates/writing-templates.md @@ -274,6 +274,58 @@ spec: password: ${{ secrets.password }} ``` +You can also consume secrets within `each` step of the template. + +```yaml +apiVersion: scaffolder.backstage.io/v1beta3 +kind: Template +metadata: + name: v1beta3-demo + title: Test Action template + description: scaffolder v1beta3 template demo +spec: + owner: backstage/techdocs-core + type: service + + parameters: + - title: Authentication + description: Provide authentication for the resource + required: + - service1 + - token1 + - service2 + - token2 + properties: + service1: + type: string + token1: + type: string + ui:field: Secret + service2: + type: string + token2: + type: string + ui:field: Secret + + steps: + - id: setupAuthentication + action: auth:create + each: + [ + { + name: '${{ parameters.service1 }}', + token: '${{ secrets.token1 }}', + }, + { + name: '${{ parameters.service2 }}', + token: '${{ secrets.token2 }}', + }, + ] + input: + name: ${{ each.value.name }} + token: ${{ each.value.token }} +``` + ### Custom step layouts If you find that the default layout of the form used in a particular step does not meet your needs then you can supply your own [custom step layout](./writing-custom-step-layouts.md). diff --git a/docs/features/techdocs/README.md b/docs/features/techdocs/README.md index beec6d1fad..0306a9746b 100644 --- a/docs/features/techdocs/README.md +++ b/docs/features/techdocs/README.md @@ -2,7 +2,6 @@ id: techdocs-overview title: TechDocs Documentation sidebar_label: Overview -# prettier-ignore description: TechDocs is Spotify’s homegrown docs-like-code solution built directly into Backstage --- diff --git a/docs/features/techdocs/cli.md b/docs/features/techdocs/cli.md index 517b2a3547..a52730d335 100644 --- a/docs/features/techdocs/cli.md +++ b/docs/features/techdocs/cli.md @@ -1,7 +1,6 @@ --- id: cli title: TechDocs CLI -# prettier-ignore description: TechDocs CLI - a utility command line interface for managing TechDocs sites in Backstage. --- diff --git a/docs/features/techdocs/concepts.md b/docs/features/techdocs/concepts.md index 2944197dfb..f427f0cd2b 100644 --- a/docs/features/techdocs/concepts.md +++ b/docs/features/techdocs/concepts.md @@ -1,7 +1,6 @@ --- id: concepts title: Concepts -# prettier-ignore description: Documentation on concepts that are introduced with Spotify's docs-like-code solution in Backstage --- diff --git a/docs/features/techdocs/configuration.md b/docs/features/techdocs/configuration.md index 05f184e90f..e21e452b7c 100644 --- a/docs/features/techdocs/configuration.md +++ b/docs/features/techdocs/configuration.md @@ -1,7 +1,6 @@ --- id: configuration title: TechDocs Configuration Options -# prettier-ignore description: Reference documentation for configuring TechDocs using app-config.yaml --- diff --git a/docs/features/techdocs/configuring-ci-cd.md b/docs/features/techdocs/configuring-ci-cd.md index 20a73798a4..d818c129a4 100644 --- a/docs/features/techdocs/configuring-ci-cd.md +++ b/docs/features/techdocs/configuring-ci-cd.md @@ -1,7 +1,6 @@ --- id: configuring-ci-cd title: Configuring CI/CD to generate and publish TechDocs sites -# prettier-ignore description: Configuring CI/CD to generate and publish TechDocs sites to cloud storage --- diff --git a/docs/frontend-system/architecture/00-index.md b/docs/frontend-system/architecture/00-index.md index 20a12ba1e8..8307877f16 100644 --- a/docs/frontend-system/architecture/00-index.md +++ b/docs/frontend-system/architecture/00-index.md @@ -2,7 +2,6 @@ id: index title: Frontend System Architecture sidebar_label: Overview -# prettier-ignore description: The structure and architecture of the new Frontend System --- diff --git a/docs/frontend-system/architecture/10-app.md b/docs/frontend-system/architecture/10-app.md index f0d7ff3d1e..3fcfec9e9b 100644 --- a/docs/frontend-system/architecture/10-app.md +++ b/docs/frontend-system/architecture/10-app.md @@ -2,7 +2,6 @@ id: app title: App Instances sidebar_label: App -# prettier-ignore description: App instances --- diff --git a/docs/frontend-system/architecture/15-plugins.md b/docs/frontend-system/architecture/15-plugins.md index 6d2b14d77f..13c93c6962 100644 --- a/docs/frontend-system/architecture/15-plugins.md +++ b/docs/frontend-system/architecture/15-plugins.md @@ -2,7 +2,6 @@ id: plugins title: Frontend Plugins sidebar_label: Plugins -# prettier-ignore description: Frontend plugins --- diff --git a/docs/frontend-system/architecture/20-extensions.md b/docs/frontend-system/architecture/20-extensions.md index eae0405bda..590d0a7bb9 100644 --- a/docs/frontend-system/architecture/20-extensions.md +++ b/docs/frontend-system/architecture/20-extensions.md @@ -2,7 +2,6 @@ id: extensions title: Frontend Extensions sidebar_label: Extensions -# prettier-ignore description: Frontend extensions --- diff --git a/docs/frontend-system/architecture/23-extension-blueprints.md b/docs/frontend-system/architecture/23-extension-blueprints.md index fb10749845..081497655e 100644 --- a/docs/frontend-system/architecture/23-extension-blueprints.md +++ b/docs/frontend-system/architecture/23-extension-blueprints.md @@ -2,7 +2,6 @@ id: extension-blueprints title: Frontend Extension Blueprints sidebar_label: Extensions Blueprints -# prettier-ignore description: Frontend extensions --- diff --git a/docs/frontend-system/architecture/25-extension-overrides.md b/docs/frontend-system/architecture/25-extension-overrides.md index faaf446f41..6b07fe4faa 100644 --- a/docs/frontend-system/architecture/25-extension-overrides.md +++ b/docs/frontend-system/architecture/25-extension-overrides.md @@ -2,7 +2,6 @@ id: extension-overrides title: Frontend Extension Overrides sidebar_label: Extension Overrides -# prettier-ignore description: Frontend extension overrides --- diff --git a/docs/frontend-system/architecture/30-references.md b/docs/frontend-system/architecture/30-references.md index 24a9e5df2a..618f2868bb 100644 --- a/docs/frontend-system/architecture/30-references.md +++ b/docs/frontend-system/architecture/30-references.md @@ -2,7 +2,6 @@ id: references title: Value References sidebar_label: Value References -# prettier-ignore description: Value References --- diff --git a/docs/frontend-system/architecture/33-utility-apis.md b/docs/frontend-system/architecture/33-utility-apis.md index fd069319de..ce67956281 100644 --- a/docs/frontend-system/architecture/33-utility-apis.md +++ b/docs/frontend-system/architecture/33-utility-apis.md @@ -2,7 +2,6 @@ id: utility-apis title: Utility APIs sidebar_label: Utility APIs -# prettier-ignore description: Utility APIs --- diff --git a/docs/frontend-system/architecture/36-routes.md b/docs/frontend-system/architecture/36-routes.md index 7b6376b2eb..c07eea304d 100644 --- a/docs/frontend-system/architecture/36-routes.md +++ b/docs/frontend-system/architecture/36-routes.md @@ -2,7 +2,6 @@ id: routes title: Frontend Routes sidebar_label: Routes -# prettier-ignore description: Frontend routes --- diff --git a/docs/frontend-system/architecture/50-naming-patterns.md b/docs/frontend-system/architecture/50-naming-patterns.md index 55068d8ea1..14634b4355 100644 --- a/docs/frontend-system/architecture/50-naming-patterns.md +++ b/docs/frontend-system/architecture/50-naming-patterns.md @@ -2,7 +2,6 @@ id: naming-patterns title: Frontend System Naming Patterns sidebar_label: Naming Patterns -# prettier-ignore description: Naming patterns in the frontend system --- diff --git a/docs/frontend-system/architecture/60-migrations.md b/docs/frontend-system/architecture/60-migrations.md index 3a33e663f4..413b3b07f4 100644 --- a/docs/frontend-system/architecture/60-migrations.md +++ b/docs/frontend-system/architecture/60-migrations.md @@ -2,7 +2,6 @@ id: migrations title: Frontend System Changelog sidebar_label: Changelog -# prettier-ignore description: Changelog documentation for different versions of the frontend system core APIs. --- diff --git a/docs/frontend-system/building-apps/01-index.md b/docs/frontend-system/building-apps/01-index.md index 5b5298a2c5..0a65ddf122 100644 --- a/docs/frontend-system/building-apps/01-index.md +++ b/docs/frontend-system/building-apps/01-index.md @@ -2,7 +2,6 @@ id: index title: Building Frontend Apps sidebar_label: Overview -# prettier-ignore description: Building frontend apps using the new frontend system --- diff --git a/docs/frontend-system/building-apps/02-configuring-extensions.md b/docs/frontend-system/building-apps/02-configuring-extensions.md index 4052ef47f0..11da9810a4 100644 --- a/docs/frontend-system/building-apps/02-configuring-extensions.md +++ b/docs/frontend-system/building-apps/02-configuring-extensions.md @@ -2,7 +2,6 @@ id: configuring-extensions title: Configuring Extensions in the App sidebar_label: Configuring Extensions -# prettier-ignore description: Documentation for how to configure extensions in a Backstage app --- diff --git a/docs/frontend-system/building-apps/03-built-in-extensions.md b/docs/frontend-system/building-apps/03-built-in-extensions.md index 5f74100df0..4cca7cebe2 100644 --- a/docs/frontend-system/building-apps/03-built-in-extensions.md +++ b/docs/frontend-system/building-apps/03-built-in-extensions.md @@ -2,7 +2,6 @@ id: built-in-extensions title: App Built-in Extensions sidebar_label: Built-in extensions -# prettier-ignore description: Configuring or overriding built-in extensions --- diff --git a/docs/frontend-system/building-apps/06-plugin-conversion.md b/docs/frontend-system/building-apps/06-plugin-conversion.md index 88c4b69d45..720a29ddb7 100644 --- a/docs/frontend-system/building-apps/06-plugin-conversion.md +++ b/docs/frontend-system/building-apps/06-plugin-conversion.md @@ -2,7 +2,6 @@ id: plugin-conversion title: Converting 3rd-party plugins from the old system sidebar_label: Converting 3rd-party Plugins -# prettier-ignore description: Documentation for how to convert 3rd-party plugins to support the new frontend system. --- diff --git a/docs/frontend-system/building-apps/08-migrating.md b/docs/frontend-system/building-apps/08-migrating.md index 7b1fbf28d8..6b1332834a 100644 --- a/docs/frontend-system/building-apps/08-migrating.md +++ b/docs/frontend-system/building-apps/08-migrating.md @@ -2,7 +2,6 @@ id: migrating title: Migrating Apps sidebar_label: Migration Guide -# prettier-ignore description: How to migrate existing apps to the new frontend system --- diff --git a/docs/frontend-system/building-plugins/01-index.md b/docs/frontend-system/building-plugins/01-index.md index 33ec65d9d1..e9d6f1cbe2 100644 --- a/docs/frontend-system/building-plugins/01-index.md +++ b/docs/frontend-system/building-plugins/01-index.md @@ -2,7 +2,6 @@ id: index title: Building Frontend Plugins sidebar_label: Overview -# prettier-ignore description: Building frontend plugins using the new frontend system --- diff --git a/docs/frontend-system/building-plugins/02-testing.md b/docs/frontend-system/building-plugins/02-testing.md index 87c22b839b..f37c7cb106 100644 --- a/docs/frontend-system/building-plugins/02-testing.md +++ b/docs/frontend-system/building-plugins/02-testing.md @@ -2,7 +2,6 @@ id: testing title: Frontend System Testing Plugins sidebar_label: Testing -# prettier-ignore description: Testing plugins in the frontend system --- diff --git a/docs/frontend-system/building-plugins/03-common-extension-blueprints.md b/docs/frontend-system/building-plugins/03-common-extension-blueprints.md index b437a44552..e1e903eadd 100644 --- a/docs/frontend-system/building-plugins/03-common-extension-blueprints.md +++ b/docs/frontend-system/building-plugins/03-common-extension-blueprints.md @@ -2,7 +2,6 @@ id: common-extension-blueprints title: Common Extension Blueprints sidebar_label: Common Extension Blueprints -# prettier-ignore description: Extension blueprints provided by the frontend system and core features --- diff --git a/docs/frontend-system/building-plugins/04-built-in-data-refs.md b/docs/frontend-system/building-plugins/04-built-in-data-refs.md index a26f6549b7..00392ed467 100644 --- a/docs/frontend-system/building-plugins/04-built-in-data-refs.md +++ b/docs/frontend-system/building-plugins/04-built-in-data-refs.md @@ -2,7 +2,6 @@ id: built-in-data-refs title: Built-in data refs sidebar_label: Built-in data refs -# prettier-ignore description: Configuring or overriding built-in extension data references --- diff --git a/docs/frontend-system/building-plugins/05-migrating.md b/docs/frontend-system/building-plugins/05-migrating.md index ba292aa5d5..483ebf68f8 100644 --- a/docs/frontend-system/building-plugins/05-migrating.md +++ b/docs/frontend-system/building-plugins/05-migrating.md @@ -2,7 +2,6 @@ id: migrating title: Migrating Plugins sidebar_label: Migration Guide -# prettier-ignore description: How to migrate an existing frontend plugin to the new frontend system --- diff --git a/docs/frontend-system/index.md b/docs/frontend-system/index.md index 201718f6d3..c9a8059086 100644 --- a/docs/frontend-system/index.md +++ b/docs/frontend-system/index.md @@ -2,7 +2,6 @@ id: index title: The Frontend System sidebar_label: Introduction -# prettier-ignore description: The Frontend System --- diff --git a/docs/frontend-system/utility-apis/01-index.md b/docs/frontend-system/utility-apis/01-index.md index 07f7dcc2a8..71e1eea740 100644 --- a/docs/frontend-system/utility-apis/01-index.md +++ b/docs/frontend-system/utility-apis/01-index.md @@ -2,7 +2,6 @@ id: index title: Utility APIs sidebar_label: Overview -# prettier-ignore description: Working with Utility APIs in the New Frontend System --- diff --git a/docs/frontend-system/utility-apis/02-creating.md b/docs/frontend-system/utility-apis/02-creating.md index bf53911d24..d02b74cbf6 100644 --- a/docs/frontend-system/utility-apis/02-creating.md +++ b/docs/frontend-system/utility-apis/02-creating.md @@ -2,7 +2,6 @@ id: creating title: Creating Utility APIs sidebar_label: Creating APIs -# prettier-ignore description: Creating new utility APIs in your plugins and app --- diff --git a/docs/frontend-system/utility-apis/03-consuming.md b/docs/frontend-system/utility-apis/03-consuming.md index bdf3b8dcdb..d5ea537284 100644 --- a/docs/frontend-system/utility-apis/03-consuming.md +++ b/docs/frontend-system/utility-apis/03-consuming.md @@ -2,7 +2,6 @@ id: consuming title: Consuming Utility APIs sidebar_label: Consuming APIs -# prettier-ignore description: Consuming utility APIs --- diff --git a/docs/frontend-system/utility-apis/04-configuring.md b/docs/frontend-system/utility-apis/04-configuring.md index 4847fc6eaf..1b28bf1351 100644 --- a/docs/frontend-system/utility-apis/04-configuring.md +++ b/docs/frontend-system/utility-apis/04-configuring.md @@ -2,7 +2,6 @@ id: configuring title: Configuring Utility APIs sidebar_label: Configuring -# prettier-ignore description: Configuring, extending, and overriding utility APIs --- diff --git a/docs/integrations/aws-codecommit/locations.md b/docs/integrations/aws-codecommit/locations.md index 35187b1b89..28e77769b2 100644 --- a/docs/integrations/aws-codecommit/locations.md +++ b/docs/integrations/aws-codecommit/locations.md @@ -2,7 +2,6 @@ id: locations sidebar_label: Locations title: Amazon Web Services CodeCommit Locations -# prettier-ignore description: Setting up an integration with Amazon Web Services CodeCommit --- diff --git a/docs/integrations/aws-s3/discovery.md b/docs/integrations/aws-s3/discovery.md index fa1eb017fc..fcba5ca04f 100644 --- a/docs/integrations/aws-s3/discovery.md +++ b/docs/integrations/aws-s3/discovery.md @@ -2,7 +2,6 @@ id: discovery title: AWS S3 Discovery sidebar_label: Discovery -# prettier-ignore description: Automatically discovering catalog entities from an AWS S3 Bucket --- diff --git a/docs/integrations/aws-s3/locations.md b/docs/integrations/aws-s3/locations.md index 9bac28f906..3ed6af62fe 100644 --- a/docs/integrations/aws-s3/locations.md +++ b/docs/integrations/aws-s3/locations.md @@ -2,7 +2,6 @@ id: locations sidebar_label: Locations title: Amazon Web Services S3 Locations -# prettier-ignore description: Setting up an integration with Amazon Web Services S3 --- diff --git a/docs/integrations/azure-blobStorage/discovery.md b/docs/integrations/azure-blobStorage/discovery.md index 32612daf75..bed97441f9 100644 --- a/docs/integrations/azure-blobStorage/discovery.md +++ b/docs/integrations/azure-blobStorage/discovery.md @@ -2,7 +2,6 @@ id: discovery title: Azure Blob Storage Discovery sidebar_label: Discovery -# prettier-ignore description: Automatically discovering catalog entities from an Azure Blob Storage account --- diff --git a/docs/integrations/azure-blobStorage/locations.md b/docs/integrations/azure-blobStorage/locations.md index 38d8555c2e..abe2a238ba 100644 --- a/docs/integrations/azure-blobStorage/locations.md +++ b/docs/integrations/azure-blobStorage/locations.md @@ -2,7 +2,6 @@ id: locations sidebar_label: Locations title: Azure Blob Storage account Locations -# prettier-ignore description: Setting up an integration with Azure Blob Storage account --- diff --git a/docs/integrations/azure/discovery.md b/docs/integrations/azure/discovery.md index b749f8e9ed..a4584ef338 100644 --- a/docs/integrations/azure/discovery.md +++ b/docs/integrations/azure/discovery.md @@ -2,7 +2,6 @@ id: discovery title: Azure DevOps Discovery sidebar_label: Discovery -# prettier-ignore description: Automatically discovering catalog entities from repositories in an Azure DevOps organization --- diff --git a/docs/integrations/azure/locations.md b/docs/integrations/azure/locations.md index 61c54287c9..3ea180f5bd 100644 --- a/docs/integrations/azure/locations.md +++ b/docs/integrations/azure/locations.md @@ -2,7 +2,6 @@ id: locations title: Azure DevOps Locations sidebar_label: Locations -# prettier-ignore description: Integrating source code stored in Azure DevOps into the Backstage catalog --- diff --git a/docs/integrations/azure/org.md b/docs/integrations/azure/org.md index 58c6c9f889..efcd8ae612 100644 --- a/docs/integrations/azure/org.md +++ b/docs/integrations/azure/org.md @@ -2,7 +2,6 @@ id: org title: Microsoft Entra Tenant Data sidebar_label: Org Data -# prettier-ignore description: Importing users and groups from Microsoft Entra ID into Backstage --- diff --git a/docs/integrations/bitbucketCloud/discovery.md b/docs/integrations/bitbucketCloud/discovery.md index 9560c5e06b..e0fab954ac 100644 --- a/docs/integrations/bitbucketCloud/discovery.md +++ b/docs/integrations/bitbucketCloud/discovery.md @@ -2,7 +2,6 @@ id: discovery title: Bitbucket Cloud Discovery sidebar_label: Discovery -# prettier-ignore description: Automatically discovering catalog entities from repositories in Bitbucket Cloud --- diff --git a/docs/integrations/bitbucketCloud/locations.md b/docs/integrations/bitbucketCloud/locations.md index 9b08a79c63..f0a032353c 100644 --- a/docs/integrations/bitbucketCloud/locations.md +++ b/docs/integrations/bitbucketCloud/locations.md @@ -2,7 +2,6 @@ id: locations title: Bitbucket Cloud Locations sidebar_label: Locations -# prettier-ignore description: Integrating source code stored in Bitbucket Cloud into the Backstage catalog --- diff --git a/docs/integrations/bitbucketServer/discovery.md b/docs/integrations/bitbucketServer/discovery.md index 36282b1f48..350bc33aed 100644 --- a/docs/integrations/bitbucketServer/discovery.md +++ b/docs/integrations/bitbucketServer/discovery.md @@ -2,7 +2,6 @@ id: discovery title: Bitbucket Server Discovery sidebar_label: Discovery -# prettier-ignore description: Automatically discovering catalog entities from repositories in Bitbucket Server --- @@ -67,6 +66,7 @@ catalog: projectKey: '^apis-.*$' # optional; RegExp repoSlug: '^service-.*$' # optional; RegExp skipArchivedRepos: true # optional; boolean + validateLocationsExist: false # optional; boolean schedule: # same options as in SchedulerServiceTaskScheduleDefinition # supports cron, ISO duration, "human duration" as used in code frequency: { minutes: 30 } @@ -87,6 +87,10 @@ catalog: Regular expression used to filter results based on the repo slug. - **`skipArchivedRepos`** _(optional)_: Boolean flag to filter out archived repositories. +- **`validateLocationsExist`** _(optional)_: + Defaults to `false`. + Whether to validate locations that exist before emitting them. + This option avoids generating locations for catalog info files that do not exist in the source repository. - **`schedule`**: - **`frequency`**: How often you want the task to run. The system does its best to avoid overlapping invocations. diff --git a/docs/integrations/bitbucketServer/locations.md b/docs/integrations/bitbucketServer/locations.md index 7ff19b8b27..0c8b0e16b4 100644 --- a/docs/integrations/bitbucketServer/locations.md +++ b/docs/integrations/bitbucketServer/locations.md @@ -2,7 +2,6 @@ id: locations title: Bitbucket Server Locations sidebar_label: Locations -# prettier-ignore description: Integrating source code stored in Bitbucket Server into the Backstage catalog --- diff --git a/docs/integrations/datadog-rum/installation.md b/docs/integrations/datadog-rum/installation.md index 6659bec182..5b4fe8bd40 100644 --- a/docs/integrations/datadog-rum/installation.md +++ b/docs/integrations/datadog-rum/installation.md @@ -2,7 +2,6 @@ id: installation title: Datadog RUM Installation sidebar_label: Installation -# prettier-ignore description: Adding Datadog Real User Monitoring (RUM) to Your App --- diff --git a/docs/integrations/gerrit/discovery.md b/docs/integrations/gerrit/discovery.md index dbbc7ba7a4..06fb144e50 100644 --- a/docs/integrations/gerrit/discovery.md +++ b/docs/integrations/gerrit/discovery.md @@ -2,7 +2,6 @@ id: discovery title: Gerrit Discovery sidebar_label: Discovery -# prettier-ignore description: Automatically discovering catalog entities from Gerrit repositories --- diff --git a/docs/integrations/gitea/discovery.md b/docs/integrations/gitea/discovery.md index 6cae169b58..ce8ad9d360 100644 --- a/docs/integrations/gitea/discovery.md +++ b/docs/integrations/gitea/discovery.md @@ -30,7 +30,7 @@ backend.add(import('@backstage/plugin-catalog-backend-module-gitea')); ## Configuration -To use the discovery processor, you'll need a Gitea integration +To use the discovery provider, you'll need a Gitea integration [set up](locations.md). Then you can add any number of providers. ```yaml diff --git a/docs/integrations/github/discovery.md b/docs/integrations/github/discovery.md index 01567a7191..5dd13a7bec 100644 --- a/docs/integrations/github/discovery.md +++ b/docs/integrations/github/discovery.md @@ -2,7 +2,6 @@ id: discovery title: GitHub Discovery sidebar_label: Discovery -# prettier-ignore description: Automatically discovering catalog entities from repositories in a GitHub organization --- diff --git a/docs/integrations/github/org.md b/docs/integrations/github/org.md index 3d0e0a4221..b054daf343 100644 --- a/docs/integrations/github/org.md +++ b/docs/integrations/github/org.md @@ -2,7 +2,6 @@ id: org title: GitHub Organizational Data sidebar_label: Org Data -# prettier-ignore description: Importing users and groups from a GitHub organization into Backstage --- diff --git a/docs/integrations/gitlab/discovery.md b/docs/integrations/gitlab/discovery.md index de35fbcc96..e0ededd1fa 100644 --- a/docs/integrations/gitlab/discovery.md +++ b/docs/integrations/gitlab/discovery.md @@ -2,7 +2,6 @@ id: discovery title: GitLab Discovery sidebar_label: Discovery -# prettier-ignore description: Automatically discovering catalog entities from repositories in GitLab --- diff --git a/docs/integrations/google-cloud-storage/locations.md b/docs/integrations/google-cloud-storage/locations.md index 1f0334ff17..99bba9feb7 100644 --- a/docs/integrations/google-cloud-storage/locations.md +++ b/docs/integrations/google-cloud-storage/locations.md @@ -2,7 +2,6 @@ id: locations sidebar_label: Locations title: Google Cloud Storage Locations -# prettier-ignore description: Setting up an integration with Google Cloud Storage --- diff --git a/docs/integrations/index.md b/docs/integrations/index.md index b090d6d77e..00463a810f 100644 --- a/docs/integrations/index.md +++ b/docs/integrations/index.md @@ -2,8 +2,7 @@ id: index title: Integrations sidebar_label: Overview -# prettier-ignore -description: Configuring Backstage to read or publish data with external providers using integrations +description: Configuring Backstage to read or publish data with external providers using integrations --- Integrations allow Backstage to read or publish data using external providers diff --git a/docs/integrations/ldap/org--old.md b/docs/integrations/ldap/org--old.md index 448e9bbed1..03862d8625 100644 --- a/docs/integrations/ldap/org--old.md +++ b/docs/integrations/ldap/org--old.md @@ -2,7 +2,6 @@ id: org--old title: LDAP Organizational Data sidebar_label: Org Data -# prettier-ignore description: Setting up ingestion of organizational data from LDAP --- diff --git a/docs/integrations/ldap/org.md b/docs/integrations/ldap/org.md index 9913cf0729..8adc81184a 100644 --- a/docs/integrations/ldap/org.md +++ b/docs/integrations/ldap/org.md @@ -2,7 +2,6 @@ id: org title: LDAP Organizational Data sidebar_label: Org Data -# prettier-ignore description: Setting up ingestion of organizational data from LDAP --- diff --git a/docs/notifications/index.md b/docs/notifications/index.md index 2af8879ac0..c31d2716e4 100644 --- a/docs/notifications/index.md +++ b/docs/notifications/index.md @@ -158,6 +158,21 @@ You can customize the origin names shown in the UI by passing an object where th Each notification processor will receive its own row in the settings page, where the user can enable or disable notifications from that processor. +### Automatic notification cleanup + +Notifications are deleted automatically after a certain period of time to prevent the database from growing indefinitely +and to keep the user interface clean. The default retention period is set to 1 year, meaning that notifications older +than that will be deleted automatically. + +The retention period can be configured by setting the `notifications.retention` in the `app-config.yaml` file. + +```yaml +notifications: + retention: 1y +``` + +If the retention is set to false, notifications will not be automatically deleted. + ## Additional info An example of a backend plugin sending notifications can be found in the [`@backstage/plugin-scaffolder-backend-module-notifications` package](https://github.com/backstage/backstage/tree/master/plugins/scaffolder-backend-module-notifications). diff --git a/docs/overview/adopting.md b/docs/overview/adopting.md index a6053d0f85..e924cfbeb0 100644 --- a/docs/overview/adopting.md +++ b/docs/overview/adopting.md @@ -1,7 +1,6 @@ --- id: adopting title: Strategies for adopting -# prettier-ignore description: Documentation on some general best practices that have been key to Backstage's success inside Spotify --- diff --git a/docs/overview/background.md b/docs/overview/background.md index 5e59967b21..147fe8ce7b 100644 --- a/docs/overview/background.md +++ b/docs/overview/background.md @@ -1,7 +1,6 @@ --- id: background title: The Spotify Story -# prettier-ignore description: Backstage was born out of necessity at Spotify. We found that as we grew, our infrastructure was becoming more fragmented, our engineers less productive. --- diff --git a/docs/overview/vision.md b/docs/overview/vision.md index f6d6af90dd..aab5eaa9b8 100644 --- a/docs/overview/vision.md +++ b/docs/overview/vision.md @@ -1,7 +1,6 @@ --- id: vision title: Vision -# prettier-ignore description: Goal is to provide engineers with the best developer experience in the world --- diff --git a/docs/overview/what-is-backstage.md b/docs/overview/what-is-backstage.md index ef452d5d15..fa1c75de44 100644 --- a/docs/overview/what-is-backstage.md +++ b/docs/overview/what-is-backstage.md @@ -1,7 +1,6 @@ --- id: what-is-backstage title: What is Backstage? -# prettier-ignore description: Backstage is an open source framework for building developer portals. Powered by a centralized software catalog, Backstage restores order to your microservices and infrastructure --- diff --git a/docs/permissions/frontend-integration.md b/docs/permissions/frontend-integration.md index 1e83f8ad7d..d5329eca96 100644 --- a/docs/permissions/frontend-integration.md +++ b/docs/permissions/frontend-integration.md @@ -4,6 +4,10 @@ title: Frontend Integration description: How to place your Backstage frontend components behind authorization --- +:::info +Starting with a [fresh Backstage installation](https://backstage.io/docs/getting-started/), the code example below is already implemented, so there are no actual code changes required. +::: + Now that we understand how to [author a permission policy](./writing-a-policy.md), let's consider cases where we'll need to supplement our policy with authorization checks on the frontend. In most cases, actual functionality that live within various plugins will already have been placed behind authorization by the plugin authors. The permission backend will use your permission policy to return an authorization result, and the plugin frontend will correspondingly show/hide/disable the relevant UI component. @@ -13,25 +17,20 @@ However, there are some cases where the integrator needs to supplement the polic If your Backstage permission policy may return a `DENY` for users requesting the `catalogEntityCreatePermission`, it may make sense, for example, to remove access to the `/catalog-import` page entirely: ```tsx title="packages/app/src/App.tsx" -/* highlight-add-start */ import { RequirePermission } from '@backstage/plugin-permission-react'; -import { catalogEntityCreatePermission } from '@backstage/plugin-catalog-common'; -/* highlight-add-end */ +import { catalogEntityCreatePermission } from '@backstage/plugin-catalog-common/alpha'; const routes = ( - {/* highlight-remove-next-line */} - } /> - {/* highlight-add-start */} } /> - {/* highlight-add-end */} {/* ... */} ); diff --git a/docs/permissions/writing-a-policy.md b/docs/permissions/writing-a-policy.md index a479684287..576afcac21 100644 --- a/docs/permissions/writing-a-policy.md +++ b/docs/permissions/writing-a-policy.md @@ -92,6 +92,13 @@ import { catalogEntityDeletePermission, } from '@backstage/plugin-catalog-common/alpha'; /* highlight-add-end */ +import { + PermissionPolicy, + PolicyQuery, + /* highlight-add-next-line */ + PolicyQueryUser, +} from '@backstage/plugin-permission-node'; + class CustomPermissionPolicy implements PermissionPolicy { /* highlight-remove-next-line */ @@ -143,8 +150,8 @@ import { PolicyDecision, /* highlight-remove-next-line */ isPermission, - isResourcePermission, /* highlight-add-next-line */ + isResourcePermission, } from '@backstage/plugin-permission-common'; import { catalogConditions, @@ -155,6 +162,11 @@ import { catalogEntityDeletePermission, } from '@backstage/plugin-catalog-common/alpha'; /* highlight-remove-end */ +import { + PermissionPolicy, + PolicyQuery, + PolicyQueryUser, +} from '@backstage/plugin-permission-node'; class CustomPermissionPolicy implements PermissionPolicy { async handle( diff --git a/docs/plugins/call-existing-api.md b/docs/plugins/call-existing-api.md index f8cfe23275..35a6d8d599 100644 --- a/docs/plugins/call-existing-api.md +++ b/docs/plugins/call-existing-api.md @@ -1,7 +1,6 @@ --- id: call-existing-api title: Call Existing API -# prettier-ignore description: Describes the various options that Backstage frontend plugins have, in communicating with service APIs that already exist --- diff --git a/docs/plugins/composability.md b/docs/plugins/composability.md index a0e0e2d5e6..d6c9abc98f 100644 --- a/docs/plugins/composability.md +++ b/docs/plugins/composability.md @@ -1,7 +1,6 @@ --- id: composability title: Composability System -# prettier-ignore description: Documentation for the Backstage plugin composability APIs. --- diff --git a/docs/plugins/observability.md b/docs/plugins/observability.md index c294001606..7803d90bd5 100644 --- a/docs/plugins/observability.md +++ b/docs/plugins/observability.md @@ -1,7 +1,6 @@ --- id: observability title: Observability -# prettier-ignore description: Adding Observability to Your Plugin --- diff --git a/docs/references/glossary.md b/docs/references/glossary.md index 906260e710..273749323f 100644 --- a/docs/references/glossary.md +++ b/docs/references/glossary.md @@ -1,7 +1,6 @@ --- id: glossary title: Glossary -# prettier-ignore description: List of terms, abbreviations, and phrases used in Backstage, together with their explanations. --- diff --git a/docs/releases/v1.40.0-changelog.md b/docs/releases/v1.40.0-changelog.md new file mode 100644 index 0000000000..e5b65ab8ed --- /dev/null +++ b/docs/releases/v1.40.0-changelog.md @@ -0,0 +1,2771 @@ +# Release v1.40.0 + +Upgrade Helper: [https://backstage.github.io/upgrade-helper/?to=1.40.0](https://backstage.github.io/upgrade-helper/?to=1.40.0) + +## @backstage/plugin-scaffolder-backend@2.0.0 + +### Major Changes + +- 33394db: **BREAKING CHANGES** + + Removal of deprecated re-exports from module packages. + + The following functions have been re-exported from the `scaffolder-backend` plugin for quite some time, and now it's time to clean them up. They've been moved as follows: + + - `createPublishAzureAction` should be imported from `@backstage/plugin-scaffolder-backend-module-azure` instead. + + - `createPublishBitbucketCloudAction` should be imported from `@backstage/plugin-scaffolder-backend-module-bitbucket-cloud` instead. + + - `createPublishBitbucketServerAction` and `createPublishBitbucketServerPullRequestAction` can be imported from `@backstage/plugin-scaffolder-backend-module-bitbucket-server` instead. + + - `createPublishBitbucketAction` should be imported from `@backstage/plugin-scaffolder-backend-module-bitbucket` instead. + + - `createPublishGerritAction` and `createPublishGerritReviewAction` can be imported from `@backstage/plugin-scaffolder-backend-module-gerrit` instead. + + - `createGithubActionsDispatchAction`, `createGithubDeployKeyAction`, `createGithubEnvironmentAction`, `createGithubIssuesLabelAction`, `CreateGithubPullRequestActionOptions`, `createGithubRepoCreateAction`, `createGithubRepoPushAction`, `createGithubWebhookAction`, and `createPublishGithubAction` can be imported from `@backstage/plugin-scaffolder-backend-module-github` instead. + + - `createPublishGitlabAction` should be imported from `@backstage/plugin-scaffolder-backend-module-gitlab` instead. + + - `ActionContext`. `createTemplateAction`, `executeShellCommand`, `ExecuteShellCommandOptions`, `fetchContents`, `TaskSecrets`, and `TemplateAction` should be imported from `@backstage/plugin-scaffolder-node` instead. + + - `ScaffolderEntitiesProcessor` should be imported from `@backstage/plugin-catalog-backend-module-scaffolder-entity-model` instead. + +- a8fcf04: **BREAKING ALPHA**: The `/alpha` export no longer exports the plugin. Please use `import('@backstage/plugin-scaffolder-backend')` instead as this has been removed. + + **BREAKING CHANGES**: The old `createRouter` function which was used in the old backend system has been removed along with the `RouterOptions` type. + +- 73b94d7: **BREAKING CHANGES** + + The following functions have been re-exported from the `scaffolder-backend` plugin for quite some time, and now it's time to clean them up. They've been moved as follows: + + - `SerializedTask`, `SerializedTaskEvent`, `TaskBroker`, `TaskBrokerDispatchOptions`, `TaskBrokerDispatchResult`, `TaskCompletionState`, `TaskContext`, `TaskEventType`, `TaskStatus`, `TemplateFilter`, and `TemplateGlobal` should be imported from `@backstage/plugin-scaffolder-node` instead. + + - The deprecated `copyWithoutRender` option has been removed from `fetch:template` action. You should rename the option to `copyWithoutTemplating` instead. + +- 5863b04: **BREAKING CHANGES** + + - The `createBuiltinActions` method has been removed, as this should no longer be needed with the new backend system route, and was only useful when passing the default list of actions again in the old backend system. You should be able to rely on the default behaviour of the new backend system which is to merge the actions. + + - The `createCatalogRegisterAction` and `createFetchCatalogEntityAction` actions no longer require an `AuthService`, and now accepts a `CatalogService` instead of `CatalogClient`. + + Unless you're providing your own override action to the default, this should be a non-breaking change. + + You can migrate using the following if you're getting typescript errors: + + ```ts + import { catalogServiceRef } from '@backstage/plugin-catalog-node'; + import { scaffolderActionsExtensionPoint } from '@backstage/plugin-scaffolder-node/alpha'; + + export const myModule = createBackendModule({ + pluginId: 'scaffolder', + moduleId: 'test', + register({ registerInit }) { + registerInit({ + deps: { + scaffolder: scaffolderActionsExtensionPoint, + catalog: catalogServiceRef, + }, + async init({ scaffolder, catalog }) { + scaffolder.addActions( + createCatalogRegisterAction({ + catalog, + }), + createFetchCatalogEntityAction({ + catalog, + integrations, + }), + ); + }, + }); + }, + }); + ``` + +### Minor Changes + +- 73b94d7: **DEPRECATIONS** + + The following types and implementations have been deprecated, either because they're no longer relevant, or because upcoming changes to the `scaffolder-backend` after `2.0.0` will influence the changes to these API surfaces. + + - `CreateWorkerOptions` + - `DatabaseTaskStore` + - `DatabaseTaskStoreOptions` + - `TaskManager` + - `TaskStoreCreateTaskOptions` + - `TaskStoreCreateTaskResult` + - `TaskStoreEmitOptions` + - `TaskStoreListEventsOptions` + - `TaskStoreRecoverTaskOptions` + - `TaskStoreShutDownTaskOptions` + + There is no current path off deprecation, these types are going to be removed and rethought with a better way to define workers in the new backend system. + +### Patch Changes + +- 89a941d: Migrating to latest action format + +- 023629e: Enable usage of secrets within 'each' step of software templates. For example, you can now structure your `each` step like this: + + each: + [ + { name: "Service1", token: "${{ secrets.token1 }}" }, + { name: "Service2", token: "${{ secrets.token2 }}" }, + ] + +- e92e481: Add tests for Scaffolder + +- Updated dependencies + - @backstage/plugin-scaffolder-backend-module-gitlab@0.9.2 + - @backstage/plugin-scaffolder-backend-module-azure@0.2.10 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.2.10 + - @backstage/plugin-scaffolder-backend-module-github@0.8.0 + - @backstage/backend-defaults@0.11.0 + - @backstage/plugin-scaffolder-node@0.9.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.2.10 + - @backstage/plugin-scaffolder-backend-module-gerrit@0.2.10 + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/plugin-auth-node@0.6.4 + - @backstage/plugin-scaffolder-backend-module-gitea@0.2.10 + - @backstage/plugin-scaffolder-backend-module-bitbucket@0.3.11 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + - @backstage/types@1.2.1 + - @backstage/plugin-bitbucket-cloud-common@0.3.0 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.2.9 + - @backstage/plugin-events-node@0.4.12 + - @backstage/plugin-permission-common@0.9.0 + - @backstage/plugin-permission-node@0.10.1 + - @backstage/plugin-scaffolder-common@1.5.11 + +## @backstage/backend-defaults@0.11.0 + +### Minor Changes + +- 3ccb7fc: Enhanced error handling in the auditor service factory to pass errors as objects. Aligned WinstonRootAuditorService with the default service factory's error handling. + +### Patch Changes + +- 1220cf8: Added new rate limit middleware to allow rate limiting requests to the backend + + If you are using the `configure` callback of the root HTTP router service and do NOT call `applyDefaults()` inside it, please see [the relevant changes](https://github.com/backstage/backstage/pull/28708/files#diff-86ad1b6a694dd250823aee39d410428dd837c9d9a04ca8c33bd1081fbe3f22af) that were made, to see if you want to apply them as well to your custom configuration. + Rate limiting can be turned on by adding the following configuration to `app-config.yaml`: + + ```yaml + backend: + rateLimit: + window: 6s + incomingRequestLimit: 100 + ``` + + Plugin specific rate limiting can be configured by adding the following configuration to `app-config.yaml`: + + ```yaml + backend: + rateLimit: + global: false # This will disable the global rate limiting + plugin: + catalog: + window: 6s + incomingRequestLimit: 100 + ``` + +- c999c25: Added some default implementations for the experimental `ActionsService` and `ActionsRegistryService` under `/alpha` that allow registration of actions for a particular plugin. + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-app-api@1.2.4 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/backend-dev-utils@0.1.5 + - @backstage/cli-node@0.2.13 + - @backstage/config@1.3.2 + - @backstage/config-loader@1.10.1 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + - @backstage/integration-aws-node@0.1.16 + - @backstage/types@1.2.1 + - @backstage/plugin-events-node@0.4.12 + - @backstage/plugin-permission-node@0.10.1 + +## @backstage/backend-plugin-api@1.4.0 + +### Minor Changes + +- 664c07a: Added `actionsRegistry` and `actions` experimental services to `/alpha` to allow registration of distributed actions from plugins, and the ability to invoke these actions. You can use these services by including them like the following: + + ```ts + import { + actionsRegistryServiceRef, + actionsServiceRef, + } from '@backstage/backend-plugin-api/alpha'; + + createBackendPlugin({ + pluginId: 'test-plugin', + register({ registerInit }) { + registerInit({ + deps: { + actions: actionsServiceRef, + actionsRegistry: actionsRegistryServiceRef, + }, + async init({ actions, actionsRegistry }) { + actionsRegistry.register({ + ..., + }); + + await actions.invoke(...); + }, + }); + }, + }); + ``` + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.4 + - @backstage/cli-common@0.1.15 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/plugin-permission-common@0.9.0 + - @backstage/plugin-permission-node@0.10.1 + +## @backstage/backend-test-utils@1.6.0 + +### Minor Changes + +- 6dfb7be: Added `mockServices.permissions()` that can return actual results. +- c999c25: Added an `actionsRegistryServiceMock` and `actionsServiceMock` to `/alpha` export for the experimental services. + + This allows you to write tests for your actions by doing something similar to the following: + + ```ts + import { actionsRegistryServiceMock } from '@backstage/backend-test-utils/alpha'; + + const mockActionsRegistry = actionsRegistryServiceMock(); + const mockCatalog = catalogServiceMock({ + entities: [ + ... + ], + }); + + createGetCatalogEntityAction({ + catalog: mockCatalog, + actionsRegistry: mockActionsRegistry, + }); + + await expect( + mockActionsRegistry.invoke({ + id: 'test:get-catalog-entity', + input: { name: 'test' }, + }), + ).resolves.toEqual(...) + ``` + +### Patch Changes + +- 12c1fd4: Make the `user` credentials mock behave more like production +- Updated dependencies + - @backstage/backend-defaults@0.11.0 + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-app-api@1.2.4 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/plugin-events-node@0.4.12 + - @backstage/plugin-permission-common@0.9.0 + +## @backstage/canon@0.5.0 + +### Minor Changes + +- 621fac9: We are updating the default size of the Button component in Canon to be small instead of medium. +- a842554: We set the default size for IconButton in Canon to be small instead of medium. +- 35fd51d: Move TextField component to use react Aria under the hood. Introducing a new FieldLabel component to help build custom fields. +- 78204a2: **Breaking** We are adding a new as prop on the Heading and Text component to make it easier to change the component tag. We are removing the render prop in favour of the as prop. +- c49e335: TextField in Canon now has multiple label sizes as well as the capacity to hide label and description but still make them available for screen readers. +- 24b45ef: Fixes spacing props on layout components and aligned on naming for the Grid component. You should now call the Grid root component using <Grid.Root /> instead of just . + +### Patch Changes + +- 44df879: Add min-width: 0; by default on every Flex components in Canon to help support truncated texts inside flex elements. +- ee6ffe6: Fix styling for the title4 prop on the Heading component in Canon. +- f2f814a: Added a render prop to the Button component in Canon to use it as a link. +- 98f02a6: Add new Switch component in Canon. +- c94f8e0: The filter input in menu comboboxes should now always use the full width of the menu it's in. +- 269316d: Remove leftover console.log from Container component. + +## @backstage/cli@0.33.0 + +### Minor Changes + +- eef0e83: Internal update to promote the modular CLI entrypoint to stable. + +### Patch Changes + +- d07fe35: Added user feedback when opening config docs in browser. The command now clearly indicates what it's doing and provides fallback instructions if the browser fails to open. +- ce70439: The `BACKSTAGE_CLI_EXPERIMENTAL_BUILD_CACHE` flag has been removed. Existing users are encouraged to switch to `EXPERIMENTAL_RSPACK` instead. +- 1d8f00b: Switched to using the `ModuleFederationPlugin` from `@module-federation/enhanced/rspack` for Rspack, rather than the built-in one. +- 2b9633f: The experimental `FORCE_REACT_DEVELOPMENT` flag has been removed. +- d8c4a54: Only use the caching Jest module loader for frontend packages in order to avoid breaking real ESM module imports. +- d6d63c7: Updating the scaffolder action boilerplate to use new `zod` schema +- e36e855: Added `backstage.pluginId` field in `package.json` to all default plugin package templates for the `new` command. +- 1bab255: Internal refactor to combine alpha `build` and `start` modules. +- 713e957: fix: merge eslint reports when using json format +- 8a0164c: Fix an issue where some commands were not usable because of missing dist files +- Updated dependencies + - @backstage/eslint-plugin@0.1.11 + - @backstage/catalog-model@1.7.4 + - @backstage/cli-common@0.1.15 + - @backstage/cli-node@0.2.13 + - @backstage/config@1.3.2 + - @backstage/config-loader@1.10.1 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + - @backstage/release-manifests@0.0.13 + - @backstage/types@1.2.1 + +## @backstage/create-app@0.7.0 + +### Minor Changes + +- 30474c4: Add .cache directory to shipped gitignore. + +### Patch Changes + +- d57a6f7: Bumped create-app version. +- f628f44: Bumped create-app version. +- 9c9faf2: Bumped create-app version. +- Updated dependencies + - @backstage/cli-common@0.1.15 + +## @backstage/repo-tools@0.14.0 + +### Minor Changes + +- bf9a173: Add support for caching the per-package output from the `package-docs` command. + +### Patch Changes + +- 4bff5d0: Fixed a bug where linting would fail with the generated clients when defining top-level `enum` schema values. +- 2d20024: Fix an issue where errors were not printed to console when running `backstage-repo-tools schema openapi generate` without the `--watch` flag. +- e643ee4: Add missing highlight language for the `package-docs` command. +- c83cd8b: Fixed some circular or otherwise unclear imports +- a372bf1: Updated dependency `@electric-sql/pglite` to `^0.3.0`. +- Updated dependencies + - @backstage/backend-plugin-api@1.4.0 + - @backstage/catalog-model@1.7.4 + - @backstage/cli-common@0.1.15 + - @backstage/cli-node@0.2.13 + - @backstage/config-loader@1.10.1 + - @backstage/errors@1.2.7 + +## @backstage/plugin-catalog@1.31.0 + +### Minor Changes + +- 406acb6: Add support to customize the about card icon links via `EntityIconLinkBlueprint` and provide a default catalog view catalog source, launch scaffolder template and read techdocs docs icon links extensions. + + **BREAKING ALPHA** + + The `Scaffolder` launch template and `TechDocs` read documentation icons have been extracted from the default `Catalog` about card links and are now provided respectively by the `Scaffolder` and `TechDocs` plugins in the new frontend system. It means that they will not be available unless you install the `TechDocs` and `Scaffolder` plugins. Also If you are using translation for these icon link titles other than the default, you should now translate them using the scaffolder translation reference or the TechDocs translation reference (the translation keys are still the same, `aboutCard.viewTechdocs` and `aboutCard.launchTemplate`). + +- ec7b35d: Introduced `backstage.io/techdocs-entity-path` annotation which allows deep linking into another entities TechDocs in conjunction with `backstage.io/techdocs-entity`. + +### Patch Changes + +- 18c64e9: Added the `info.packageJson` option to the plugin instance for the new frontend system. +- Updated dependencies + - @backstage/core-components@0.17.3 + - @backstage/catalog-client@1.10.1 + - @backstage/core-plugin-api@1.10.8 + - @backstage/frontend-plugin-api@0.10.3 + - @backstage/plugin-catalog-react@1.19.0 + - @backstage/plugin-techdocs-react@1.3.0 + - @backstage/plugin-techdocs-common@0.1.1 + - @backstage/plugin-search-react@1.9.1 + - @backstage/integration-react@1.2.8 + - @backstage/catalog-model@1.7.4 + - @backstage/core-compat-api@0.4.3 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/version-bridge@1.0.11 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-permission-react@0.4.35 + - @backstage/plugin-scaffolder-common@1.5.11 + - @backstage/plugin-search-common@1.2.18 + +## @backstage/plugin-catalog-backend@2.1.0 + +### Minor Changes + +- 2e7adf0: Implement the action `get-catalog-entity` with the `ActionsRegistry` + +### Patch Changes + +- 2cac8b0: You can now specify an optional value when applying the `HAS_LABEL` permission rule, similar to the `HAS_ANNOTATION` permission rule. +- c83cd8b: Fixed some circular or otherwise unclear imports +- 4654a78: Update `refresh_state_references.id` to be a big int +- Updated dependencies + - @backstage/catalog-client@1.10.1 + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/backend-openapi-utils@0.5.4 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + - @backstage/types@1.2.1 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-events-node@0.4.12 + - @backstage/plugin-permission-common@0.9.0 + - @backstage/plugin-permission-node@0.10.1 + +## @backstage/plugin-catalog-backend-module-bitbucket-cloud@0.5.0 + +### Minor Changes + +- 8a150bf: **BREAKING**: `BitbucketCloudEntityProvider` now accepts a `CatalogService` instead of a `CatalogApi`. + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.10.1 + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/integration@1.17.0 + - @backstage/plugin-bitbucket-cloud-common@0.3.0 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-events-node@0.4.12 + +## @backstage/plugin-catalog-backend-module-bitbucket-server@0.5.0 + +### Minor Changes + +- eb8b3aa: Add validateLocationsExist option to avoid generating locations for catalog-info.yaml files that do not exist in the source repository. + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.10.1 + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-events-node@0.4.12 + +## @backstage/plugin-catalog-backend-module-github@0.10.0 + +### Minor Changes + +- 7c0dfb0: GitHub organization now matches in a case-insensitive manner when processing events. + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.10.1 + - @backstage/plugin-catalog-backend@2.1.0 + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/integration@1.17.0 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-events-node@0.4.12 + +## @backstage/plugin-catalog-backend-module-gitlab@0.7.0 + +### Minor Changes + +- 42bb3b8: **BREAKING CHANGE**: User and Group discovery will default to ingesting all users in sub groups that belong to the specified root group in config. Disable by setting `restrictUsersToGroup: true` in app-config under your module settings. + +### Patch Changes + +- 57a0bad: Implement retry for GitLab API calls to handle rate limiting +- Updated dependencies + - @backstage/backend-defaults@0.11.0 + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/integration@1.17.0 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-events-node@0.4.12 + +## @backstage/plugin-catalog-react@1.19.0 + +### Minor Changes + +- 406acb6: Introduces a new `EntityIconLinkBlueprint` that customizes the `About` card icon links on the `Catalog` entity page. + + The blueprint currently accepts a `useProps` hook as `param` and this function returns the following props that will be passed to the icon link component: + + | Name | Description | Type | Default Value | + | ---------- | --------------------------------------------------- | ------------- | ------------- | + | `icon` | The icon to display. | `JSX.Element` | N/A | + | `label` | The label for the element. | `string` | N/A | + | `title` | The title for the element. | `string` | N/A | + | `disabled` | Whether the element is disabled. | `boolean` | `false` | + | `href` | The URL to navigate to when the element is clicked. | `string` | N/A | + | `onClick` | A function to call when the element is clicked. | `() => void` | N/A | + + Here is an usage example: + + ```tsx + import { EntityIconLinkBlueprint } from '@backstage/plugin-catalog-react/alpha'; + //... + + EntityIconLinkBlueprint.make({ + name: 'my-icon-link', + params: { + useProps() { + const { t } = useTranslationRef(myIconLinkTranslationRef); + return { + label: t('myIconLink.label'), + icon: , + href: '/my-plugin', + }; + }, + }, + }); + ``` + + Additionally, the `app-config.yaml` file allows you to override some of the default icon link parameters, including `label` and `title` values. Here's how to set them: + + ```yaml + app: + extensions: + - entity-icon-link:my-plugin/my-icon-link: + config: + label: 'My Custom Icon Link label' + ``` + + Finally, you can disable all links if you want to hide the About card header completely (useful, for example, when links are displayed on separate cards). The header is hidden when no icon links extensions are enabled. + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3 + - @backstage/catalog-client@1.10.1 + - @backstage/core-plugin-api@1.10.8 + - @backstage/frontend-plugin-api@0.10.3 + - @backstage/integration-react@1.2.8 + - @backstage/catalog-model@1.7.4 + - @backstage/core-compat-api@0.4.3 + - @backstage/errors@1.2.7 + - @backstage/frontend-test-utils@0.3.3 + - @backstage/types@1.2.1 + - @backstage/version-bridge@1.0.11 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-permission-common@0.9.0 + - @backstage/plugin-permission-react@0.4.35 + +## @backstage/plugin-events-backend-module-kafka@0.1.0 + +### Minor Changes + +- b034b9d: Adds a new module `kafka` for plugin-events-backend + + The module introduces the `KafkaConsumerClient` which creates a Kafka client used to establish consumer connections. It also provides the `KafkaConsumingEventPublisher`, a consumer that subscribes to configured Kafka topics and publishes received messages to the Event Service. + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/types@1.2.1 + - @backstage/plugin-events-node@0.4.12 + +## @backstage/plugin-mcp-actions-backend@0.1.0 + +### Minor Changes + +- 4ed0fb6: Initial implementation of an `mcp-actions` backend + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.10.1 + - @backstage/backend-defaults@0.11.0 + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + +## @backstage/plugin-scaffolder@1.32.0 + +### Minor Changes + +- 6c972fe: Added information about the `entityRef` and `taskId` to the analytics events whenever is possible. +- 3c59ece: **New Frontend System Only:** + The `Scaffolder` plugin is now responsible for providing an entity icon link extension to launch templates from the catalog entity page. + +### Patch Changes + +- d781b33: render details for composite property schemas +- 18c64e9: Added the `info.packageJson` option to the plugin instance for the new frontend system. +- b00c160: Remove React import form notification and scaffolder plugin +- 95a1d72: Added appropriate message when global templating function metadata is absent. +- Updated dependencies + - @backstage/core-components@0.17.3 + - @backstage/catalog-client@1.10.1 + - @backstage/plugin-scaffolder-react@1.17.0 + - @backstage/core-plugin-api@1.10.8 + - @backstage/frontend-plugin-api@0.10.3 + - @backstage/plugin-catalog-react@1.19.0 + - @backstage/integration-react@1.2.8 + - @backstage/catalog-model@1.7.4 + - @backstage/core-compat-api@0.4.3 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + - @backstage/types@1.2.1 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-permission-react@0.4.35 + - @backstage/plugin-scaffolder-common@1.5.11 + +## @backstage/plugin-scaffolder-backend-module-github@0.8.0 + +### Minor Changes + +- 5863b04: **BREAKING CHANGES** + + The `createGithubEnvironmentAction` action no longer requires an `AuthService`, and now accepts a `CatalogService` instead of `CatalogClient`. + + Unless you're providing your own override action to the default, this should be a non-breaking change. + + You can migrate using the following if you're getting typescript errors: + + ```ts + import { catalogServiceRef } from '@backstage/plugin-catalog-node'; + import { scaffolderActionsExtensionPoint } from '@backstage/plugin-scaffolder-node/alpha'; + + export const myModule = createBackendModule({ + pluginId: 'scaffolder', + moduleId: 'test', + register({ registerInit }) { + registerInit({ + deps: { + scaffolder: scaffolderActionsExtensionPoint, + catalog: catalogServiceRef, + }, + async init({ scaffolder, catalog }) { + scaffolder.addActions( + createGithubEnvironmentAction({ + catalog, + }), + ); + }, + }); + }, + }); + ``` + +### Patch Changes + +- 575c76b: Migrate to using new actions +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.9.0 + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + - @backstage/types@1.2.1 + +## @backstage/plugin-scaffolder-node@0.9.0 + +### Minor Changes + +- 5863b04: **BREAKING CHANGES** + + The legacy methods to define `createTemplateActions` have been replaced with the new native `zod` approaches for defining input and output schemas. + + You can migrate actions that look like the following with the below examples: + + ```ts + // really old legacy json schema + createTemplateAction<{ repoUrl: string }, { repoOutput: string }>({ + id: 'test', + schema: { + input: { + type: 'object' + required: ['repoUrl'] + properties: { + repoUrl: { + type: 'string', + description: 'repository url description' + } + } + } + } + }); + + // old zod method + createTemplateAction({ + id: 'test' + schema: { + input: { + repoUrl: z.string({ description: 'repository url description' }) + } + } + }) + + // new method: + createTemplateAction({ + id: 'test', + schema: { + input: { + repoUrl: z => z.string({ description: 'repository url description' }) + } + } + }) + + // or for more complex zod types like unions + createTemplateAction({ + id: 'test', + schema: { + input: z => z.object({ + repoUrl: z.string({ description: 'repository url description' }) + }) + } + }) + ``` + + This breaking change also means that `logStream` has been removed entirely from `ActionsContext`, and that the `logger` is now just a `LoggerService` implementation instead. There is no replacement for the `logStream`, if you wish to still keep using a `logStream` we recommend that you create your own stream that writes to `ctx.logger` instead. + +### Patch Changes + +- e89d7b6: Use `LoggerService` instead of `Logger`. This is a non-breaking change, as the `LoggerService` is a subset of the `Logger` interface. +- 9c8ff0c: Update pull request creation filter to include .gitignore files in the created pull request +- Updated dependencies + - @backstage/backend-plugin-api@1.4.0 + - @backstage/catalog-model@1.7.4 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + - @backstage/types@1.2.1 + - @backstage/plugin-scaffolder-common@1.5.11 + +## @backstage/plugin-scaffolder-node-test-utils@0.3.0 + +### Minor Changes + +- 3cea7ee: **BREAKING CHANGES** + + Because of the removal of the `logStream` property to the `ActionsContext` this has been removed from the `createMockActionContext` method. + + You can remove this as it's no longer supported in the scaffolder actions. + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.9.0 + - @backstage/backend-test-utils@1.6.0 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/types@1.2.1 + +## @backstage/plugin-scaffolder-react@1.17.0 + +### Minor Changes + +- 6c972fe: Added information about the `entityRef` and `taskId` to the analytics events whenever is possible. + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3 + - @backstage/catalog-client@1.10.1 + - @backstage/core-plugin-api@1.10.8 + - @backstage/frontend-plugin-api@0.10.3 + - @backstage/plugin-catalog-react@1.19.0 + - @backstage/catalog-model@1.7.4 + - @backstage/theme@0.6.6 + - @backstage/types@1.2.1 + - @backstage/version-bridge@1.0.11 + - @backstage/plugin-permission-react@0.4.35 + - @backstage/plugin-scaffolder-common@1.5.11 + +## @backstage/plugin-techdocs@1.13.0 + +### Minor Changes + +- 3c59ece: **New Frontend System Only:** + The `TechDocs` plugin is now responsible for providing an entity icon link extension to read documentation from the catalog entity page. +- ec7b35d: Introduced `backstage.io/techdocs-entity-path` annotation which allows deep linking into another entities TechDocs in conjunction with `backstage.io/techdocs-entity`. + +### Patch Changes + +- 18c64e9: Added the `info.packageJson` option to the plugin instance for the new frontend system. +- 9dde3ba: Improved Keyboard accessibility in techdocs. +- Updated dependencies + - @backstage/core-components@0.17.3 + - @backstage/catalog-client@1.10.1 + - @backstage/core-plugin-api@1.10.8 + - @backstage/frontend-plugin-api@0.10.3 + - @backstage/plugin-catalog-react@1.19.0 + - @backstage/plugin-techdocs-react@1.3.0 + - @backstage/plugin-techdocs-common@0.1.1 + - @backstage/plugin-search-react@1.9.1 + - @backstage/integration-react@1.2.8 + - @backstage/plugin-auth-react@0.1.16 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/core-compat-api@0.4.3 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + - @backstage/theme@0.6.6 + - @backstage/plugin-search-common@1.2.18 + +## @backstage/plugin-techdocs-react@1.3.0 + +### Minor Changes + +- ec7b35d: Introduced `backstage.io/techdocs-entity-path` annotation which allows deep linking into another entities TechDocs in conjunction with `backstage.io/techdocs-entity`. + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3 + - @backstage/core-plugin-api@1.10.8 + - @backstage/frontend-plugin-api@0.10.3 + - @backstage/plugin-techdocs-common@0.1.1 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/version-bridge@1.0.11 + +## @backstage/app-defaults@1.6.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3 + - @backstage/core-plugin-api@1.10.8 + - @backstage/core-app-api@1.17.1 + - @backstage/theme@0.6.6 + - @backstage/plugin-permission-react@0.4.35 + +## @backstage/backend-app-api@1.2.4 + +### Patch Changes + +- bb9a501: Fixed a bug where occasionally the initialization order of multiple modules consuming a single extension point could happen in the wrong order. +- Updated dependencies + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + +## @backstage/backend-dynamic-feature-service@0.7.1 + +### Patch Changes + +- c83cd8b: Fixed some circular or otherwise unclear imports +- Updated dependencies + - @backstage/backend-defaults@0.11.0 + - @backstage/plugin-scaffolder-node@0.9.0 + - @backstage/plugin-catalog-backend@2.1.0 + - @backstage/plugin-events-backend@0.5.3 + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/backend-openapi-utils@0.5.4 + - @backstage/cli-common@0.1.15 + - @backstage/cli-node@0.2.13 + - @backstage/config@1.3.2 + - @backstage/config-loader@1.10.1 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/plugin-app-node@0.1.34 + - @backstage/plugin-events-node@0.4.12 + - @backstage/plugin-permission-common@0.9.0 + - @backstage/plugin-permission-node@0.10.1 + - @backstage/plugin-search-backend-node@1.3.12 + - @backstage/plugin-search-common@1.2.18 + +## @backstage/backend-openapi-utils@0.5.4 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.0 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + +## @backstage/catalog-client@1.10.1 + +### Patch Changes + +- 22fad0d: Fixed `CatalogClient` error responses for `refreshEntity` and `addLocation`. +- Updated dependencies + - @backstage/catalog-model@1.7.4 + - @backstage/errors@1.2.7 + +## @backstage/core-app-api@1.17.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.10.8 + - @backstage/config@1.3.2 + - @backstage/types@1.2.1 + - @backstage/version-bridge@1.0.11 + +## @backstage/core-compat-api@0.4.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.10.8 + - @backstage/frontend-plugin-api@0.10.3 + - @backstage/plugin-catalog-react@1.19.0 + - @backstage/version-bridge@1.0.11 + +## @backstage/core-components@0.17.3 + +### Patch Changes + +- 6232160: table actions header support i18n +- Updated dependencies + - @backstage/core-plugin-api@1.10.8 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/theme@0.6.6 + - @backstage/version-bridge@1.0.11 + +## @backstage/core-plugin-api@1.10.8 + +### Patch Changes + +- c83cd8b: Fixed some circular or otherwise unclear imports +- 0169b23: Internal tweak to avoid circular dependencies +- Updated dependencies + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/version-bridge@1.0.11 + +## @backstage/dev-utils@1.1.11 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3 + - @backstage/core-plugin-api@1.10.8 + - @backstage/plugin-catalog-react@1.19.0 + - @backstage/app-defaults@1.6.3 + - @backstage/integration-react@1.2.8 + - @backstage/catalog-model@1.7.4 + - @backstage/core-app-api@1.17.1 + - @backstage/theme@0.6.6 + +## @backstage/eslint-plugin@0.1.11 + +### Patch Changes + +- 098ef95: Fix custom rules package scanning performance. +- 063b2d3: Added new eslint rule to restrict mixed plugin imports. + + New rule `@backstage/no-mixed-plugin-imports` disallows mixed imports between plugins that are mixing + the backstage architecture. This rule forces that: + + - No imports from frontend plugins to backend plugins or other frontend plugins. + - No imports from backend plugins to frontend plugins or other backend plugins. + - No imports from common plugins to frontend or backend plugins. + + The current recommended configuration is giving a warning for mixed imports. This is to be changed in + the future to an error so please adjust your workspace accordingly. + +## @backstage/frontend-app-api@0.11.3 + +### Patch Changes + +- 0169b23: Internal tweak to avoid circular dependencies +- c38c9e8: Implemented support for the `plugin.info()` method in specialized apps with a default resolved for `package.json` and `catalog-info.yaml`. The default resolution logic can be overridden via the `pluginInfoResolver` option to `createSpecializedApp`, and plugin-specific overrides can be applied via the new `app.pluginOverrides` key in static configuration. +- Updated dependencies + - @backstage/core-plugin-api@1.10.8 + - @backstage/frontend-plugin-api@0.10.3 + - @backstage/frontend-defaults@0.2.3 + - @backstage/config@1.3.2 + - @backstage/core-app-api@1.17.1 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/version-bridge@1.0.11 + +## @backstage/frontend-defaults@0.2.3 + +### Patch Changes + +- fa5650c: Forwarded the new `pluginInfoResolver` option for `createApp`. +- Updated dependencies + - @backstage/plugin-app@0.1.10 + - @backstage/frontend-plugin-api@0.10.3 + - @backstage/frontend-app-api@0.11.3 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + +## @backstage/frontend-dynamic-feature-loader@0.1.2 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.10.3 + - @backstage/config@1.3.2 + +## @backstage/frontend-plugin-api@0.10.3 + +### Patch Changes + +- 0169b23: Internal tweak to avoid circular dependencies + +- 9e3868f: Added a new optional `info` option to `createFrontendPlugin` that lets you provide a loaders for different sources of metadata information about the plugin. + + There are two available loaders. The first one is `info.packageJson`, which can be used to point to a `package.json` file for the plugin. This is recommended for any plugin that is defined within its own package, especially all plugins that are published to a package registry. Typical usage looks like this: + + ```ts + export default createFrontendPlugin({ + pluginId: '...', + info: { + packageJson: () => import('../package.json'), + }, + }); + ``` + + The second loader is `info.manifest`, which can be used to point to an opaque plugin manifest. This **MUST ONLY** be used by plugins that are intended for use within a single organization. Plugins that are published to an open package registry should **NOT** use this loader. The loader is useful for adding additional internal metadata associated with the plugin, and it is up to the Backstage app to decide how these manifests are parsed and used. The default manifest parser in an app created with `createApp` from `@backstage/frontend-defaults` is able to parse the default `catalog-info.yaml` format and built-in fields such as `spec.owner`. + + Typical usage looks like this: + + ```ts + export default createFrontendPlugin({ + pluginId: '...', + info: { + manifest: () => import('../catalog-info.yaml'), + }, + }); + ``` + +- 6f48f71: Added a new `useAppNode` hook, which can be used to get a reference to the `AppNode` from by the closest `ExtensionBoundary`. + +- Updated dependencies + - @backstage/core-components@0.17.3 + - @backstage/core-plugin-api@1.10.8 + - @backstage/types@1.2.1 + - @backstage/version-bridge@1.0.11 + +## @backstage/frontend-test-utils@0.3.3 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-app@0.1.10 + - @backstage/frontend-plugin-api@0.10.3 + - @backstage/frontend-app-api@0.11.3 + - @backstage/config@1.3.2 + - @backstage/test-utils@1.7.9 + - @backstage/types@1.2.1 + - @backstage/version-bridge@1.0.11 + +## @backstage/integration-react@1.2.8 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.10.8 + - @backstage/config@1.3.2 + - @backstage/integration@1.17.0 + +## @techdocs/cli@1.9.4 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.11.0 + - @backstage/catalog-model@1.7.4 + - @backstage/cli-common@0.1.15 + - @backstage/config@1.3.2 + - @backstage/plugin-techdocs-node@1.13.4 + +## @backstage/test-utils@1.7.9 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.10.8 + - @backstage/config@1.3.2 + - @backstage/core-app-api@1.17.1 + - @backstage/theme@0.6.6 + - @backstage/types@1.2.1 + - @backstage/plugin-permission-common@0.9.0 + - @backstage/plugin-permission-react@0.4.35 + +## @backstage/plugin-api-docs@0.12.8 + +### Patch Changes + +- 18c64e9: Added the `info.packageJson` option to the plugin instance for the new frontend system. +- Updated dependencies + - @backstage/core-components@0.17.3 + - @backstage/plugin-catalog@1.31.0 + - @backstage/core-plugin-api@1.10.8 + - @backstage/frontend-plugin-api@0.10.3 + - @backstage/plugin-catalog-react@1.19.0 + - @backstage/catalog-model@1.7.4 + - @backstage/core-compat-api@0.4.3 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-permission-react@0.4.35 + +## @backstage/plugin-app@0.1.10 + +### Patch Changes + +- 18c64e9: Added the `info.packageJson` option to the plugin instance for the new frontend system. +- Updated dependencies + - @backstage/core-components@0.17.3 + - @backstage/core-plugin-api@1.10.8 + - @backstage/frontend-plugin-api@0.10.3 + - @backstage/integration-react@1.2.8 + - @backstage/theme@0.6.6 + - @backstage/types@1.2.1 + - @backstage/plugin-permission-react@0.4.35 + +## @backstage/plugin-app-backend@0.5.3 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/config-loader@1.10.1 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/plugin-app-node@0.1.34 + +## @backstage/plugin-app-node@0.1.34 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config-loader@1.10.1 + +## @backstage/plugin-app-visualizer@0.1.20 + +### Patch Changes + +- 18c64e9: Added the `info.packageJson` option to the plugin instance for the new frontend system. +- Updated dependencies + - @backstage/core-components@0.17.3 + - @backstage/core-plugin-api@1.10.8 + - @backstage/frontend-plugin-api@0.10.3 + +## @backstage/plugin-auth-backend@0.25.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + +## @backstage/plugin-auth-backend-module-atlassian-provider@0.4.4 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-plugin-api@1.4.0 + +## @backstage/plugin-auth-backend-module-auth0-provider@0.2.4 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-plugin-api@1.4.0 + +## @backstage/plugin-auth-backend-module-aws-alb-provider@0.4.4 + +### Patch Changes + +- c83cd8b: Fixed some circular or otherwise unclear imports +- Updated dependencies + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/errors@1.2.7 + - @backstage/plugin-auth-backend@0.25.1 + +## @backstage/plugin-auth-backend-module-azure-easyauth-provider@0.2.9 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/catalog-model@1.7.4 + - @backstage/errors@1.2.7 + +## @backstage/plugin-auth-backend-module-bitbucket-provider@0.3.4 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-plugin-api@1.4.0 + +## @backstage/plugin-auth-backend-module-bitbucket-server-provider@0.2.4 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-plugin-api@1.4.0 + +## @backstage/plugin-auth-backend-module-cloudflare-access-provider@0.4.4 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + +## @backstage/plugin-auth-backend-module-gcp-iap-provider@0.4.4 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + +## @backstage/plugin-auth-backend-module-github-provider@0.3.4 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-plugin-api@1.4.0 + +## @backstage/plugin-auth-backend-module-gitlab-provider@0.3.4 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-plugin-api@1.4.0 + +## @backstage/plugin-auth-backend-module-google-provider@0.3.4 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-plugin-api@1.4.0 + +## @backstage/plugin-auth-backend-module-guest-provider@0.2.9 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/catalog-model@1.7.4 + - @backstage/errors@1.2.7 + +## @backstage/plugin-auth-backend-module-microsoft-provider@0.3.4 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-plugin-api@1.4.0 + +## @backstage/plugin-auth-backend-module-oauth2-provider@0.4.4 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-plugin-api@1.4.0 + +## @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.2.9 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/errors@1.2.7 + +## @backstage/plugin-auth-backend-module-oidc-provider@0.4.4 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/types@1.2.1 + - @backstage/plugin-auth-backend@0.25.1 + +## @backstage/plugin-auth-backend-module-okta-provider@0.2.4 + +### Patch Changes + +- b25977f: Updated dependency `@davidzemon/passport-okta-oauth` to `^0.0.6`. +- Updated dependencies + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-plugin-api@1.4.0 + +## @backstage/plugin-auth-backend-module-onelogin-provider@0.3.4 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-plugin-api@1.4.0 + +## @backstage/plugin-auth-backend-module-pinniped-provider@0.3.4 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/types@1.2.1 + +## @backstage/plugin-auth-backend-module-vmware-cloud-provider@0.5.4 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/catalog-model@1.7.4 + +## @backstage/plugin-auth-node@0.6.4 + +### Patch Changes + +- 0169b23: Internal tweak to avoid circular dependencies +- Updated dependencies + - @backstage/catalog-client@1.10.1 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + +## @backstage/plugin-auth-react@0.1.16 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3 + - @backstage/core-plugin-api@1.10.8 + - @backstage/errors@1.2.7 + +## @backstage/plugin-catalog-backend-module-aws@0.4.12 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.11.0 + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + - @backstage/integration-aws-node@0.1.16 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-kubernetes-common@0.9.5 + +## @backstage/plugin-catalog-backend-module-azure@0.3.6 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/integration@1.17.0 + - @backstage/plugin-catalog-common@1.1.4 + +## @backstage/plugin-catalog-backend-module-backstage-openapi@0.5.3 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/backend-openapi-utils@0.5.4 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + +## @backstage/plugin-catalog-backend-module-gcp@0.3.9 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/plugin-kubernetes-common@0.9.5 + +## @backstage/plugin-catalog-backend-module-gerrit@0.3.3 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + - @backstage/plugin-catalog-common@1.1.4 + +## @backstage/plugin-catalog-backend-module-gitea@0.1.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + - @backstage/plugin-catalog-common@1.1.4 + +## @backstage/plugin-catalog-backend-module-github-org@0.3.11 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/plugin-catalog-backend-module-github@0.10.0 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/plugin-events-node@0.4.12 + +## @backstage/plugin-catalog-backend-module-gitlab-org@0.2.10 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend-module-gitlab@0.7.0 + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/plugin-events-node@0.4.12 + +## @backstage/plugin-catalog-backend-module-incremental-ingestion@0.7.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.11.0 + - @backstage/plugin-catalog-backend@2.1.0 + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/plugin-events-node@0.4.12 + - @backstage/plugin-permission-common@0.9.0 + +## @backstage/plugin-catalog-backend-module-ldap@0.11.6 + +### Patch Changes + +- 087d51d: Export LDAP vendor types and instances for testing custom transformers + +- f07b0ad: Added the ability to configure disabling one side of the relations tree with LDAP. + + Groups have a `member` attribute and users have a `memberOf` attribute, however these can drift out of sync in some LDAP installations, leaving weird states in the Catalog as we collate these results together and deduplicate them. + + You can chose to optionally disable one side of these relationships, or even both by setting the respective mapping to `null` in your `app-config.yaml` for your groups and/or users: + + ```yaml + catalog: + providers: + ldapOrg: + default: + target: ldaps://ds.example.net + bind: + dn: uid=ldap-reader-user,ou=people,ou=example,dc=example,dc=net + secret: ${LDAP_SECRET} + users: + - dn: ou=people,ou=example,dc=example,dc=net + options: + filter: (uid=*) + map: + # this ensures that outgoing memberships from users is ignored + memberOf: null + groups: + - dn: ou=access,ou=groups,ou=example,dc=example,dc=net + options: + filter: (&(objectClass=some-group-class)(!(groupType=email))) + map: + description: l + set: + metadata.customField: 'hello' + map: + # this ensures that outgoing memberships from groups is ignored + members: null + ``` + +- Updated dependencies + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/plugin-catalog-common@1.1.4 + +## @backstage/plugin-catalog-backend-module-logs@0.1.11 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@2.1.0 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/plugin-events-node@0.4.12 + +## @backstage/plugin-catalog-backend-module-msgraph@0.7.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/plugin-catalog-common@1.1.4 + +## @backstage/plugin-catalog-backend-module-openapi@0.2.11 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/catalog-model@1.7.4 + - @backstage/integration@1.17.0 + - @backstage/types@1.2.1 + - @backstage/plugin-catalog-common@1.1.4 + +## @backstage/plugin-catalog-backend-module-puppetdb@0.2.11 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + +## @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.2.9 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/catalog-model@1.7.4 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-scaffolder-common@1.5.11 + +## @backstage/plugin-catalog-backend-module-unprocessed@0.6.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/catalog-model@1.7.4 + - @backstage/errors@1.2.7 + - @backstage/plugin-catalog-unprocessed-entities-common@0.0.8 + - @backstage/plugin-permission-common@0.9.0 + +## @backstage/plugin-catalog-graph@0.4.20 + +### Patch Changes + +- 18c64e9: Added the `info.packageJson` option to the plugin instance for the new frontend system. +- Updated dependencies + - @backstage/core-components@0.17.3 + - @backstage/catalog-client@1.10.1 + - @backstage/core-plugin-api@1.10.8 + - @backstage/frontend-plugin-api@0.10.3 + - @backstage/plugin-catalog-react@1.19.0 + - @backstage/catalog-model@1.7.4 + - @backstage/core-compat-api@0.4.3 + - @backstage/types@1.2.1 + +## @backstage/plugin-catalog-import@0.13.1 + +### Patch Changes + +- 18c64e9: Added the `info.packageJson` option to the plugin instance for the new frontend system. +- 5d7c539: Catalog import plugin full support i18n +- Updated dependencies + - @backstage/core-components@0.17.3 + - @backstage/catalog-client@1.10.1 + - @backstage/core-plugin-api@1.10.8 + - @backstage/frontend-plugin-api@0.10.3 + - @backstage/plugin-catalog-react@1.19.0 + - @backstage/integration-react@1.2.8 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/core-compat-api@0.4.3 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + - @backstage/plugin-catalog-common@1.1.4 + +## @backstage/plugin-catalog-node@1.17.1 + +### Patch Changes + +- 0169b23: Internal tweak to avoid circular dependencies +- Updated dependencies + - @backstage/catalog-client@1.10.1 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/catalog-model@1.7.4 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-permission-common@0.9.0 + - @backstage/plugin-permission-node@0.10.1 + +## @backstage/plugin-catalog-unprocessed-entities@0.2.18 + +### Patch Changes + +- 18c64e9: Added the `info.packageJson` option to the plugin instance for the new frontend system. +- Updated dependencies + - @backstage/core-components@0.17.3 + - @backstage/core-plugin-api@1.10.8 + - @backstage/frontend-plugin-api@0.10.3 + - @backstage/catalog-model@1.7.4 + - @backstage/core-compat-api@0.4.3 + - @backstage/errors@1.2.7 + +## @backstage/plugin-config-schema@0.1.69 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3 + - @backstage/core-plugin-api@1.10.8 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + +## @backstage/plugin-devtools@0.1.28 + +### Patch Changes + +- 18c64e9: Added the `info.packageJson` option to the plugin instance for the new frontend system. +- Updated dependencies + - @backstage/core-components@0.17.3 + - @backstage/core-plugin-api@1.10.8 + - @backstage/frontend-plugin-api@0.10.3 + - @backstage/core-compat-api@0.4.3 + - @backstage/errors@1.2.7 + - @backstage/plugin-devtools-common@0.1.16 + - @backstage/plugin-permission-react@0.4.35 + +## @backstage/plugin-devtools-backend@0.5.6 + +### Patch Changes + +- 9a99735: Removed the usage of `permissionIntegrationRouter` in favor of using the new `coreServices.permissionsRegistry` +- Updated dependencies + - @backstage/backend-defaults@0.11.0 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/cli-common@0.1.15 + - @backstage/config@1.3.2 + - @backstage/config-loader@1.10.1 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/plugin-devtools-common@0.1.16 + - @backstage/plugin-permission-common@0.9.0 + - @backstage/plugin-permission-node@0.10.1 + +## @backstage/plugin-events-backend@0.5.3 + +### Patch Changes + +- c83cd8b: Fixed some circular or otherwise unclear imports +- Updated dependencies + - @backstage/backend-plugin-api@1.4.0 + - @backstage/backend-openapi-utils@0.5.4 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/plugin-events-node@0.4.12 + +## @backstage/plugin-events-backend-module-aws-sqs@0.4.12 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/types@1.2.1 + - @backstage/plugin-events-node@0.4.12 + +## @backstage/plugin-events-backend-module-azure@0.2.21 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.0 + - @backstage/plugin-events-node@0.4.12 + +## @backstage/plugin-events-backend-module-bitbucket-cloud@0.2.21 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.0 + - @backstage/plugin-events-node@0.4.12 + +## @backstage/plugin-events-backend-module-bitbucket-server@0.1.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.0 + - @backstage/plugin-events-node@0.4.12 + +## @backstage/plugin-events-backend-module-gerrit@0.2.21 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.0 + - @backstage/plugin-events-node@0.4.12 + +## @backstage/plugin-events-backend-module-github@0.4.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/integration@1.17.0 + - @backstage/types@1.2.1 + - @backstage/plugin-events-node@0.4.12 + +## @backstage/plugin-events-backend-module-gitlab@0.3.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/plugin-events-node@0.4.12 + +## @backstage/plugin-events-backend-module-google-pubsub@0.1.1 + +### Patch Changes + +- f983e99: Add an `EventConsumingGooglePubSubPublisher`, for pushing Backstage events to pubsub +- Updated dependencies + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/plugin-events-node@0.4.12 + +## @backstage/plugin-events-backend-test-utils@0.1.45 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.4.12 + +## @backstage/plugin-events-node@0.4.12 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.0 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + +## @backstage/plugin-gateway-backend@1.0.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.0 + +## @backstage/plugin-home@0.8.9 + +### Patch Changes + +- 18c64e9: Added the `info.packageJson` option to the plugin instance for the new frontend system. +- 0ebad54: Fixed the `WelcomeTitle` to properly default to the previous value of `inherit` +- cef60db: Home plugin support i18n +- Updated dependencies + - @backstage/core-components@0.17.3 + - @backstage/catalog-client@1.10.1 + - @backstage/core-plugin-api@1.10.8 + - @backstage/plugin-home-react@0.1.27 + - @backstage/frontend-plugin-api@0.10.3 + - @backstage/plugin-catalog-react@1.19.0 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/core-app-api@1.17.1 + - @backstage/core-compat-api@0.4.3 + - @backstage/theme@0.6.6 + +## @backstage/plugin-home-react@0.1.27 + +### Patch Changes + +- c83cd8b: Fixed some circular or otherwise unclear imports +- cef60db: Home plugin support i18n +- Updated dependencies + - @backstage/core-components@0.17.3 + - @backstage/core-plugin-api@1.10.8 + - @backstage/frontend-plugin-api@0.10.3 + +## @backstage/plugin-kubernetes@0.12.8 + +### Patch Changes + +- 18c64e9: Added the `info.packageJson` option to the plugin instance for the new frontend system. +- 3ea5d1b: chore(deps): Update deprecated xterm to new package under @xterm +- Updated dependencies + - @backstage/core-components@0.17.3 + - @backstage/plugin-kubernetes-react@0.5.8 + - @backstage/core-plugin-api@1.10.8 + - @backstage/frontend-plugin-api@0.10.3 + - @backstage/plugin-catalog-react@1.19.0 + - @backstage/catalog-model@1.7.4 + - @backstage/core-compat-api@0.4.3 + - @backstage/plugin-kubernetes-common@0.9.5 + - @backstage/plugin-permission-react@0.4.35 + +## @backstage/plugin-kubernetes-backend@0.19.7 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.10.1 + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration-aws-node@0.1.16 + - @backstage/types@1.2.1 + - @backstage/plugin-kubernetes-common@0.9.5 + - @backstage/plugin-kubernetes-node@0.3.1 + - @backstage/plugin-permission-common@0.9.0 + - @backstage/plugin-permission-node@0.10.1 + +## @backstage/plugin-kubernetes-cluster@0.0.26 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3 + - @backstage/plugin-kubernetes-react@0.5.8 + - @backstage/core-plugin-api@1.10.8 + - @backstage/plugin-catalog-react@1.19.0 + - @backstage/catalog-model@1.7.4 + - @backstage/plugin-kubernetes-common@0.9.5 + - @backstage/plugin-permission-react@0.4.35 + +## @backstage/plugin-kubernetes-node@0.3.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.0 + - @backstage/catalog-model@1.7.4 + - @backstage/types@1.2.1 + - @backstage/plugin-kubernetes-common@0.9.5 + +## @backstage/plugin-kubernetes-react@0.5.8 + +### Patch Changes + +- 3ea5d1b: chore(deps): Update deprecated xterm to new package under @xterm +- Updated dependencies + - @backstage/core-components@0.17.3 + - @backstage/core-plugin-api@1.10.8 + - @backstage/catalog-model@1.7.4 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/plugin-kubernetes-common@0.9.5 + +## @backstage/plugin-notifications@0.5.6 + +### Patch Changes + +- 18c64e9: Added the `info.packageJson` option to the plugin instance for the new frontend system. +- b00c160: Remove React import form notification and scaffolder plugin +- 1fb5f06: Adds ability for user to turn on/off notifications for specific topics within an origin. +- Updated dependencies + - @backstage/core-components@0.17.3 + - @backstage/core-plugin-api@1.10.8 + - @backstage/plugin-notifications-common@0.0.9 + - @backstage/frontend-plugin-api@0.10.3 + - @backstage/core-compat-api@0.4.3 + - @backstage/errors@1.2.7 + - @backstage/theme@0.6.6 + - @backstage/types@1.2.1 + - @backstage/plugin-signals-react@0.0.14 + +## @backstage/plugin-notifications-backend@0.5.7 + +### Patch Changes + +- 41d4d6e: Notifications are now automatically deleted after 1 year by default. + + There is a new scheduled task that runs every 24 hours to delete notifications older than 1 year. + This can be configured by setting the `notifications.retention` in the `app-config.yaml` file. + + ```yaml + notifications: + retention: 1y + ``` + + If the retention is set to false, notifications will not be automatically deleted. + +- 8a150bf: Internal changes to switch to the non-alpha `catalogServiceRef` + +- 1fb5f06: Adds ability for user to turn on/off notifications for specific topics within an origin. + +- ef9ab82: Notifications API will now return user as null always for broadcast notifications + +- Updated dependencies + - @backstage/plugin-notifications-common@0.0.9 + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/plugin-notifications-node@0.2.16 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/plugin-events-node@0.4.12 + - @backstage/plugin-signals-node@0.1.21 + +## @backstage/plugin-notifications-backend-module-email@0.3.10 + +### Patch Changes + +- 8a150bf: Internal changes to switch to the non-alpha `catalogServiceRef` +- Updated dependencies + - @backstage/catalog-client@1.10.1 + - @backstage/plugin-notifications-common@0.0.9 + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/plugin-notifications-node@0.2.16 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/integration-aws-node@0.1.16 + - @backstage/types@1.2.1 + +## @backstage/plugin-notifications-backend-module-slack@0.1.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-notifications-common@0.0.9 + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/plugin-notifications-node@0.2.16 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + +## @backstage/plugin-notifications-common@0.0.9 + +### Patch Changes + +- 1fb5f06: Adds ability for user to turn on/off notifications for specific topics within an origin. +- Updated dependencies + - @backstage/config@1.3.2 + +## @backstage/plugin-notifications-node@0.2.16 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.10.1 + - @backstage/plugin-notifications-common@0.0.9 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/catalog-model@1.7.4 + - @backstage/plugin-signals-node@0.1.21 + +## @backstage/plugin-org@0.6.40 + +### Patch Changes + +- 18c64e9: Added the `info.packageJson` option to the plugin instance for the new frontend system. +- 4fe364f: Org plugin support i18n +- Updated dependencies + - @backstage/core-components@0.17.3 + - @backstage/core-plugin-api@1.10.8 + - @backstage/frontend-plugin-api@0.10.3 + - @backstage/plugin-catalog-react@1.19.0 + - @backstage/catalog-model@1.7.4 + - @backstage/core-compat-api@0.4.3 + - @backstage/plugin-catalog-common@1.1.4 + +## @backstage/plugin-org-react@0.1.39 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3 + - @backstage/catalog-client@1.10.1 + - @backstage/core-plugin-api@1.10.8 + - @backstage/plugin-catalog-react@1.19.0 + - @backstage/catalog-model@1.7.4 + +## @backstage/plugin-permission-backend@0.7.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/plugin-permission-common@0.9.0 + - @backstage/plugin-permission-node@0.10.1 + +## @backstage/plugin-permission-backend-module-allow-all-policy@0.2.9 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/plugin-permission-common@0.9.0 + - @backstage/plugin-permission-node@0.10.1 + +## @backstage/plugin-permission-node@0.10.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/plugin-permission-common@0.9.0 + +## @backstage/plugin-permission-react@0.4.35 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.10.8 + - @backstage/config@1.3.2 + - @backstage/plugin-permission-common@0.9.0 + +## @backstage/plugin-proxy-backend@0.6.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.0 + - @backstage/types@1.2.1 + - @backstage/plugin-proxy-node@0.1.5 + +## @backstage/plugin-proxy-node@0.1.5 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.0 + +## @backstage/plugin-scaffolder-backend-module-azure@0.2.10 + +### Patch Changes + +- e89d7b6: Migrating `azure` actions to using the new `zod` schema format +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.9.0 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + +## @backstage/plugin-scaffolder-backend-module-bitbucket@0.3.11 + +### Patch Changes + +- 7f710d2: Migrating `bitbucket` actions to use the new `zod` format +- Updated dependencies + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.2.10 + - @backstage/plugin-scaffolder-node@0.9.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.2.10 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + +## @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.2.10 + +### Patch Changes + +- ca9fdc0: Migrate `bitbucket-cloud` to new actions format +- 9c8ff0c: Update pull request creation filter to include .gitignore files in the created pull request +- 280611d: Fix `bitbucketCloudBranchRestrictions` API calls to accept null to prevent 400 errors for some branch restriction kinds defined. +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.9.0 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + - @backstage/plugin-bitbucket-cloud-common@0.3.0 + +## @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.2.10 + +### Patch Changes + +- d8169fc: Migrate the actions to the new format +- 9c8ff0c: Update pull request creation filter to include .gitignore files in the created pull request +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.9.0 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + +## @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.3.10 + +### Patch Changes + +- 4a86bca: Migrate actions to new format +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.9.0 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + +## @backstage/plugin-scaffolder-backend-module-cookiecutter@0.3.11 + +### Patch Changes + +- 0b2bbf1: Migrate using new actions format +- Updated dependencies + - @backstage/backend-defaults@0.11.0 + - @backstage/plugin-scaffolder-node@0.9.0 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + - @backstage/types@1.2.1 + +## @backstage/plugin-scaffolder-backend-module-gcp@0.2.10 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.9.0 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + +## @backstage/plugin-scaffolder-backend-module-gerrit@0.2.10 + +### Patch Changes + +- e24b29b: Migrating to use new format for actions +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.9.0 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + +## @backstage/plugin-scaffolder-backend-module-gitea@0.2.10 + +### Patch Changes + +- ed41017: Migrate to new actions format +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.9.0 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + +## @backstage/plugin-scaffolder-backend-module-gitlab@0.9.2 + +### Patch Changes + +- 063b2d3: Fixed dependency to frontend package from tests +- a296637: Migrate to new action format +- 3d6493a: Support merge request labels in publish:gitlab:merge-request +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.9.0 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + +## @backstage/plugin-scaffolder-backend-module-notifications@0.1.11 + +### Patch Changes + +- 1fb5f06: Adds ability for user to turn on/off notifications for specific topics within an origin. +- 3f56115: Removed `octokit` dependency as it was not being used +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.9.0 + - @backstage/plugin-notifications-common@0.0.9 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/plugin-notifications-node@0.2.16 + +## @backstage/plugin-scaffolder-backend-module-rails@0.5.10 + +### Patch Changes + +- a579693: Migrate to new actions format +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.9.0 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + - @backstage/types@1.2.1 + +## @backstage/plugin-scaffolder-backend-module-sentry@0.2.10 + +### Patch Changes + +- 6c6fb4a: Migrate to new actions format +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.9.0 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + +## @backstage/plugin-scaffolder-backend-module-yeoman@0.4.11 + +### Patch Changes + +- b392a34: Migrate to new actions format +- Updated dependencies + - @backstage/plugin-scaffolder-node-test-utils@0.3.0 + - @backstage/plugin-scaffolder-node@0.9.0 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/types@1.2.1 + +## @backstage/plugin-search@1.4.27 + +### Patch Changes + +- 18c64e9: Added the `info.packageJson` option to the plugin instance for the new frontend system. +- Updated dependencies + - @backstage/core-components@0.17.3 + - @backstage/core-plugin-api@1.10.8 + - @backstage/frontend-plugin-api@0.10.3 + - @backstage/plugin-catalog-react@1.19.0 + - @backstage/plugin-search-react@1.9.1 + - @backstage/core-compat-api@0.4.3 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/version-bridge@1.0.11 + - @backstage/plugin-search-common@1.2.18 + +## @backstage/plugin-search-backend@2.0.3 + +### Patch Changes + +- c83cd8b: Fixed some circular or otherwise unclear imports +- Updated dependencies + - @backstage/backend-defaults@0.11.0 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/backend-openapi-utils@0.5.4 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/plugin-permission-common@0.9.0 + - @backstage/plugin-permission-node@0.10.1 + - @backstage/plugin-search-backend-node@1.3.12 + - @backstage/plugin-search-common@1.2.18 + +## @backstage/plugin-search-backend-module-catalog@0.3.5 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.10.1 + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-permission-common@0.9.0 + - @backstage/plugin-search-backend-node@1.3.12 + - @backstage/plugin-search-common@1.2.18 + +## @backstage/plugin-search-backend-module-elasticsearch@1.7.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/integration-aws-node@0.1.16 + - @backstage/plugin-search-backend-node@1.3.12 + - @backstage/plugin-search-common@1.2.18 + +## @backstage/plugin-search-backend-module-explore@0.3.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/plugin-search-backend-node@1.3.12 + - @backstage/plugin-search-common@1.2.18 + +## @backstage/plugin-search-backend-module-pg@0.5.45 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/plugin-search-backend-node@1.3.12 + - @backstage/plugin-search-common@1.2.18 + +## @backstage/plugin-search-backend-module-stack-overflow-collator@0.3.10 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/plugin-search-backend-node@1.3.12 + - @backstage/plugin-search-common@1.2.18 + +## @backstage/plugin-search-backend-module-techdocs@0.4.3 + +### Patch Changes + +- b47ec38: Exports the default document collator for use in document transformation during search indexing. +- Updated dependencies + - @backstage/catalog-client@1.10.1 + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-permission-common@0.9.0 + - @backstage/plugin-search-backend-node@1.3.12 + - @backstage/plugin-search-common@1.2.18 + - @backstage/plugin-techdocs-node@1.13.4 + +## @backstage/plugin-search-backend-node@1.3.12 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/plugin-permission-common@0.9.0 + - @backstage/plugin-search-common@1.2.18 + +## @backstage/plugin-search-react@1.9.1 + +### Patch Changes + +- 869fa46: SearchBar clear button support i18n +- Updated dependencies + - @backstage/core-components@0.17.3 + - @backstage/core-plugin-api@1.10.8 + - @backstage/frontend-plugin-api@0.10.3 + - @backstage/theme@0.6.6 + - @backstage/types@1.2.1 + - @backstage/version-bridge@1.0.11 + - @backstage/plugin-search-common@1.2.18 + +## @backstage/plugin-signals@0.0.20 + +### Patch Changes + +- 18c64e9: Added the `info.packageJson` option to the plugin instance for the new frontend system. +- Updated dependencies + - @backstage/core-components@0.17.3 + - @backstage/core-plugin-api@1.10.8 + - @backstage/frontend-plugin-api@0.10.3 + - @backstage/theme@0.6.6 + - @backstage/types@1.2.1 + - @backstage/plugin-signals-react@0.0.14 + +## @backstage/plugin-signals-backend@0.3.5 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/types@1.2.1 + - @backstage/plugin-events-node@0.4.12 + - @backstage/plugin-signals-node@0.1.21 + +## @backstage/plugin-signals-node@0.1.21 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/types@1.2.1 + - @backstage/plugin-events-node@0.4.12 + +## @backstage/plugin-signals-react@0.0.14 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.10.8 + - @backstage/types@1.2.1 + +## @backstage/plugin-techdocs-addons-test-utils@1.0.49 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs@1.13.0 + - @backstage/plugin-catalog@1.31.0 + - @backstage/core-plugin-api@1.10.8 + - @backstage/plugin-catalog-react@1.19.0 + - @backstage/plugin-techdocs-react@1.3.0 + - @backstage/plugin-search-react@1.9.1 + - @backstage/integration-react@1.2.8 + - @backstage/core-app-api@1.17.1 + - @backstage/test-utils@1.7.9 + +## @backstage/plugin-techdocs-backend@2.0.3 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.10.1 + - @backstage/backend-defaults@0.11.0 + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/plugin-search-backend-module-techdocs@0.4.3 + - @backstage/plugin-techdocs-common@0.1.1 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-permission-common@0.9.0 + - @backstage/plugin-techdocs-node@1.13.4 + +## @backstage/plugin-techdocs-common@0.1.1 + +### Patch Changes + +- ec7b35d: Introduced `backstage.io/techdocs-entity-path` annotation which allows deep linking into another entities TechDocs in conjunction with `backstage.io/techdocs-entity`. + +## @backstage/plugin-techdocs-module-addons-contrib@1.1.25 + +### Patch Changes + +- 9dde3ba: Improved Keyboard accessibility in techdocs. +- Updated dependencies + - @backstage/core-components@0.17.3 + - @backstage/core-plugin-api@1.10.8 + - @backstage/frontend-plugin-api@0.10.3 + - @backstage/plugin-techdocs-react@1.3.0 + - @backstage/integration-react@1.2.8 + - @backstage/integration@1.17.0 + +## @backstage/plugin-techdocs-node@1.13.4 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs-common@0.1.1 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + - @backstage/integration-aws-node@0.1.16 + - @backstage/plugin-search-common@1.2.18 + +## @backstage/plugin-user-settings@0.8.23 + +### Patch Changes + +- 18c64e9: Added the `info.packageJson` option to the plugin instance for the new frontend system. +- ab6d3dd: Add some translation to user-setting plugin +- c83cd8b: Fixed some circular or otherwise unclear imports +- Updated dependencies + - @backstage/core-components@0.17.3 + - @backstage/core-plugin-api@1.10.8 + - @backstage/frontend-plugin-api@0.10.3 + - @backstage/plugin-catalog-react@1.19.0 + - @backstage/catalog-model@1.7.4 + - @backstage/core-app-api@1.17.1 + - @backstage/core-compat-api@0.4.3 + - @backstage/errors@1.2.7 + - @backstage/theme@0.6.6 + - @backstage/types@1.2.1 + - @backstage/plugin-signals-react@0.0.14 + - @backstage/plugin-user-settings-common@0.0.1 + +## @backstage/plugin-user-settings-backend@0.3.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.11.0 + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/plugin-signals-node@0.1.21 + - @backstage/plugin-user-settings-common@0.0.1 + +## example-app@0.2.110 + +### Patch Changes + +- Updated dependencies + - @backstage/canon@0.5.0 + - @backstage/core-components@0.17.3 + - @backstage/cli@0.33.0 + - @backstage/plugin-scaffolder-react@1.17.0 + - @backstage/plugin-scaffolder@1.32.0 + - @backstage/plugin-catalog-unprocessed-entities@0.2.18 + - @backstage/plugin-catalog-import@0.13.1 + - @backstage/plugin-catalog-graph@0.4.20 + - @backstage/plugin-notifications@0.5.6 + - @backstage/plugin-user-settings@0.8.23 + - @backstage/plugin-kubernetes@0.12.8 + - @backstage/plugin-api-docs@0.12.8 + - @backstage/plugin-devtools@0.1.28 + - @backstage/plugin-techdocs@1.13.0 + - @backstage/plugin-catalog@1.31.0 + - @backstage/plugin-signals@0.0.20 + - @backstage/plugin-search@1.4.27 + - @backstage/plugin-home@0.8.9 + - @backstage/plugin-org@0.6.40 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.25 + - @backstage/core-plugin-api@1.10.8 + - @backstage/frontend-app-api@0.11.3 + - @backstage/plugin-catalog-react@1.19.0 + - @backstage/plugin-techdocs-react@1.3.0 + - @backstage/plugin-search-react@1.9.1 + - @backstage/app-defaults@1.6.3 + - @backstage/integration-react@1.2.8 + - @backstage/plugin-auth-react@0.1.16 + - @backstage/plugin-kubernetes-cluster@0.0.26 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/core-app-api@1.17.1 + - @backstage/theme@0.6.6 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-permission-react@0.4.35 + - @backstage/plugin-search-common@1.2.18 + +## example-app-next@0.0.24 + +### Patch Changes + +- Updated dependencies + - @backstage/canon@0.5.0 + - @backstage/core-components@0.17.3 + - @backstage/cli@0.33.0 + - @backstage/plugin-scaffolder-react@1.17.0 + - @backstage/plugin-scaffolder@1.32.0 + - @backstage/plugin-catalog-unprocessed-entities@0.2.18 + - @backstage/plugin-app-visualizer@0.1.20 + - @backstage/plugin-catalog-import@0.13.1 + - @backstage/plugin-catalog-graph@0.4.20 + - @backstage/plugin-notifications@0.5.6 + - @backstage/plugin-user-settings@0.8.23 + - @backstage/plugin-kubernetes@0.12.8 + - @backstage/plugin-api-docs@0.12.8 + - @backstage/plugin-techdocs@1.13.0 + - @backstage/plugin-catalog@1.31.0 + - @backstage/plugin-signals@0.0.20 + - @backstage/plugin-search@1.4.27 + - @backstage/plugin-home@0.8.9 + - @backstage/plugin-app@0.1.10 + - @backstage/plugin-org@0.6.40 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.25 + - @backstage/core-plugin-api@1.10.8 + - @backstage/frontend-plugin-api@0.10.3 + - @backstage/frontend-app-api@0.11.3 + - @backstage/plugin-catalog-react@1.19.0 + - @backstage/plugin-techdocs-react@1.3.0 + - @backstage/frontend-defaults@0.2.3 + - @backstage/plugin-search-react@1.9.1 + - @backstage/app-defaults@1.6.3 + - @backstage/integration-react@1.2.8 + - @backstage/plugin-auth-react@0.1.16 + - @backstage/plugin-kubernetes-cluster@0.0.26 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/core-app-api@1.17.1 + - @backstage/core-compat-api@0.4.3 + - @backstage/theme@0.6.6 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-permission-react@0.4.35 + - @backstage/plugin-search-common@1.2.18 + +## app-next-example-plugin@0.0.24 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3 + - @backstage/frontend-plugin-api@0.10.3 + +## example-backend@0.0.39 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-notifications-backend@0.5.7 + - @backstage/plugin-scaffolder-backend-module-github@0.8.0 + - @backstage/backend-defaults@0.11.0 + - @backstage/plugin-scaffolder-backend@2.0.0 + - @backstage/plugin-catalog-backend@2.1.0 + - @backstage/plugin-devtools-backend@0.5.6 + - @backstage/plugin-mcp-actions-backend@0.1.0 + - @backstage/plugin-events-backend@0.5.3 + - @backstage/plugin-search-backend@2.0.3 + - @backstage/plugin-events-backend-module-google-pubsub@0.1.1 + - @backstage/plugin-scaffolder-backend-module-notifications@0.1.11 + - @backstage/plugin-auth-node@0.6.4 + - @backstage/plugin-search-backend-module-techdocs@0.4.3 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/plugin-kubernetes-backend@0.19.7 + - @backstage/plugin-search-backend-module-catalog@0.3.5 + - @backstage/plugin-techdocs-backend@2.0.3 + - @backstage/catalog-model@1.7.4 + - @backstage/plugin-app-backend@0.5.3 + - @backstage/plugin-auth-backend@0.25.1 + - @backstage/plugin-auth-backend-module-github-provider@0.3.4 + - @backstage/plugin-auth-backend-module-guest-provider@0.2.9 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.5.3 + - @backstage/plugin-catalog-backend-module-openapi@0.2.11 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.2.9 + - @backstage/plugin-catalog-backend-module-unprocessed@0.6.1 + - @backstage/plugin-permission-backend@0.7.1 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.2.9 + - @backstage/plugin-permission-common@0.9.0 + - @backstage/plugin-permission-node@0.10.1 + - @backstage/plugin-proxy-backend@0.6.3 + - @backstage/plugin-search-backend-module-explore@0.3.3 + - @backstage/plugin-search-backend-node@1.3.12 + - @backstage/plugin-signals-backend@0.3.5 + +## e2e-test@0.2.29 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.7.0 + - @backstage/cli-common@0.1.15 + - @backstage/errors@1.2.7 + +## @internal/frontend@0.0.10 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.10.3 + - @backstage/types@1.2.1 + - @backstage/version-bridge@1.0.11 + +## @internal/scaffolder@0.0.10 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-react@1.17.0 + - @backstage/frontend-plugin-api@0.10.3 + +## techdocs-cli-embedded-app@0.2.109 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3 + - @backstage/cli@0.33.0 + - @backstage/plugin-techdocs@1.13.0 + - @backstage/plugin-catalog@1.31.0 + - @backstage/core-plugin-api@1.10.8 + - @backstage/plugin-techdocs-react@1.3.0 + - @backstage/app-defaults@1.6.3 + - @backstage/integration-react@1.2.8 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/core-app-api@1.17.1 + - @backstage/test-utils@1.7.9 + - @backstage/theme@0.6.6 + +## yarn-plugin-backstage@0.0.6 + +### Patch Changes + +- a0f9e4e: added functionality so that adding or updating a backstage dependency to a package would maintain the "backstage:^" placeholder for the version. +- Updated dependencies + - @backstage/cli-common@0.1.15 + - @backstage/release-manifests@0.0.13 + +## @internal/plugin-todo-list@1.0.40 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3 + - @backstage/core-plugin-api@1.10.8 + +## @internal/plugin-todo-list-backend@1.0.40 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.0 + - @backstage/errors@1.2.7 diff --git a/docs/releases/v1.40.0-next.2-changelog.md b/docs/releases/v1.40.0-next.2-changelog.md new file mode 100644 index 0000000000..ed14cbf003 --- /dev/null +++ b/docs/releases/v1.40.0-next.2-changelog.md @@ -0,0 +1,1539 @@ +# Release v1.40.0-next.2 + +Upgrade Helper: [https://backstage.github.io/upgrade-helper/?to=1.40.0-next.2](https://backstage.github.io/upgrade-helper/?to=1.40.0-next.2) + +## @backstage/plugin-scaffolder-backend@2.0.0-next.2 + +### Major Changes + +- 5863b04: **BREAKING CHANGES** + + - The `createBuiltinActions` method has been removed, as this should no longer be needed with the new backend system route, and was only useful when passing the default list of actions again in the old backend system. You should be able to rely on the default behaviour of the new backend system which is to merge the actions. + + - The `createCatalogRegisterAction` and `createFetchCatalogEntityAction` actions no longer require an `AuthService`, and now accepts a `CatalogService` instead of `CatalogClient`. + + Unless you're providing your own override action to the default, this should be a non-breaking change. + + You can migrate using the following if you're getting typescript errors: + + ```ts + import { catalogServiceRef } from '@backstage/plugin-catalog-node'; + import { scaffolderActionsExtensionPoint } from '@backstage/plugin-scaffolder-node/alpha'; + + export const myModule = createBackendModule({ + pluginId: 'scaffolder', + moduleId: 'test', + register({ registerInit }) { + registerInit({ + deps: { + scaffolder: scaffolderActionsExtensionPoint, + catalog: catalogServiceRef, + }, + async init({ scaffolder, catalog }) { + scaffolder.addActions( + createCatalogRegisterAction({ + catalog, + }), + createFetchCatalogEntityAction({ + catalog, + integrations, + }), + ); + }, + }); + }, + }); + ``` + +### Patch Changes + +- 89a941d: Migrating to latest action format + +- 023629e: Enable usage of secrets within 'each' step of software templates. For example, you can now structure your `each` step like this: + + each: + [ + { name: "Service1", token: "${{ secrets.token1 }}" }, + { name: "Service2", token: "${{ secrets.token2 }}" }, + ] + +- e92e481: Add tests for Scaffolder + +- Updated dependencies + - @backstage/plugin-scaffolder-backend-module-gitlab@0.9.2-next.2 + - @backstage/plugin-scaffolder-backend-module-github@0.8.0-next.2 + - @backstage/backend-defaults@0.11.0-next.2 + - @backstage/plugin-scaffolder-node@0.9.0-next.2 + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + - @backstage/types@1.2.1 + - @backstage/plugin-auth-node@0.6.4-next.1 + - @backstage/plugin-bitbucket-cloud-common@0.3.0 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.2.9-next.1 + - @backstage/plugin-catalog-node@1.17.1-next.1 + - @backstage/plugin-events-node@0.4.12-next.1 + - @backstage/plugin-permission-common@0.9.0 + - @backstage/plugin-permission-node@0.10.1-next.1 + - @backstage/plugin-scaffolder-backend-module-azure@0.2.10-next.2 + - @backstage/plugin-scaffolder-backend-module-bitbucket@0.3.11-next.2 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.2.10-next.2 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.2.10-next.2 + - @backstage/plugin-scaffolder-backend-module-gerrit@0.2.10-next.2 + - @backstage/plugin-scaffolder-backend-module-gitea@0.2.10-next.2 + - @backstage/plugin-scaffolder-common@1.5.11 + +## @backstage/backend-defaults@0.11.0-next.2 + +### Minor Changes + +- 3ccb7fc: Enhanced error handling in the auditor service factory to pass errors as objects. Aligned WinstonRootAuditorService with the default service factory's error handling. + +### Patch Changes + +- Updated dependencies + - @backstage/backend-app-api@1.2.4-next.2 + - @backstage/backend-dev-utils@0.1.5 + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/cli-node@0.2.13 + - @backstage/config@1.3.2 + - @backstage/config-loader@1.10.1 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + - @backstage/integration-aws-node@0.1.16 + - @backstage/types@1.2.1 + - @backstage/plugin-auth-node@0.6.4-next.1 + - @backstage/plugin-events-node@0.4.12-next.1 + - @backstage/plugin-permission-node@0.10.1-next.1 + +## @backstage/cli@0.33.0-next.1 + +### Minor Changes + +- eef0e83: Internal update to promote the modular CLI entrypoint to stable. + +### Patch Changes + +- d07fe35: Added user feedback when opening config docs in browser. The command now clearly indicates what it's doing and provides fallback instructions if the browser fails to open. +- d6d63c7: Updating the scaffolder action boilerplate to use new `zod` schema +- e36e855: Added `backstage.pluginId` field in `package.json` to all default plugin package templates for the `new` command. +- Updated dependencies + - @backstage/catalog-model@1.7.4 + - @backstage/cli-common@0.1.15 + - @backstage/cli-node@0.2.13 + - @backstage/config@1.3.2 + - @backstage/config-loader@1.10.1 + - @backstage/errors@1.2.7 + - @backstage/eslint-plugin@0.1.10 + - @backstage/integration@1.17.0 + - @backstage/release-manifests@0.0.13 + - @backstage/types@1.2.1 + +## @backstage/plugin-catalog@1.31.0-next.2 + +### Minor Changes + +- 406acb6: Add support to customize the about card icon links via `EntityIconLinkBlueprint` and provide a default catalog view catalog source, launch scaffolder template and read techdocs docs icon links extensions. + + **BREAKING ALPHA** + + The `Scaffolder` launch template and `TechDocs` read documentation icons have been extracted from the default `Catalog` about card links and are now provided respectively by the `Scaffolder` and `TechDocs` plugins in the new frontend system. It means that they will not be available unless you install the `TechDocs` and `Scaffolder` plugins. Also If you are using translation for these icon link titles other than the default, you should now translate them using the scaffolder translation reference or the TechDocs translation reference (the translation keys are still the same, `aboutCard.viewTechdocs` and `aboutCard.launchTemplate`). + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/plugin-catalog-react@1.19.0-next.2 + - @backstage/plugin-search-react@1.9.1-next.1 + - @backstage/frontend-plugin-api@0.10.3-next.1 + - @backstage/integration-react@1.2.7 + - @backstage/plugin-techdocs-react@1.3.0-next.1 + - @backstage/catalog-client@1.10.1-next.0 + - @backstage/catalog-model@1.7.4 + - @backstage/core-compat-api@0.4.3-next.2 + - @backstage/core-plugin-api@1.10.7 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/version-bridge@1.0.11 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-permission-react@0.4.34 + - @backstage/plugin-scaffolder-common@1.5.11 + - @backstage/plugin-search-common@1.2.18 + - @backstage/plugin-techdocs-common@0.1.1-next.0 + +## @backstage/plugin-catalog-backend-module-bitbucket-cloud@0.5.0-next.2 + +### Minor Changes + +- 8a150bf: **BREAKING**: `BitbucketCloudEntityProvider` now accepts a `CatalogService` instead of a `CatalogApi`. + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/catalog-client@1.10.1-next.0 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/integration@1.17.0 + - @backstage/plugin-bitbucket-cloud-common@0.3.0 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-catalog-node@1.17.1-next.1 + - @backstage/plugin-events-node@0.4.12-next.1 + +## @backstage/plugin-catalog-backend-module-gitlab@0.7.0-next.2 + +### Minor Changes + +- 42bb3b8: **BREAKING CHANGE**: User and Group discovery will default to ingesting all users in sub groups that belong to the specified root group in config. Disable by setting `restrictUsersToGroup: true` in app-config under your module settings. + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.11.0-next.2 + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/integration@1.17.0 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-catalog-node@1.17.1-next.1 + - @backstage/plugin-events-node@0.4.12-next.1 + +## @backstage/plugin-catalog-react@1.19.0-next.2 + +### Minor Changes + +- 406acb6: Introduces a new `EntityIconLinkBlueprint` that customizes the `About` card icon links on the `Catalog` entity page. + + The blueprint currently accepts a `useProps` hook as `param` and this function returns the following props that will be passed to the icon link component: + + | Name | Description | Type | Default Value | + | ---------- | --------------------------------------------------- | ------------- | ------------- | + | `icon` | The icon to display. | `JSX.Element` | N/A | + | `label` | The label for the element. | `string` | N/A | + | `title` | The title for the element. | `string` | N/A | + | `disabled` | Whether the element is disabled. | `boolean` | `false` | + | `href` | The URL to navigate to when the element is clicked. | `string` | N/A | + | `onClick` | A function to call when the element is clicked. | `() => void` | N/A | + + Here is an usage example: + + ```tsx + import { EntityIconLinkBlueprint } from '@backstage/plugin-catalog-react/alpha'; + //... + + EntityIconLinkBlueprint.make({ + name: 'my-icon-link', + params: { + useProps() { + const { t } = useTranslationRef(myIconLinkTranslationRef); + return { + label: t('myIconLink.label'), + icon: , + href: '/my-plugin', + }; + }, + }, + }); + ``` + + Additionally, the `app-config.yaml` file allows you to override some of the default icon link parameters, including `label` and `title` values. Here's how to set them: + + ```yaml + app: + extensions: + - entity-icon-link:my-plugin/my-icon-link: + config: + label: 'My Custom Icon Link label' + ``` + + Finally, you can disable all links if you want to hide the About card header completely (useful, for example, when links are displayed on separate cards). The header is hidden when no icon links extensions are enabled. + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/frontend-plugin-api@0.10.3-next.1 + - @backstage/integration-react@1.2.7 + - @backstage/catalog-client@1.10.1-next.0 + - @backstage/catalog-model@1.7.4 + - @backstage/core-compat-api@0.4.3-next.2 + - @backstage/core-plugin-api@1.10.7 + - @backstage/errors@1.2.7 + - @backstage/frontend-test-utils@0.3.3-next.1 + - @backstage/types@1.2.1 + - @backstage/version-bridge@1.0.11 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-permission-common@0.9.0 + - @backstage/plugin-permission-react@0.4.34 + +## @backstage/plugin-scaffolder@1.32.0-next.2 + +### Minor Changes + +- 3c59ece: **New Frontend System Only:** + The `Scaffolder` plugin is now responsible for providing an entity icon link extension to launch templates from the catalog entity page. + +### Patch Changes + +- b00c160: Remove React import form notification and scaffolder plugin +- 95a1d72: Added appropriate message when global templating function metadata is absent. +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/plugin-catalog-react@1.19.0-next.2 + - @backstage/frontend-plugin-api@0.10.3-next.1 + - @backstage/integration-react@1.2.7 + - @backstage/plugin-scaffolder-react@1.16.1-next.2 + - @backstage/catalog-client@1.10.1-next.0 + - @backstage/catalog-model@1.7.4 + - @backstage/core-compat-api@0.4.3-next.2 + - @backstage/core-plugin-api@1.10.7 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + - @backstage/types@1.2.1 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-permission-react@0.4.34 + - @backstage/plugin-scaffolder-common@1.5.11 + +## @backstage/plugin-scaffolder-backend-module-github@0.8.0-next.2 + +### Minor Changes + +- 5863b04: **BREAKING CHANGES** + + The `createGithubEnvironmentAction` action no longer requires an `AuthService`, and now accepts a `CatalogService` instead of `CatalogClient`. + + Unless you're providing your own override action to the default, this should be a non-breaking change. + + You can migrate using the following if you're getting typescript errors: + + ```ts + import { catalogServiceRef } from '@backstage/plugin-catalog-node'; + import { scaffolderActionsExtensionPoint } from '@backstage/plugin-scaffolder-node/alpha'; + + export const myModule = createBackendModule({ + pluginId: 'scaffolder', + moduleId: 'test', + register({ registerInit }) { + registerInit({ + deps: { + scaffolder: scaffolderActionsExtensionPoint, + catalog: catalogServiceRef, + }, + async init({ scaffolder, catalog }) { + scaffolder.addActions( + createGithubEnvironmentAction({ + catalog, + }), + ); + }, + }); + }, + }); + ``` + +### Patch Changes + +- 575c76b: Migrate to using new actions +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.9.0-next.2 + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + - @backstage/types@1.2.1 + - @backstage/plugin-catalog-node@1.17.1-next.1 + +## @backstage/plugin-scaffolder-node@0.9.0-next.2 + +### Minor Changes + +- 5863b04: **BREAKING CHANGES** + + The legacy methods to define `createTemplateActions` have been replaced with the new native `zod` approaches for defining input and output schemas. + + You can migrate actions that look like the following with the below examples: + + ```ts + // really old legacy json schema + createTemplateAction<{ repoUrl: string }, { repoOutput: string }>({ + id: 'test', + schema: { + input: { + type: 'object' + required: ['repoUrl'] + properties: { + repoUrl: { + type: 'string', + description: 'repository url description' + } + } + } + } + }); + + // old zod method + createTemplateAction({ + id: 'test' + schema: { + input: { + repoUrl: z.string({ description: 'repository url description' }) + } + } + }) + + // new method: + createTemplateAction({ + id: 'test', + schema: { + input: { + repoUrl: z => z.string({ description: 'repository url description' }) + } + } + }) + + // or for more complex zod types like unions + createTemplateAction({ + id: 'test', + schema: { + input: z => z.object({ + repoUrl: z.string({ description: 'repository url description' }) + }) + } + }) + ``` + + This breaking change also means that `logStream` has been removed entirely from `ActionsContext`, and that the `logger` is now just a `LoggerService` implementation instead. There is no replacement for the `logStream`, if you wish to still keep using a `logStream` we recommend that you create your own stream that writes to `ctx.logger` instead. + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/catalog-model@1.7.4 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + - @backstage/types@1.2.1 + - @backstage/plugin-scaffolder-common@1.5.11 + +## @backstage/plugin-scaffolder-node-test-utils@0.3.0-next.2 + +### Minor Changes + +- 3cea7ee: **BREAKING CHANGES** + + Because of the removal of the `logStream` property to the `ActionsContext` this has been removed from the `createMockActionContext` method. + + You can remove this as it's no longer supported in the scaffolder actions. + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.9.0-next.2 + - @backstage/backend-test-utils@1.6.0-next.2 + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/types@1.2.1 + +## @backstage/plugin-techdocs@1.13.0-next.2 + +### Minor Changes + +- 3c59ece: **New Frontend System Only:** + The `TechDocs` plugin is now responsible for providing an entity icon link extension to read documentation from the catalog entity page. + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/plugin-catalog-react@1.19.0-next.2 + - @backstage/plugin-search-react@1.9.1-next.1 + - @backstage/frontend-plugin-api@0.10.3-next.1 + - @backstage/integration-react@1.2.7 + - @backstage/plugin-auth-react@0.1.16-next.0 + - @backstage/plugin-techdocs-react@1.3.0-next.1 + - @backstage/catalog-client@1.10.1-next.0 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/core-compat-api@0.4.3-next.2 + - @backstage/core-plugin-api@1.10.7 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + - @backstage/theme@0.6.6 + - @backstage/plugin-search-common@1.2.18 + - @backstage/plugin-techdocs-common@0.1.1-next.0 + +## @backstage/app-defaults@1.6.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/core-app-api@1.17.0 + - @backstage/core-plugin-api@1.10.7 + - @backstage/theme@0.6.6 + - @backstage/plugin-permission-react@0.4.34 + +## @backstage/backend-app-api@1.2.4-next.2 + +### Patch Changes + +- bb9a501: Fixed a bug where occasionally the initialization order of multiple modules consuming a single extension point could happen in the wrong order. +- Updated dependencies + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + +## @backstage/backend-dynamic-feature-service@0.7.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.11.0-next.2 + - @backstage/plugin-catalog-backend@2.0.1-next.2 + - @backstage/plugin-scaffolder-node@0.9.0-next.2 + - @backstage/backend-openapi-utils@0.5.4-next.1 + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/cli-common@0.1.15 + - @backstage/cli-node@0.2.13 + - @backstage/config@1.3.2 + - @backstage/config-loader@1.10.1 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/plugin-app-node@0.1.34-next.1 + - @backstage/plugin-auth-node@0.6.4-next.1 + - @backstage/plugin-events-backend@0.5.3-next.1 + - @backstage/plugin-events-node@0.4.12-next.1 + - @backstage/plugin-permission-common@0.9.0 + - @backstage/plugin-permission-node@0.10.1-next.1 + - @backstage/plugin-search-backend-node@1.3.12-next.1 + - @backstage/plugin-search-common@1.2.18 + +## @backstage/backend-test-utils@1.6.0-next.2 + +### Patch Changes + +- 12c1fd4: Make the `user` credentials mock behave more like production +- Updated dependencies + - @backstage/backend-defaults@0.11.0-next.2 + - @backstage/backend-app-api@1.2.4-next.2 + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/plugin-auth-node@0.6.4-next.1 + - @backstage/plugin-events-node@0.4.12-next.1 + +## @backstage/canon@0.5.0-next.2 + +### Patch Changes + +- 44df879: Add min-width: 0; by default on every Flex components in Canon to help support truncated texts inside flex elements. +- ee6ffe6: Fix styling for the title4 prop on the Heading component in Canon. +- f2f814a: Added a render prop to the Button component in Canon to use it as a link. + +## @backstage/core-compat-api@0.4.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.19.0-next.2 + - @backstage/frontend-plugin-api@0.10.3-next.1 + - @backstage/core-plugin-api@1.10.7 + - @backstage/version-bridge@1.0.11 + +## @backstage/core-components@0.17.3-next.0 + +### Patch Changes + +- 6232160: table actions header support i18n +- Updated dependencies + - @backstage/config@1.3.2 + - @backstage/core-plugin-api@1.10.7 + - @backstage/errors@1.2.7 + - @backstage/theme@0.6.6 + - @backstage/version-bridge@1.0.11 + +## @backstage/create-app@0.7.0-next.2 + +### Patch Changes + +- Bumped create-app version. +- Updated dependencies + - @backstage/cli-common@0.1.15 + +## @backstage/dev-utils@1.1.11-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/plugin-catalog-react@1.19.0-next.2 + - @backstage/app-defaults@1.6.3-next.0 + - @backstage/integration-react@1.2.7 + - @backstage/catalog-model@1.7.4 + - @backstage/core-app-api@1.17.0 + - @backstage/core-plugin-api@1.10.7 + - @backstage/theme@0.6.6 + +## @backstage/frontend-app-api@0.11.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.10.3-next.1 + - @backstage/config@1.3.2 + - @backstage/core-app-api@1.17.0 + - @backstage/core-plugin-api@1.10.7 + - @backstage/errors@1.2.7 + - @backstage/frontend-defaults@0.2.3-next.1 + - @backstage/types@1.2.1 + - @backstage/version-bridge@1.0.11 + +## @backstage/frontend-defaults@0.2.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.10.3-next.1 + - @backstage/plugin-app@0.1.10-next.1 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/frontend-app-api@0.11.3-next.1 + +## @backstage/frontend-dynamic-feature-loader@0.1.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.10.3-next.1 + - @backstage/config@1.3.2 + +## @backstage/frontend-plugin-api@0.10.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/core-plugin-api@1.10.7 + - @backstage/types@1.2.1 + - @backstage/version-bridge@1.0.11 + +## @backstage/frontend-test-utils@0.3.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.10.3-next.1 + - @backstage/plugin-app@0.1.10-next.1 + - @backstage/config@1.3.2 + - @backstage/frontend-app-api@0.11.3-next.1 + - @backstage/test-utils@1.7.8 + - @backstage/types@1.2.1 + - @backstage/version-bridge@1.0.11 + +## @backstage/repo-tools@0.14.0-next.2 + +### Patch Changes + +- 4bff5d0: Fixed a bug where linting would fail with the generated clients when defining top-level `enum` schema values. +- Updated dependencies + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/catalog-model@1.7.4 + - @backstage/cli-common@0.1.15 + - @backstage/cli-node@0.2.13 + - @backstage/config-loader@1.10.1 + - @backstage/errors@1.2.7 + +## @techdocs/cli@1.9.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.11.0-next.2 + - @backstage/catalog-model@1.7.4 + - @backstage/cli-common@0.1.15 + - @backstage/config@1.3.2 + - @backstage/plugin-techdocs-node@1.13.4-next.1 + +## @backstage/plugin-api-docs@0.12.8-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/plugin-catalog@1.31.0-next.2 + - @backstage/plugin-catalog-react@1.19.0-next.2 + - @backstage/frontend-plugin-api@0.10.3-next.1 + - @backstage/catalog-model@1.7.4 + - @backstage/core-compat-api@0.4.3-next.2 + - @backstage/core-plugin-api@1.10.7 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-permission-react@0.4.34 + +## @backstage/plugin-app@0.1.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/frontend-plugin-api@0.10.3-next.1 + - @backstage/integration-react@1.2.7 + - @backstage/core-plugin-api@1.10.7 + - @backstage/theme@0.6.6 + - @backstage/types@1.2.1 + - @backstage/plugin-permission-react@0.4.34 + +## @backstage/plugin-app-visualizer@0.1.20-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/frontend-plugin-api@0.10.3-next.1 + - @backstage/core-plugin-api@1.10.7 + +## @backstage/plugin-auth-react@0.1.16-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/core-plugin-api@1.10.7 + - @backstage/errors@1.2.7 + +## @backstage/plugin-catalog-backend@2.0.1-next.2 + +### Patch Changes + +- 2cac8b0: You can now specify an optional value when applying the `HAS_LABEL` permission rule, similar to the `HAS_ANNOTATION` permission rule. +- Updated dependencies + - @backstage/backend-openapi-utils@0.5.4-next.1 + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/catalog-client@1.10.1-next.0 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + - @backstage/types@1.2.1 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-catalog-node@1.17.1-next.1 + - @backstage/plugin-events-node@0.4.12-next.1 + - @backstage/plugin-permission-common@0.9.0 + - @backstage/plugin-permission-node@0.10.1-next.1 + +## @backstage/plugin-catalog-backend-module-aws@0.4.12-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.11.0-next.2 + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + - @backstage/integration-aws-node@0.1.16 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-catalog-node@1.17.1-next.1 + - @backstage/plugin-kubernetes-common@0.9.5 + +## @backstage/plugin-catalog-backend-module-github@0.9.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@2.0.1-next.2 + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/catalog-client@1.10.1-next.0 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/integration@1.17.0 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-catalog-node@1.17.1-next.1 + - @backstage/plugin-events-node@0.4.12-next.1 + +## @backstage/plugin-catalog-backend-module-github-org@0.3.11-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/config@1.3.2 + - @backstage/plugin-catalog-backend-module-github@0.9.1-next.2 + - @backstage/plugin-catalog-node@1.17.1-next.1 + - @backstage/plugin-events-node@0.4.12-next.1 + +## @backstage/plugin-catalog-backend-module-gitlab-org@0.2.10-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend-module-gitlab@0.7.0-next.2 + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/plugin-catalog-node@1.17.1-next.1 + - @backstage/plugin-events-node@0.4.12-next.1 + +## @backstage/plugin-catalog-backend-module-incremental-ingestion@0.7.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.11.0-next.2 + - @backstage/plugin-catalog-backend@2.0.1-next.2 + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/plugin-catalog-node@1.17.1-next.1 + - @backstage/plugin-events-node@0.4.12-next.1 + - @backstage/plugin-permission-common@0.9.0 + +## @backstage/plugin-catalog-backend-module-logs@0.1.11-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@2.0.1-next.2 + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/plugin-events-node@0.4.12-next.1 + +## @backstage/plugin-catalog-graph@0.4.20-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/plugin-catalog-react@1.19.0-next.2 + - @backstage/frontend-plugin-api@0.10.3-next.1 + - @backstage/catalog-client@1.10.1-next.0 + - @backstage/catalog-model@1.7.4 + - @backstage/core-compat-api@0.4.3-next.2 + - @backstage/core-plugin-api@1.10.7 + - @backstage/types@1.2.1 + +## @backstage/plugin-catalog-import@0.13.1-next.2 + +### Patch Changes + +- 5d7c539: Catalog import plugin full support i18n +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/plugin-catalog-react@1.19.0-next.2 + - @backstage/frontend-plugin-api@0.10.3-next.1 + - @backstage/integration-react@1.2.7 + - @backstage/catalog-client@1.10.1-next.0 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/core-compat-api@0.4.3-next.2 + - @backstage/core-plugin-api@1.10.7 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + - @backstage/plugin-catalog-common@1.1.4 + +## @backstage/plugin-catalog-unprocessed-entities@0.2.18-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/frontend-plugin-api@0.10.3-next.1 + - @backstage/catalog-model@1.7.4 + - @backstage/core-compat-api@0.4.3-next.2 + - @backstage/core-plugin-api@1.10.7 + - @backstage/errors@1.2.7 + +## @backstage/plugin-config-schema@0.1.69-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/core-plugin-api@1.10.7 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + +## @backstage/plugin-devtools@0.1.28-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/frontend-plugin-api@0.10.3-next.1 + - @backstage/core-compat-api@0.4.3-next.2 + - @backstage/core-plugin-api@1.10.7 + - @backstage/errors@1.2.7 + - @backstage/plugin-devtools-common@0.1.16 + - @backstage/plugin-permission-react@0.4.34 + +## @backstage/plugin-devtools-backend@0.5.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.11.0-next.2 + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/cli-common@0.1.15 + - @backstage/config@1.3.2 + - @backstage/config-loader@1.10.1 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/plugin-devtools-common@0.1.16 + - @backstage/plugin-permission-common@0.9.0 + - @backstage/plugin-permission-node@0.10.1-next.1 + +## @backstage/plugin-home@0.8.9-next.2 + +### Patch Changes + +- 0ebad54: Fixed the `WelcomeTitle` to properly default to the previous value of `inherit` +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/plugin-catalog-react@1.19.0-next.2 + - @backstage/frontend-plugin-api@0.10.3-next.1 + - @backstage/plugin-home-react@0.1.27-next.0 + - @backstage/catalog-client@1.10.1-next.0 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/core-app-api@1.17.0 + - @backstage/core-compat-api@0.4.3-next.2 + - @backstage/core-plugin-api@1.10.7 + - @backstage/theme@0.6.6 + +## @backstage/plugin-home-react@0.1.27-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/core-plugin-api@1.10.7 + +## @backstage/plugin-kubernetes@0.12.8-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/plugin-catalog-react@1.19.0-next.2 + - @backstage/frontend-plugin-api@0.10.3-next.1 + - @backstage/plugin-kubernetes-react@0.5.8-next.0 + - @backstage/catalog-model@1.7.4 + - @backstage/core-compat-api@0.4.3-next.2 + - @backstage/core-plugin-api@1.10.7 + - @backstage/plugin-kubernetes-common@0.9.5 + - @backstage/plugin-permission-react@0.4.34 + +## @backstage/plugin-kubernetes-cluster@0.0.26-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/plugin-catalog-react@1.19.0-next.2 + - @backstage/plugin-kubernetes-react@0.5.8-next.0 + - @backstage/catalog-model@1.7.4 + - @backstage/core-plugin-api@1.10.7 + - @backstage/plugin-kubernetes-common@0.9.5 + - @backstage/plugin-permission-react@0.4.34 + +## @backstage/plugin-kubernetes-react@0.5.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/catalog-model@1.7.4 + - @backstage/core-plugin-api@1.10.7 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/plugin-kubernetes-common@0.9.5 + +## @backstage/plugin-notifications@0.5.6-next.2 + +### Patch Changes + +- b00c160: Remove React import form notification and scaffolder plugin +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/frontend-plugin-api@0.10.3-next.1 + - @backstage/core-compat-api@0.4.3-next.2 + - @backstage/core-plugin-api@1.10.7 + - @backstage/errors@1.2.7 + - @backstage/theme@0.6.6 + - @backstage/types@1.2.1 + - @backstage/plugin-notifications-common@0.0.9-next.0 + - @backstage/plugin-signals-react@0.0.13 + +## @backstage/plugin-notifications-backend@0.5.7-next.2 + +### Patch Changes + +- 8a150bf: Internal changes to switch to the non-alpha `catalogServiceRef` +- Updated dependencies + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/plugin-auth-node@0.6.4-next.1 + - @backstage/plugin-catalog-node@1.17.1-next.1 + - @backstage/plugin-events-node@0.4.12-next.1 + - @backstage/plugin-notifications-common@0.0.9-next.0 + - @backstage/plugin-notifications-node@0.2.16-next.1 + - @backstage/plugin-signals-node@0.1.21-next.1 + +## @backstage/plugin-notifications-backend-module-email@0.3.10-next.2 + +### Patch Changes + +- 8a150bf: Internal changes to switch to the non-alpha `catalogServiceRef` +- Updated dependencies + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/catalog-client@1.10.1-next.0 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/integration-aws-node@0.1.16 + - @backstage/types@1.2.1 + - @backstage/plugin-catalog-node@1.17.1-next.1 + - @backstage/plugin-notifications-common@0.0.9-next.0 + - @backstage/plugin-notifications-node@0.2.16-next.1 + +## @backstage/plugin-org@0.6.40-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/plugin-catalog-react@1.19.0-next.2 + - @backstage/frontend-plugin-api@0.10.3-next.1 + - @backstage/catalog-model@1.7.4 + - @backstage/core-compat-api@0.4.3-next.2 + - @backstage/core-plugin-api@1.10.7 + - @backstage/plugin-catalog-common@1.1.4 + +## @backstage/plugin-org-react@0.1.39-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/plugin-catalog-react@1.19.0-next.2 + - @backstage/catalog-client@1.10.1-next.0 + - @backstage/catalog-model@1.7.4 + - @backstage/core-plugin-api@1.10.7 + +## @backstage/plugin-scaffolder-backend-module-azure@0.2.10-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.9.0-next.2 + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + +## @backstage/plugin-scaffolder-backend-module-bitbucket@0.3.11-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.9.0-next.2 + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.2.10-next.2 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.2.10-next.2 + +## @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.2.10-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.9.0-next.2 + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + - @backstage/plugin-bitbucket-cloud-common@0.3.0 + +## @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.2.10-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.9.0-next.2 + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + +## @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.3.10-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.9.0-next.2 + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + +## @backstage/plugin-scaffolder-backend-module-cookiecutter@0.3.11-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.11.0-next.2 + - @backstage/plugin-scaffolder-node@0.9.0-next.2 + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + - @backstage/types@1.2.1 + +## @backstage/plugin-scaffolder-backend-module-gcp@0.2.10-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.9.0-next.2 + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + +## @backstage/plugin-scaffolder-backend-module-gerrit@0.2.10-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.9.0-next.2 + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + +## @backstage/plugin-scaffolder-backend-module-gitea@0.2.10-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.9.0-next.2 + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + +## @backstage/plugin-scaffolder-backend-module-gitlab@0.9.2-next.2 + +### Patch Changes + +- a296637: Migrate to new action format +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.9.0-next.2 + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + +## @backstage/plugin-scaffolder-backend-module-notifications@0.1.11-next.2 + +### Patch Changes + +- 3f56115: Removed `octokit` dependency as it was not being used +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.9.0-next.2 + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/plugin-notifications-common@0.0.9-next.0 + - @backstage/plugin-notifications-node@0.2.16-next.1 + +## @backstage/plugin-scaffolder-backend-module-rails@0.5.10-next.2 + +### Patch Changes + +- a579693: Migrate to new actions format +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.9.0-next.2 + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + - @backstage/types@1.2.1 + +## @backstage/plugin-scaffolder-backend-module-sentry@0.2.10-next.2 + +### Patch Changes + +- 6c6fb4a: Migrate to new actions format +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.9.0-next.2 + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + +## @backstage/plugin-scaffolder-backend-module-yeoman@0.4.11-next.2 + +### Patch Changes + +- b392a34: Migrate to new actions format +- Updated dependencies + - @backstage/plugin-scaffolder-node-test-utils@0.3.0-next.2 + - @backstage/plugin-scaffolder-node@0.9.0-next.2 + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/types@1.2.1 + +## @backstage/plugin-scaffolder-react@1.16.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/plugin-catalog-react@1.19.0-next.2 + - @backstage/frontend-plugin-api@0.10.3-next.1 + - @backstage/catalog-client@1.10.1-next.0 + - @backstage/catalog-model@1.7.4 + - @backstage/core-plugin-api@1.10.7 + - @backstage/theme@0.6.6 + - @backstage/types@1.2.1 + - @backstage/version-bridge@1.0.11 + - @backstage/plugin-permission-react@0.4.34 + - @backstage/plugin-scaffolder-common@1.5.11 + +## @backstage/plugin-search@1.4.27-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/plugin-catalog-react@1.19.0-next.2 + - @backstage/plugin-search-react@1.9.1-next.1 + - @backstage/frontend-plugin-api@0.10.3-next.1 + - @backstage/core-compat-api@0.4.3-next.2 + - @backstage/core-plugin-api@1.10.7 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/version-bridge@1.0.11 + - @backstage/plugin-search-common@1.2.18 + +## @backstage/plugin-search-backend@2.0.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.11.0-next.2 + - @backstage/backend-openapi-utils@0.5.4-next.1 + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/plugin-permission-common@0.9.0 + - @backstage/plugin-permission-node@0.10.1-next.1 + - @backstage/plugin-search-backend-node@1.3.12-next.1 + - @backstage/plugin-search-common@1.2.18 + +## @backstage/plugin-search-react@1.9.1-next.1 + +### Patch Changes + +- 869fa46: SearchBar clear button support i18n +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/frontend-plugin-api@0.10.3-next.1 + - @backstage/core-plugin-api@1.10.7 + - @backstage/theme@0.6.6 + - @backstage/types@1.2.1 + - @backstage/version-bridge@1.0.11 + - @backstage/plugin-search-common@1.2.18 + +## @backstage/plugin-signals@0.0.20-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/frontend-plugin-api@0.10.3-next.1 + - @backstage/core-plugin-api@1.10.7 + - @backstage/theme@0.6.6 + - @backstage/types@1.2.1 + - @backstage/plugin-signals-react@0.0.13 + +## @backstage/plugin-techdocs-addons-test-utils@1.0.49-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog@1.31.0-next.2 + - @backstage/plugin-techdocs@1.13.0-next.2 + - @backstage/plugin-catalog-react@1.19.0-next.2 + - @backstage/plugin-search-react@1.9.1-next.1 + - @backstage/integration-react@1.2.7 + - @backstage/plugin-techdocs-react@1.3.0-next.1 + - @backstage/core-app-api@1.17.0 + - @backstage/core-plugin-api@1.10.7 + - @backstage/test-utils@1.7.8 + +## @backstage/plugin-techdocs-backend@2.0.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.11.0-next.2 + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/catalog-client@1.10.1-next.0 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-catalog-node@1.17.1-next.1 + - @backstage/plugin-permission-common@0.9.0 + - @backstage/plugin-search-backend-module-techdocs@0.4.3-next.1 + - @backstage/plugin-techdocs-common@0.1.1-next.0 + - @backstage/plugin-techdocs-node@1.13.4-next.1 + +## @backstage/plugin-techdocs-module-addons-contrib@1.1.25-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/frontend-plugin-api@0.10.3-next.1 + - @backstage/integration-react@1.2.7 + - @backstage/plugin-techdocs-react@1.3.0-next.1 + - @backstage/core-plugin-api@1.10.7 + - @backstage/integration@1.17.0 + +## @backstage/plugin-techdocs-react@1.3.0-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/frontend-plugin-api@0.10.3-next.1 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/core-plugin-api@1.10.7 + - @backstage/version-bridge@1.0.11 + - @backstage/plugin-techdocs-common@0.1.1-next.0 + +## @backstage/plugin-user-settings@0.8.23-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/plugin-catalog-react@1.19.0-next.2 + - @backstage/frontend-plugin-api@0.10.3-next.1 + - @backstage/catalog-model@1.7.4 + - @backstage/core-app-api@1.17.0 + - @backstage/core-compat-api@0.4.3-next.2 + - @backstage/core-plugin-api@1.10.7 + - @backstage/errors@1.2.7 + - @backstage/theme@0.6.6 + - @backstage/types@1.2.1 + - @backstage/plugin-signals-react@0.0.13 + - @backstage/plugin-user-settings-common@0.0.1 + +## @backstage/plugin-user-settings-backend@0.3.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.11.0-next.2 + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/plugin-auth-node@0.6.4-next.1 + - @backstage/plugin-signals-node@0.1.21-next.1 + - @backstage/plugin-user-settings-common@0.0.1 + +## example-app@0.2.110-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/cli@0.33.0-next.1 + - @backstage/canon@0.5.0-next.2 + - @backstage/plugin-notifications@0.5.6-next.2 + - @backstage/plugin-scaffolder@1.32.0-next.2 + - @backstage/plugin-catalog@1.31.0-next.2 + - @backstage/plugin-techdocs@1.13.0-next.2 + - @backstage/plugin-catalog-react@1.19.0-next.2 + - @backstage/plugin-catalog-import@0.13.1-next.2 + - @backstage/plugin-home@0.8.9-next.2 + - @backstage/plugin-search-react@1.9.1-next.1 + - @backstage/app-defaults@1.6.3-next.0 + - @backstage/integration-react@1.2.7 + - @backstage/plugin-api-docs@0.12.8-next.2 + - @backstage/plugin-auth-react@0.1.16-next.0 + - @backstage/plugin-catalog-graph@0.4.20-next.2 + - @backstage/plugin-catalog-unprocessed-entities@0.2.18-next.2 + - @backstage/plugin-devtools@0.1.28-next.2 + - @backstage/plugin-kubernetes@0.12.8-next.2 + - @backstage/plugin-kubernetes-cluster@0.0.26-next.2 + - @backstage/plugin-org@0.6.40-next.2 + - @backstage/plugin-scaffolder-react@1.16.1-next.2 + - @backstage/plugin-search@1.4.27-next.2 + - @backstage/plugin-signals@0.0.20-next.1 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.25-next.2 + - @backstage/plugin-techdocs-react@1.3.0-next.1 + - @backstage/plugin-user-settings@0.8.23-next.2 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/core-app-api@1.17.0 + - @backstage/core-plugin-api@1.10.7 + - @backstage/frontend-app-api@0.11.3-next.1 + - @backstage/theme@0.6.6 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-permission-react@0.4.34 + - @backstage/plugin-search-common@1.2.18 + +## example-app-next@0.0.24-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/cli@0.33.0-next.1 + - @backstage/canon@0.5.0-next.2 + - @backstage/plugin-notifications@0.5.6-next.2 + - @backstage/plugin-scaffolder@1.32.0-next.2 + - @backstage/plugin-catalog@1.31.0-next.2 + - @backstage/plugin-techdocs@1.13.0-next.2 + - @backstage/plugin-catalog-react@1.19.0-next.2 + - @backstage/plugin-catalog-import@0.13.1-next.2 + - @backstage/plugin-home@0.8.9-next.2 + - @backstage/plugin-search-react@1.9.1-next.1 + - @backstage/app-defaults@1.6.3-next.0 + - @backstage/frontend-plugin-api@0.10.3-next.1 + - @backstage/integration-react@1.2.7 + - @backstage/plugin-api-docs@0.12.8-next.2 + - @backstage/plugin-app@0.1.10-next.1 + - @backstage/plugin-app-visualizer@0.1.20-next.1 + - @backstage/plugin-auth-react@0.1.16-next.0 + - @backstage/plugin-catalog-graph@0.4.20-next.2 + - @backstage/plugin-catalog-unprocessed-entities@0.2.18-next.2 + - @backstage/plugin-kubernetes@0.12.8-next.2 + - @backstage/plugin-kubernetes-cluster@0.0.26-next.2 + - @backstage/plugin-org@0.6.40-next.2 + - @backstage/plugin-scaffolder-react@1.16.1-next.2 + - @backstage/plugin-search@1.4.27-next.2 + - @backstage/plugin-signals@0.0.20-next.1 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.25-next.2 + - @backstage/plugin-techdocs-react@1.3.0-next.1 + - @backstage/plugin-user-settings@0.8.23-next.2 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/core-app-api@1.17.0 + - @backstage/core-compat-api@0.4.3-next.2 + - @backstage/core-plugin-api@1.10.7 + - @backstage/frontend-app-api@0.11.3-next.1 + - @backstage/frontend-defaults@0.2.3-next.1 + - @backstage/theme@0.6.6 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-permission-react@0.4.34 + - @backstage/plugin-search-common@1.2.18 + +## app-next-example-plugin@0.0.24-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/frontend-plugin-api@0.10.3-next.1 + +## example-backend@0.0.39-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend-module-github@0.8.0-next.2 + - @backstage/backend-defaults@0.11.0-next.2 + - @backstage/plugin-scaffolder-backend@2.0.0-next.2 + - @backstage/plugin-notifications-backend@0.5.7-next.2 + - @backstage/plugin-catalog-backend@2.0.1-next.2 + - @backstage/plugin-scaffolder-backend-module-notifications@0.1.11-next.2 + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/catalog-model@1.7.4 + - @backstage/plugin-app-backend@0.5.3-next.1 + - @backstage/plugin-auth-backend@0.25.1-next.1 + - @backstage/plugin-auth-backend-module-github-provider@0.3.4-next.1 + - @backstage/plugin-auth-backend-module-guest-provider@0.2.9-next.1 + - @backstage/plugin-auth-node@0.6.4-next.1 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.5.3-next.1 + - @backstage/plugin-catalog-backend-module-openapi@0.2.11-next.1 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.2.9-next.1 + - @backstage/plugin-catalog-backend-module-unprocessed@0.6.1-next.1 + - @backstage/plugin-devtools-backend@0.5.6-next.2 + - @backstage/plugin-events-backend@0.5.3-next.1 + - @backstage/plugin-events-backend-module-google-pubsub@0.1.1-next.1 + - @backstage/plugin-kubernetes-backend@0.19.7-next.1 + - @backstage/plugin-permission-backend@0.7.1-next.1 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.2.9-next.1 + - @backstage/plugin-permission-common@0.9.0 + - @backstage/plugin-permission-node@0.10.1-next.1 + - @backstage/plugin-proxy-backend@0.6.3-next.1 + - @backstage/plugin-search-backend@2.0.3-next.2 + - @backstage/plugin-search-backend-module-catalog@0.3.5-next.1 + - @backstage/plugin-search-backend-module-explore@0.3.3-next.1 + - @backstage/plugin-search-backend-module-techdocs@0.4.3-next.1 + - @backstage/plugin-search-backend-node@1.3.12-next.1 + - @backstage/plugin-signals-backend@0.3.5-next.1 + - @backstage/plugin-techdocs-backend@2.0.3-next.2 + +## e2e-test@0.2.29-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.7.0-next.2 + - @backstage/cli-common@0.1.15 + - @backstage/errors@1.2.7 + +## @internal/frontend@0.0.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.10.3-next.1 + - @backstage/types@1.2.1 + - @backstage/version-bridge@1.0.11 + +## @internal/scaffolder@0.0.10-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.10.3-next.1 + - @backstage/plugin-scaffolder-react@1.16.1-next.2 + +## techdocs-cli-embedded-app@0.2.109-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/cli@0.33.0-next.1 + - @backstage/plugin-catalog@1.31.0-next.2 + - @backstage/plugin-techdocs@1.13.0-next.2 + - @backstage/app-defaults@1.6.3-next.0 + - @backstage/integration-react@1.2.7 + - @backstage/plugin-techdocs-react@1.3.0-next.1 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/core-app-api@1.17.0 + - @backstage/core-plugin-api@1.10.7 + - @backstage/test-utils@1.7.8 + - @backstage/theme@0.6.6 + +## @internal/plugin-todo-list@1.0.40-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/core-plugin-api@1.10.7 diff --git a/docs/releases/v1.40.0-next.3-changelog.md b/docs/releases/v1.40.0-next.3-changelog.md new file mode 100644 index 0000000000..6dfc2aa342 --- /dev/null +++ b/docs/releases/v1.40.0-next.3-changelog.md @@ -0,0 +1,166 @@ +# Release v1.40.0-next.3 + +Upgrade Helper: [https://backstage.github.io/upgrade-helper/?to=1.40.0-next.3](https://backstage.github.io/upgrade-helper/?to=1.40.0-next.3) + +## @backstage/plugin-events-backend-module-kafka@0.1.0-next.0 + +### Minor Changes + +- b034b9d: Adds a new module `kafka` for plugin-events-backend + + The module introduces the `KafkaConsumerClient` which creates a Kafka client used to establish consumer connections. It also provides the `KafkaConsumingEventPublisher`, a consumer that subscribes to configured Kafka topics and publishes received messages to the Event Service. + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/config@1.3.2 + - @backstage/types@1.2.1 + - @backstage/plugin-events-node@0.4.12-next.1 + +## @backstage/cli@0.33.0-next.2 + +### Patch Changes + +- 8a0164c: Fix an issue where some commands were not usable because of missing dist files +- Updated dependencies + - @backstage/eslint-plugin@0.1.11-next.0 + - @backstage/catalog-model@1.7.4 + - @backstage/cli-common@0.1.15 + - @backstage/cli-node@0.2.13 + - @backstage/config@1.3.2 + - @backstage/config-loader@1.10.1 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + - @backstage/release-manifests@0.0.13 + - @backstage/types@1.2.1 + +## @backstage/create-app@0.7.0-next.3 + +### Patch Changes + +- Bumped create-app version. +- Updated dependencies + - @backstage/cli-common@0.1.15 + +## @backstage/eslint-plugin@0.1.11-next.0 + +### Patch Changes + +- 098ef95: Fix custom rules package scanning performance. + +## example-app@0.2.110-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.33.0-next.2 + - @backstage/app-defaults@1.6.3-next.0 + - @backstage/canon@0.5.0-next.2 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/core-app-api@1.17.0 + - @backstage/core-components@0.17.3-next.0 + - @backstage/core-plugin-api@1.10.7 + - @backstage/frontend-app-api@0.11.3-next.1 + - @backstage/integration-react@1.2.7 + - @backstage/theme@0.6.6 + - @backstage/plugin-api-docs@0.12.8-next.2 + - @backstage/plugin-auth-react@0.1.16-next.0 + - @backstage/plugin-catalog@1.31.0-next.2 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-catalog-graph@0.4.20-next.2 + - @backstage/plugin-catalog-import@0.13.1-next.2 + - @backstage/plugin-catalog-react@1.19.0-next.2 + - @backstage/plugin-catalog-unprocessed-entities@0.2.18-next.2 + - @backstage/plugin-devtools@0.1.28-next.2 + - @backstage/plugin-home@0.8.9-next.2 + - @backstage/plugin-kubernetes@0.12.8-next.2 + - @backstage/plugin-kubernetes-cluster@0.0.26-next.2 + - @backstage/plugin-notifications@0.5.6-next.2 + - @backstage/plugin-org@0.6.40-next.2 + - @backstage/plugin-permission-react@0.4.34 + - @backstage/plugin-scaffolder@1.32.0-next.2 + - @backstage/plugin-scaffolder-react@1.16.1-next.2 + - @backstage/plugin-search@1.4.27-next.2 + - @backstage/plugin-search-common@1.2.18 + - @backstage/plugin-search-react@1.9.1-next.1 + - @backstage/plugin-signals@0.0.20-next.1 + - @backstage/plugin-techdocs@1.13.0-next.2 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.25-next.2 + - @backstage/plugin-techdocs-react@1.3.0-next.1 + - @backstage/plugin-user-settings@0.8.23-next.2 + +## example-app-next@0.0.24-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.33.0-next.2 + - @backstage/app-defaults@1.6.3-next.0 + - @backstage/canon@0.5.0-next.2 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/core-app-api@1.17.0 + - @backstage/core-compat-api@0.4.3-next.2 + - @backstage/core-components@0.17.3-next.0 + - @backstage/core-plugin-api@1.10.7 + - @backstage/frontend-app-api@0.11.3-next.1 + - @backstage/frontend-defaults@0.2.3-next.1 + - @backstage/frontend-plugin-api@0.10.3-next.1 + - @backstage/integration-react@1.2.7 + - @backstage/theme@0.6.6 + - @backstage/plugin-api-docs@0.12.8-next.2 + - @backstage/plugin-app@0.1.10-next.1 + - @backstage/plugin-app-visualizer@0.1.20-next.1 + - @backstage/plugin-auth-react@0.1.16-next.0 + - @backstage/plugin-catalog@1.31.0-next.2 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-catalog-graph@0.4.20-next.2 + - @backstage/plugin-catalog-import@0.13.1-next.2 + - @backstage/plugin-catalog-react@1.19.0-next.2 + - @backstage/plugin-catalog-unprocessed-entities@0.2.18-next.2 + - @backstage/plugin-home@0.8.9-next.2 + - @backstage/plugin-kubernetes@0.12.8-next.2 + - @backstage/plugin-kubernetes-cluster@0.0.26-next.2 + - @backstage/plugin-notifications@0.5.6-next.2 + - @backstage/plugin-org@0.6.40-next.2 + - @backstage/plugin-permission-react@0.4.34 + - @backstage/plugin-scaffolder@1.32.0-next.2 + - @backstage/plugin-scaffolder-react@1.16.1-next.2 + - @backstage/plugin-search@1.4.27-next.2 + - @backstage/plugin-search-common@1.2.18 + - @backstage/plugin-search-react@1.9.1-next.1 + - @backstage/plugin-signals@0.0.20-next.1 + - @backstage/plugin-techdocs@1.13.0-next.2 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.25-next.2 + - @backstage/plugin-techdocs-react@1.3.0-next.1 + - @backstage/plugin-user-settings@0.8.23-next.2 + +## e2e-test@0.2.29-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.7.0-next.3 + - @backstage/cli-common@0.1.15 + - @backstage/errors@1.2.7 + +## techdocs-cli-embedded-app@0.2.109-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.33.0-next.2 + - @backstage/app-defaults@1.6.3-next.0 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/core-app-api@1.17.0 + - @backstage/core-components@0.17.3-next.0 + - @backstage/core-plugin-api@1.10.7 + - @backstage/integration-react@1.2.7 + - @backstage/test-utils@1.7.8 + - @backstage/theme@0.6.6 + - @backstage/plugin-catalog@1.31.0-next.2 + - @backstage/plugin-techdocs@1.13.0-next.2 + - @backstage/plugin-techdocs-react@1.3.0-next.1 diff --git a/docs/releases/v1.40.0.md b/docs/releases/v1.40.0.md new file mode 100644 index 0000000000..b5ef87ffe1 --- /dev/null +++ b/docs/releases/v1.40.0.md @@ -0,0 +1,190 @@ +--- +id: v1.40.0 +title: v1.40.0 +description: Backstage Release v1.40.0 +--- + +These are the release notes for the v1.40.0 release of [Backstage](https://backstage.io/). + +A huge thanks to the whole team of maintainers and contributors as well as the amazing Backstage Community for the hard work in getting this release developed and done. + +## Highlights + +### Scaffolder 2.0 Breaking Changes + +The deprecated legacy action formats have been removed and replaced with the new native `zod` formats. + +This also cleaned up some deprecated `logStream` and `WinstonLogger` usages in the old patterns. + +```ts +// really old legacy json schema +createTemplateAction<{ repoUrl: string }, { repoOutput: string }>({ + id: 'test', + schema: { + input: { + type: 'object' + required: ['repoUrl'] + properties: { + repoUrl: { + type: 'string', + description: 'repository url description' + } + } + } + } +}); + +// old zod method +createTemplateAction({ + id: 'test' + schema: { + input: { + repoUrl: z.string({ description: 'repository url description' }) + } + } +}) + +// new method: +createTemplateAction({ + id: 'test', + schema: { + input: { + repoUrl: z => z.string({ description: 'repository url description' }) + } + } +}) + +``` + +The `scaffolder-backend` plugin has been converted to being New Backend System only, which means a lot of the public API has been cleaned up. + +The `createRouter` and `createBuiltinActions` have been removed as they were only used in the legacy backend system. + +A lot of deprecated types which were re-exported in the `-backend` package from `-common` and `-node` have been removed, and can be fixed by importing them from the correct package. + +The deprecated `copyWithoutRender` option has been removed from `fetch:template` and should be renamed to `copyWithoutTemplating`. + +The re-exported action creators from the provider packages such as `createPublishAzureAction` and `createPublishGithubAction` should now be imported from the provider modules themselves. + +As always you can head over the latest changelogs for [`@backstage/plugin-scaffolder-backend`](https://github.com/backstage/backstage/blob/master/plugins/scaffolder-backend/CHANGELOG.md) and [`@backstage/plugin-scaffolder-node`](https://github.com/backstage/backstage/blob/master/plugins/scaffolder-node/CHANGELOG.md) +for more detailed information. + +There’s also a number of new deprecation for types which are currently exported from `plugin-scaffolder-node`. We’re going to be looking at re-working the Scaffolder architecture in the future, so we’re going to be removing these types in a future version to iterate on the new API surfaces. Stay tuned for more updates! + +### Actions Registry + +We’ve added two new `alpha` services which can be used to define distributed Actions across Backstage. Plugins can use the `ActionsRegistry` to define actions that are automatically installed with their associated plugin. + +On top of this Actions Registry is a new `mcp-actions` backend plugin, which will surface these actions as tools as an MCP server. This can be used to expose plugin Actions with your favourite AI tools, such as Cursor, Claude or ChatGPT. + +You can find out more information about the `ActionsRegistry` and MCP integration in [this RFC](https://github.com/backstage/backstage/issues/30218). + +We’re actively working on this area, therefore it’s currently highly experimental and could be subject to breaking changes in future releases. However we’d really appreciate some feedback if you want to try and create some Actions for your plugins and surface them in an MCP server! + +In the next release we’ll be looking to integrate these Actions with the Scaffolder allowing you to call these actions from a template. + +### TechDocs deep linking + +Introduced `backstage.io/techdocs-entity-path` annotation which allows deep linking into other TechDocs in conjunction with `backstage.io/techdocs-entity`. + +Contributed by [@csuich2](https://github.com/csuich2) in [#29760](https://github.com/backstage/backstage/pull/29760) + +### Catalog modules Breaking Changes + +- `BitbucketCloudEntityProvider` now accepts a `CatalogService` instead of `CatalogApi` +- User and Group discovery for GitLab will default to ingesting all users in sub groups that belong to the specified root group in config. Disable by setting `restrictUsersToGroup: true` in app-config under your module settings. + +### New Module drop: `@backstage/plugin-events-backend-module-kafka` + +The module introduces the `KafkaConsumerClient` which creates a Kafka client used to establish consumer connections. It also provides the `KafkaConsumingEventPublisher`, a consumer that subscribes to configured Kafka topics and publishes received messages to the Backstage events service where Backstage plugins can access them. + +Contributed by [@Jonas-Beck](https://github.com/Jonas-Beck) in [#29315](https://github.com/backstage/backstage/pull/29315) + +### New lint rule added + +A new lint rule `@backstage/no-mixed-plugin-imports` was added to the defaults. This enforces rules that were always true but until now were implicit: that you should not import across frontend and backend package boundaries, isomorphic packages should not import non-isomorphic, etc. + +This rule is initially only set at a warning level, to give you some time to react. You may see warnings appear in your build output that were not there before - do pay attention to them, because they may expose some issues that you had not yet noticed. + +We intend to make this rule be at an error level in a future release. + +The rule has an option `excludedTargetPackages` that lets you opt out of enforcement in specific packages. You can put something like this in your root `.eslintrc.js`: + +```js +module.exports = { + root: true, + plugins: ['@spotify', 'react', 'testing-library', '@backstage'], + rules: { + '@backstage/no-mixed-plugin-imports': [ + 'error', // if you want to opt in to strict checks early + { + excludedTargetPackages: [ + '@internal/plugin-foo', + // ... +``` + +Contributed by [@drodil](https://github.com/drodil) in [#30227](https://github.com/backstage/backstage/pull/30227) + +### CLI: movement toward `rspack` + +The `BACKSTAGE_CLI_EXPERIMENTAL_BUILD_CACHE` flag has been removed entirely. If you were using this flag, we encourage you to switch to `EXPERIMENTAL_RSPACK` instead. In the near future, we hope to make `rspack` the default out of the box. + +While making these changes, the experimental `FORCE_REACT_DEVELOPMENT` flag was removed as well. + +### Backend rate limiting + +The backend system now has builtin support for rate limiting of incoming requests, both for your entire backends and on a per-plugin basis. It can use different backing stores for its state, and in-memory and redis is currently implemented out of the box. + +You can read more about this opt-in feature in [the documentation](https://backstage.io/docs/backend-system/core-services/http-router) for the HTTP router service. + +Contributed by [@drodil](https://github.com/drodil) in [#28708](https://github.com/backstage/backstage/pull/28708) + +### New Frontend System plugin info + +Plugins in the new frontend system can now expose rich, extensible metadata about themselves. This data is accessible at runtime inside your app. This is for example useful for adding contact and support information, and much more - and you can even overlay your own data on top of what is provided by open-source plugins. + +You can read more about this in the [frontend app](https://backstage.io/docs/frontend-system/architecture/app) and [plugin](https://backstage.io/docs/frontend-system/architecture/plugins) architecture documentation. + +### Notifications retention + +Notifications that are stored by the notifications backend plugin now have a default retention of one year before being deleted. This helps keep the storage size in check over time. You can override this using the `notifications.retention` duration setting in your app-config. + +Contributed by [@drodil](https://github.com/drodil) in [#30206](https://github.com/backstage/backstage/pull/30206) + +### Lots of i18n work + +A bunch of work was done to enable i18n (translations) in several plugins! This affected at least the following: + +- core components +- the org plugin +- the catalog import plugin +- the home plugin +- the search plugin +- the user settings plugin + +Contributed by [@mario-mui](https://github.com/mario-mui) + +### Canon steams ahead + +While it’s still early days, we still want to call out that the canon design system work steams ahead with various controls added and improvements made. Hang tight! + +## Security Fixes + +This release does not contain any security fixes. + +## Upgrade path + +We recommend that you keep your Backstage project up to date with this latest release. For more guidance on how to upgrade, check out the documentation for [keeping Backstage updated](https://backstage.io/docs/getting-started/keeping-backstage-updated). + +## Links and References + +Below you can find a list of links and references to help you learn about and start using this new release. + +- [Backstage official website](https://backstage.io/), [documentation](https://backstage.io/docs/), and [getting started guide](https://backstage.io/docs/getting-started/) +- [GitHub repository](https://github.com/backstage/backstage) +- Backstage's [versioning and support policy](https://backstage.io/docs/overview/versioning-policy) +- [Community Discord](https://discord.gg/backstage-687207715902193673) for discussions and support +- [Changelog](https://github.com/backstage/backstage/tree/master/docs/releases/v1.40.0-changelog.md) +- Backstage [Demos](https://backstage.io/demos), [Blog](https://backstage.io/blog), [Roadmap](https://backstage.io/docs/overview/roadmap) and [Plugins](https://backstage.io/plugins) + +Sign up for our [newsletter](https://info.backstage.spotify.com/newsletter_subscribe) if you want to be informed about what is happening in the world of Backstage. diff --git a/docs/tutorials/configuring-plugin-databases.md b/docs/tutorials/configuring-plugin-databases.md index c6d9869d38..2bbe83557c 100644 --- a/docs/tutorials/configuring-plugin-databases.md +++ b/docs/tutorials/configuring-plugin-databases.md @@ -1,7 +1,6 @@ --- id: configuring-plugin-databases title: Configuring Plugin Databases -# prettier-ignore description: Guide on how to configure Backstage databases. --- diff --git a/docs/tutorials/manual-knex-rollback.md b/docs/tutorials/manual-knex-rollback.md index 14e00d6659..b0f67ba3e0 100644 --- a/docs/tutorials/manual-knex-rollback.md +++ b/docs/tutorials/manual-knex-rollback.md @@ -1,7 +1,6 @@ --- id: manual-knex-rollback title: Manual Rollback using Knex -# prettier-ignore description: Guide on how to rollback Knex migrations. --- diff --git a/docs/tutorials/switching-sqlite-postgres.md b/docs/tutorials/switching-sqlite-postgres.md index aec9ca2ee9..4fc405c61c 100644 --- a/docs/tutorials/switching-sqlite-postgres.md +++ b/docs/tutorials/switching-sqlite-postgres.md @@ -1,7 +1,6 @@ --- id: switching-sqlite-postgres title: Switching Backstage from SQLite to PostgreSQL -# prettier-ignore description: How to get ready for deploying Backstage to production with PostgreSQL --- diff --git a/docs/tutorials/using-backstage-proxy-within-plugin.md b/docs/tutorials/using-backstage-proxy-within-plugin.md index c82db9ff6c..58e973d891 100644 --- a/docs/tutorials/using-backstage-proxy-within-plugin.md +++ b/docs/tutorials/using-backstage-proxy-within-plugin.md @@ -1,7 +1,6 @@ --- id: using-backstage-proxy-within-plugin title: Using the Backstage Proxy from Within a Plugin -# prettier-ignore description: Guide on how to create a set of API bindings that interface with a backend via the backstage proxy --- diff --git a/microsite/blog/2020-05-22-phase-2-service-catalog.mdx b/microsite/blog/2020-05-22-phase-2-service-catalog.mdx index 81c99c7c07..9e681b9da3 100644 --- a/microsite/blog/2020-05-22-phase-2-service-catalog.mdx +++ b/microsite/blog/2020-05-22-phase-2-service-catalog.mdx @@ -1,6 +1,5 @@ --- -# prettier-ignore -title: "Starting Phase 2: The Service Catalog" +title: 'Starting Phase 2: The Service Catalog' author: Stefan Ålund, Spotify authorURL: http://twitter.com/stalund authorImageURL: https://pbs.twimg.com/profile_images/121166861/6919c047c0d0edaace78c3009b28e917-user-full-200-130.generated_400x400.jpg diff --git a/microsite/blog/2020-09-08-announcing-tech-docs.mdx b/microsite/blog/2020-09-08-announcing-tech-docs.mdx index 4200ac0a65..9235eeb401 100644 --- a/microsite/blog/2020-09-08-announcing-tech-docs.mdx +++ b/microsite/blog/2020-09-08-announcing-tech-docs.mdx @@ -1,6 +1,5 @@ --- -# prettier-ignore -title: "Announcing TechDocs: Spotify’s docs-like-code plugin for Backstage" +title: 'Announcing TechDocs: Spotify’s docs-like-code plugin for Backstage' author: Gary Niemen, Spotify authorURL: https://github.com/garyniemen --- diff --git a/microsite/blog/2020-10-22-cost-insights-plugin.mdx b/microsite/blog/2020-10-22-cost-insights-plugin.mdx index 1ffddd3303..293cd1c927 100644 --- a/microsite/blog/2020-10-22-cost-insights-plugin.mdx +++ b/microsite/blog/2020-10-22-cost-insights-plugin.mdx @@ -1,6 +1,5 @@ --- -# prettier-ignore -title: "New Cost Insights plugin: The engineer’s solution to taming cloud costs" +title: 'New Cost Insights plugin: The engineer’s solution to taming cloud costs' author: Janisa Anandamohan, Spotify authorURL: https://twitter.com/janisa_a --- diff --git a/microsite/blog/2021-01-12-new-backstage-feature-kubernetes-for-service-owners.mdx b/microsite/blog/2021-01-12-new-backstage-feature-kubernetes-for-service-owners.mdx index c1232a5f12..1303f0dd15 100644 --- a/microsite/blog/2021-01-12-new-backstage-feature-kubernetes-for-service-owners.mdx +++ b/microsite/blog/2021-01-12-new-backstage-feature-kubernetes-for-service-owners.mdx @@ -1,6 +1,5 @@ --- -# prettier-ignore -title: "New Backstage feature: Kubernetes for Service owners" +title: 'New Backstage feature: Kubernetes for Service owners' author: Matthew Clarke, Spotify authorURL: https://github.com/mclarke47 --- diff --git a/microsite/blog/2021-06-24-announcing-backstage-search-platform.mdx b/microsite/blog/2021-06-24-announcing-backstage-search-platform.mdx index bb30a3b9ec..8ac14b14d4 100644 --- a/microsite/blog/2021-06-24-announcing-backstage-search-platform.mdx +++ b/microsite/blog/2021-06-24-announcing-backstage-search-platform.mdx @@ -1,6 +1,5 @@ --- -# prettier-ignore -title: "Announcing the Backstage Search platform: a customizable search tool built just for you" +title: 'Announcing the Backstage Search platform: a customizable search tool built just for you' author: Emma Indal, Spotify authorURL: https://www.linkedin.com/in/emma-indal --- diff --git a/microsite/blog/2022-03-17-backstage-1.0.mdx b/microsite/blog/2022-03-17-backstage-1.0.mdx index 6f9dd3ee09..3cade0d79f 100644 --- a/microsite/blog/2022-03-17-backstage-1.0.mdx +++ b/microsite/blog/2022-03-17-backstage-1.0.mdx @@ -1,6 +1,5 @@ --- -# prettier-ignore -title: "New release: Backstage 1.0" +title: 'New release: Backstage 1.0' author: Francesco Corti, Spotify authorURL: https://github.com/fcorti/ authorImageURL: https://avatars.githubusercontent.com/u/6010860?v=4 diff --git a/microsite/blog/2022-05-13-techdocs-addon-framework.mdx b/microsite/blog/2022-05-13-techdocs-addon-framework.mdx index 7f2a588834..37d746b3c2 100644 --- a/microsite/blog/2022-05-13-techdocs-addon-framework.mdx +++ b/microsite/blog/2022-05-13-techdocs-addon-framework.mdx @@ -1,6 +1,5 @@ --- -# prettier-ignore -title: "Introducing the TechDocs Addon Framework" +title: 'Introducing the TechDocs Addon Framework' author: Gary Niemen, Spotify authorURL: https://github.com/garyniemen/ authorImageURL: https://avatars.githubusercontent.com/u/65337273?v=4 diff --git a/microsite/blog/2022-07-19-releasing-backstage-search-1.0.mdx b/microsite/blog/2022-07-19-releasing-backstage-search-1.0.mdx index 1936dd4fc3..9ff3539b0d 100644 --- a/microsite/blog/2022-07-19-releasing-backstage-search-1.0.mdx +++ b/microsite/blog/2022-07-19-releasing-backstage-search-1.0.mdx @@ -1,5 +1,4 @@ --- -# prettier-ignore title: Releasing Backstage Search 1.0 author: Emma Indal, Spotify authorURL: https://www.linkedin.com/in/emma-indal diff --git a/microsite/blog/2022-08-23-backstage-security-audit.mdx b/microsite/blog/2022-08-23-backstage-security-audit.mdx index 6b9f2f6463..9c6de6eeeb 100644 --- a/microsite/blog/2022-08-23-backstage-security-audit.mdx +++ b/microsite/blog/2022-08-23-backstage-security-audit.mdx @@ -1,5 +1,4 @@ --- -# prettier-ignore title: Backstage Security Audit & Updates author: Patrik Oldsberg, Spotify authorURL: https://github.com/Rugvip diff --git a/microsite/blog/2022-09-08-fyi-plugin-analytics-api.mdx b/microsite/blog/2022-09-08-fyi-plugin-analytics-api.mdx index aff30752ec..b07dfffc06 100644 --- a/microsite/blog/2022-09-08-fyi-plugin-analytics-api.mdx +++ b/microsite/blog/2022-09-08-fyi-plugin-analytics-api.mdx @@ -1,5 +1,4 @@ --- -# prettier-ignore title: FYI 📣 The Plugin Analytics API author: Eric Peterson, Spotify authorURL: https://github.com/iamEAP diff --git a/microsite/blog/2023-07-08-stash-adopter-post.mdx b/microsite/blog/2023-07-08-stash-adopter-post.mdx index 6c1edea764..c5fe9e03b4 100644 --- a/microsite/blog/2023-07-08-stash-adopter-post.mdx +++ b/microsite/blog/2023-07-08-stash-adopter-post.mdx @@ -1,6 +1,5 @@ --- -# prettier-ignore -title: "Adopter Spotlight: How Stash simplified monitoring, ownership and true app health with microservices" +title: 'Adopter Spotlight: How Stash simplified monitoring, ownership and true app health with microservices' author: Taylor Webber, Staff Engineer, Stash --- diff --git a/microsite/blog/2023-07-28-frontside-adopter-post.mdx b/microsite/blog/2023-07-28-frontside-adopter-post.mdx index c6f3cba403..5ea73fb089 100644 --- a/microsite/blog/2023-07-28-frontside-adopter-post.mdx +++ b/microsite/blog/2023-07-28-frontside-adopter-post.mdx @@ -1,6 +1,5 @@ --- -# prettier-ignore -title: "Five common traits of successful Backstage adopters" +title: 'Five common traits of successful Backstage adopters' author: Taras Mankovski, CXO, Frontside --- diff --git a/microsite/blog/2023-08-17-expedia-proof-of-value-metrics-2.mdx b/microsite/blog/2023-08-17-expedia-proof-of-value-metrics-2.mdx index 9c6e67fcf1..f7f6ddfe77 100644 --- a/microsite/blog/2023-08-17-expedia-proof-of-value-metrics-2.mdx +++ b/microsite/blog/2023-08-17-expedia-proof-of-value-metrics-2.mdx @@ -1,6 +1,5 @@ --- -# prettier-ignore -title: "Expedia Group shares Backstage proof of value metrics 2.0" +title: 'Expedia Group shares Backstage proof of value metrics 2.0' author: Guillermo Manzo, Expedia Group authorURL: https://www.linkedin.com/in/guillermomanzo --- diff --git a/microsite/blog/2023-09-29-chicago-traiding-company-adopter-spotlight.mdx b/microsite/blog/2023-09-29-chicago-traiding-company-adopter-spotlight.mdx index 8b4f332d54..bd479a6a86 100644 --- a/microsite/blog/2023-09-29-chicago-traiding-company-adopter-spotlight.mdx +++ b/microsite/blog/2023-09-29-chicago-traiding-company-adopter-spotlight.mdx @@ -1,6 +1,5 @@ --- -# prettier-ignore -title: "Adopter Spotlight: How Chicago Trading Company saved 18 months of developer effort with Backstage" +title: 'Adopter Spotlight: How Chicago Trading Company saved 18 months of developer effort with Backstage' author: Tiffany Cox, Spotify --- diff --git a/microsite/blog/2023-11-15-backstagecon-kubecon-23.mdx b/microsite/blog/2023-11-15-backstagecon-kubecon-23.mdx index 7b7f7c0f0b..cdb2d9e582 100644 --- a/microsite/blog/2023-11-15-backstagecon-kubecon-23.mdx +++ b/microsite/blog/2023-11-15-backstagecon-kubecon-23.mdx @@ -1,6 +1,5 @@ --- -# prettier-ignore -title: "Wrap up: BackstageCon ‘23, KubeCon + Cloud Native NA" +title: 'Wrap up: BackstageCon ‘23, KubeCon + Cloud Native NA' author: Jorge Lainfiesta, Spotify authorURL: https://www.linkedin.com/in/jrlainfiesta/ authorImageURL: https://avatars.githubusercontent.com/u/4451393?v=4 diff --git a/microsite/blog/2024-03-27-backstagecon-kubecon-24.mdx b/microsite/blog/2024-03-27-backstagecon-kubecon-24.mdx index 2164a8732e..6dd8691d82 100644 --- a/microsite/blog/2024-03-27-backstagecon-kubecon-24.mdx +++ b/microsite/blog/2024-03-27-backstagecon-kubecon-24.mdx @@ -1,6 +1,5 @@ --- -# prettier-ignore -title: "Backstage in Paris: Wrapping up BackstageCon and KubeCon + CloudNativeCon Europe 2024" +title: 'Backstage in Paris: Wrapping up BackstageCon and KubeCon + CloudNativeCon Europe 2024' author: André Wanlin, Spotify authorURL: https://github.com/awanlin authorImageURL: https://avatars.githubusercontent.com/u/67169551?v=4 diff --git a/microsite/blog/2024-04-19-community-plugins.mdx b/microsite/blog/2024-04-19-community-plugins.mdx index 49d1765bce..801a2f7437 100644 --- a/microsite/blog/2024-04-19-community-plugins.mdx +++ b/microsite/blog/2024-04-19-community-plugins.mdx @@ -1,6 +1,5 @@ --- -# prettier-ignore -title: "Introducing the Backstage Community Plugins Repository" +title: 'Introducing the Backstage Community Plugins Repository' author: Ben Lambert, Spotify authorURL: https://github.com/benjdlambert authorImageURL: https://avatars.githubusercontent.com/u/3645856?v=4 diff --git a/microsite/blog/2024-06-27-backstage-engineer-journey.mdx b/microsite/blog/2024-06-27-backstage-engineer-journey.mdx index d7fac5fd46..9180a4b6d7 100644 --- a/microsite/blog/2024-06-27-backstage-engineer-journey.mdx +++ b/microsite/blog/2024-06-27-backstage-engineer-journey.mdx @@ -1,6 +1,5 @@ --- -# prettier-ignore -title: "1,186 days with Backstage: A journey through the eyes of a developer" +title: '1,186 days with Backstage: A journey through the eyes of a developer' author: Camila Loiola, Spotify authorURL: https://github.com/camilaibs authorImageURL: https://avatars.githubusercontent.com/u/6290749?v=4 diff --git a/microsite/blog/2024-12-09-kubecon-slc-24.mdx b/microsite/blog/2024-12-09-kubecon-slc-24.mdx index c3fa2f70a8..c77d82d1aa 100644 --- a/microsite/blog/2024-12-09-kubecon-slc-24.mdx +++ b/microsite/blog/2024-12-09-kubecon-slc-24.mdx @@ -1,6 +1,5 @@ --- -# prettier-ignore -title: "Backstage in Salt Lake City: Highlights from BackstageCon and KubeCon + CloudNativeCon North America 2024" +title: 'Backstage in Salt Lake City: Highlights from BackstageCon and KubeCon + CloudNativeCon North America 2024' author: André Wanlin, Spotify & Camila Loiola, Spotify --- diff --git a/microsite/blog/2024-12-17-backstage-security-audit-2024.mdx b/microsite/blog/2024-12-17-backstage-security-audit-2024.mdx index f9a1afef9e..5d4294b6c6 100644 --- a/microsite/blog/2024-12-17-backstage-security-audit-2024.mdx +++ b/microsite/blog/2024-12-17-backstage-security-audit-2024.mdx @@ -1,5 +1,4 @@ --- -# prettier-ignore title: The 2024 Backstage Security Audit author: Patrik Oldsberg, Spotify authorURL: https://github.com/Rugvip diff --git a/microsite/blog/2024-12-18-backstage-wrapped-2024.mdx b/microsite/blog/2024-12-18-backstage-wrapped-2024.mdx index a136d644b5..f0e4eb8a05 100644 --- a/microsite/blog/2024-12-18-backstage-wrapped-2024.mdx +++ b/microsite/blog/2024-12-18-backstage-wrapped-2024.mdx @@ -1,5 +1,4 @@ --- -# prettier-ignore title: "Backstage Wrapped 2024: The year's Top 5 milestones and highlights" author: Patrik Oldsberg, Spotify & Ben Lambert, Spotify --- diff --git a/microsite/blog/2025-04-29-backstagecon-kubecon-25-london.mdx b/microsite/blog/2025-04-29-backstagecon-kubecon-25-london.mdx index 99da880900..3eca9563a9 100644 --- a/microsite/blog/2025-04-29-backstagecon-kubecon-25-london.mdx +++ b/microsite/blog/2025-04-29-backstagecon-kubecon-25-london.mdx @@ -1,6 +1,5 @@ --- -# prettier-ignore -title: "Backstage in London: Highlights from BackstageCon and KubeCon + CloudNativeCon Europe 2025" +title: 'Backstage in London: Highlights from BackstageCon and KubeCon + CloudNativeCon Europe 2025' author: André Wanlin, Spotify authorURL: https://github.com/awanlin authorImageURL: https://avatars.githubusercontent.com/u/67169551?v=4 diff --git a/microsite/data/plugins/hetzner-cloud.yaml b/microsite/data/plugins/hetzner-cloud.yaml new file mode 100644 index 0000000000..6f1fbe3f25 --- /dev/null +++ b/microsite/data/plugins/hetzner-cloud.yaml @@ -0,0 +1,10 @@ +--- +title: Hetzner Cloud +author: Gluo NV +authorUrl: https://github.com/gluobe +category: Infrastructure +description: Integrate Hetzner Cloud resources into Backstage. +documentation: https://github.com/gluobe/hetzner-backstage-plugin/blob/main/README.md +iconUrl: https://avatars.githubusercontent.com/u/18439789?s=200&v=4 +npmPackageName: '@gluo-nv/backstage-plugin-hetzner' +addedDate: '2025-06-03' diff --git a/microsite/data/plugins/spacelift-io.yaml b/microsite/data/plugins/spacelift-io.yaml new file mode 100644 index 0000000000..fe9b48139f --- /dev/null +++ b/microsite/data/plugins/spacelift-io.yaml @@ -0,0 +1,10 @@ +--- +title: Spacelift.io +author: Spacelift.io +authorUrl: https://spacelift.io/ +category: Infrastructure +description: The Spacelift plugin allows you to manage your infrastructure directly from Backstage. Visualize your IaC stacks and trigger runs with ease. +documentation: https://docs.spacelift.io/integrations/external-integrations/backstage +iconUrl: https://avatars.githubusercontent.com/u/53318513?s=200&v=4 +npmPackageName: '@spacelift-io/backstage-integration-frontend' +addedDate: '2025-06-10' diff --git a/microsite/data/plugins/stackoverflow-teams.yaml b/microsite/data/plugins/stackoverflow-teams.yaml new file mode 100644 index 0000000000..cfe08757d3 --- /dev/null +++ b/microsite/data/plugins/stackoverflow-teams.yaml @@ -0,0 +1,10 @@ +--- +title: Stack Overflow for Teams +author: EstoesMoises +authorUrl: https://github.com/estoesmoises/ +category: Discovery +description: Provide seamless access to Stack Overflow Teams most relevant data, allowing you to display the top users, top tags, and top questions directly within Backstage. It also allows to securely create SO Teams questions from Backstage. +documentation: https://github.com/StackExchange/backstage-stackoverflow/blob/main/README.md +iconUrl: /img/stack-overflow-logo.svg +npmPackageName: 'backstage-plugin-stack-overflow-teams' +addedDate: '2025-06-10' diff --git a/microsite/docusaurus.config.ts b/microsite/docusaurus.config.ts index d71483ab8f..d7538cd12d 100644 --- a/microsite/docusaurus.config.ts +++ b/microsite/docusaurus.config.ts @@ -483,7 +483,7 @@ const config: Config = { copyright: `

Made with ❤️ at Spotify

`, }, algolia: { - apiKey: '1f0ba86672ccfc3576faa94583e5b318', + apiKey: '60d2643a9c6306463f15f8c3556e7f2e', // Owned by @Rugvip indexName: 'crawler_Backstage Docusaurus 2', appId: 'JCMFNHCHI8', searchParameters: {}, diff --git a/microsite/sidebars.ts b/microsite/sidebars.ts index 1f8d3defb7..eef7ef5ee9 100644 --- a/microsite/sidebars.ts +++ b/microsite/sidebars.ts @@ -330,7 +330,7 @@ export default { { type: 'category', label: 'Gitea', - items: ['integrations/gitea/locations'], + items: ['integrations/gitea/locations', 'integrations/gitea/discovery'], }, { type: 'category', @@ -462,6 +462,8 @@ export default { 'backend-system/core-services/token-manager', 'backend-system/core-services/url-reader', 'backend-system/core-services/user-info', + 'backend-system/core-services/actions-registry', + 'backend-system/core-services/actions', ], }, ], diff --git a/microsite/yarn.lock b/microsite/yarn.lock index e6454c4e82..a200d0f9da 100644 --- a/microsite/yarn.lock +++ b/microsite/yarn.lock @@ -4430,12 +4430,12 @@ __metadata: linkType: hard "brace-expansion@npm:^1.1.7": - version: 1.1.11 - resolution: "brace-expansion@npm:1.1.11" + version: 1.1.12 + resolution: "brace-expansion@npm:1.1.12" dependencies: balanced-match: "npm:^1.0.0" concat-map: "npm:0.0.1" - checksum: 10/faf34a7bb0c3fcf4b59c7808bc5d2a96a40988addf2e7e09dfbb67a2251800e0d14cd2bfc1aa79174f2f5095c54ff27f46fb1289fe2d77dac755b5eb3434cc07 + checksum: 10/12cb6d6310629e3048cadb003e1aca4d8c9bb5c67c3c321bafdd7e7a50155de081f78ea3e0ed92ecc75a9015e784f301efc8132383132f4f7904ad1ac529c562 languageName: node linkType: hard diff --git a/mkdocs.yml b/mkdocs.yml index 688ca1a078..eea5fc9c40 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -126,6 +126,9 @@ nav: - GitLab: - Locations: 'integrations/gitlab/locations.md' - Discovery: 'integrations/gitlab/discovery.md' + - Gitea: + - Locations: 'integrations/gitea/locations.md' + - Discovery: 'integrations/gitea/discovery.md' - Google GCS: - Locations: 'integrations/google-cloud-storage/locations.md' - LDAP: diff --git a/package.json b/package.json index 3cc5755ccb..4e20ea9d63 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "root", - "version": "1.40.0-next.1", + "version": "1.40.0", "backstage": { "cli": { "new": { @@ -122,6 +122,7 @@ "@backstage/codemods": "workspace:*", "@backstage/create-app": "workspace:*", "@backstage/e2e-test-utils": "workspace:*", + "@backstage/eslint-plugin": "workspace:*", "@backstage/repo-tools": "workspace:*", "@changesets/cli": "^2.14.0", "@octokit/rest": "^19.0.3", diff --git a/packages/app-defaults/CHANGELOG.md b/packages/app-defaults/CHANGELOG.md index b798c5a20e..3e6d00d3a2 100644 --- a/packages/app-defaults/CHANGELOG.md +++ b/packages/app-defaults/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/app-defaults +## 1.6.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3 + - @backstage/core-plugin-api@1.10.8 + - @backstage/core-app-api@1.17.1 + - @backstage/theme@0.6.6 + - @backstage/plugin-permission-react@0.4.35 + +## 1.6.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/core-app-api@1.17.0 + - @backstage/core-plugin-api@1.10.7 + - @backstage/theme@0.6.6 + - @backstage/plugin-permission-react@0.4.34 + ## 1.6.2 ### Patch Changes diff --git a/packages/app-defaults/package.json b/packages/app-defaults/package.json index 3969bf8a2e..ccfced26c5 100644 --- a/packages/app-defaults/package.json +++ b/packages/app-defaults/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/app-defaults", - "version": "1.6.2", + "version": "1.6.3", "description": "Provides the default wiring of a Backstage App", "backstage": { "role": "web-library" diff --git a/packages/app-next-example-plugin/CHANGELOG.md b/packages/app-next-example-plugin/CHANGELOG.md index 35f6bf7dcb..4cb53ae6d7 100644 --- a/packages/app-next-example-plugin/CHANGELOG.md +++ b/packages/app-next-example-plugin/CHANGELOG.md @@ -1,5 +1,21 @@ # app-next-example-plugin +## 0.0.24 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3 + - @backstage/frontend-plugin-api@0.10.3 + +## 0.0.24-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/frontend-plugin-api@0.10.3-next.1 + ## 0.0.24-next.0 ### Patch Changes diff --git a/packages/app-next-example-plugin/package.json b/packages/app-next-example-plugin/package.json index d2ac22833e..13dcf483fc 100644 --- a/packages/app-next-example-plugin/package.json +++ b/packages/app-next-example-plugin/package.json @@ -1,6 +1,6 @@ { "name": "app-next-example-plugin", - "version": "0.0.24-next.0", + "version": "0.0.24", "description": "Backstage internal example plugin", "backstage": { "role": "frontend-plugin", diff --git a/packages/app-next/CHANGELOG.md b/packages/app-next/CHANGELOG.md index 4d446d4d5d..aea61a779f 100644 --- a/packages/app-next/CHANGELOG.md +++ b/packages/app-next/CHANGELOG.md @@ -1,5 +1,143 @@ # example-app-next +## 0.0.24 + +### Patch Changes + +- Updated dependencies + - @backstage/canon@0.5.0 + - @backstage/core-components@0.17.3 + - @backstage/cli@0.33.0 + - @backstage/plugin-scaffolder-react@1.17.0 + - @backstage/plugin-scaffolder@1.32.0 + - @backstage/plugin-catalog-unprocessed-entities@0.2.18 + - @backstage/plugin-app-visualizer@0.1.20 + - @backstage/plugin-catalog-import@0.13.1 + - @backstage/plugin-catalog-graph@0.4.20 + - @backstage/plugin-notifications@0.5.6 + - @backstage/plugin-user-settings@0.8.23 + - @backstage/plugin-kubernetes@0.12.8 + - @backstage/plugin-api-docs@0.12.8 + - @backstage/plugin-techdocs@1.13.0 + - @backstage/plugin-catalog@1.31.0 + - @backstage/plugin-signals@0.0.20 + - @backstage/plugin-search@1.4.27 + - @backstage/plugin-home@0.8.9 + - @backstage/plugin-app@0.1.10 + - @backstage/plugin-org@0.6.40 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.25 + - @backstage/core-plugin-api@1.10.8 + - @backstage/frontend-plugin-api@0.10.3 + - @backstage/frontend-app-api@0.11.3 + - @backstage/plugin-catalog-react@1.19.0 + - @backstage/plugin-techdocs-react@1.3.0 + - @backstage/frontend-defaults@0.2.3 + - @backstage/plugin-search-react@1.9.1 + - @backstage/app-defaults@1.6.3 + - @backstage/integration-react@1.2.8 + - @backstage/plugin-auth-react@0.1.16 + - @backstage/plugin-kubernetes-cluster@0.0.26 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/core-app-api@1.17.1 + - @backstage/core-compat-api@0.4.3 + - @backstage/theme@0.6.6 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-permission-react@0.4.35 + - @backstage/plugin-search-common@1.2.18 + +## 0.0.24-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.33.0-next.2 + - @backstage/app-defaults@1.6.3-next.0 + - @backstage/canon@0.5.0-next.2 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/core-app-api@1.17.0 + - @backstage/core-compat-api@0.4.3-next.2 + - @backstage/core-components@0.17.3-next.0 + - @backstage/core-plugin-api@1.10.7 + - @backstage/frontend-app-api@0.11.3-next.1 + - @backstage/frontend-defaults@0.2.3-next.1 + - @backstage/frontend-plugin-api@0.10.3-next.1 + - @backstage/integration-react@1.2.7 + - @backstage/theme@0.6.6 + - @backstage/plugin-api-docs@0.12.8-next.2 + - @backstage/plugin-app@0.1.10-next.1 + - @backstage/plugin-app-visualizer@0.1.20-next.1 + - @backstage/plugin-auth-react@0.1.16-next.0 + - @backstage/plugin-catalog@1.31.0-next.2 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-catalog-graph@0.4.20-next.2 + - @backstage/plugin-catalog-import@0.13.1-next.2 + - @backstage/plugin-catalog-react@1.19.0-next.2 + - @backstage/plugin-catalog-unprocessed-entities@0.2.18-next.2 + - @backstage/plugin-home@0.8.9-next.2 + - @backstage/plugin-kubernetes@0.12.8-next.2 + - @backstage/plugin-kubernetes-cluster@0.0.26-next.2 + - @backstage/plugin-notifications@0.5.6-next.2 + - @backstage/plugin-org@0.6.40-next.2 + - @backstage/plugin-permission-react@0.4.34 + - @backstage/plugin-scaffolder@1.32.0-next.2 + - @backstage/plugin-scaffolder-react@1.16.1-next.2 + - @backstage/plugin-search@1.4.27-next.2 + - @backstage/plugin-search-common@1.2.18 + - @backstage/plugin-search-react@1.9.1-next.1 + - @backstage/plugin-signals@0.0.20-next.1 + - @backstage/plugin-techdocs@1.13.0-next.2 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.25-next.2 + - @backstage/plugin-techdocs-react@1.3.0-next.1 + - @backstage/plugin-user-settings@0.8.23-next.2 + +## 0.0.24-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/cli@0.33.0-next.1 + - @backstage/canon@0.5.0-next.2 + - @backstage/plugin-notifications@0.5.6-next.2 + - @backstage/plugin-scaffolder@1.32.0-next.2 + - @backstage/plugin-catalog@1.31.0-next.2 + - @backstage/plugin-techdocs@1.13.0-next.2 + - @backstage/plugin-catalog-react@1.19.0-next.2 + - @backstage/plugin-catalog-import@0.13.1-next.2 + - @backstage/plugin-home@0.8.9-next.2 + - @backstage/plugin-search-react@1.9.1-next.1 + - @backstage/app-defaults@1.6.3-next.0 + - @backstage/frontend-plugin-api@0.10.3-next.1 + - @backstage/integration-react@1.2.7 + - @backstage/plugin-api-docs@0.12.8-next.2 + - @backstage/plugin-app@0.1.10-next.1 + - @backstage/plugin-app-visualizer@0.1.20-next.1 + - @backstage/plugin-auth-react@0.1.16-next.0 + - @backstage/plugin-catalog-graph@0.4.20-next.2 + - @backstage/plugin-catalog-unprocessed-entities@0.2.18-next.2 + - @backstage/plugin-kubernetes@0.12.8-next.2 + - @backstage/plugin-kubernetes-cluster@0.0.26-next.2 + - @backstage/plugin-org@0.6.40-next.2 + - @backstage/plugin-scaffolder-react@1.16.1-next.2 + - @backstage/plugin-search@1.4.27-next.2 + - @backstage/plugin-signals@0.0.20-next.1 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.25-next.2 + - @backstage/plugin-techdocs-react@1.3.0-next.1 + - @backstage/plugin-user-settings@0.8.23-next.2 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/core-app-api@1.17.0 + - @backstage/core-compat-api@0.4.3-next.2 + - @backstage/core-plugin-api@1.10.7 + - @backstage/frontend-app-api@0.11.3-next.1 + - @backstage/frontend-defaults@0.2.3-next.1 + - @backstage/theme@0.6.6 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-permission-react@0.4.34 + - @backstage/plugin-search-common@1.2.18 + ## 0.0.24-next.1 ### Patch Changes diff --git a/packages/app-next/package.json b/packages/app-next/package.json index d094ca942f..1ae22eb5e9 100644 --- a/packages/app-next/package.json +++ b/packages/app-next/package.json @@ -1,6 +1,6 @@ { "name": "example-app-next", - "version": "0.0.24-next.1", + "version": "0.0.24", "backstage": { "role": "frontend" }, diff --git a/packages/app/CHANGELOG.md b/packages/app/CHANGELOG.md index c27e814e51..1f43c868ef 100644 --- a/packages/app/CHANGELOG.md +++ b/packages/app/CHANGELOG.md @@ -1,5 +1,131 @@ # example-app +## 0.2.110 + +### Patch Changes + +- Updated dependencies + - @backstage/canon@0.5.0 + - @backstage/core-components@0.17.3 + - @backstage/cli@0.33.0 + - @backstage/plugin-scaffolder-react@1.17.0 + - @backstage/plugin-scaffolder@1.32.0 + - @backstage/plugin-catalog-unprocessed-entities@0.2.18 + - @backstage/plugin-catalog-import@0.13.1 + - @backstage/plugin-catalog-graph@0.4.20 + - @backstage/plugin-notifications@0.5.6 + - @backstage/plugin-user-settings@0.8.23 + - @backstage/plugin-kubernetes@0.12.8 + - @backstage/plugin-api-docs@0.12.8 + - @backstage/plugin-devtools@0.1.28 + - @backstage/plugin-techdocs@1.13.0 + - @backstage/plugin-catalog@1.31.0 + - @backstage/plugin-signals@0.0.20 + - @backstage/plugin-search@1.4.27 + - @backstage/plugin-home@0.8.9 + - @backstage/plugin-org@0.6.40 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.25 + - @backstage/core-plugin-api@1.10.8 + - @backstage/frontend-app-api@0.11.3 + - @backstage/plugin-catalog-react@1.19.0 + - @backstage/plugin-techdocs-react@1.3.0 + - @backstage/plugin-search-react@1.9.1 + - @backstage/app-defaults@1.6.3 + - @backstage/integration-react@1.2.8 + - @backstage/plugin-auth-react@0.1.16 + - @backstage/plugin-kubernetes-cluster@0.0.26 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/core-app-api@1.17.1 + - @backstage/theme@0.6.6 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-permission-react@0.4.35 + - @backstage/plugin-search-common@1.2.18 + +## 0.2.110-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.33.0-next.2 + - @backstage/app-defaults@1.6.3-next.0 + - @backstage/canon@0.5.0-next.2 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/core-app-api@1.17.0 + - @backstage/core-components@0.17.3-next.0 + - @backstage/core-plugin-api@1.10.7 + - @backstage/frontend-app-api@0.11.3-next.1 + - @backstage/integration-react@1.2.7 + - @backstage/theme@0.6.6 + - @backstage/plugin-api-docs@0.12.8-next.2 + - @backstage/plugin-auth-react@0.1.16-next.0 + - @backstage/plugin-catalog@1.31.0-next.2 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-catalog-graph@0.4.20-next.2 + - @backstage/plugin-catalog-import@0.13.1-next.2 + - @backstage/plugin-catalog-react@1.19.0-next.2 + - @backstage/plugin-catalog-unprocessed-entities@0.2.18-next.2 + - @backstage/plugin-devtools@0.1.28-next.2 + - @backstage/plugin-home@0.8.9-next.2 + - @backstage/plugin-kubernetes@0.12.8-next.2 + - @backstage/plugin-kubernetes-cluster@0.0.26-next.2 + - @backstage/plugin-notifications@0.5.6-next.2 + - @backstage/plugin-org@0.6.40-next.2 + - @backstage/plugin-permission-react@0.4.34 + - @backstage/plugin-scaffolder@1.32.0-next.2 + - @backstage/plugin-scaffolder-react@1.16.1-next.2 + - @backstage/plugin-search@1.4.27-next.2 + - @backstage/plugin-search-common@1.2.18 + - @backstage/plugin-search-react@1.9.1-next.1 + - @backstage/plugin-signals@0.0.20-next.1 + - @backstage/plugin-techdocs@1.13.0-next.2 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.25-next.2 + - @backstage/plugin-techdocs-react@1.3.0-next.1 + - @backstage/plugin-user-settings@0.8.23-next.2 + +## 0.2.110-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/cli@0.33.0-next.1 + - @backstage/canon@0.5.0-next.2 + - @backstage/plugin-notifications@0.5.6-next.2 + - @backstage/plugin-scaffolder@1.32.0-next.2 + - @backstage/plugin-catalog@1.31.0-next.2 + - @backstage/plugin-techdocs@1.13.0-next.2 + - @backstage/plugin-catalog-react@1.19.0-next.2 + - @backstage/plugin-catalog-import@0.13.1-next.2 + - @backstage/plugin-home@0.8.9-next.2 + - @backstage/plugin-search-react@1.9.1-next.1 + - @backstage/app-defaults@1.6.3-next.0 + - @backstage/integration-react@1.2.7 + - @backstage/plugin-api-docs@0.12.8-next.2 + - @backstage/plugin-auth-react@0.1.16-next.0 + - @backstage/plugin-catalog-graph@0.4.20-next.2 + - @backstage/plugin-catalog-unprocessed-entities@0.2.18-next.2 + - @backstage/plugin-devtools@0.1.28-next.2 + - @backstage/plugin-kubernetes@0.12.8-next.2 + - @backstage/plugin-kubernetes-cluster@0.0.26-next.2 + - @backstage/plugin-org@0.6.40-next.2 + - @backstage/plugin-scaffolder-react@1.16.1-next.2 + - @backstage/plugin-search@1.4.27-next.2 + - @backstage/plugin-signals@0.0.20-next.1 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.25-next.2 + - @backstage/plugin-techdocs-react@1.3.0-next.1 + - @backstage/plugin-user-settings@0.8.23-next.2 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/core-app-api@1.17.0 + - @backstage/core-plugin-api@1.10.7 + - @backstage/frontend-app-api@0.11.3-next.1 + - @backstage/theme@0.6.6 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-permission-react@0.4.34 + - @backstage/plugin-search-common@1.2.18 + ## 0.2.110-next.1 ### Patch Changes diff --git a/packages/app/package.json b/packages/app/package.json index 569f84ea7f..0f80bcdacb 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -1,6 +1,6 @@ { "name": "example-app", - "version": "0.2.110-next.1", + "version": "0.2.110", "backstage": { "role": "frontend" }, diff --git a/packages/backend-app-api/CHANGELOG.md b/packages/backend-app-api/CHANGELOG.md index 20f035ea76..c590baad83 100644 --- a/packages/backend-app-api/CHANGELOG.md +++ b/packages/backend-app-api/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/backend-app-api +## 1.2.4 + +### Patch Changes + +- bb9a501: Fixed a bug where occasionally the initialization order of multiple modules consuming a single extension point could happen in the wrong order. +- Updated dependencies + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + +## 1.2.4-next.2 + +### Patch Changes + +- bb9a501: Fixed a bug where occasionally the initialization order of multiple modules consuming a single extension point could happen in the wrong order. +- Updated dependencies + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + ## 1.2.4-next.1 ### Patch Changes diff --git a/packages/backend-app-api/package.json b/packages/backend-app-api/package.json index b78bb4a5be..12a7be3127 100644 --- a/packages/backend-app-api/package.json +++ b/packages/backend-app-api/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/backend-app-api", - "version": "1.2.4-next.1", + "version": "1.2.4", "description": "Core API used by Backstage backend apps", "backstage": { "role": "node-library" diff --git a/packages/backend-app-api/src/lib/DependencyGraph.test.ts b/packages/backend-app-api/src/lib/DependencyGraph.test.ts index 394359e486..8aafcb21aa 100644 --- a/packages/backend-app-api/src/lib/DependencyGraph.test.ts +++ b/packages/backend-app-api/src/lib/DependencyGraph.test.ts @@ -514,5 +514,21 @@ describe('DependencyGraph', () => { }).parallelTopologicalTraversal(async id => id), ).rejects.toThrow('Circular dependency detected'); }); + + it('awaits all producers', async () => { + await expect( + DependencyGraph.fromMap({ + 1: { provides: ['a'] }, + 2: { provides: ['a'] }, + 3: { consumes: ['a'] }, + }).parallelTopologicalTraversal(async id => { + // Delaying 2 should not make 3 run, wait for 1 too first + if (id === '2') { + await new Promise(resolve => setTimeout(resolve, 100)); + } + return id; + }), + ).resolves.toEqual(['1', '2', '3']); + }); }); }); diff --git a/packages/backend-app-api/src/lib/DependencyGraph.ts b/packages/backend-app-api/src/lib/DependencyGraph.ts index 86fad3fbf2..8b3de48ff2 100644 --- a/packages/backend-app-api/src/lib/DependencyGraph.ts +++ b/packages/backend-app-api/src/lib/DependencyGraph.ts @@ -188,12 +188,25 @@ export class DependencyGraph { fn: (value: T) => Promise, ): Promise { const allProvided = this.#allProvided; - const producedSoFar = new Set(); const waiting = new Set(this.#nodes.values()); const visited = new Set>(); const results = new Array(); let inFlight = 0; // Keep track of how many callbacks are in flight, so that we know if we got stuck + // This keeps track of a counter of how many providers there are still left + // to be visited for each dependency. This needs to be a counter instead of + // a flag for the special case where there are several providers of a given + // value, even though there may be only one consumer of it. + const producedRemaining = new Map(); + for (const node of this.#nodes) { + for (const provided of node.provides) { + producedRemaining.set( + provided, + (producedRemaining.get(provided) ?? 0) + 1, + ); + } + } + // Find all nodes that have no dependencies that have not already been produced by visited nodes async function processMoreNodes() { if (waiting.size === 0) { @@ -203,7 +216,10 @@ export class DependencyGraph { for (const node of waiting) { let ready = true; for (const consumed of node.consumes) { - if (allProvided.has(consumed) && !producedSoFar.has(consumed)) { + if ( + allProvided.has(consumed) && + producedRemaining.get(consumed) !== 0 + ) { ready = false; continue; } @@ -234,7 +250,17 @@ export class DependencyGraph { const result = await fn(node.value); results.push(result); - node.provides.forEach(produced => producedSoFar.add(produced)); + node.provides.forEach(produced => { + const remaining = producedRemaining.get(produced); + if (!remaining) { + // This should be impossible, if the code that generates the map is correct + throw new Error( + `Internal error: Node provided superfluous dependency '${produced}'`, + ); + } + producedRemaining.set(produced, remaining - 1); + }); + inFlight -= 1; await processMoreNodes(); } diff --git a/packages/backend-app-api/src/wiring/BackendInitializer.test.ts b/packages/backend-app-api/src/wiring/BackendInitializer.test.ts index 3b0596cd13..9e8a6579fd 100644 --- a/packages/backend-app-api/src/wiring/BackendInitializer.test.ts +++ b/packages/backend-app-api/src/wiring/BackendInitializer.test.ts @@ -1134,4 +1134,68 @@ describe('BackendInitializer', () => { backend.add(instanceMetadataPlugin); await backend.start(); }); + + it('should properly wait for all modules that consume an extension point to really finish, before starting the module that provides that extension point', async () => { + expect.assertions(3); + const backend = new BackendInitializer(baseFactories); + const ext = createExtensionPoint<{ hello: (message: string) => void }>({ + id: 'a', + }); + const plugin = createBackendPlugin({ + pluginId: 'test', + register(reg) { + reg.registerInit({ + deps: {}, + async init() {}, + }); + }, + }); + const producerModule = createBackendModule({ + pluginId: 'test', + moduleId: 'producer', + register(reg) { + const hello = jest.fn(); + reg.registerExtensionPoint(ext, { hello }); + reg.registerInit({ + deps: {}, + async init() { + // we must not have been initialized before both of the consuming modules have been initialized + expect(hello).toHaveBeenCalledTimes(2); + expect(hello).toHaveBeenNthCalledWith(1, 'fast'); + expect(hello).toHaveBeenNthCalledWith(2, 'slow'); + }, + }); + }, + }); + const fastConsumerModule = createBackendModule({ + pluginId: 'test', + moduleId: 'fast-consumer', + register(reg) { + reg.registerInit({ + deps: { x: ext }, + async init({ x }) { + x.hello('fast'); + }, + }); + }, + }); + const slowConsumerModule = createBackendModule({ + pluginId: 'test', + moduleId: 'slow-consumer', + register(reg) { + reg.registerInit({ + deps: { x: ext }, + async init({ x }) { + await new Promise(resolve => setTimeout(resolve, 100)); + x.hello('slow'); + }, + }); + }, + }); + await backend.add(plugin); + await backend.add(producerModule); + await backend.add(fastConsumerModule); + await backend.add(slowConsumerModule); + await backend.start(); + }); }); diff --git a/packages/backend-defaults/CHANGELOG.md b/packages/backend-defaults/CHANGELOG.md index e6237db287..5d8a6b300d 100644 --- a/packages/backend-defaults/CHANGELOG.md +++ b/packages/backend-defaults/CHANGELOG.md @@ -1,5 +1,76 @@ # @backstage/backend-defaults +## 0.11.0 + +### Minor Changes + +- 3ccb7fc: Enhanced error handling in the auditor service factory to pass errors as objects. Aligned WinstonRootAuditorService with the default service factory's error handling. + +### Patch Changes + +- 1220cf8: Added new rate limit middleware to allow rate limiting requests to the backend + + If you are using the `configure` callback of the root HTTP router service and do NOT call `applyDefaults()` inside it, please see [the relevant changes](https://github.com/backstage/backstage/pull/28708/files#diff-86ad1b6a694dd250823aee39d410428dd837c9d9a04ca8c33bd1081fbe3f22af) that were made, to see if you want to apply them as well to your custom configuration. + Rate limiting can be turned on by adding the following configuration to `app-config.yaml`: + + ```yaml + backend: + rateLimit: + window: 6s + incomingRequestLimit: 100 + ``` + + Plugin specific rate limiting can be configured by adding the following configuration to `app-config.yaml`: + + ```yaml + backend: + rateLimit: + global: false # This will disable the global rate limiting + plugin: + catalog: + window: 6s + incomingRequestLimit: 100 + ``` + +- c999c25: Added some default implementations for the experimental `ActionsService` and `ActionsRegistryService` under `/alpha` that allow registration of actions for a particular plugin. +- Updated dependencies + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-app-api@1.2.4 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/backend-dev-utils@0.1.5 + - @backstage/cli-node@0.2.13 + - @backstage/config@1.3.2 + - @backstage/config-loader@1.10.1 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + - @backstage/integration-aws-node@0.1.16 + - @backstage/types@1.2.1 + - @backstage/plugin-events-node@0.4.12 + - @backstage/plugin-permission-node@0.10.1 + +## 0.11.0-next.2 + +### Minor Changes + +- 3ccb7fc: Enhanced error handling in the auditor service factory to pass errors as objects. Aligned WinstonRootAuditorService with the default service factory's error handling. + +### Patch Changes + +- Updated dependencies + - @backstage/backend-app-api@1.2.4-next.2 + - @backstage/backend-dev-utils@0.1.5 + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/cli-node@0.2.13 + - @backstage/config@1.3.2 + - @backstage/config-loader@1.10.1 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + - @backstage/integration-aws-node@0.1.16 + - @backstage/types@1.2.1 + - @backstage/plugin-auth-node@0.6.4-next.1 + - @backstage/plugin-events-node@0.4.12-next.1 + - @backstage/plugin-permission-node@0.10.1-next.1 + ## 0.10.1-next.1 ### Patch Changes diff --git a/packages/backend-defaults/config.d.ts b/packages/backend-defaults/config.d.ts index 1ef054a537..167a8935f9 100644 --- a/packages/backend-defaults/config.d.ts +++ b/packages/backend-defaults/config.d.ts @@ -790,6 +790,92 @@ export interface Config { headers?: { [name: string]: string }; }; + /** + * Rate limiting options. Defining this as `true` will enable rate limiting with default values. + */ + rateLimit?: + | true + | { + store?: + | { + type: 'redis'; + connection: string; + } + | { + type: 'memory'; + }; + /** + * Enable/disable global rate limiting. If this is disabled, plugin specific rate limiting must be + * used. + */ + global?: boolean; + /** + * Time frame in milliseconds or as human duration for which requests are checked/remembered. + * Defaults to one minute. + */ + window?: string | HumanDuration; + /** + * The maximum number of connections to allow during the `window` before rate limiting the client. + * Defaults to 5. + */ + incomingRequestLimit?: number; + /** + * Whether to pass requests in case of store failure. + * Defaults to false. + */ + passOnStoreError?: boolean; + /** + * List of allowed IP addresses that are not rate limited. + * Defaults to [127.0.0.1, 0:0:0:0:0:0:0:1, ::1]. + */ + ipAllowList?: string[]; + /** + * Skip rate limiting for requests that have been successful. + * Defaults to false. + */ + skipSuccessfulRequests?: boolean; + /** + * Skip rate limiting for requests that have failed. + * Defaults to false. + */ + skipFailedRequests?: boolean; + /** Plugin specific rate limiting configuration */ + plugin?: { + [pluginId: string]: { + /** + * Time frame in milliseconds or as human duration for which requests are checked/remembered. + * Defaults to one minute. + */ + window?: string | HumanDuration; + /** + * The maximum number of connections to allow during the `window` before rate limiting the client. + * Defaults to 5. + */ + incomingRequestLimit?: number; + /** + * Whether to pass requests in case of store failure. + * Defaults to false. + */ + passOnStoreError?: boolean; + /** + * List of allowed IP addresses that are not rate limited. + * Defaults to [127.0.0.1, 0:0:0:0:0:0:0:1, ::1]. + */ + ipAllowList?: string[]; + /** + * Skip rate limiting for requests that have been successful. + * Defaults to false. + */ + skipSuccessfulRequests?: boolean; + /** + * Skip rate limiting for requests that have failed. + * Defaults to false. + */ + skipFailedRequests?: boolean; + }; + }; + }; + /** * Configuration related to URL reading, used for example for reading catalog info * files, scaffolder templates, and techdocs content. diff --git a/packages/backend-defaults/package.json b/packages/backend-defaults/package.json index 3c74bad2d5..90c9280e7f 100644 --- a/packages/backend-defaults/package.json +++ b/packages/backend-defaults/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/backend-defaults", - "version": "0.10.1-next.1", + "version": "0.11.0", "description": "Backend defaults used by Backstage backend apps", "backstage": { "role": "node-library" @@ -20,8 +20,6 @@ "license": "Apache-2.0", "exports": { ".": "./src/index.ts", - "./actions": "./src/entrypoints/actions/index.ts", - "./actionsRegistry": "./src/entrypoints/actionsRegistry/index.ts", "./auditor": "./src/entrypoints/auditor/index.ts", "./auth": "./src/entrypoints/auth/index.ts", "./cache": "./src/entrypoints/cache/index.ts", @@ -41,18 +39,13 @@ "./scheduler": "./src/entrypoints/scheduler/index.ts", "./urlReader": "./src/entrypoints/urlReader/index.ts", "./userInfo": "./src/entrypoints/userInfo/index.ts", + "./alpha": "./src/alpha/index.ts", "./package.json": "./package.json" }, "main": "src/index.ts", "types": "src/index.ts", "typesVersions": { "*": { - "actions": [ - "src/entrypoints/actions/index.ts" - ], - "actionsRegistry": [ - "src/entrypoints/actionsRegistry/index.ts" - ], "auditor": [ "src/entrypoints/auditor/index.ts" ], @@ -110,6 +103,9 @@ "userInfo": [ "src/entrypoints/userInfo/index.ts" ], + "alpha": [ + "src/alpha/index.ts" + ], "package.json": [ "package.json" ] @@ -168,6 +164,7 @@ "cron": "^3.0.0", "express": "^4.17.1", "express-promise-router": "^4.1.0", + "express-rate-limit": "^7.5.0", "fs-extra": "^11.2.0", "git-url-parse": "^15.0.0", "helmet": "^6.0.0", @@ -187,6 +184,7 @@ "pg": "^8.11.3", "pg-connection-string": "^2.3.0", "pg-format": "^1.0.4", + "rate-limit-redis": "^4.2.0", "raw-body": "^2.4.1", "selfsigned": "^2.0.0", "tar": "^6.1.12", diff --git a/packages/backend-defaults/report-actions.api.md b/packages/backend-defaults/report-actions.api.md deleted file mode 100644 index 4c072af02a..0000000000 --- a/packages/backend-defaults/report-actions.api.md +++ /dev/null @@ -1,17 +0,0 @@ -## API Report File for "@backstage/backend-defaults" - -> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). - -```ts -import { ActionsService } from '@backstage/backend-plugin-api'; -import { ServiceFactory } from '@backstage/backend-plugin-api'; - -// @public (undocumented) -export const actionsServiceFactory: ServiceFactory< - ActionsService, - 'plugin', - 'singleton' ->; - -// (No @packageDocumentation comment for this package) -``` diff --git a/packages/backend-defaults/report-actionsRegistry.api.md b/packages/backend-defaults/report-alpha.api.md similarity index 69% rename from packages/backend-defaults/report-actionsRegistry.api.md rename to packages/backend-defaults/report-alpha.api.md index d35bf4cef4..58277b5e1e 100644 --- a/packages/backend-defaults/report-actionsRegistry.api.md +++ b/packages/backend-defaults/report-alpha.api.md @@ -3,7 +3,8 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts -import { ActionsRegistryService } from '@backstage/backend-plugin-api'; +import { ActionsRegistryService } from '@backstage/backend-plugin-api/alpha'; +import { ActionsService } from '@backstage/backend-plugin-api/alpha'; import { ServiceFactory } from '@backstage/backend-plugin-api'; // @public (undocumented) @@ -13,5 +14,12 @@ export const actionsRegistryServiceFactory: ServiceFactory< 'singleton' >; +// @public (undocumented) +export const actionsServiceFactory: ServiceFactory< + ActionsService, + 'plugin', + 'singleton' +>; + // (No @packageDocumentation comment for this package) ``` diff --git a/packages/backend-defaults/report-auditor.api.md b/packages/backend-defaults/report-auditor.api.md index 353b6f241f..cc00b5c349 100644 --- a/packages/backend-defaults/report-auditor.api.md +++ b/packages/backend-defaults/report-auditor.api.md @@ -8,6 +8,7 @@ import type { AuditorServiceCreateEventOptions } from '@backstage/backend-plugin import type { AuditorServiceEvent } from '@backstage/backend-plugin-api'; import type { AuditorServiceEventSeverityLevel } from '@backstage/backend-plugin-api'; import type { AuthService } from '@backstage/backend-plugin-api'; +import { Config } from '@backstage/config'; import type { Format } from 'logform'; import type { HttpAuthService } from '@backstage/backend-plugin-api'; import type { JsonObject } from '@backstage/types'; @@ -58,7 +59,7 @@ export type AuditorEventStatus = } | { status: 'failed'; - error: string; + error: Error; }; // @public @@ -95,6 +96,7 @@ export class WinstonRootAuditorService { // (undocumented) forPlugin(deps: { auth: AuthService; + config: Config; httpAuth: HttpAuthService; plugin: PluginMetadataService; }): AuditorService; diff --git a/packages/backend-defaults/report-rootHttpRouter.api.md b/packages/backend-defaults/report-rootHttpRouter.api.md index 826d592e8b..84424be39d 100644 --- a/packages/backend-defaults/report-rootHttpRouter.api.md +++ b/packages/backend-defaults/report-rootHttpRouter.api.md @@ -93,6 +93,7 @@ export class MiddlewareFactory { helmet(): RequestHandler; logging(): RequestHandler; notFound(): RequestHandler; + rateLimit(): RequestHandler; } // @public diff --git a/packages/backend-defaults/src/CreateBackend.ts b/packages/backend-defaults/src/CreateBackend.ts index 032978c806..4b201fded3 100644 --- a/packages/backend-defaults/src/CreateBackend.ts +++ b/packages/backend-defaults/src/CreateBackend.ts @@ -35,12 +35,12 @@ import { schedulerServiceFactory } from '@backstage/backend-defaults/scheduler'; import { urlReaderServiceFactory } from '@backstage/backend-defaults/urlReader'; import { userInfoServiceFactory } from '@backstage/backend-defaults/userInfo'; import { eventsServiceFactory } from '@backstage/plugin-events-node'; -import { actionsRegistryServiceFactory } from './entrypoints/actionsRegistry'; -import { actionsServiceFactory } from './entrypoints/actions'; - -export const defaultServiceFactories = [ +import { actionsRegistryServiceFactory, actionsServiceFactory, +} from '@backstage/backend-defaults/alpha'; + +export const defaultServiceFactories = [ auditorServiceFactory, authServiceFactory, cacheServiceFactory, @@ -61,6 +61,10 @@ export const defaultServiceFactories = [ userInfoServiceFactory, urlReaderServiceFactory, eventsServiceFactory, + + // alpha services + actionsRegistryServiceFactory, + actionsServiceFactory, ]; /** diff --git a/packages/backend-defaults/src/entrypoints/actions/DefaultActionsService.ts b/packages/backend-defaults/src/alpha/entrypoints/actions/DefaultActionsService.ts similarity index 98% rename from packages/backend-defaults/src/entrypoints/actions/DefaultActionsService.ts rename to packages/backend-defaults/src/alpha/entrypoints/actions/DefaultActionsService.ts index 2421482f4c..d8847c2187 100644 --- a/packages/backend-defaults/src/entrypoints/actions/DefaultActionsService.ts +++ b/packages/backend-defaults/src/alpha/entrypoints/actions/DefaultActionsService.ts @@ -14,8 +14,6 @@ * limitations under the License. */ import { - ActionsService, - ActionsServiceAction, AuthService, BackstageCredentials, DiscoveryService, @@ -24,6 +22,10 @@ import { } from '@backstage/backend-plugin-api'; import { ResponseError } from '@backstage/errors'; import { JsonObject } from '@backstage/types'; +import { + ActionsService, + ActionsServiceAction, +} from '@backstage/backend-plugin-api/alpha'; export class DefaultActionsService implements ActionsService { private constructor( diff --git a/packages/backend-defaults/src/entrypoints/actions/actionsServiceFactory.test.ts b/packages/backend-defaults/src/alpha/entrypoints/actions/actionsServiceFactory.test.ts similarity index 93% rename from packages/backend-defaults/src/entrypoints/actions/actionsServiceFactory.test.ts rename to packages/backend-defaults/src/alpha/entrypoints/actions/actionsServiceFactory.test.ts index 7b7285c89a..af2fcb0c12 100644 --- a/packages/backend-defaults/src/entrypoints/actions/actionsServiceFactory.test.ts +++ b/packages/backend-defaults/src/alpha/entrypoints/actions/actionsServiceFactory.test.ts @@ -21,18 +21,20 @@ import { startTestBackend, } from '@backstage/backend-test-utils'; import { actionsRegistryServiceFactory } from '../actionsRegistry'; -import { httpRouterServiceFactory } from '../httpRouter'; +import { httpRouterServiceFactory } from '../../../entrypoints/httpRouter'; import { actionsServiceFactory } from './actionsServiceFactory'; import { setupServer } from 'msw/node'; import { rest } from 'msw'; import { - ActionsServiceAction, coreServices, createBackendPlugin, } from '@backstage/backend-plugin-api'; import { json } from 'express'; import Router from 'express-promise-router'; import request from 'supertest'; +import { ActionsServiceAction } from '@backstage/backend-plugin-api/alpha'; +import { actionsRegistryServiceRef } from '@backstage/backend-plugin-api/alpha'; +import { actionsServiceRef } from '@backstage/backend-plugin-api/alpha'; const server = setupServer(); @@ -70,6 +72,11 @@ describe('actionsServiceFactory', () => { input: {}, output: {}, }, + attributes: { + destructive: false, + idempotent: false, + readOnly: false, + }, }; beforeEach(() => { @@ -196,7 +203,7 @@ describe('actionsServiceFactory', () => { pluginId: 'plugin-with-action', register({ registerInit }) { registerInit({ - deps: { actionsRegistry: coreServices.actionsRegistry }, + deps: { actionsRegistry: actionsRegistryServiceRef }, async init({ actionsRegistry }) { actionsRegistry.register({ name: 'with-validation', @@ -231,7 +238,7 @@ describe('actionsServiceFactory', () => { register({ registerInit }) { registerInit({ deps: { - actionsService: coreServices.actions, + actionsService: actionsServiceRef, router: coreServices.httpRouter, httpAuth: coreServices.httpAuth, }, @@ -306,6 +313,11 @@ describe('actionsServiceFactory', () => { type: 'object', }, }, + attributes: { + destructive: true, + idempotent: false, + readOnly: false, + }, title: 'Test', }, ], diff --git a/packages/backend-defaults/src/entrypoints/actions/actionsServiceFactory.ts b/packages/backend-defaults/src/alpha/entrypoints/actions/actionsServiceFactory.ts similarity index 92% rename from packages/backend-defaults/src/entrypoints/actions/actionsServiceFactory.ts rename to packages/backend-defaults/src/alpha/entrypoints/actions/actionsServiceFactory.ts index 466cc02121..4325da7d13 100644 --- a/packages/backend-defaults/src/entrypoints/actions/actionsServiceFactory.ts +++ b/packages/backend-defaults/src/alpha/entrypoints/actions/actionsServiceFactory.ts @@ -16,12 +16,13 @@ import { createServiceFactory } from '@backstage/backend-plugin-api'; import { coreServices } from '@backstage/backend-plugin-api'; import { DefaultActionsService } from './DefaultActionsService'; +import { actionsServiceRef } from '@backstage/backend-plugin-api/alpha'; /** * @public */ export const actionsServiceFactory = createServiceFactory({ - service: coreServices.actions, + service: actionsServiceRef, deps: { discovery: coreServices.discovery, config: coreServices.rootConfig, diff --git a/packages/backend-defaults/src/entrypoints/actions/index.ts b/packages/backend-defaults/src/alpha/entrypoints/actions/index.ts similarity index 100% rename from packages/backend-defaults/src/entrypoints/actions/index.ts rename to packages/backend-defaults/src/alpha/entrypoints/actions/index.ts diff --git a/packages/backend-defaults/src/entrypoints/actionsRegistry/DefaultActionsRegistryService.ts b/packages/backend-defaults/src/alpha/entrypoints/actionsRegistry/DefaultActionsRegistryService.ts similarity index 84% rename from packages/backend-defaults/src/entrypoints/actionsRegistry/DefaultActionsRegistryService.ts rename to packages/backend-defaults/src/alpha/entrypoints/actionsRegistry/DefaultActionsRegistryService.ts index 17523a2ee5..2284935787 100644 --- a/packages/backend-defaults/src/entrypoints/actionsRegistry/DefaultActionsRegistryService.ts +++ b/packages/backend-defaults/src/alpha/entrypoints/actionsRegistry/DefaultActionsRegistryService.ts @@ -15,8 +15,6 @@ */ import { - ActionsRegistryActionOptions, - ActionsRegistryService, AuthService, HttpAuthService, LoggerService, @@ -24,8 +22,12 @@ import { } from '@backstage/backend-plugin-api'; import PromiseRouter from 'express-promise-router'; import { Router, json } from 'express'; -import { z, ZodType } from 'zod'; +import { z, AnyZodObject } from 'zod'; import zodToJsonSchema from 'zod-to-json-schema'; +import { + ActionsRegistryActionOptions, + ActionsRegistryService, +} from '@backstage/backend-plugin-api/alpha'; import { ForwardedError, InputError, @@ -67,13 +69,20 @@ export class DefaultActionsRegistryService implements ActionsRegistryService { actions: Array.from(this.actions.entries()).map(([id, action]) => ({ id, ...action, + attributes: { + // Inspired by the @modelcontextprotocol/sdk defaults for the hints. + // https://github.com/modelcontextprotocol/typescript-sdk/blob/dd69efa1de8646bb6b195ff8d5f52e13739f4550/src/types.ts#L777-L812 + destructive: action.attributes?.destructive ?? true, + idempotent: action.attributes?.idempotent ?? false, + readOnly: action.attributes?.readOnly ?? false, + }, schema: { input: action.schema?.input ? zodToJsonSchema(action.schema.input(z)) - : zodToJsonSchema(z.any()), + : zodToJsonSchema(z.object({})), output: action.schema?.output ? zodToJsonSchema(action.schema.output(z)) - : zodToJsonSchema(z.any()), + : zodToJsonSchema(z.object({})), }, })), }); @@ -142,9 +151,10 @@ export class DefaultActionsRegistryService implements ActionsRegistryService { return router; } - register( - options: ActionsRegistryActionOptions, - ): void { + register< + TInputSchema extends AnyZodObject, + TOutputSchema extends AnyZodObject, + >(options: ActionsRegistryActionOptions): void { const id = `${this.metadata.getId()}:${options.name}`; if (this.actions.has(id)) { diff --git a/packages/backend-defaults/src/entrypoints/actionsRegistry/actionsRegistryServiceFactory.test.ts b/packages/backend-defaults/src/alpha/entrypoints/actionsRegistry/actionsRegistryServiceFactory.test.ts similarity index 76% rename from packages/backend-defaults/src/entrypoints/actionsRegistry/actionsRegistryServiceFactory.test.ts rename to packages/backend-defaults/src/alpha/entrypoints/actionsRegistry/actionsRegistryServiceFactory.test.ts index 5d47ff055d..79c103c284 100644 --- a/packages/backend-defaults/src/entrypoints/actionsRegistry/actionsRegistryServiceFactory.test.ts +++ b/packages/backend-defaults/src/alpha/entrypoints/actionsRegistry/actionsRegistryServiceFactory.test.ts @@ -13,19 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { - coreServices, - createBackendPlugin, -} from '@backstage/backend-plugin-api'; +import { createBackendPlugin } from '@backstage/backend-plugin-api'; import { mockCredentials, mockServices, startTestBackend, } from '@backstage/backend-test-utils'; -import { httpRouterServiceFactory } from '../httpRouter'; +import { httpRouterServiceFactory } from '../../../entrypoints/httpRouter'; import request from 'supertest'; import { actionsRegistryServiceFactory } from './actionsRegistryServiceFactory'; import { InputError } from '@backstage/errors'; +import { actionsRegistryServiceRef } from '@backstage/backend-plugin-api/alpha'; describe('actionsRegistryServiceFactory', () => { const defaultServices = [ @@ -43,7 +41,7 @@ describe('actionsRegistryServiceFactory', () => { register(reg) { reg.registerInit({ deps: { - actionsRegistry: coreServices.actionsRegistry, + actionsRegistry: actionsRegistryServiceRef, }, async init({ actionsRegistry }) { actionsRegistry.register({ @@ -80,7 +78,7 @@ describe('actionsRegistryServiceFactory', () => { register(reg) { reg.registerInit({ deps: { - actionsRegistry: coreServices.actionsRegistry, + actionsRegistry: actionsRegistryServiceRef, }, async init({ actionsRegistry }) { actionsRegistry.register({ @@ -118,7 +116,7 @@ describe('actionsRegistryServiceFactory', () => { register(reg) { reg.registerInit({ deps: { - actionsRegistry: coreServices.actionsRegistry, + actionsRegistry: actionsRegistryServiceRef, }, async init({ actionsRegistry }) { actionsRegistry.register({ @@ -181,13 +179,13 @@ describe('actionsRegistryServiceFactory', () => { }); }); - it('should allow registering of actions with no schema', async () => { + it('should set default attributes', async () => { const pluginSubject = createBackendPlugin({ pluginId: 'my-plugin', register(reg) { reg.registerInit({ deps: { - actionsRegistry: coreServices.actionsRegistry, + actionsRegistry: actionsRegistryServiceRef, }, async init({ actionsRegistry }) { actionsRegistry.register({ @@ -195,9 +193,115 @@ describe('actionsRegistryServiceFactory', () => { title: 'Test', description: 'Test', schema: { + input: z => z.object({}), + output: z => z.object({}), + }, + action: async () => ({ output: { ok: true } }), + }); + }, + }); + }, + }); + + const { server } = await startTestBackend({ + features: [pluginSubject, ...defaultServices], + }); + + const { body, status } = await request(server).get( + '/api/my-plugin/.backstage/actions/v1/actions', + ); + + expect(status).toBe(200); + + expect(body).toMatchObject({ + actions: [ + { + name: 'test', + attributes: { + destructive: true, + idempotent: false, + readOnly: false, + }, + }, + ], + }); + }); + + it('should allow setting attributes', async () => { + const pluginSubject = createBackendPlugin({ + pluginId: 'my-plugin', + register(reg) { + reg.registerInit({ + deps: { + actionsRegistry: actionsRegistryServiceRef, + }, + async init({ actionsRegistry }) { + actionsRegistry.register({ + name: 'test', + title: 'Test', + description: 'Test', + attributes: { + destructive: false, + idempotent: true, + readOnly: true, + }, + schema: { + input: z => z.object({}), + output: z => z.object({}), + }, + action: async () => ({ output: { ok: true } }), + }); + }, + }); + }, + }); + + const { server } = await startTestBackend({ + features: [pluginSubject, ...defaultServices], + }); + + const { body, status } = await request(server).get( + '/api/my-plugin/.backstage/actions/v1/actions', + ); + + expect(status).toBe(200); + + expect(body).toMatchObject({ + actions: [ + { + name: 'test', + title: 'Test', + description: 'Test', + attributes: { + destructive: false, + idempotent: true, + readOnly: true, + }, + }, + ], + }); + }); + + it('should forces registration of input and output schema as objects', async () => { + const pluginSubject = createBackendPlugin({ + pluginId: 'my-plugin', + register(reg) { + reg.registerInit({ + deps: { + actionsRegistry: actionsRegistryServiceRef, + }, + async init({ actionsRegistry }) { + actionsRegistry.register({ + name: 'test', + title: 'Test', + description: 'Test', + schema: { + // @ts-expect-error - z.undefined is not a valid schema input: z => z.undefined(), + // @ts-expect-error - z.string is not a valid schema output: z => z.string(), }, + // @ts-expect-error - output is not a valid, needs to be an object action: async () => ({ output: 'ok' }), }); }, @@ -243,7 +347,7 @@ describe('actionsRegistryServiceFactory', () => { register(reg) { reg.registerInit({ deps: { - actionsRegistry: coreServices.actionsRegistry, + actionsRegistry: actionsRegistryServiceRef, }, async init({ actionsRegistry }) { actionsRegistry.register({ diff --git a/packages/backend-defaults/src/entrypoints/actionsRegistry/actionsRegistryServiceFactory.ts b/packages/backend-defaults/src/alpha/entrypoints/actionsRegistry/actionsRegistryServiceFactory.ts similarity index 92% rename from packages/backend-defaults/src/entrypoints/actionsRegistry/actionsRegistryServiceFactory.ts rename to packages/backend-defaults/src/alpha/entrypoints/actionsRegistry/actionsRegistryServiceFactory.ts index 85515a6046..8c19b8148c 100644 --- a/packages/backend-defaults/src/entrypoints/actionsRegistry/actionsRegistryServiceFactory.ts +++ b/packages/backend-defaults/src/alpha/entrypoints/actionsRegistry/actionsRegistryServiceFactory.ts @@ -19,12 +19,13 @@ import { createServiceFactory, } from '@backstage/backend-plugin-api'; import { DefaultActionsRegistryService } from './DefaultActionsRegistryService'; +import { actionsRegistryServiceRef } from '@backstage/backend-plugin-api/alpha'; /** * @public */ export const actionsRegistryServiceFactory = createServiceFactory({ - service: coreServices.actionsRegistry, + service: actionsRegistryServiceRef, deps: { metadata: coreServices.pluginMetadata, httpRouter: coreServices.httpRouter, diff --git a/packages/backend-defaults/src/entrypoints/actionsRegistry/index.ts b/packages/backend-defaults/src/alpha/entrypoints/actionsRegistry/index.ts similarity index 100% rename from packages/backend-defaults/src/entrypoints/actionsRegistry/index.ts rename to packages/backend-defaults/src/alpha/entrypoints/actionsRegistry/index.ts diff --git a/packages/backend-defaults/src/alpha/index.ts b/packages/backend-defaults/src/alpha/index.ts new file mode 100644 index 0000000000..13bb439acd --- /dev/null +++ b/packages/backend-defaults/src/alpha/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export { actionsRegistryServiceFactory } from './entrypoints/actionsRegistry'; +export { actionsServiceFactory } from './entrypoints/actions'; diff --git a/packages/backend-defaults/src/entrypoints/auditor/DefaultAuditorService.test.ts b/packages/backend-defaults/src/entrypoints/auditor/DefaultAuditorService.test.ts index c960a1daa2..ac32c9e911 100644 --- a/packages/backend-defaults/src/entrypoints/auditor/DefaultAuditorService.test.ts +++ b/packages/backend-defaults/src/entrypoints/auditor/DefaultAuditorService.test.ts @@ -83,7 +83,7 @@ describe('DefaultAuditorService', () => { expect(logFn).toHaveBeenLastCalledWith({ eventId: 'test-event', status: 'failed', - error: error.toString(), + error, plugin: 'test', severityLevel: 'low', actor: {}, @@ -135,7 +135,7 @@ describe('DefaultAuditorService', () => { initiated: 'test', failed: 'test', }, - error: error.toString(), + error, plugin: 'test', severityLevel: 'low', actor: {}, diff --git a/packages/backend-defaults/src/entrypoints/auditor/DefaultAuditorService.ts b/packages/backend-defaults/src/entrypoints/auditor/DefaultAuditorService.ts index 79e206e305..b13565d841 100644 --- a/packages/backend-defaults/src/entrypoints/auditor/DefaultAuditorService.ts +++ b/packages/backend-defaults/src/entrypoints/auditor/DefaultAuditorService.ts @@ -48,7 +48,7 @@ export type AuditorEventStatus = | { status: 'succeeded' } | { status: 'failed'; - error: string; + error: Error; }; /** @@ -195,7 +195,7 @@ export class DefaultAuditorService implements AuditorService { await this.log({ ...options, ...params, - error: String(params.error), + error: params.error, meta: { ...options.meta, ...params?.meta }, status: 'failed', }); diff --git a/packages/backend-defaults/src/entrypoints/auditor/WinstonRootAuditorService.test.ts b/packages/backend-defaults/src/entrypoints/auditor/WinstonRootAuditorService.test.ts index 2d9a959c64..d8ffda2473 100644 --- a/packages/backend-defaults/src/entrypoints/auditor/WinstonRootAuditorService.test.ts +++ b/packages/backend-defaults/src/entrypoints/auditor/WinstonRootAuditorService.test.ts @@ -32,6 +32,7 @@ describe('WinstonRootAuditorService', () => { plugin: { getId: () => 'test-plugin', }, + config: mockServices.rootConfig.mock(), }); expect(childLogger).toBeInstanceOf(DefaultAuditorService); }); @@ -45,6 +46,7 @@ describe('WinstonRootAuditorService', () => { plugin: { getId: () => pluginId, }, + config: mockServices.rootConfig.mock(), }); // workaround to spy on private method const auditorSpy = jest.spyOn(auditor as any, 'log'); @@ -68,6 +70,7 @@ describe('WinstonRootAuditorService', () => { plugin: { getId: () => pluginId, }, + config: mockServices.rootConfig.mock(), }); // workaround to spy on private method const auditorSpy = jest.spyOn(auditor as any, 'log'); @@ -95,6 +98,7 @@ describe('WinstonRootAuditorService', () => { plugin: { getId: () => pluginId, }, + config: mockServices.rootConfig.mock(), }); // workaround to spy on private method const auditorSpy = jest.spyOn(auditor as any, 'log'); @@ -111,7 +115,7 @@ describe('WinstonRootAuditorService', () => { eventId: 'test-event', meta: {}, status: 'failed', - error: error.toString(), + error, }); }); @@ -124,6 +128,7 @@ describe('WinstonRootAuditorService', () => { plugin: { getId: () => pluginId, }, + config: mockServices.rootConfig.mock(), }); // workaround to spy on private method const auditorSpy = jest.spyOn(auditor as any, 'log'); @@ -163,7 +168,7 @@ describe('WinstonRootAuditorService', () => { initiated: 'test', failed: 'test', }, - error: error.toString(), + error, }); }); }); diff --git a/packages/backend-defaults/src/entrypoints/auditor/WinstonRootAuditorService.ts b/packages/backend-defaults/src/entrypoints/auditor/WinstonRootAuditorService.ts index 6ea5d02606..67a28cf74b 100644 --- a/packages/backend-defaults/src/entrypoints/auditor/WinstonRootAuditorService.ts +++ b/packages/backend-defaults/src/entrypoints/auditor/WinstonRootAuditorService.ts @@ -20,11 +20,13 @@ import type { HttpAuthService, PluginMetadataService, } from '@backstage/backend-plugin-api'; +import { Config } from '@backstage/config'; import type { JsonObject } from '@backstage/types'; import type { Format } from 'logform'; import * as winston from 'winston'; import { WinstonLogger } from '../rootLogger'; import { DefaultAuditorService } from './DefaultAuditorService'; +import { getSeverityLogLevelMappings } from './utils'; /** @public */ export const defaultFormatter = winston.format.combine( @@ -108,12 +110,28 @@ export class WinstonRootAuditorService { forPlugin(deps: { auth: AuthService; + config: Config; httpAuth: HttpAuthService; plugin: PluginMetadataService; }): AuditorService { - return DefaultAuditorService.create( - e => this.winstonLogger.info(`${e.plugin}.${e.eventId}`, e), - deps, - ); + const severityLogLevelMappings = getSeverityLogLevelMappings(deps.config); + + return DefaultAuditorService.create(event => { + if ('error' in event) { + const { error, ...rest } = event; + const childAuditLogger = this.winstonLogger.child(rest); + + childAuditLogger[severityLogLevelMappings[event.severityLevel]]( + `${event.plugin}.${event.eventId}`, + error, + ); + } else { + // the else statement is required for typechecking + this.winstonLogger[severityLogLevelMappings[event.severityLevel]]( + `${event.plugin}.${event.eventId}`, + event, + ); + } + }, deps); } } diff --git a/packages/backend-defaults/src/entrypoints/auditor/auditorServiceFactory.ts b/packages/backend-defaults/src/entrypoints/auditor/auditorServiceFactory.ts index 34ea627762..3c82f95ce6 100644 --- a/packages/backend-defaults/src/entrypoints/auditor/auditorServiceFactory.ts +++ b/packages/backend-defaults/src/entrypoints/auditor/auditorServiceFactory.ts @@ -19,15 +19,7 @@ import { createServiceFactory, } from '@backstage/backend-plugin-api'; import { DefaultAuditorService } from './DefaultAuditorService'; -import { z } from 'zod'; -import { InputError } from '@backstage/errors'; - -const CONFIG_ROOT_KEY = 'backend.auditor'; - -const severityLogLevelMappingsSchema = z.record( - z.enum(['low', 'medium', 'high', 'critical']), - z.enum(['debug', 'info', 'warn', 'error']), -); +import { getSeverityLogLevelMappings } from './utils'; /** * Plugin-level auditing. @@ -49,47 +41,26 @@ export const auditorServiceFactory = createServiceFactory({ }, factory({ config, logger, plugin, auth, httpAuth }) { const auditLogger = logger.child({ isAuditEvent: true }); - const auditorConfig = config.getOptionalConfig(CONFIG_ROOT_KEY); - const severityLogLevelMappings = { - low: - auditorConfig?.getOptionalString('severityLogLevelMappings.low') ?? - 'debug', - medium: - auditorConfig?.getOptionalString('severityLogLevelMappings.medium') ?? - 'info', - high: - auditorConfig?.getOptionalString('severityLogLevelMappings.high') ?? - 'info', - critical: - auditorConfig?.getOptionalString('severityLogLevelMappings.critical') ?? - 'info', - } as Required>; - - const res = severityLogLevelMappingsSchema.safeParse( - severityLogLevelMappings, - ); - if (!res.success) { - const key = res.error.issues.at(0)?.path.at(0) as string; - const value = ( - res.error.issues.at(0) as unknown as Record - ).received as string; - const validKeys = ( - res.error.issues.at(0) as unknown as Record - ).options as string[]; - throw new InputError( - `The configuration value for 'backend.auditor.severityLogLevelMappings.${key}' was given an invalid value: '${value}'. Expected one of the following valid values: '${validKeys.join( - ', ', - )}'.`, - ); - } + const severityLogLevelMappings = getSeverityLogLevelMappings(config); return DefaultAuditorService.create( event => { - auditLogger[severityLogLevelMappings[event.severityLevel]]( - `${event.plugin}.${event.eventId}`, - event, - ); + if ('error' in event) { + const { error, ...rest } = event; + const childAuditLogger = auditLogger.child(rest); + + childAuditLogger[severityLogLevelMappings[event.severityLevel]]( + `${event.plugin}.${event.eventId}`, + error, + ); + } else { + // the else statement is required for typechecking + auditLogger[severityLogLevelMappings[event.severityLevel]]( + `${event.plugin}.${event.eventId}`, + event, + ); + } }, { plugin, auth, httpAuth }, ); diff --git a/packages/backend-defaults/src/entrypoints/auditor/types.ts b/packages/backend-defaults/src/entrypoints/auditor/types.ts new file mode 100644 index 0000000000..7827a31d1f --- /dev/null +++ b/packages/backend-defaults/src/entrypoints/auditor/types.ts @@ -0,0 +1,26 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { z } from 'zod'; + +/** @internal */ +export const severityLogLevelMappingsSchema = z.record( + z.enum(['low', 'medium', 'high', 'critical']), + z.enum(['debug', 'info', 'warn', 'error']), +); + +/** @internal */ +export const CONFIG_ROOT_KEY = 'backend.auditor'; diff --git a/packages/backend-defaults/src/entrypoints/auditor/utils.ts b/packages/backend-defaults/src/entrypoints/auditor/utils.ts new file mode 100644 index 0000000000..719a227bf9 --- /dev/null +++ b/packages/backend-defaults/src/entrypoints/auditor/utils.ts @@ -0,0 +1,66 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { Config } from '@backstage/config'; +import { InputError } from '@backstage/errors'; +import { z } from 'zod'; +import { CONFIG_ROOT_KEY, severityLogLevelMappingsSchema } from './types'; + +/** + * Gets the `backend.auditor.severityLogLevelMappings` configuration. + * + * @param config - The root Backstage {@link @backstage/config#Config} object. + * @returns The validated severity-to-log-level mappings. + * @throws error - {@link @backstage/errors#InputError} if the mapping configuration is invalid. + */ +export function getSeverityLogLevelMappings(config: Config) { + const auditorConfig = config.getOptionalConfig(CONFIG_ROOT_KEY); + + const severityLogLevelMappings = { + low: + auditorConfig?.getOptionalString('severityLogLevelMappings.low') ?? + 'debug', + medium: + auditorConfig?.getOptionalString('severityLogLevelMappings.medium') ?? + 'info', + high: + auditorConfig?.getOptionalString('severityLogLevelMappings.high') ?? + 'info', + critical: + auditorConfig?.getOptionalString('severityLogLevelMappings.critical') ?? + 'info', + } as Required>; + + const res = severityLogLevelMappingsSchema.safeParse( + severityLogLevelMappings, + ); + if (!res.success) { + const key = res.error.issues.at(0)?.path.at(0) as string; + const value = ( + res.error.issues.at(0) as unknown as Record + ).received as string; + const validKeys = ( + res.error.issues.at(0) as unknown as Record + ).options as string[]; + throw new InputError( + `The configuration value for 'backend.auditor.severityLogLevelMappings.${key}' was given an invalid value: '${value}'. Expected one of the following valid values: '${validKeys.join( + ', ', + )}'.`, + ); + } + + return severityLogLevelMappings; +} diff --git a/packages/backend-defaults/src/entrypoints/httpRouter/http/createRateLimitMiddleware.ts b/packages/backend-defaults/src/entrypoints/httpRouter/http/createRateLimitMiddleware.ts new file mode 100644 index 0000000000..b139b212d2 --- /dev/null +++ b/packages/backend-defaults/src/entrypoints/httpRouter/http/createRateLimitMiddleware.ts @@ -0,0 +1,40 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { NextFunction, Request, Response } from 'express'; +import { RateLimitStoreFactory } from '../../../lib/RateLimitStoreFactory.ts'; +import { Config } from '@backstage/config'; +import { rateLimitMiddleware } from '../../../lib/rateLimitMiddleware.ts'; + +export const createRateLimitMiddleware = (options: { + pluginId: string; + config: Config; +}) => { + const { pluginId, config } = options; + const configKey = `backend.rateLimit.plugin.${pluginId}`; + const enabled = config.has(configKey); + if (!enabled) { + return (_req: Request, _res: Response, next: NextFunction) => { + next(); + }; + } + + const rateLimitOptions = config.getConfig(configKey); + + return rateLimitMiddleware({ + store: RateLimitStoreFactory.create({ config, prefix: pluginId }), + config: rateLimitOptions, + }); +}; diff --git a/packages/backend-defaults/src/entrypoints/httpRouter/httpRouterServiceFactory.ts b/packages/backend-defaults/src/entrypoints/httpRouter/httpRouterServiceFactory.ts index 1f2b989018..0fc70a07f0 100644 --- a/packages/backend-defaults/src/entrypoints/httpRouter/httpRouterServiceFactory.ts +++ b/packages/backend-defaults/src/entrypoints/httpRouter/httpRouterServiceFactory.ts @@ -22,12 +22,13 @@ import { HttpRouterServiceAuthPolicy, } from '@backstage/backend-plugin-api'; import { - createLifecycleMiddleware, + createAuthIntegrationRouter, createCookieAuthRefreshMiddleware, createCredentialsBarrier, - createAuthIntegrationRouter, + createLifecycleMiddleware, } from './http'; import { MiddlewareFactory } from '../rootHttpRouter'; +import { createRateLimitMiddleware } from './http/createRateLimitMiddleware.ts'; /** * HTTP route registration for plugins. @@ -61,6 +62,8 @@ export const httpRouterServiceFactory = createServiceFactory({ }) { const router = PromiseRouter(); + router.use(createRateLimitMiddleware({ pluginId: plugin.getId(), config })); + rootHttpRouter.use(`/api/${plugin.getId()}`, router); const credentialsBarrier = createCredentialsBarrier({ diff --git a/packages/backend-defaults/src/entrypoints/rootHttpRouter/http/MiddlewareFactory.ts b/packages/backend-defaults/src/entrypoints/rootHttpRouter/http/MiddlewareFactory.ts index 1ff9bd15d1..80a10fe0eb 100644 --- a/packages/backend-defaults/src/entrypoints/rootHttpRouter/http/MiddlewareFactory.ts +++ b/packages/backend-defaults/src/entrypoints/rootHttpRouter/http/MiddlewareFactory.ts @@ -15,15 +15,15 @@ */ import { - RootConfigService, LoggerService, + RootConfigService, } from '@backstage/backend-plugin-api'; import { - Request, - Response, ErrorRequestHandler, NextFunction, + Request, RequestHandler, + Response, } from 'express'; import cors from 'cors'; import helmet from 'helmet'; @@ -37,12 +37,14 @@ import { InputError, NotAllowedError, NotFoundError, + NotImplementedError, NotModifiedError, - ServiceUnavailableError, serializeError, + ServiceUnavailableError, } from '@backstage/errors'; -import { NotImplementedError } from '@backstage/errors'; import { applyInternalErrorFilter } from './applyInternalErrorFilter'; +import { RateLimitStoreFactory } from '../../../lib/RateLimitStoreFactory.ts'; +import { rateLimitMiddleware } from '../../../lib/rateLimitMiddleware.ts'; type LogMeta = { date: string; @@ -227,6 +229,47 @@ export class MiddlewareFactory { return cors(readCorsOptions(this.#config.getOptionalConfig('backend'))); } + /** + * Returns a middleware that implements rate limiting. + * + * @remarks + * + * Rate limiting is a common technique to prevent abuse of APIs. This middleware is + * configured using the config key `backend.rateLimit`. + * + * @returns An Express request handler + */ + rateLimit(): RequestHandler { + const enabled = this.#config.has('backend.rateLimit'); + if (!enabled) { + return (_req: Request, _res: Response, next: NextFunction) => { + next(); + }; + } + + const useDefaults = this.#config.getOptional('backend.rateLimit') === true; + const rateLimitOptions = useDefaults + ? undefined + : this.#config.getOptionalConfig('backend.rateLimit'); + + // Global rate limiting disabled + if ( + rateLimitOptions && + rateLimitOptions.getOptionalBoolean('global') === false + ) { + return (_req: Request, _res: Response, next: NextFunction) => { + next(); + }; + } + + return rateLimitMiddleware({ + store: useDefaults + ? undefined + : RateLimitStoreFactory.create({ config: this.#config }), + config: rateLimitOptions, + }); + } + /** * Express middleware to handle errors during request processing. * diff --git a/packages/backend-defaults/src/entrypoints/rootHttpRouter/rootHttpRouterServiceFactory.ts b/packages/backend-defaults/src/entrypoints/rootHttpRouter/rootHttpRouterServiceFactory.ts index da7fcfe3f9..3b50515742 100644 --- a/packages/backend-defaults/src/entrypoints/rootHttpRouter/rootHttpRouterServiceFactory.ts +++ b/packages/backend-defaults/src/entrypoints/rootHttpRouter/rootHttpRouterServiceFactory.ts @@ -15,13 +15,13 @@ */ import { - RootConfigService, coreServices, createServiceFactory, LifecycleService, LoggerService, + RootConfigService, } from '@backstage/backend-plugin-api'; -import express, { RequestHandler, Express } from 'express'; +import express, { Express, RequestHandler } from 'express'; import type { Server } from 'node:http'; import { createHttpServer, @@ -121,6 +121,7 @@ const rootHttpRouterServiceFactoryWithOptions = ( app.use(middleware.cors()); app.use(middleware.compression()); app.use(middleware.logging()); + app.use(middleware.rateLimit()); app.use(healthRouter); app.use(routes); app.use(middleware.notFound()); diff --git a/packages/backend-defaults/src/lib/RateLimitStoreFactory.test.ts b/packages/backend-defaults/src/lib/RateLimitStoreFactory.test.ts new file mode 100644 index 0000000000..684c204cb8 --- /dev/null +++ b/packages/backend-defaults/src/lib/RateLimitStoreFactory.test.ts @@ -0,0 +1,68 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { mockServices } from '@backstage/backend-test-utils'; +import { RateLimitStoreFactory } from './RateLimitStoreFactory.ts'; +import { RedisStore } from 'rate-limit-redis'; + +jest.mock('@keyv/redis', () => { + const Actual = jest.requireActual('@keyv/redis'); + return { + ...Actual, + __esModule: true, + default: jest.fn(() => { + return { + getClient: jest.fn(() => ({ + sendCommand: jest.fn().mockReturnValue('mock'), + })), + }; + }), + }; +}); + +describe('CacheRateLimitStoreFactory', () => { + afterEach(jest.clearAllMocks); + + it('should return undefined store with auto configuration if redis is not available', () => { + const config = mockServices.rootConfig({ + data: { + backend: { + rateLimit: { + store: undefined, + }, + }, + }, + }); + const store = RateLimitStoreFactory.create({ config }); + expect(store).toBeUndefined(); + }); + + it('should return redis store if configured explicitly', async () => { + const config = mockServices.rootConfig({ + data: { + backend: { + rateLimit: { + store: { + type: 'redis', + connection: 'redis://localhost:6379', + }, + }, + }, + }, + }); + const store = RateLimitStoreFactory.create({ config }); + expect(store).toBeInstanceOf(RedisStore); + }); +}); diff --git a/packages/backend-defaults/src/lib/RateLimitStoreFactory.ts b/packages/backend-defaults/src/lib/RateLimitStoreFactory.ts new file mode 100644 index 0000000000..9df6f03225 --- /dev/null +++ b/packages/backend-defaults/src/lib/RateLimitStoreFactory.ts @@ -0,0 +1,58 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { Config } from '@backstage/config'; +import type { Store } from 'express-rate-limit'; +import { RedisStore } from 'rate-limit-redis'; + +/** + * Creates a store for `express-rate-limit` based on the configuration. + * + * @internal + */ +export class RateLimitStoreFactory { + static create(options: { + config: Config; + prefix?: string; + }): Store | undefined { + const { config, prefix } = options; + const store = config.getOptionalConfig('backend.rateLimit.store'); + if (!store) { + return undefined; + } + const type = store.getString('type'); + switch (type) { + case 'redis': + return this.redis({ store, prefix }); + case 'memory': + default: + return undefined; + } + } + + private static redis(options: { store: Config; prefix?: string }): Store { + const { store, prefix } = options; + const connectionString = store.getString('connection'); + const KeyvRedis = require('@keyv/redis').default; + const keyv = new KeyvRedis(connectionString); + return new RedisStore({ + prefix, + sendCommand: async (...args: string[]) => { + const client = await keyv.getClient(); + return client.sendCommand(args); + }, + }); + } +} diff --git a/packages/backend-defaults/src/lib/rateLimitMiddleware.ts b/packages/backend-defaults/src/lib/rateLimitMiddleware.ts new file mode 100644 index 0000000000..57163b5908 --- /dev/null +++ b/packages/backend-defaults/src/lib/rateLimitMiddleware.ts @@ -0,0 +1,81 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { RequestHandler } from 'express'; +import { rateLimit, Store } from 'express-rate-limit'; +import { Config, readDurationFromConfig } from '@backstage/config'; +import { durationToMilliseconds } from '@backstage/types'; + +export const rateLimitMiddleware = (options: { + store?: Store; + config?: Config; +}): RequestHandler => { + const { store, config } = options; + let windowMs: number = 60000; + if (config && config.has('window')) { + const windowDuration = readDurationFromConfig(config, { + key: 'window', + }); + windowMs = durationToMilliseconds(windowDuration); + } + const limit = config?.getOptionalNumber('incomingRequestLimit'); + const ipAllowList = config?.getOptionalStringArray('ipAllowList') ?? [ + '127.0.0.1', + '0:0:0:0:0:0:0:1', + '::1', + ]; + const skipSuccessfulRequests = config?.getOptionalBoolean( + 'skipSuccessfulRequests', + ); + const skipFailedRequests = config?.getOptionalBoolean('skipFailedRequests'); + const passOnStoreError = config?.getOptionalBoolean('passOnStoreError'); + + return rateLimit({ + windowMs, + limit, + skipSuccessfulRequests, + message: { + error: { + name: 'Error', + message: `Too many requests, please try again later`, + }, + response: { + statusCode: 429, + }, + }, + statusCode: 429, + skipFailedRequests, + passOnStoreError: passOnStoreError, + keyGenerator(req, _res): string { + if (!req.ip) { + return req.socket.remoteAddress!; + } + return req.ip; + }, + skip: (req, _res) => { + return ( + Boolean(req.ip && ipAllowList.includes(req.ip)) || + Boolean( + req.socket.remoteAddress && + ipAllowList.includes(req.socket.remoteAddress), + ) + ); + }, + validate: { + trustProxy: false, + }, + store, + }); +}; diff --git a/packages/backend-dynamic-feature-service/CHANGELOG.md b/packages/backend-dynamic-feature-service/CHANGELOG.md index 390629ace4..01548dc489 100644 --- a/packages/backend-dynamic-feature-service/CHANGELOG.md +++ b/packages/backend-dynamic-feature-service/CHANGELOG.md @@ -1,5 +1,56 @@ # @backstage/backend-dynamic-feature-service +## 0.7.1 + +### Patch Changes + +- c83cd8b: Fixed some circular or otherwise unclear imports +- Updated dependencies + - @backstage/backend-defaults@0.11.0 + - @backstage/plugin-scaffolder-node@0.9.0 + - @backstage/plugin-catalog-backend@2.1.0 + - @backstage/plugin-events-backend@0.5.3 + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/backend-openapi-utils@0.5.4 + - @backstage/cli-common@0.1.15 + - @backstage/cli-node@0.2.13 + - @backstage/config@1.3.2 + - @backstage/config-loader@1.10.1 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/plugin-app-node@0.1.34 + - @backstage/plugin-events-node@0.4.12 + - @backstage/plugin-permission-common@0.9.0 + - @backstage/plugin-permission-node@0.10.1 + - @backstage/plugin-search-backend-node@1.3.12 + - @backstage/plugin-search-common@1.2.18 + +## 0.7.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.11.0-next.2 + - @backstage/plugin-catalog-backend@2.0.1-next.2 + - @backstage/plugin-scaffolder-node@0.9.0-next.2 + - @backstage/backend-openapi-utils@0.5.4-next.1 + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/cli-common@0.1.15 + - @backstage/cli-node@0.2.13 + - @backstage/config@1.3.2 + - @backstage/config-loader@1.10.1 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/plugin-app-node@0.1.34-next.1 + - @backstage/plugin-auth-node@0.6.4-next.1 + - @backstage/plugin-events-backend@0.5.3-next.1 + - @backstage/plugin-events-node@0.4.12-next.1 + - @backstage/plugin-permission-common@0.9.0 + - @backstage/plugin-permission-node@0.10.1-next.1 + - @backstage/plugin-search-backend-node@1.3.12-next.1 + - @backstage/plugin-search-common@1.2.18 + ## 0.7.1-next.1 ### Patch Changes diff --git a/packages/backend-dynamic-feature-service/package.json b/packages/backend-dynamic-feature-service/package.json index bf2a88e015..0b49364260 100644 --- a/packages/backend-dynamic-feature-service/package.json +++ b/packages/backend-dynamic-feature-service/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/backend-dynamic-feature-service", - "version": "0.7.1-next.1", + "version": "0.7.1", "description": "Backstage dynamic feature service", "backstage": { "role": "node-library" diff --git a/packages/backend-dynamic-feature-service/src/schema/openapi/generated/router.ts b/packages/backend-dynamic-feature-service/src/schema/openapi/generated/router.ts index 9f1ef68a77..cf48bcfc95 100644 --- a/packages/backend-dynamic-feature-service/src/schema/openapi/generated/router.ts +++ b/packages/backend-dynamic-feature-service/src/schema/openapi/generated/router.ts @@ -18,7 +18,7 @@ // * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * // ****************************************************************** import { createValidatedOpenApiRouterFromGeneratedEndpointMap } from '@backstage/backend-openapi-utils'; -import { EndpointMap } from './'; +import { EndpointMap } from './apis'; export const spec = { openapi: '3.0.3', diff --git a/packages/backend-openapi-utils/CHANGELOG.md b/packages/backend-openapi-utils/CHANGELOG.md index bfdc32df2e..1e1117b448 100644 --- a/packages/backend-openapi-utils/CHANGELOG.md +++ b/packages/backend-openapi-utils/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/backend-openapi-utils +## 0.5.4 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.0 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + ## 0.5.4-next.1 ### Patch Changes diff --git a/packages/backend-openapi-utils/package.json b/packages/backend-openapi-utils/package.json index d4b17a4e61..5bacdc4709 100644 --- a/packages/backend-openapi-utils/package.json +++ b/packages/backend-openapi-utils/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/backend-openapi-utils", - "version": "0.5.4-next.1", + "version": "0.5.4", "description": "OpenAPI typescript support.", "backstage": { "role": "node-library" diff --git a/packages/backend-plugin-api/CHANGELOG.md b/packages/backend-plugin-api/CHANGELOG.md index 3aea27d1de..c3f0dffa3e 100644 --- a/packages/backend-plugin-api/CHANGELOG.md +++ b/packages/backend-plugin-api/CHANGELOG.md @@ -1,5 +1,48 @@ # @backstage/backend-plugin-api +## 1.4.0 + +### Minor Changes + +- 664c07a: Added `actionsRegistry` and `actions` experimental services to `/alpha` to allow registration of distributed actions from plugins, and the ability to invoke these actions. You can use these services by including them like the following: + + ```ts + import { + actionsRegistryServiceRef, + actionsServiceRef, + } from '@backstage/backend-plugin-api/alpha'; + + createBackendPlugin({ + pluginId: 'test-plugin', + register({ registerInit }) { + registerInit({ + deps: { + actions: actionsServiceRef, + actionsRegistry: actionsRegistryServiceRef, + }, + async init({ actions, actionsRegistry }) { + actionsRegistry.register({ + ..., + }); + + await actions.invoke(...); + }, + }); + }, + }); + ``` + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.4 + - @backstage/cli-common@0.1.15 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/plugin-permission-common@0.9.0 + - @backstage/plugin-permission-node@0.10.1 + ## 1.4.0-next.1 ### Patch Changes diff --git a/packages/backend-plugin-api/package.json b/packages/backend-plugin-api/package.json index 52c1c6a66a..61228fd228 100644 --- a/packages/backend-plugin-api/package.json +++ b/packages/backend-plugin-api/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/backend-plugin-api", - "version": "1.4.0-next.1", + "version": "1.4.0", "description": "Core API used by Backstage backend plugins", "backstage": { "role": "node-library" @@ -20,7 +20,7 @@ "license": "Apache-2.0", "exports": { ".": "./src/index.ts", - "./alpha": "./src/alpha.ts", + "./alpha": "./src/alpha/index.ts", "./testUtils": "./src/testUtils.ts", "./package.json": "./package.json" }, @@ -29,7 +29,7 @@ "typesVersions": { "*": { "alpha": [ - "src/alpha.ts" + "src/alpha/index.ts" ], "testUtils": [ "src/testUtils.ts" diff --git a/packages/backend-plugin-api/report-alpha.api.md b/packages/backend-plugin-api/report-alpha.api.md index d485e2132e..9be7a29ed5 100644 --- a/packages/backend-plugin-api/report-alpha.api.md +++ b/packages/backend-plugin-api/report-alpha.api.md @@ -3,7 +3,105 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts +import { AnyZodObject } from 'zod'; +import { BackstageCredentials } from '@backstage/backend-plugin-api'; +import { JsonObject } from '@backstage/types'; +import { JSONSchema7 } from 'json-schema'; +import { JsonValue } from '@backstage/types'; +import { LoggerService } from '@backstage/backend-plugin-api'; import { ServiceRef } from '@backstage/backend-plugin-api'; +import { z } from 'zod'; + +// @alpha (undocumented) +export type ActionsRegistryActionContext = { + input: z.infer; + logger: LoggerService; + credentials: BackstageCredentials; +}; + +// @alpha (undocumented) +export type ActionsRegistryActionOptions< + TInputSchema extends AnyZodObject, + TOutputSchema extends AnyZodObject, +> = { + name: string; + title: string; + description: string; + schema: { + input: (zod: typeof z) => TInputSchema; + output: (zod: typeof z) => TOutputSchema; + }; + attributes?: { + destructive?: boolean; + idempotent?: boolean; + readOnly?: boolean; + }; + action: (context: ActionsRegistryActionContext) => Promise< + z.infer extends void + ? void + : { + output: z.infer; + } + >; +}; + +// @alpha (undocumented) +export interface ActionsRegistryService { + // (undocumented) + register< + TInputSchema extends AnyZodObject, + TOutputSchema extends AnyZodObject, + >( + options: ActionsRegistryActionOptions, + ): void; +} + +// @alpha +export const actionsRegistryServiceRef: ServiceRef< + ActionsRegistryService, + 'plugin', + 'singleton' +>; + +// @alpha (undocumented) +export interface ActionsService { + // (undocumented) + invoke(opts: { + id: string; + input?: JsonObject; + credentials: BackstageCredentials; + }): Promise<{ + output: JsonValue; + }>; + // (undocumented) + list: (opts: { credentials: BackstageCredentials }) => Promise<{ + actions: ActionsServiceAction[]; + }>; +} + +// @alpha (undocumented) +export type ActionsServiceAction = { + id: string; + name: string; + title: string; + description: string; + schema: { + input: JSONSchema7; + output: JSONSchema7; + }; + attributes: { + readOnly: boolean; + destructive: boolean; + idempotent: boolean; + }; +}; + +// @alpha +export const actionsServiceRef: ServiceRef< + ActionsService, + 'plugin', + 'singleton' +>; // @alpha (undocumented) export type BackendFeatureMeta = @@ -23,7 +121,7 @@ export interface InstanceMetadataService { getInstalledFeatures: () => BackendFeatureMeta[]; } -// @alpha +// @alpha (undocumented) export const instanceMetadataServiceRef: ServiceRef< InstanceMetadataService, 'plugin', diff --git a/packages/backend-plugin-api/report.api.md b/packages/backend-plugin-api/report.api.md index 68597dcbe1..52843dec96 100644 --- a/packages/backend-plugin-api/report.api.md +++ b/packages/backend-plugin-api/report.api.md @@ -12,7 +12,6 @@ import type { Handler } from 'express'; import { HumanDuration } from '@backstage/types'; import { isChildPath } from '@backstage/cli-common'; import { JsonObject } from '@backstage/types'; -import { JSONSchema7 } from 'json-schema'; import { JsonValue } from '@backstage/types'; import { Knex } from 'knex'; import { Permission } from '@backstage/plugin-permission-common'; @@ -26,72 +25,6 @@ import { QueryPermissionResponse } from '@backstage/plugin-permission-common'; import { Readable } from 'stream'; import type { Request as Request_2 } from 'express'; import type { Response as Response_2 } from 'express'; -import { z } from 'zod'; -import { ZodType } from 'zod'; - -// @public (undocumented) -export type ActionsRegistryActionContext = { - input: z.infer; - logger: LoggerService; - credentials: BackstageCredentials; -}; - -// @public (undocumented) -export type ActionsRegistryActionOptions< - TInputSchema extends ZodType, - TOutputSchema extends ZodType, -> = { - name: string; - title: string; - description: string; - schema: { - input: (zod: typeof z) => TInputSchema; - output: (zod: typeof z) => TOutputSchema; - }; - action: (context: ActionsRegistryActionContext) => Promise< - z.infer extends void - ? void - : { - output: z.infer; - } - >; -}; - -// @public (undocumented) -export interface ActionsRegistryService { - // (undocumented) - register( - options: ActionsRegistryActionOptions, - ): void; -} - -// @public (undocumented) -export interface ActionsService { - // (undocumented) - invoke(opts: { - id: string; - input?: JsonObject; - credentials: BackstageCredentials; - }): Promise<{ - output: JsonValue; - }>; - // (undocumented) - list: (opts: { credentials: BackstageCredentials }) => Promise<{ - actions: ActionsServiceAction[]; - }>; -} - -// @public (undocumented) -export type ActionsServiceAction = { - id: string; - name: string; - title: string; - description: string; - schema: { - input: JSONSchema7; - output: JSONSchema7; - }; -}; // @public export interface AuditorService { @@ -272,12 +205,6 @@ export type CacheServiceSetOptions = { // @public export namespace coreServices { const auth: ServiceRef; - const actions: ServiceRef; - const actionsRegistry: ServiceRef< - ActionsRegistryService, - 'plugin', - 'singleton' - >; const userInfo: ServiceRef; const cache: ServiceRef; const rootConfig: ServiceRef; diff --git a/packages/backend-plugin-api/src/alpha/ActionsRegistryService.ts b/packages/backend-plugin-api/src/alpha/ActionsRegistryService.ts new file mode 100644 index 0000000000..9a7820e354 --- /dev/null +++ b/packages/backend-plugin-api/src/alpha/ActionsRegistryService.ts @@ -0,0 +1,69 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { z, AnyZodObject } from 'zod'; +import { + LoggerService, + BackstageCredentials, +} from '@backstage/backend-plugin-api'; + +/** + * @alpha + */ +export type ActionsRegistryActionContext = { + input: z.infer; + logger: LoggerService; + credentials: BackstageCredentials; +}; + +/** + * @alpha + */ +export type ActionsRegistryActionOptions< + TInputSchema extends AnyZodObject, + TOutputSchema extends AnyZodObject, +> = { + name: string; + title: string; + description: string; + schema: { + input: (zod: typeof z) => TInputSchema; + output: (zod: typeof z) => TOutputSchema; + }; + attributes?: { + destructive?: boolean; + idempotent?: boolean; + readOnly?: boolean; + }; + action: ( + context: ActionsRegistryActionContext, + ) => Promise< + z.infer extends void + ? void + : { output: z.infer } + >; +}; + +/** + * @alpha + */ +export interface ActionsRegistryService { + register< + TInputSchema extends AnyZodObject, + TOutputSchema extends AnyZodObject, + >( + options: ActionsRegistryActionOptions, + ): void; +} diff --git a/packages/backend-plugin-api/src/alpha/ActionsService.ts b/packages/backend-plugin-api/src/alpha/ActionsService.ts new file mode 100644 index 0000000000..528b6cea67 --- /dev/null +++ b/packages/backend-plugin-api/src/alpha/ActionsService.ts @@ -0,0 +1,51 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { JsonObject, JsonValue } from '@backstage/types'; +import { JSONSchema7 } from 'json-schema'; +import { BackstageCredentials } from '@backstage/backend-plugin-api'; + +/** + * @alpha + */ +export type ActionsServiceAction = { + id: string; + name: string; + title: string; + description: string; + schema: { + input: JSONSchema7; + output: JSONSchema7; + }; + attributes: { + readOnly: boolean; + destructive: boolean; + idempotent: boolean; + }; +}; + +/** + * @alpha + */ +export interface ActionsService { + list: (opts: { + credentials: BackstageCredentials; + }) => Promise<{ actions: ActionsServiceAction[] }>; + invoke(opts: { + id: string; + input?: JsonObject; + credentials: BackstageCredentials; + }): Promise<{ output: JsonValue }>; +} diff --git a/packages/backend-plugin-api/src/services/definitions/InstanceMetadataService.ts b/packages/backend-plugin-api/src/alpha/InstanceMetadataService.ts similarity index 100% rename from packages/backend-plugin-api/src/services/definitions/InstanceMetadataService.ts rename to packages/backend-plugin-api/src/alpha/InstanceMetadataService.ts diff --git a/packages/backend-plugin-api/src/alpha.ts b/packages/backend-plugin-api/src/alpha/index.ts similarity index 60% rename from packages/backend-plugin-api/src/alpha.ts rename to packages/backend-plugin-api/src/alpha/index.ts index 6e91e10671..5bb69eb4e2 100644 --- a/packages/backend-plugin-api/src/alpha.ts +++ b/packages/backend-plugin-api/src/alpha/index.ts @@ -1,5 +1,5 @@ /* - * Copyright 2023 The Backstage Authors + * Copyright 2025 The Backstage Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,20 +14,21 @@ * limitations under the License. */ -import { createServiceRef } from '@backstage/backend-plugin-api'; - -/** - * EXPERIMENTAL: Instance metadata service. - * - * @alpha - */ -export const instanceMetadataServiceRef = createServiceRef< - import('./services/definitions/InstanceMetadataService').InstanceMetadataService ->({ - id: 'core.instanceMetadata', -}); - export type { BackendFeatureMeta, InstanceMetadataService, -} from './services/definitions/InstanceMetadataService'; +} from './InstanceMetadataService'; + +export type { + ActionsRegistryService, + ActionsRegistryActionOptions, + ActionsRegistryActionContext, +} from './ActionsRegistryService'; + +export type { ActionsService, ActionsServiceAction } from './ActionsService'; + +export { + actionsRegistryServiceRef, + actionsServiceRef, + instanceMetadataServiceRef, +} from './refs'; diff --git a/packages/backend-plugin-api/src/alpha/refs.ts b/packages/backend-plugin-api/src/alpha/refs.ts new file mode 100644 index 0000000000..81996679f7 --- /dev/null +++ b/packages/backend-plugin-api/src/alpha/refs.ts @@ -0,0 +1,56 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { createServiceRef } from '@backstage/backend-plugin-api'; + +/** + * @alpha + */ +export const instanceMetadataServiceRef = createServiceRef< + import('./InstanceMetadataService').InstanceMetadataService +>({ + id: 'core.instanceMetadata', +}); + +/** + * Service for calling distributed actions + * + * See {@link ActionsService} + * and {@link https://backstage.io/docs/backend-system/core-services/actions | the service docs} + * for more information. + * + * @alpha + */ +export const actionsServiceRef = createServiceRef< + import('./ActionsService').ActionsService +>({ + id: 'alpha.core.actions', +}); + +/** + * Service for registering and managing distributed actions. + * + * See {@link ActionsRegistryService} + * and {@link https://backstage.io/docs/backend-system/core-services/actions-registry | the service docs} + * for more information. + * + * @alpha + */ +export const actionsRegistryServiceRef = createServiceRef< + import('./ActionsRegistryService').ActionsRegistryService +>({ + id: 'alpha.core.actionsRegistry', +}); diff --git a/packages/backend-plugin-api/src/services/definitions/ActionsRegistryService.ts b/packages/backend-plugin-api/src/services/definitions/ActionsRegistryService.ts index 3044c84ed8..6c0936f85c 100644 --- a/packages/backend-plugin-api/src/services/definitions/ActionsRegistryService.ts +++ b/packages/backend-plugin-api/src/services/definitions/ActionsRegistryService.ts @@ -13,14 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { z, ZodType } from 'zod'; +import { z, AnyZodObject } from 'zod'; import { LoggerService } from './LoggerService'; import { BackstageCredentials } from './AuthService'; /** * @public */ -export type ActionsRegistryActionContext = { +export type ActionsRegistryActionContext = { input: z.infer; logger: LoggerService; credentials: BackstageCredentials; @@ -30,8 +30,8 @@ export type ActionsRegistryActionContext = { * @public */ export type ActionsRegistryActionOptions< - TInputSchema extends ZodType, - TOutputSchema extends ZodType, + TInputSchema extends AnyZodObject, + TOutputSchema extends AnyZodObject, > = { name: string; title: string; @@ -40,6 +40,11 @@ export type ActionsRegistryActionOptions< input: (zod: typeof z) => TInputSchema; output: (zod: typeof z) => TOutputSchema; }; + attributes?: { + destructive?: boolean; + idempotent?: boolean; + readOnly?: boolean; + }; action: ( context: ActionsRegistryActionContext, ) => Promise< @@ -53,7 +58,10 @@ export type ActionsRegistryActionOptions< * @public */ export interface ActionsRegistryService { - register( + register< + TInputSchema extends AnyZodObject, + TOutputSchema extends AnyZodObject, + >( options: ActionsRegistryActionOptions, ): void; } diff --git a/packages/backend-plugin-api/src/services/definitions/ActionsService.ts b/packages/backend-plugin-api/src/services/definitions/ActionsService.ts index 69b13afaaa..d595008a42 100644 --- a/packages/backend-plugin-api/src/services/definitions/ActionsService.ts +++ b/packages/backend-plugin-api/src/services/definitions/ActionsService.ts @@ -29,6 +29,11 @@ export type ActionsServiceAction = { input: JSONSchema7; output: JSONSchema7; }; + attributes: { + readOnly: boolean; + destructive: boolean; + idempotent: boolean; + }; }; /** diff --git a/packages/backend-plugin-api/src/services/definitions/coreServices.ts b/packages/backend-plugin-api/src/services/definitions/coreServices.ts index c5282368ac..8c8c6c0f82 100644 --- a/packages/backend-plugin-api/src/services/definitions/coreServices.ts +++ b/packages/backend-plugin-api/src/services/definitions/coreServices.ts @@ -35,36 +35,6 @@ export namespace coreServices { id: 'core.auth', }); - /** - * Service for calling distributed actions - * - * See {@link ActionsService} - * and {@link https://backstage.io/docs/backend-system/core-services/actions | the service docs} - * for more information. - * - * @public - */ - export const actions = createServiceRef< - import('./ActionsService').ActionsService - >({ - id: 'core.actions', - }); - - /** - * Service for registering and managing distributed actions. - * - * See {@link ActionsRegistryService} - * and {@link https://backstage.io/docs/backend-system/core-services/actions-registry | the service docs} - * for more information. - * - * @public - */ - export const actionsRegistry = createServiceRef< - import('./ActionsRegistryService').ActionsRegistryService - >({ - id: 'core.actionsRegistry', - }); - /** * Authenticated user information retrieval. * diff --git a/packages/backend-plugin-api/src/services/definitions/index.ts b/packages/backend-plugin-api/src/services/definitions/index.ts index a01544b60f..c811a513a8 100644 --- a/packages/backend-plugin-api/src/services/definitions/index.ts +++ b/packages/backend-plugin-api/src/services/definitions/index.ts @@ -13,14 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -export type { - ActionsRegistryService, - ActionsRegistryActionOptions, - ActionsRegistryActionContext, -} from './ActionsRegistryService'; - -export type { ActionsService, ActionsServiceAction } from './ActionsService'; export type { AuditorService, AuditorServiceCreateEventOptions, diff --git a/packages/backend-test-utils/CHANGELOG.md b/packages/backend-test-utils/CHANGELOG.md index 58c728d457..39d291828e 100644 --- a/packages/backend-test-utils/CHANGELOG.md +++ b/packages/backend-test-utils/CHANGELOG.md @@ -1,5 +1,66 @@ # @backstage/backend-test-utils +## 1.6.0 + +### Minor Changes + +- 6dfb7be: Added `mockServices.permissions()` that can return actual results. +- c999c25: Added an `actionsRegistryServiceMock` and `actionsServiceMock` to `/alpha` export for the experimental services. + + This allows you to write tests for your actions by doing something similar to the following: + + ```ts + import { actionsRegistryServiceMock } from '@backstage/backend-test-utils/alpha'; + + const mockActionsRegistry = actionsRegistryServiceMock(); + const mockCatalog = catalogServiceMock({ + entities: [ + ... + ], + }); + + createGetCatalogEntityAction({ + catalog: mockCatalog, + actionsRegistry: mockActionsRegistry, + }); + + await expect( + mockActionsRegistry.invoke({ + id: 'test:get-catalog-entity', + input: { name: 'test' }, + }), + ).resolves.toEqual(...) + ``` + +### Patch Changes + +- 12c1fd4: Make the `user` credentials mock behave more like production +- Updated dependencies + - @backstage/backend-defaults@0.11.0 + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-app-api@1.2.4 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/plugin-events-node@0.4.12 + - @backstage/plugin-permission-common@0.9.0 + +## 1.6.0-next.2 + +### Patch Changes + +- 12c1fd4: Make the `user` credentials mock behave more like production +- Updated dependencies + - @backstage/backend-defaults@0.11.0-next.2 + - @backstage/backend-app-api@1.2.4-next.2 + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/plugin-auth-node@0.6.4-next.1 + - @backstage/plugin-events-node@0.4.12-next.1 + ## 1.6.0-next.1 ### Patch Changes diff --git a/packages/backend-test-utils/package.json b/packages/backend-test-utils/package.json index 26ba29ad0f..acf3e6f7b3 100644 --- a/packages/backend-test-utils/package.json +++ b/packages/backend-test-utils/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/backend-test-utils", - "version": "1.6.0-next.1", + "version": "1.6.0", "description": "Test helpers library for Backstage backends", "backstage": { "role": "node-library" @@ -21,7 +21,8 @@ "license": "Apache-2.0", "exports": { ".": "./src/index.ts", - "./package.json": "./package.json" + "./package.json": "./package.json", + "./alpha": "./src/alpha/index.ts" }, "main": "src/index.ts", "types": "src/index.ts", @@ -29,6 +30,9 @@ "*": { "package.json": [ "package.json" + ], + "alpha": [ + "src/alpha/index.ts" ] } }, @@ -52,6 +56,7 @@ "@backstage/errors": "workspace:^", "@backstage/plugin-auth-node": "workspace:^", "@backstage/plugin-events-node": "workspace:^", + "@backstage/plugin-permission-common": "workspace:^", "@backstage/types": "workspace:^", "@keyv/memcache": "^2.0.1", "@keyv/redis": "^4.0.1", @@ -72,7 +77,9 @@ "testcontainers": "^10.0.0", "textextensions": "^5.16.0", "uuid": "^11.0.0", - "yn": "^4.0.0" + "yn": "^4.0.0", + "zod": "^3.22.4", + "zod-to-json-schema": "^3.20.4" }, "devDependencies": { "@backstage/cli": "workspace:^", diff --git a/packages/backend-test-utils/report-alpha.api.md b/packages/backend-test-utils/report-alpha.api.md new file mode 100644 index 0000000000..ccbf96c0c7 --- /dev/null +++ b/packages/backend-test-utils/report-alpha.api.md @@ -0,0 +1,85 @@ +## API Report File for "@backstage/backend-test-utils" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { ActionsRegistryActionOptions } from '@backstage/backend-plugin-api/alpha'; +import { ActionsRegistryService } from '@backstage/backend-plugin-api/alpha'; +import { ActionsService } from '@backstage/backend-plugin-api/alpha'; +import { ActionsServiceAction } from '@backstage/backend-plugin-api/alpha'; +import { AnyZodObject } from 'zod'; +import { BackstageCredentials } from '@backstage/backend-plugin-api'; +import { JsonObject } from '@backstage/types'; +import { JsonValue } from '@backstage/types'; +import { LoggerService } from '@backstage/backend-plugin-api'; +import { ServiceFactory } from '@backstage/backend-plugin-api'; + +// @alpha (undocumented) +export function actionsRegistryServiceMock(options?: { + logger: LoggerService; +}): MockActionsRegistry; + +// @alpha (undocumented) +export namespace actionsRegistryServiceMock { + const // (undocumented) + factory: () => ServiceFactory< + ActionsRegistryService, + 'plugin', + 'singleton' + >; + const // (undocumented) + mock: ( + partialImpl?: Partial | undefined, + ) => ServiceMock; +} + +// @alpha (undocumented) +export namespace actionsServiceMock { + const // (undocumented) + factory: () => ServiceFactory; + const // (undocumented) + mock: ( + partialImpl?: Partial | undefined, + ) => ServiceMock; +} + +// @alpha +export class MockActionsRegistry + implements ActionsRegistryService, ActionsService +{ + // (undocumented) + readonly actions: Map>; + // (undocumented) + static create(opts: { logger: LoggerService }): MockActionsRegistry; + // (undocumented) + invoke(opts: { + id: string; + input?: JsonObject; + credentials?: BackstageCredentials; + }): Promise<{ + output: JsonValue; + }>; + // (undocumented) + list(): Promise<{ + actions: ActionsServiceAction[]; + }>; + // (undocumented) + register< + TInputSchema extends AnyZodObject, + TOutputSchema extends AnyZodObject, + >(options: ActionsRegistryActionOptions): void; +} + +// @alpha (undocumented) +export type ServiceMock = { + factory: ServiceFactory; +} & { + [Key in keyof TService]: TService[Key] extends ( + ...args: infer Args + ) => infer Return + ? TService[Key] & jest.MockInstance + : TService[Key]; +}; + +// (No @packageDocumentation comment for this package) +``` diff --git a/packages/backend-test-utils/report.api.md b/packages/backend-test-utils/report.api.md index 379a2a70ac..4853ca57c5 100644 --- a/packages/backend-test-utils/report.api.md +++ b/packages/backend-test-utils/report.api.md @@ -3,9 +3,8 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts -import { ActionsRegistryService } from '@backstage/backend-plugin-api'; -import { ActionsService } from '@backstage/backend-plugin-api'; import { AuditorService } from '@backstage/backend-plugin-api'; +import { AuthorizeResult } from '@backstage/plugin-permission-common'; import { AuthService } from '@backstage/backend-plugin-api'; import { Backend } from '@backstage/backend-app-api'; import { BackendFeature } from '@backstage/backend-plugin-api'; @@ -163,28 +162,6 @@ export function mockErrorHandler(): ErrorRequestHandler< // @public export namespace mockServices { - // (undocumented) - export namespace actions { - const // (undocumented) - factory: () => ServiceFactory; - const // (undocumented) - mock: ( - partialImpl?: Partial | undefined, - ) => ServiceMock; - } - // (undocumented) - export namespace actionsRegistry { - const // (undocumented) - factory: () => ServiceFactory< - ActionsRegistryService, - 'plugin', - 'singleton' - >; - const // (undocumented) - mock: ( - partialImpl?: Partial | undefined, - ) => ServiceMock; - } // (undocumented) export namespace auditor { const // (undocumented) @@ -299,14 +276,17 @@ export namespace mockServices { partialImpl?: Partial | undefined, ) => ServiceMock; } + export function permissions(options?: { + result: AuthorizeResult.ALLOW | AuthorizeResult.DENY; + }): PermissionsService; // (undocumented) export namespace permissions { - const // (undocumented) - factory: () => ServiceFactory; - const // (undocumented) - mock: ( - partialImpl?: Partial | undefined, - ) => ServiceMock; + const factory: (options?: { + result: AuthorizeResult.ALLOW | AuthorizeResult.DENY; + }) => ServiceFactory; + const mock: ( + partialImpl?: Partial | undefined, + ) => ServiceMock; } // (undocumented) export namespace permissionsRegistry { diff --git a/packages/backend-test-utils/src/next/index.ts b/packages/backend-test-utils/src/alpha/index.ts similarity index 96% rename from packages/backend-test-utils/src/next/index.ts rename to packages/backend-test-utils/src/alpha/index.ts index 572fb3a9e7..d891744260 100644 --- a/packages/backend-test-utils/src/next/index.ts +++ b/packages/backend-test-utils/src/alpha/index.ts @@ -14,5 +14,4 @@ * limitations under the License. */ -export * from './wiring'; export * from './services'; diff --git a/packages/backend-test-utils/src/alpha/services/ActionsRegistryServiceMock.ts b/packages/backend-test-utils/src/alpha/services/ActionsRegistryServiceMock.ts new file mode 100644 index 0000000000..faf89b393a --- /dev/null +++ b/packages/backend-test-utils/src/alpha/services/ActionsRegistryServiceMock.ts @@ -0,0 +1,49 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { mockServices } from '../../services'; +import { LoggerService } from '@backstage/backend-plugin-api'; +import { MockActionsRegistry } from './MockActionsRegistry'; +import { simpleMock } from './simpleMock'; +import { + ActionsRegistryService, + actionsRegistryServiceRef, +} from '@backstage/backend-plugin-api/alpha'; +import { actionsRegistryServiceFactory } from '@backstage/backend-defaults/alpha'; + +/** + * @alpha + */ +export function actionsRegistryServiceMock(options?: { + logger: LoggerService; +}): MockActionsRegistry { + return MockActionsRegistry.create({ + logger: options?.logger ?? mockServices.logger.mock(), + }); +} + +/** + * @alpha + */ +export namespace actionsRegistryServiceMock { + export const factory = () => actionsRegistryServiceFactory; + + export const mock = simpleMock( + actionsRegistryServiceRef, + () => ({ + register: jest.fn(), + }), + ); +} diff --git a/packages/backend-test-utils/src/alpha/services/ActionsServiceMock.ts b/packages/backend-test-utils/src/alpha/services/ActionsServiceMock.ts new file mode 100644 index 0000000000..63abff4c37 --- /dev/null +++ b/packages/backend-test-utils/src/alpha/services/ActionsServiceMock.ts @@ -0,0 +1,34 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { simpleMock } from './simpleMock'; +import { + ActionsService, + actionsServiceRef, +} from '@backstage/backend-plugin-api/alpha'; +import { actionsServiceFactory } from '@backstage/backend-defaults/alpha'; + +/** + * @alpha + */ +export namespace actionsServiceMock { + export const factory = () => actionsServiceFactory; + + export const mock = simpleMock(actionsServiceRef, () => ({ + invoke: jest.fn(), + list: jest.fn(), + })); +} diff --git a/packages/backend-test-utils/src/alpha/services/MockActionsRegistry.test.ts b/packages/backend-test-utils/src/alpha/services/MockActionsRegistry.test.ts new file mode 100644 index 0000000000..f604689c63 --- /dev/null +++ b/packages/backend-test-utils/src/alpha/services/MockActionsRegistry.test.ts @@ -0,0 +1,236 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { + coreServices, + createBackendPlugin, +} from '@backstage/backend-plugin-api'; +import { startTestBackend } from '../../wiring'; +import { actionsRegistryServiceMock } from './ActionsRegistryServiceMock'; +import { mockCredentials } from '../../services'; +import { Router } from 'express'; +import supertest from 'supertest'; +import { + actionsRegistryServiceRef, + actionsServiceRef, +} from '@backstage/backend-plugin-api/alpha'; + +describe('MockActionsRegistry', () => { + it('should be able to register and invoke actions', async () => { + const registry = actionsRegistryServiceMock(); + + registry.register({ + name: 'my-demo-action', + title: 'Test', + description: 'Test', + schema: { + input: z => + z.object({ + name: z.string(), + }), + output: z => + z.object({ + name: z.string(), + }), + }, + action: async ({ input }) => ({ output: { name: input.name } }), + }); + + const result = await registry.invoke({ + id: 'test:my-demo-action', + input: { name: 'test' }, + }); + + expect(result).toEqual({ output: { name: 'test' } }); + }); + + it('should throw an error when the input is invalid to the action', async () => { + const registry = actionsRegistryServiceMock(); + + registry.register({ + name: 'my-demo-action', + title: 'Test', + description: 'Test', + schema: { + input: z => z.object({ name: z.string() }), + output: z => z.object({ name: z.string() }), + }, + action: async ({ input }) => ({ output: { name: input.name } }), + }); + + await expect( + registry.invoke({ id: 'test:my-demo-action', input: { name: 1 } }), + ).rejects.toThrow('Invalid input to action "test:my-demo-action"'); + }); + + it('should throw an error when the action is not found', async () => { + const registry = actionsRegistryServiceMock(); + + await expect(registry.invoke({ id: 'test' })).rejects.toThrow( + 'Action "test" not found, available actions: none', + ); + }); + + it('should throw an error when the action is not found with recommended actions', async () => { + const registry = actionsRegistryServiceMock(); + + registry.register({ + name: 'my-demo-action', + title: 'Test', + description: 'Test', + schema: { + input: z => z.object({ name: z.string() }), + output: z => z.object({ name: z.string() }), + }, + action: async ({ input }) => ({ output: { name: input.name } }), + }); + + await expect(registry.invoke({ id: 'test' })).rejects.toThrow( + 'Action "test" not found, available actions: "test:my-demo-action"', + ); + }); + + it('should throw an error when the output is invalid', async () => { + const registry = actionsRegistryServiceMock(); + + registry.register({ + name: 'my-demo-action', + title: 'Test', + description: 'Test', + schema: { + input: z => z.object({ name: z.number() }), + output: z => z.object({ name: z.string() }), + }, + // @ts-expect-error - we want to test the error case + action: async ({ input }) => ({ output: { name: input.name } }), + }); + + await expect( + registry.invoke({ id: 'test:my-demo-action', input: { name: 1 } }), + ).rejects.toThrow('Invalid output from action "test:my-demo-action"'); + }); + + it('should list the actions correctly', async () => { + const registry = actionsRegistryServiceMock(); + + registry.register({ + name: 'my-demo-action', + title: 'Test', + description: 'Test', + schema: { + input: z => z.object({ name: z.string() }), + output: z => z.object({ name: z.string() }), + }, + action: async ({ input }) => ({ output: { name: input.name } }), + }); + + const result = await registry.list(); + + expect(result).toMatchObject({ + actions: [ + { + id: 'test:my-demo-action', + name: 'my-demo-action', + title: 'Test', + description: 'Test', + attributes: { + destructive: true, + idempotent: false, + readOnly: false, + }, + schema: { + input: { + type: 'object', + properties: { + name: { type: 'string' }, + }, + }, + output: { + type: 'object', + properties: { + name: { type: 'string' }, + }, + }, + }, + }, + ], + }); + }); + + describe('actionsRegistryServiceMock + mockService.actionsRegistry', () => { + it('should be able to register and invoke actions', async () => { + const pluginWithAction = createBackendPlugin({ + pluginId: 'my-plugin', + register(reg) { + reg.registerInit({ + deps: { actionsRegistry: actionsRegistryServiceRef }, + async init({ actionsRegistry }) { + actionsRegistry.register({ + name: 'test', + title: 'Test', + description: 'Test', + schema: { + input: z => z.object({ name: z.string() }), + output: z => z.object({ name: z.string() }), + }, + action: async ({ input }) => { + expect(input).toEqual({ name: 'test' }); + return { output: { name: input.name } }; + }, + }); + }, + }); + }, + }); + + const pluginToCallAction = createBackendPlugin({ + pluginId: 'my-plugin-to-call-action', + register(reg) { + reg.registerInit({ + deps: { + actions: actionsServiceRef, + router: coreServices.httpRouter, + }, + async init({ actions, router }) { + const testRouter = Router(); + router.use(testRouter); + + testRouter.post('/test', async (_, res) => { + const { output } = await actions.invoke({ + id: 'my-plugin:test', + input: { name: 'test' }, + credentials: mockCredentials.service(), + }); + + res.json(output); + }); + }, + }); + }, + }); + + const { server } = await startTestBackend({ + features: [pluginWithAction, pluginToCallAction], + }); + + const { body, status } = await supertest(server).post( + '/api/my-plugin-to-call-action/test', + ); + + expect(status).toBe(200); + expect(body).toEqual({ name: 'test' }); + }); + }); +}); diff --git a/packages/backend-test-utils/src/alpha/services/MockActionsRegistry.ts b/packages/backend-test-utils/src/alpha/services/MockActionsRegistry.ts new file mode 100644 index 0000000000..49c80b7a3d --- /dev/null +++ b/packages/backend-test-utils/src/alpha/services/MockActionsRegistry.ts @@ -0,0 +1,168 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { + BackstageCredentials, + LoggerService, +} from '@backstage/backend-plugin-api'; +import { ForwardedError, InputError, NotFoundError } from '@backstage/errors'; +import { JsonObject, JsonValue } from '@backstage/types'; +import { z, AnyZodObject } from 'zod'; +import zodToJsonSchema from 'zod-to-json-schema'; +import { mockCredentials } from '../../services'; +import { + ActionsRegistryActionOptions, + ActionsRegistryService, + ActionsService, + ActionsServiceAction, +} from '@backstage/backend-plugin-api/alpha'; + +/** + * A mock implementation of the ActionsRegistryService and ActionsService that can be used in tests. + * + * This is useful for testing actions that are registered with the ActionsRegistryService and ActionsService. + * + * The plugin ID is hardcoded to `testing` in the mock implementation. + * + * @example + * ```ts + * const actionsRegistry = mockServices.actionsRegistry(); + * + * actionsRegistry.register({ + * name: 'test', + * title: 'Test', + * description: 'Test', + * schema: { + * input: z.object({ name: z.string() }), + * output: z.object({ name: z.string() }), + * }, + * action: async ({ input }) => ({ output: { name: input.name } }), + * }); + * + * + * const result = await actionsRegistry.invoke({ + * id: 'testing:test', + * input: { name: 'test' }, + * }); + * + * expect(result).toEqual({ output: { name: 'test' } }); + * ``` + * + * @alpha + */ +export class MockActionsRegistry + implements ActionsRegistryService, ActionsService +{ + private constructor(private readonly logger: LoggerService) {} + + static create(opts: { logger: LoggerService }) { + return new MockActionsRegistry(opts.logger); + } + + readonly actions: Map> = + new Map(); + + async list(): Promise<{ actions: ActionsServiceAction[] }> { + return { + actions: Array.from(this.actions.entries()).map(([id, action]) => ({ + id, + name: action.name, + title: action.title, + description: action.description, + attributes: { + destructive: action.attributes?.destructive ?? true, + idempotent: action.attributes?.idempotent ?? false, + readOnly: action.attributes?.readOnly ?? false, + }, + schema: { + input: action.schema?.input + ? zodToJsonSchema(action.schema.input(z)) + : zodToJsonSchema(z.object({})), + output: action.schema?.output + ? zodToJsonSchema(action.schema.output(z)) + : zodToJsonSchema(z.object({})), + } as ActionsServiceAction['schema'], + })), + }; + } + + async invoke(opts: { + id: string; + input?: JsonObject; + credentials?: BackstageCredentials; + }): Promise<{ output: JsonValue }> { + const action = this.actions.get(opts.id); + + if (!action) { + const availableActionIds = Array.from(this.actions.keys()).join(', '); + throw new NotFoundError( + `Action "${opts.id}" not found, available actions: ${ + availableActionIds ? `"${availableActionIds}"` : 'none' + }`, + ); + } + + const input = action.schema?.input + ? action.schema.input(z).safeParse(opts.input) + : ({ success: true, data: undefined } as const); + + if (!input.success) { + throw new InputError(`Invalid input to action "${opts.id}"`, input.error); + } + + try { + const result = await action.action({ + input: input.data, + credentials: opts.credentials ?? mockCredentials.none(), + logger: this.logger, + }); + + const output = action.schema?.output + ? action.schema.output(z).safeParse(result?.output) + : ({ success: true, data: result?.output } as const); + + if (!output.success) { + throw new InputError( + `Invalid output from action "${opts.id}"`, + output.error, + ); + } + + return { output: output.data }; + } catch (error) { + throw new ForwardedError( + `Failed execution of action "${opts.id}"`, + error, + ); + } + } + + register< + TInputSchema extends AnyZodObject, + TOutputSchema extends AnyZodObject, + >(options: ActionsRegistryActionOptions): void { + // hardcode test: prefix similar to how the default actions registry does it + // and other places around the testing ecosystem: + // https://github.com/backstage/backstage/blob/a9219496d5c073aaa0b8caf32ece10455cf65e61/packages/backend-test-utils/src/next/services/mockServices.ts#L321 + // https://github.com/backstage/backstage/blob/861f162b4a39117b824669d67a951ed1db142e3d/packages/backend-test-utils/src/next/wiring/ServiceFactoryTester.ts#L99 + const id = `test:${options.name}`; + + if (this.actions.has(id)) { + throw new Error(`Action with id "${id}" is already registered`); + } + + this.actions.set(id, options); + } +} diff --git a/packages/backend-test-utils/src/alpha/services/index.ts b/packages/backend-test-utils/src/alpha/services/index.ts new file mode 100644 index 0000000000..ca9b3f23a0 --- /dev/null +++ b/packages/backend-test-utils/src/alpha/services/index.ts @@ -0,0 +1,20 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { actionsRegistryServiceMock } from './ActionsRegistryServiceMock'; +export { MockActionsRegistry } from './MockActionsRegistry'; +export { actionsServiceMock } from './ActionsServiceMock'; +export { type ServiceMock } from './simpleMock'; diff --git a/packages/backend-test-utils/src/alpha/services/simpleMock.ts b/packages/backend-test-utils/src/alpha/services/simpleMock.ts new file mode 100644 index 0000000000..d07b143f7a --- /dev/null +++ b/packages/backend-test-utils/src/alpha/services/simpleMock.ts @@ -0,0 +1,57 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { + createServiceFactory, + ServiceFactory, + ServiceRef, +} from '@backstage/backend-plugin-api'; + +/** @alpha */ +export type ServiceMock = { + factory: ServiceFactory; +} & { + [Key in keyof TService]: TService[Key] extends ( + ...args: infer Args + ) => infer Return + ? TService[Key] & jest.MockInstance + : TService[Key]; +}; + +/** @internal */ +export function simpleMock( + ref: ServiceRef, + mockFactory: () => jest.Mocked, +): (partialImpl?: Partial) => ServiceMock { + return partialImpl => { + const mock = mockFactory(); + if (partialImpl) { + for (const [key, impl] of Object.entries(partialImpl)) { + if (typeof impl === 'function') { + (mock as any)[key].mockImplementation(impl); + } else { + (mock as any)[key] = impl; + } + } + } + return Object.assign(mock, { + factory: createServiceFactory({ + service: ref, + deps: {}, + factory: () => mock, + }), + }) as ServiceMock; + }; +} diff --git a/packages/backend-test-utils/src/index.ts b/packages/backend-test-utils/src/index.ts index d8e0e2c4a6..7cc4546415 100644 --- a/packages/backend-test-utils/src/index.ts +++ b/packages/backend-test-utils/src/index.ts @@ -24,5 +24,6 @@ export * from './cache'; export * from './database'; export * from './msw'; export * from './filesystem'; -export * from './next'; +export * from './services'; +export * from './wiring'; export { mockErrorHandler } from './util'; diff --git a/packages/backend-test-utils/src/next/services/MockAuthService.test.ts b/packages/backend-test-utils/src/services/MockAuthService.test.ts similarity index 100% rename from packages/backend-test-utils/src/next/services/MockAuthService.test.ts rename to packages/backend-test-utils/src/services/MockAuthService.test.ts diff --git a/packages/backend-test-utils/src/next/services/MockAuthService.ts b/packages/backend-test-utils/src/services/MockAuthService.ts similarity index 100% rename from packages/backend-test-utils/src/next/services/MockAuthService.ts rename to packages/backend-test-utils/src/services/MockAuthService.ts diff --git a/packages/backend-test-utils/src/next/services/MockEventsService.test.ts b/packages/backend-test-utils/src/services/MockEventsService.test.ts similarity index 100% rename from packages/backend-test-utils/src/next/services/MockEventsService.test.ts rename to packages/backend-test-utils/src/services/MockEventsService.test.ts diff --git a/packages/backend-test-utils/src/next/services/MockEventsService.ts b/packages/backend-test-utils/src/services/MockEventsService.ts similarity index 100% rename from packages/backend-test-utils/src/next/services/MockEventsService.ts rename to packages/backend-test-utils/src/services/MockEventsService.ts diff --git a/packages/backend-test-utils/src/next/services/MockHttpAuthService.test.ts b/packages/backend-test-utils/src/services/MockHttpAuthService.test.ts similarity index 100% rename from packages/backend-test-utils/src/next/services/MockHttpAuthService.test.ts rename to packages/backend-test-utils/src/services/MockHttpAuthService.test.ts diff --git a/packages/backend-test-utils/src/next/services/MockHttpAuthService.ts b/packages/backend-test-utils/src/services/MockHttpAuthService.ts similarity index 100% rename from packages/backend-test-utils/src/next/services/MockHttpAuthService.ts rename to packages/backend-test-utils/src/services/MockHttpAuthService.ts diff --git a/packages/backend-test-utils/src/services/MockPermissionsService.test.ts b/packages/backend-test-utils/src/services/MockPermissionsService.test.ts new file mode 100644 index 0000000000..eb98fe9457 --- /dev/null +++ b/packages/backend-test-utils/src/services/MockPermissionsService.test.ts @@ -0,0 +1,57 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { AuthorizeResult } from '@backstage/plugin-permission-common'; +import { MockPermissionsService } from './MockPermissionsService'; + +describe('MockPermissionsService', () => { + it('should return the correct result', async () => { + const permission = { + permission: { + name: 'test', + type: 'basic', + attributes: {}, + }, + } as const; + + const defaultService = new MockPermissionsService(); + const allowService = new MockPermissionsService({ + result: AuthorizeResult.ALLOW, + }); + const denyService = new MockPermissionsService({ + result: AuthorizeResult.DENY, + }); + + await expect(defaultService.authorize([permission])).resolves.toEqual([ + { + ...permission, + result: AuthorizeResult.ALLOW, + }, + ]); + await expect(allowService.authorize([permission])).resolves.toEqual([ + { + ...permission, + result: AuthorizeResult.ALLOW, + }, + ]); + await expect(denyService.authorize([permission])).resolves.toEqual([ + { + ...permission, + result: AuthorizeResult.DENY, + }, + ]); + }); +}); diff --git a/packages/backend-test-utils/src/services/MockPermissionsService.ts b/packages/backend-test-utils/src/services/MockPermissionsService.ts new file mode 100644 index 0000000000..3637c34554 --- /dev/null +++ b/packages/backend-test-utils/src/services/MockPermissionsService.ts @@ -0,0 +1,52 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { PermissionsService } from '@backstage/backend-plugin-api'; +import { + AuthorizePermissionRequest, + AuthorizePermissionResponse, + AuthorizeResult, + QueryPermissionRequest, + QueryPermissionResponse, +} from '@backstage/plugin-permission-common'; + +export class MockPermissionsService implements PermissionsService { + readonly #result: AuthorizeResult.ALLOW | AuthorizeResult.DENY; + + constructor(options?: { + result: AuthorizeResult.ALLOW | AuthorizeResult.DENY; + }) { + this.#result = options?.result ?? AuthorizeResult.ALLOW; + } + + async authorize( + requests: AuthorizePermissionRequest[], + ): Promise { + return requests.map(request => ({ + ...request, + result: this.#result, + })); + } + + async authorizeConditional( + requests: QueryPermissionRequest[], + ): Promise { + return requests.map(request => ({ + ...request, + result: this.#result, + })); + } +} diff --git a/packages/backend-test-utils/src/next/services/MockRootLoggerService.test.ts b/packages/backend-test-utils/src/services/MockRootLoggerService.test.ts similarity index 100% rename from packages/backend-test-utils/src/next/services/MockRootLoggerService.test.ts rename to packages/backend-test-utils/src/services/MockRootLoggerService.test.ts diff --git a/packages/backend-test-utils/src/next/services/MockRootLoggerService.ts b/packages/backend-test-utils/src/services/MockRootLoggerService.ts similarity index 100% rename from packages/backend-test-utils/src/next/services/MockRootLoggerService.ts rename to packages/backend-test-utils/src/services/MockRootLoggerService.ts diff --git a/packages/backend-test-utils/src/next/services/MockUserInfoService.test.ts b/packages/backend-test-utils/src/services/MockUserInfoService.test.ts similarity index 100% rename from packages/backend-test-utils/src/next/services/MockUserInfoService.test.ts rename to packages/backend-test-utils/src/services/MockUserInfoService.test.ts diff --git a/packages/backend-test-utils/src/next/services/MockUserInfoService.ts b/packages/backend-test-utils/src/services/MockUserInfoService.ts similarity index 100% rename from packages/backend-test-utils/src/next/services/MockUserInfoService.ts rename to packages/backend-test-utils/src/services/MockUserInfoService.ts diff --git a/packages/backend-test-utils/src/next/services/index.ts b/packages/backend-test-utils/src/services/index.ts similarity index 87% rename from packages/backend-test-utils/src/next/services/index.ts rename to packages/backend-test-utils/src/services/index.ts index 7c3949e207..73f179ca41 100644 --- a/packages/backend-test-utils/src/next/services/index.ts +++ b/packages/backend-test-utils/src/services/index.ts @@ -13,5 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export { mockServices, type ServiceMock } from './mockServices'; +export { mockServices } from './mockServices'; export { mockCredentials } from './mockCredentials'; +export { type ServiceMock } from './simpleMock'; diff --git a/packages/backend-test-utils/src/next/services/mockCredentials.test.ts b/packages/backend-test-utils/src/services/mockCredentials.test.ts similarity index 100% rename from packages/backend-test-utils/src/next/services/mockCredentials.test.ts rename to packages/backend-test-utils/src/services/mockCredentials.test.ts diff --git a/packages/backend-test-utils/src/next/services/mockCredentials.ts b/packages/backend-test-utils/src/services/mockCredentials.ts similarity index 95% rename from packages/backend-test-utils/src/next/services/mockCredentials.ts rename to packages/backend-test-utils/src/services/mockCredentials.ts index 231c108ac4..617ffdb240 100644 --- a/packages/backend-test-utils/src/next/services/mockCredentials.ts +++ b/packages/backend-test-utils/src/services/mockCredentials.ts @@ -111,16 +111,24 @@ export namespace mockCredentials { options?: { actor?: { subject: string } }, ): BackstageCredentials { validateUserEntityRef(userEntityRef); - return { - $$type: '@backstage/BackstageCredentials', - principal: { - type: 'user', - userEntityRef, - ...(options?.actor && { - actor: { type: 'service', subject: options.actor.subject }, - }), + return Object.defineProperty( + { + $$type: '@backstage/BackstageCredentials', + principal: { + type: 'user', + userEntityRef, + ...(options?.actor && { + actor: { type: 'service', subject: options.actor.subject }, + }), + }, }, - }; + 'token', + { + enumerable: false, + configurable: true, + value: user.token(), + }, + ); } /** diff --git a/packages/backend-test-utils/src/next/services/mockServices.test.ts b/packages/backend-test-utils/src/services/mockServices.test.ts similarity index 100% rename from packages/backend-test-utils/src/next/services/mockServices.test.ts rename to packages/backend-test-utils/src/services/mockServices.test.ts diff --git a/packages/backend-test-utils/src/next/services/mockServices.ts b/packages/backend-test-utils/src/services/mockServices.ts similarity index 90% rename from packages/backend-test-utils/src/next/services/mockServices.ts rename to packages/backend-test-utils/src/services/mockServices.ts index 0c5b18bd1e..06bf8f9a29 100644 --- a/packages/backend-test-utils/src/next/services/mockServices.ts +++ b/packages/backend-test-utils/src/services/mockServices.ts @@ -36,6 +36,7 @@ import { DiscoveryService, HttpAuthService, LoggerService, + PermissionsService, RootConfigService, ServiceFactory, ServiceRef, @@ -45,6 +46,7 @@ import { } from '@backstage/backend-plugin-api'; import { ConfigReader } from '@backstage/config'; import { EventsService, eventsServiceRef } from '@backstage/plugin-events-node'; +import { AuthorizeResult } from '@backstage/plugin-permission-common'; import { JsonObject } from '@backstage/types'; import { Knex } from 'knex'; import { MockAuthService } from './MockAuthService'; @@ -53,8 +55,8 @@ import { MockRootLoggerService } from './MockRootLoggerService'; import { MockUserInfoService } from './MockUserInfoService'; import { mockCredentials } from './mockCredentials'; import { MockEventsService } from './MockEventsService'; -import { actionsServiceFactory } from '@backstage/backend-defaults/actions'; -import { actionsRegistryServiceFactory } from '@backstage/backend-defaults/actionsRegistry'; +import { MockPermissionsService } from './MockPermissionsService'; +import { simpleMock } from './simpleMock'; /** @internal */ function createLoggerMock() { @@ -91,43 +93,6 @@ function simpleFactoryWithOptions< ((...options: TOptions) => ServiceFactory); } -/** @public */ -export type ServiceMock = { - factory: ServiceFactory; -} & { - [Key in keyof TService]: TService[Key] extends ( - ...args: infer Args - ) => infer Return - ? TService[Key] & jest.MockInstance - : TService[Key]; -}; - -/** @internal */ -function simpleMock( - ref: ServiceRef, - mockFactory: () => jest.Mocked, -): (partialImpl?: Partial) => ServiceMock { - return partialImpl => { - const mock = mockFactory(); - if (partialImpl) { - for (const [key, impl] of Object.entries(partialImpl)) { - if (typeof impl === 'function') { - (mock as any)[key].mockImplementation(impl); - } else { - (mock as any)[key] = impl; - } - } - } - return Object.assign(mock, { - factory: createServiceFactory({ - service: ref, - deps: {}, - factory: () => mock, - }), - }) as ServiceMock; - }; -} - /** * Mock implementations of the core services, to be used in tests. * @@ -475,8 +440,37 @@ export namespace mockServices { ); } + /** + * Creates a functional mock implementation of the + * {@link @backstage/backend-plugin-api#PermissionsService}. + */ + export function permissions(options?: { + result: AuthorizeResult.ALLOW | AuthorizeResult.DENY; + }): PermissionsService { + return new MockPermissionsService(options); + } export namespace permissions { - export const factory = () => permissionsServiceFactory; + /** + * Creates a mock factory for the + * {@link @backstage/backend-plugin-api#coreServices.permissions}. Just + * returns the given `result` if you supply one. Otherwise, it returns the + * regular default permissions factory. + */ + export const factory = (options?: { + result: AuthorizeResult.ALLOW | AuthorizeResult.DENY; + }) => + options?.result + ? createServiceFactory({ + service: coreServices.permissions, + deps: {}, + factory: () => new MockPermissionsService(options), + }) + : permissionsServiceFactory; + /** + * Creates a mock of the + * {@link @backstage/backend-plugin-api#coreServices.permissions}, + * optionally with some given method implementations. + */ export const mock = simpleMock(coreServices.permissions, () => ({ authorize: jest.fn(), authorizeConditional: jest.fn(), @@ -520,20 +514,6 @@ export namespace mockServices { search: jest.fn(), })); } - export namespace actions { - export const factory = () => actionsServiceFactory; - export const mock = simpleMock(coreServices.actions, () => ({ - list: jest.fn(), - invoke: jest.fn(), - })); - } - - export namespace actionsRegistry { - export const factory = () => actionsRegistryServiceFactory; - export const mock = simpleMock(coreServices.actionsRegistry, () => ({ - register: jest.fn(), - })); - } /** * Creates a functional mock implementation of the diff --git a/packages/backend-test-utils/src/services/simpleMock.ts b/packages/backend-test-utils/src/services/simpleMock.ts new file mode 100644 index 0000000000..484969f235 --- /dev/null +++ b/packages/backend-test-utils/src/services/simpleMock.ts @@ -0,0 +1,57 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { + createServiceFactory, + ServiceFactory, + ServiceRef, +} from '@backstage/backend-plugin-api'; + +/** @public */ +export type ServiceMock = { + factory: ServiceFactory; +} & { + [Key in keyof TService]: TService[Key] extends ( + ...args: infer Args + ) => infer Return + ? TService[Key] & jest.MockInstance + : TService[Key]; +}; + +/** @internal */ +export function simpleMock( + ref: ServiceRef, + mockFactory: () => jest.Mocked, +): (partialImpl?: Partial) => ServiceMock { + return partialImpl => { + const mock = mockFactory(); + if (partialImpl) { + for (const [key, impl] of Object.entries(partialImpl)) { + if (typeof impl === 'function') { + (mock as any)[key].mockImplementation(impl); + } else { + (mock as any)[key] = impl; + } + } + } + return Object.assign(mock, { + factory: createServiceFactory({ + service: ref, + deps: {}, + factory: () => mock, + }), + }) as ServiceMock; + }; +} diff --git a/packages/backend-test-utils/src/util/errorHandler.ts b/packages/backend-test-utils/src/util/errorHandler.ts index f534823f50..79f4d8fd04 100644 --- a/packages/backend-test-utils/src/util/errorHandler.ts +++ b/packages/backend-test-utils/src/util/errorHandler.ts @@ -15,7 +15,7 @@ */ import { MiddlewareFactory } from '@backstage/backend-defaults/rootHttpRouter'; -import { mockServices } from '../next'; +import { mockServices } from '../services'; /** * A mock for error handler middleware that can be used in router tests. diff --git a/packages/backend-test-utils/src/next/wiring/ServiceFactoryTester.test.ts b/packages/backend-test-utils/src/wiring/ServiceFactoryTester.test.ts similarity index 100% rename from packages/backend-test-utils/src/next/wiring/ServiceFactoryTester.test.ts rename to packages/backend-test-utils/src/wiring/ServiceFactoryTester.test.ts diff --git a/packages/backend-test-utils/src/next/wiring/ServiceFactoryTester.ts b/packages/backend-test-utils/src/wiring/ServiceFactoryTester.ts similarity index 97% rename from packages/backend-test-utils/src/next/wiring/ServiceFactoryTester.ts rename to packages/backend-test-utils/src/wiring/ServiceFactoryTester.ts index 83a6a42307..2b49abc88f 100644 --- a/packages/backend-test-utils/src/next/wiring/ServiceFactoryTester.ts +++ b/packages/backend-test-utils/src/wiring/ServiceFactoryTester.ts @@ -20,7 +20,7 @@ import { defaultServiceFactories } from './TestBackend'; // This is a relative import in order to make sure that the implementation is duplicated // rather than leading to an import from @backstage/backend-app-api. // eslint-disable-next-line @backstage/no-relative-monorepo-imports -import { ServiceRegistry } from '../../../../backend-app-api/src/wiring/ServiceRegistry'; +import { ServiceRegistry } from '../../../backend-app-api/src/wiring/ServiceRegistry'; /** * Options for {@link ServiceFactoryTester}. diff --git a/packages/backend-test-utils/src/next/wiring/TestBackend.test.ts b/packages/backend-test-utils/src/wiring/TestBackend.test.ts similarity index 100% rename from packages/backend-test-utils/src/next/wiring/TestBackend.test.ts rename to packages/backend-test-utils/src/wiring/TestBackend.test.ts diff --git a/packages/backend-test-utils/src/next/wiring/TestBackend.ts b/packages/backend-test-utils/src/wiring/TestBackend.ts similarity index 97% rename from packages/backend-test-utils/src/next/wiring/TestBackend.ts rename to packages/backend-test-utils/src/wiring/TestBackend.ts index 20d02cf880..cdfa1fc695 100644 --- a/packages/backend-test-utils/src/next/wiring/TestBackend.ts +++ b/packages/backend-test-utils/src/wiring/TestBackend.ts @@ -31,7 +31,7 @@ import express from 'express'; import { InternalBackendFeature, InternalBackendRegistrations, -} from '../../../../backend-plugin-api/src/wiring/types'; +} from '../../../backend-plugin-api/src/wiring/types'; import { DefaultRootHttpRouter, ExtendedHttpServer, @@ -40,6 +40,10 @@ import { createHttpServer, } from '@backstage/backend-defaults/rootHttpRouter'; import { HostDiscovery } from '@backstage/backend-defaults/discovery'; +import { + actionsRegistryServiceMock, + actionsServiceMock, +} from '../alpha/services'; /** @public */ export interface TestBackendOptions { @@ -84,6 +88,10 @@ export const defaultServiceFactories = [ mockServices.userInfo.factory(), mockServices.urlReader.factory(), mockServices.events.factory(), + + // Alpha services + actionsRegistryServiceMock.factory(), + actionsServiceMock.factory(), ]; /** diff --git a/packages/backend-test-utils/src/next/wiring/index.ts b/packages/backend-test-utils/src/wiring/index.ts similarity index 100% rename from packages/backend-test-utils/src/next/wiring/index.ts rename to packages/backend-test-utils/src/wiring/index.ts diff --git a/packages/backend/CHANGELOG.md b/packages/backend/CHANGELOG.md index 9fd8ca9920..7008ec89c3 100644 --- a/packages/backend/CHANGELOG.md +++ b/packages/backend/CHANGELOG.md @@ -1,5 +1,84 @@ # example-backend +## 0.0.39 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-notifications-backend@0.5.7 + - @backstage/plugin-scaffolder-backend-module-github@0.8.0 + - @backstage/backend-defaults@0.11.0 + - @backstage/plugin-scaffolder-backend@2.0.0 + - @backstage/plugin-catalog-backend@2.1.0 + - @backstage/plugin-devtools-backend@0.5.6 + - @backstage/plugin-mcp-actions-backend@0.1.0 + - @backstage/plugin-events-backend@0.5.3 + - @backstage/plugin-search-backend@2.0.3 + - @backstage/plugin-events-backend-module-google-pubsub@0.1.1 + - @backstage/plugin-scaffolder-backend-module-notifications@0.1.11 + - @backstage/plugin-auth-node@0.6.4 + - @backstage/plugin-search-backend-module-techdocs@0.4.3 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/plugin-kubernetes-backend@0.19.7 + - @backstage/plugin-search-backend-module-catalog@0.3.5 + - @backstage/plugin-techdocs-backend@2.0.3 + - @backstage/catalog-model@1.7.4 + - @backstage/plugin-app-backend@0.5.3 + - @backstage/plugin-auth-backend@0.25.1 + - @backstage/plugin-auth-backend-module-github-provider@0.3.4 + - @backstage/plugin-auth-backend-module-guest-provider@0.2.9 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.5.3 + - @backstage/plugin-catalog-backend-module-openapi@0.2.11 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.2.9 + - @backstage/plugin-catalog-backend-module-unprocessed@0.6.1 + - @backstage/plugin-permission-backend@0.7.1 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.2.9 + - @backstage/plugin-permission-common@0.9.0 + - @backstage/plugin-permission-node@0.10.1 + - @backstage/plugin-proxy-backend@0.6.3 + - @backstage/plugin-search-backend-module-explore@0.3.3 + - @backstage/plugin-search-backend-node@1.3.12 + - @backstage/plugin-signals-backend@0.3.5 + +## 0.0.39-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend-module-github@0.8.0-next.2 + - @backstage/backend-defaults@0.11.0-next.2 + - @backstage/plugin-scaffolder-backend@2.0.0-next.2 + - @backstage/plugin-notifications-backend@0.5.7-next.2 + - @backstage/plugin-catalog-backend@2.0.1-next.2 + - @backstage/plugin-scaffolder-backend-module-notifications@0.1.11-next.2 + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/catalog-model@1.7.4 + - @backstage/plugin-app-backend@0.5.3-next.1 + - @backstage/plugin-auth-backend@0.25.1-next.1 + - @backstage/plugin-auth-backend-module-github-provider@0.3.4-next.1 + - @backstage/plugin-auth-backend-module-guest-provider@0.2.9-next.1 + - @backstage/plugin-auth-node@0.6.4-next.1 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.5.3-next.1 + - @backstage/plugin-catalog-backend-module-openapi@0.2.11-next.1 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.2.9-next.1 + - @backstage/plugin-catalog-backend-module-unprocessed@0.6.1-next.1 + - @backstage/plugin-devtools-backend@0.5.6-next.2 + - @backstage/plugin-events-backend@0.5.3-next.1 + - @backstage/plugin-events-backend-module-google-pubsub@0.1.1-next.1 + - @backstage/plugin-kubernetes-backend@0.19.7-next.1 + - @backstage/plugin-permission-backend@0.7.1-next.1 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.2.9-next.1 + - @backstage/plugin-permission-common@0.9.0 + - @backstage/plugin-permission-node@0.10.1-next.1 + - @backstage/plugin-proxy-backend@0.6.3-next.1 + - @backstage/plugin-search-backend@2.0.3-next.2 + - @backstage/plugin-search-backend-module-catalog@0.3.5-next.1 + - @backstage/plugin-search-backend-module-explore@0.3.3-next.1 + - @backstage/plugin-search-backend-module-techdocs@0.4.3-next.1 + - @backstage/plugin-search-backend-node@1.3.12-next.1 + - @backstage/plugin-signals-backend@0.3.5-next.1 + - @backstage/plugin-techdocs-backend@2.0.3-next.2 + ## 0.0.39-next.1 ### Patch Changes diff --git a/packages/backend/package.json b/packages/backend/package.json index 54c5bb59a1..2ffba00416 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -1,6 +1,6 @@ { "name": "example-backend", - "version": "0.0.39-next.1", + "version": "0.0.39", "backstage": { "role": "backend" }, @@ -47,6 +47,7 @@ "@backstage/plugin-events-backend": "workspace:^", "@backstage/plugin-events-backend-module-google-pubsub": "workspace:^", "@backstage/plugin-kubernetes-backend": "workspace:^", + "@backstage/plugin-mcp-actions-backend": "workspace:^", "@backstage/plugin-notifications-backend": "workspace:^", "@backstage/plugin-permission-backend": "workspace:^", "@backstage/plugin-permission-backend-module-allow-all-policy": "workspace:^", diff --git a/packages/backend/src/index.ts b/packages/backend/src/index.ts index 23d814f1ae..f46e947b0d 100644 --- a/packages/backend/src/index.ts +++ b/packages/backend/src/index.ts @@ -62,4 +62,5 @@ backend.add(import('@backstage/plugin-notifications-backend')); backend.add(import('./instanceMetadata')); backend.add(import('@backstage/plugin-events-backend-module-google-pubsub')); +backend.add(import('@backstage/plugin-mcp-actions-backend')); backend.start(); diff --git a/packages/canon/.eslintrc.js b/packages/canon/.eslintrc.js index f7c0e8cbd1..9638ff6e45 100644 --- a/packages/canon/.eslintrc.js +++ b/packages/canon/.eslintrc.js @@ -3,6 +3,7 @@ module.exports = { extends: ['plugin:storybook/recommended'], rules: { 'react/forbid-elements': 'off', + '@backstage/no-mixed-plugin-imports': 'off' }, }; diff --git a/packages/canon/.storybook/main.ts b/packages/canon/.storybook/main.ts index e58c0f182f..3020ade96e 100644 --- a/packages/canon/.storybook/main.ts +++ b/packages/canon/.storybook/main.ts @@ -9,10 +9,7 @@ function getAbsolutePath(value: string): string { return dirname(require.resolve(join(value, 'package.json'))); } const config: StorybookConfig = { - stories: [ - '../src/components/**/*.stories.@(js|jsx|mjs|ts|tsx)', - '../src/stories/**/*.stories.@(js|jsx|mjs|ts|tsx)', - ], + stories: ['../src/components/**/*.stories.@(js|jsx|mjs|ts|tsx)'], staticDirs: ['../static'], addons: [ getAbsolutePath('@storybook/addon-webpack5-compiler-swc'), diff --git a/packages/canon/CHANGELOG.md b/packages/canon/CHANGELOG.md index ab6fb4ff00..c76b4658f6 100644 --- a/packages/canon/CHANGELOG.md +++ b/packages/canon/CHANGELOG.md @@ -1,5 +1,33 @@ # @backstage/canon +## 0.5.0 + +### Minor Changes + +- 621fac9: We are updating the default size of the Button component in Canon to be small instead of medium. +- a842554: We set the default size for IconButton in Canon to be small instead of medium. +- 35fd51d: Move TextField component to use react Aria under the hood. Introducing a new FieldLabel component to help build custom fields. +- 78204a2: **Breaking** We are adding a new as prop on the Heading and Text component to make it easier to change the component tag. We are removing the render prop in favour of the as prop. +- c49e335: TextField in Canon now has multiple label sizes as well as the capacity to hide label and description but still make them available for screen readers. +- 24b45ef: Fixes spacing props on layout components and aligned on naming for the Grid component. You should now call the Grid root component using instead of just . + +### Patch Changes + +- 44df879: Add min-width: 0; by default on every Flex components in Canon to help support truncated texts inside flex elements. +- ee6ffe6: Fix styling for the title4 prop on the Heading component in Canon. +- f2f814a: Added a render prop to the Button component in Canon to use it as a link. +- 98f02a6: Add new Switch component in Canon. +- c94f8e0: The filter input in menu comboboxes should now always use the full width of the menu it's in. +- 269316d: Remove leftover console.log from Container component. + +## 0.5.0-next.2 + +### Patch Changes + +- 44df879: Add min-width: 0; by default on every Flex components in Canon to help support truncated texts inside flex elements. +- ee6ffe6: Fix styling for the title4 prop on the Heading component in Canon. +- f2f814a: Added a render prop to the Button component in Canon to use it as a link. + ## 0.5.0-next.1 ### Minor Changes diff --git a/packages/canon/css/components.css b/packages/canon/css/components.css index bcdbb86235..d420031ada 100644 --- a/packages/canon/css/components.css +++ b/packages/canon/css/components.css @@ -144,80 +144,6 @@ height: 1.25rem; } -.canon-CollapsiblePanel { - height: var(--collapsible-panel-height); - transition: all .15s ease-out; - display: flex; - overflow: hidden; - - &[data-starting-style], &[data-ending-style] { - height: 0; - } -} - -.canon-DataTableRoot { - gap: var(--canon-space-3); - flex-direction: column; - display: flex; -} - -.canon-DataTablePagination { - padding-top: var(--canon-space-5); - justify-content: space-between; - align-items: center; - display: flex; -} - -.canon-DataTablePagination--left { - justify-content: space-between; - align-items: center; - display: flex; -} - -.canon-DataTablePagination--right { - justify-content: space-between; - align-items: center; - gap: var(--canon-space-2); - display: flex; -} - -.canon-DataTablePagination--select { - min-width: 10.5rem; -} - -.canon-Flex { - min-width: 0; - display: flex; -} - -.canon-Grid { - display: grid; -} - -.canon-Container { - max-width: 120rem; - padding-inline: var(--canon-space-4); - margin-inline: auto; - transition: padding .2s ease-in-out; -} - -@media (width >= 640px) { - .canon-Container { - padding-inline: var(--canon-space-8); - } -} - -@media (width >= 1024px) { - .canon-Container { - padding-inline: var(--canon-space-12); - } -} - -.canon-Icon { - width: 1rem; - height: 1rem; -} - .canon-CheckboxRoot { width: 1rem; height: 1rem; @@ -271,6 +197,475 @@ display: flex; } +.canon-CollapsiblePanel { + height: var(--collapsible-panel-height); + transition: all .15s ease-out; + display: flex; + overflow: hidden; + + &[data-starting-style], &[data-ending-style] { + height: 0; + } +} + +.canon-Container { + max-width: 120rem; + padding-inline: var(--canon-space-4); + margin-inline: auto; + transition: padding .2s ease-in-out; +} + +@media (width >= 640px) { + .canon-Container { + padding-inline: var(--canon-space-8); + } +} + +@media (width >= 1024px) { + .canon-Container { + padding-inline: var(--canon-space-12); + } +} + +.canon-DataTableRoot { + gap: var(--canon-space-3); + flex-direction: column; + display: flex; +} + +.canon-DataTablePagination { + padding-top: var(--canon-space-5); + justify-content: space-between; + align-items: center; + display: flex; +} + +.canon-DataTablePagination--left { + justify-content: space-between; + align-items: center; + display: flex; +} + +.canon-DataTablePagination--right { + justify-content: space-between; + align-items: center; + gap: var(--canon-space-2); + display: flex; +} + +.canon-DataTablePagination--select { + min-width: 10.5rem; +} + +.canon-FieldLabel { + margin-bottom: var(--canon-space-3); + gap: var(--canon-space-1); + flex-direction: column; + display: flex; +} + +.canon-FieldLabelLabel { + color: var(--canon-fg-primary); + cursor: pointer; + font-weight: var(--canon-font-weight-regular); + font-size: var(--canon-font-size-2); + margin-right: auto; +} + +.canon-FieldLabelSecondaryLabel { + color: var(--canon-fg-secondary); + font-weight: var(--canon-font-weight-regular); + margin-left: var(--canon-space-1); +} + +.canon-FieldLabelDescription { + font-weight: var(--canon-font-weight-regular); + font-size: var(--canon-font-size-2); + color: var(--canon-fg-secondary); + margin: 0; +} + +.canon-Flex { + min-width: 0; + display: flex; +} + +.canon-Grid { + display: grid; +} + +.canon-Heading { + font-family: var(--canon-font-regular); + color: var(--canon-fg-primary); + margin: 0; + padding: 0; + line-height: 100%; +} + +.canon-Heading[data-variant="display"] { + font-size: var(--canon-font-size-10); + font-weight: var(--canon-font-weight-bold); +} + +.canon-Heading[data-variant="title1"] { + font-size: var(--canon-font-size-9); + font-weight: var(--canon-font-weight-bold); +} + +.canon-Heading[data-variant="title2"] { + font-size: var(--canon-font-size-8); + font-weight: var(--canon-font-weight-bold); +} + +.canon-Heading[data-variant="title3"] { + font-size: var(--canon-font-size-7); + font-weight: var(--canon-font-weight-bold); +} + +.canon-Heading[data-variant="title4"] { + font-size: var(--canon-font-size-6); + font-weight: var(--canon-font-weight-bold); +} + +.canon-Heading[data-variant="title5"] { + font-size: var(--canon-font-size-5); + font-weight: var(--canon-font-weight-bold); +} + +.canon-Heading[data-color="primary"] { + color: var(--canon-fg-primary); +} + +.canon-Heading[data-color="secondary"] { + color: var(--canon-fg-secondary); +} + +.canon-Heading[data-truncate] { + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; +} + +.canon-Icon { + width: 1rem; + height: 1rem; +} + +.canon-IconButton { + user-select: none; + font-family: var(--canon-font-regular); + font-weight: var(--canon-font-weight-bold); + cursor: pointer; + border-radius: var(--canon-radius-2); + justify-content: center; + align-items: center; + gap: var(--canon-space-1_5); + border: none; + padding: 0; + display: inline-flex; + + &:disabled { + cursor: not-allowed; + } +} + +.canon-IconButton[data-variant="primary"] { + background-color: var(--canon-bg-solid); + color: var(--canon-fg-solid); + transition: background-color .15s, box-shadow .15s; + + &:hover { + background-color: var(--canon-bg-solid-hover); + } + + &:active { + background-color: var(--canon-bg-solid-pressed); + } + + &:focus-visible { + outline: 2px solid var(--canon-ring); + outline-offset: 2px; + } + + &:disabled { + background-color: var(--canon-bg-solid-disabled); + color: var(--canon-fg-solid-disabled); + } +} + +.canon-IconButton[data-variant="secondary"] { + background-color: var(--canon-bg-surface-1); + box-shadow: inset 0 0 0 1px var(--canon-border); + color: var(--canon-fg-primary); + transition: box-shadow .15s; + + &:hover { + box-shadow: inset 0 0 0 1px var(--canon-border-hover); + } + + &:active { + box-shadow: inset 0 0 0 1px var(--canon-border-pressed); + } + + &:focus-visible { + box-shadow: inset 0 0 0 2px var(--canon-ring); + outline: none; + transition: none; + } + + &:disabled { + box-shadow: inset 0 0 0 1px var(--canon-border-disabled); + color: var(--canon-fg-disabled); + } +} + +.canon-IconButton[data-size="medium"] { + font-size: var(--canon-font-size-4); + width: 40px; + height: 40px; +} + +.canon-IconButton[data-size="small"] { + font-size: var(--canon-font-size-3); + width: 32px; + height: 32px; +} + +.canon-IconButtonIcon[data-size="small"], .canon-IconButtonIcon[data-size="small"] svg { + width: 1rem; + height: 1rem; +} + +.canon-IconButtonIcon[data-size="medium"], .canon-IconButtonIcon[data-size="medium"] svg { + width: 1.25rem; + height: 1.25rem; +} + +.canon-Link { + font-family: var(--canon-font-regular); + color: var(--canon-fg-link); + cursor: pointer; + margin: 0; + padding: 0; + text-decoration-line: none; + + &:hover { + color: var(--canon-fg-link-hover); + text-underline-offset: calc(.025em + 2px); + text-decoration-line: underline; + text-decoration-style: solid; + text-decoration-thickness: min(2px, max(1px, .05em)); + text-decoration-color: color-mix(in srgb, var(--canon-fg-link-hover) 30%, transparent); + } +} + +.canon-Link[data-variant="body"] { + font-size: var(--canon-font-size-3); + line-height: 140%; +} + +.canon-Link[data-variant="subtitle"] { + font-size: var(--canon-font-size-4); + line-height: 140%; +} + +.canon-Link[data-variant="caption"] { + font-size: var(--canon-font-size-2); + line-height: 140%; +} + +.canon-Link[data-variant="label"] { + font-size: var(--canon-font-size-1); + line-height: 140%; +} + +.canon-Link[data-weight="regular"] { + font-weight: var(--canon-font-weight-regular); +} + +.canon-Link[data-weight="bold"] { + font-weight: var(--canon-font-weight-bold); +} + +.canon-MenuPositioner { + outline: 0; +} + +.canon-MenuPopup { + background-color: var(--canon-bg-surface-1); + border: 1px solid var(--canon-border); + color: var(--canon-fg-primary); + transform-origin: var(--transform-origin); + max-width: min(var(--available-width), 340px); + max-height: min(var(--available-height), 500px); + padding-bottom: var(--canon-space-1); + border-radius: .375rem; + outline: none; + flex-direction: column; + transition: transform .15s, opacity .15s; + display: flex; + position: relative; + overflow: auto; + + &[data-starting-style], &[data-ending-style] { + opacity: 0; + transform: scale(.9); + } +} + +.canon-MenuItem { + user-select: none; + align-items: center; + gap: var(--canon-space-2); + height: 32px; + color: var(--canon-fg-primary); + border-radius: var(--canon-radius-2); + margin-inline: var(--canon-space-1); + padding-inline: var(--canon-space-2); + font-size: var(--canon-font-size-3); + cursor: pointer; + outline: 0; + flex-shrink: 0; + text-decoration: none; + display: flex; + + &:first-child { + margin-top: var(--canon-space-1); + } + + &[data-highlighted] { + background-color: var(--canon-gray-3); + } +} + +.canon-MenuSubmenuTrigger { + user-select: none; + justify-content: space-between; + align-items: center; + gap: var(--canon-space-2); + height: 32px; + color: var(--canon-fg-primary); + border-radius: var(--canon-radius-2); + margin-inline: var(--canon-space-1); + padding-inline: var(--canon-space-2); + font-size: var(--canon-font-size-3); + cursor: pointer; + outline: 0; + flex-shrink: 0; + text-decoration: none; + display: flex; + + & .canon-Icon { + color: var(--canon-fg-secondary); + } + + &:first-child { + margin-top: var(--canon-space-1); + } + + &[data-popup-open], &[data-highlighted] { + background-color: var(--canon-gray-3); + + & .canon-Icon { + color: var(--canon-fg-primary); + } + } +} + +.canon-MenuSeparator { + background-color: var(--color-gray-200); + height: 1px; + margin: .375rem 1rem; +} + +.canon-SubmenuComboboxSearch { + padding-inline: var(--canon-space-3); + border: none; + border-bottom: 1px solid var(--canon-border); + background-color: var(--canon-bg-surface-1); + width: 100%; + height: 32px; + color: var(--canon-fg-primary); + line-height: 140%; + font-size: var(--canon-font-size-3); + z-index: 1; + outline: none; + position: sticky; + top: 0; + + &::placeholder { + color: var(--canon-fg-secondary); + } + + &:disabled { + opacity: .6; + cursor: not-allowed; + } +} + +.canon-SubmenuComboboxItems { + padding-top: var(--canon-space-2); + outline: none; + flex-direction: column; + display: flex; + overflow-y: auto; +} + +.canon-SubmenuComboboxNoResults { + padding-inline: var(--canon-space-3); + padding-top: var(--canon-space-2); + padding-bottom: var(--canon-space-4); + color: var(--canon-fg-secondary); + font-size: var(--canon-font-size-3); +} + +.canon-SubmenuComboboxItem { + user-select: none; + justify-content: space-between; + align-items: center; + gap: var(--canon-space-2); + height: 32px; + color: var(--canon-fg-primary); + border-radius: var(--canon-radius-2); + margin-inline: var(--canon-space-1); + padding-inline: var(--canon-space-2); + font-size: var(--canon-font-size-3); + cursor: pointer; + outline: 0; + flex-shrink: 0; + text-decoration: none; + display: flex; + + &[data-highlighted] { + background-color: var(--canon-gray-3); + } + + &[data-disabled] { + opacity: .5; + cursor: not-allowed; + } +} + +.canon-SubmenuComboboxItemCheckbox { + width: 16px; + height: 16px; + color: var(--canon-fg-primary); + border-radius: var(--canon-radius-2); + border: 1px solid var(--canon-border); + background: var(--canon-bg-surface-1); + flex-shrink: 0; + justify-content: center; + align-items: center; + display: flex; +} + +.canon-SubmenuComboboxItemLabel { + text-overflow: ellipsis; + white-space: nowrap; + flex: 1; + overflow: hidden; +} + .canon-TableRoot { caption-side: bottom; border-collapse: collapse; @@ -487,148 +882,6 @@ overflow: hidden; } -.canon-Heading { - font-family: var(--canon-font-regular); - color: var(--canon-fg-primary); - margin: 0; - padding: 0; - line-height: 100%; -} - -.canon-Heading[data-variant="display"] { - font-size: var(--canon-font-size-10); - font-weight: var(--canon-font-weight-bold); -} - -.canon-Heading[data-variant="title1"] { - font-size: var(--canon-font-size-9); - font-weight: var(--canon-font-weight-bold); -} - -.canon-Heading[data-variant="title2"] { - font-size: var(--canon-font-size-8); - font-weight: var(--canon-font-weight-bold); -} - -.canon-Heading[data-variant="title3"] { - font-size: var(--canon-font-size-7); - font-weight: var(--canon-font-weight-bold); -} - -.canon-Heading[data-variant="title4"] { - font-size: var(--canon-font-size-6); - font-weight: var(--canon-font-weight-bold); -} - -.canon-Heading[data-variant="title5"] { - font-size: var(--canon-font-size-5); - font-weight: var(--canon-font-weight-bold); -} - -.canon-Heading[data-color="primary"] { - color: var(--canon-fg-primary); -} - -.canon-Heading[data-color="secondary"] { - color: var(--canon-fg-secondary); -} - -.canon-Heading[data-truncate] { - text-overflow: ellipsis; - white-space: nowrap; - overflow: hidden; -} - -.canon-IconButton { - user-select: none; - font-family: var(--canon-font-regular); - font-weight: var(--canon-font-weight-bold); - cursor: pointer; - border-radius: var(--canon-radius-2); - justify-content: center; - align-items: center; - gap: var(--canon-space-1_5); - border: none; - padding: 0; - display: inline-flex; - - &:disabled { - cursor: not-allowed; - } -} - -.canon-IconButton[data-variant="primary"] { - background-color: var(--canon-bg-solid); - color: var(--canon-fg-solid); - transition: background-color .15s, box-shadow .15s; - - &:hover { - background-color: var(--canon-bg-solid-hover); - } - - &:active { - background-color: var(--canon-bg-solid-pressed); - } - - &:focus-visible { - outline: 2px solid var(--canon-ring); - outline-offset: 2px; - } - - &:disabled { - background-color: var(--canon-bg-solid-disabled); - color: var(--canon-fg-solid-disabled); - } -} - -.canon-IconButton[data-variant="secondary"] { - background-color: var(--canon-bg-surface-1); - box-shadow: inset 0 0 0 1px var(--canon-border); - color: var(--canon-fg-primary); - transition: box-shadow .15s; - - &:hover { - box-shadow: inset 0 0 0 1px var(--canon-border-hover); - } - - &:active { - box-shadow: inset 0 0 0 1px var(--canon-border-pressed); - } - - &:focus-visible { - box-shadow: inset 0 0 0 2px var(--canon-ring); - outline: none; - transition: none; - } - - &:disabled { - box-shadow: inset 0 0 0 1px var(--canon-border-disabled); - color: var(--canon-fg-disabled); - } -} - -.canon-IconButton[data-size="medium"] { - font-size: var(--canon-font-size-4); - width: 40px; - height: 40px; -} - -.canon-IconButton[data-size="small"] { - font-size: var(--canon-font-size-3); - width: 32px; - height: 32px; -} - -.canon-IconButtonIcon[data-size="small"], .canon-IconButtonIcon[data-size="small"] svg { - width: 1rem; - height: 1rem; -} - -.canon-IconButtonIcon[data-size="medium"], .canon-IconButtonIcon[data-size="medium"] svg { - width: 1.25rem; - height: 1.25rem; -} - .canon-TextField { font-family: var(--canon-font-regular); flex-direction: column; @@ -636,48 +889,26 @@ display: flex; } -.canon-TextFieldLabel { - font-size: var(--canon-font-size-2); - font-weight: var(--canon-font-weight-regular); - color: var(--canon-fg-primary); - margin-bottom: var(--canon-space-1_5); - cursor: pointer; - margin-right: auto; -} - -.canon-TextFieldLabel[data-disabled] { - cursor: default; -} - -.canon-TextFieldDescription { - font-size: var(--canon-font-size-2); - font-weight: var(--canon-font-weight-regular); - color: var(--canon-fg-secondary); - padding-top: var(--canon-space-1_5); - margin: 0; -} - -.canon-TextFieldError { - font-size: var(--canon-font-size-2); - font-weight: var(--canon-font-weight-regular); - color: var(--canon-fg-danger); - padding-top: var(--canon-space-1_5); - margin: 0; -} - .canon-TextFieldInputWrapper { - padding: 0 var(--canon-space-3); - border-radius: var(--canon-radius-3); - border: 1px solid var(--canon-border); - background-color: var(--canon-bg-surface-1); - align-items: center; - display: flex; + position: relative; +} + +.canon-TextFieldInputWrapper[data-size="small"] { + height: 2rem; +} + +.canon-TextFieldInputWrapper[data-size="medium"] { + height: 2.5rem; } .canon-TextFieldIcon { + left: var(--canon-space-3); margin-right: var(--canon-space-1); color: var(--canon-fg-primary); flex-shrink: 0; + position: absolute; + top: 50%; + transform: translateY(-50%); } .canon-TextFieldIcon[data-size="small"], .canon-TextFieldIcon[data-size="small"] svg { @@ -691,6 +922,10 @@ } .canon-TextFieldInput { + padding: 0 var(--canon-space-3); + border-radius: var(--canon-radius-3); + border: 1px solid var(--canon-border); + background-color: var(--canon-bg-surface-1); font-size: var(--canon-font-size-3); font-family: var(--canon-font-regular); font-weight: var(--canon-font-weight-regular); @@ -698,306 +933,48 @@ width: 100%; height: 100%; cursor: inherit; - background: none; - border: none; - padding: 0; + align-items: center; transition: border-color .2s ease-in-out, outline-color .2s ease-in-out; -} - -.canon-TextFieldInput:not([data-filled]):has( + .canon-TextFieldClearButton) { - padding-right: 1.25rem; -} - -.canon-TextFieldInput[type="search"]::-webkit-search-cancel-button, .canon-TextFieldInput[type="search"]::-webkit-search-decoration { - appearance: none; -} - -.canon-TextFieldClearButton { - margin-left: var(--canon-space-1); - vertical-align: middle; - color: var(--canon-fg-primary); - background: none; - border: none; - padding: 0; - display: none; -} - -.canon-TextFieldInput[data-filled] + .canon-TextFieldClearButton { - display: inline-block; -} - -.canon-TextFieldClearButtonIcon { - display: block; + display: flex; } .canon-TextFieldInput::placeholder { color: var(--canon-fg-secondary); } +.canon-TextFieldInput[data-icon] { + padding-left: var(--canon-space-8); +} + .canon-TextFieldInput[data-focused] { outline-color: var(--canon-border-pressed); outline-width: 0; } -.canon-TextFieldInputWrapper:has( > .canon-TextFieldInput:hover) { +.canon-TextFieldInput[data-hovered] { border-color: var(--canon-border-hover); } -.canon-TextField[data-focused] .canon-TextFieldInputWrapper { +.canon-TextFieldInput[data-focused] { border-color: var(--canon-border-pressed); + outline-width: 0; } -.canon-TextField[data-invalid] .canon-TextFieldInputWrapper { +.canon-TextFieldInput[data-invalid] { border-color: var(--canon-fg-danger); } -.canon-TextField[data-disabled] .canon-TextFieldInputWrapper { +.canon-TextFieldInput[data-disabled] { opacity: .5; cursor: not-allowed; border: 1px solid var(--canon-border-disabled); } -.canon-TextField[data-disabled] .canon-TextFieldClearButton { - cursor: inherit; -} - -.canon-TextFieldInputWrapper[data-size="small"] { - height: 2rem; -} - -.canon-TextFieldInputWrapper[data-size="medium"] { - height: 2.5rem; -} - -.canon-TextFieldRequired { - color: var(--canon-fg-secondary); +.canon-TextFieldError { + color: var(--canon-fg-danger); font-size: var(--canon-font-size-2); font-weight: var(--canon-font-weight-regular); - margin-left: var(--canon-space-1); -} - -.canon-MenuPositioner { - outline: 0; -} - -.canon-MenuPopup { - background-color: var(--canon-bg-surface-1); - border: 1px solid var(--canon-border); - color: var(--canon-fg-primary); - transform-origin: var(--transform-origin); - max-width: min(var(--available-width), 340px); - max-height: min(var(--available-height), 500px); - padding-bottom: var(--canon-space-1); - border-radius: .375rem; - outline: none; - flex-direction: column; - transition: transform .15s, opacity .15s; - display: flex; - position: relative; - overflow: auto; - - &[data-starting-style], &[data-ending-style] { - opacity: 0; - transform: scale(.9); - } -} - -.canon-MenuItem { - user-select: none; - align-items: center; - gap: var(--canon-space-2); - height: 32px; - color: var(--canon-fg-primary); - border-radius: var(--canon-radius-2); - margin-inline: var(--canon-space-1); - padding-inline: var(--canon-space-2); - font-size: var(--canon-font-size-3); - cursor: pointer; - outline: 0; - flex-shrink: 0; - text-decoration: none; - display: flex; - - &:first-child { - margin-top: var(--canon-space-1); - } - - &[data-highlighted] { - background-color: var(--canon-gray-3); - } -} - -.canon-MenuSubmenuTrigger { - user-select: none; - justify-content: space-between; - align-items: center; - gap: var(--canon-space-2); - height: 32px; - color: var(--canon-fg-primary); - border-radius: var(--canon-radius-2); - margin-inline: var(--canon-space-1); - padding-inline: var(--canon-space-2); - font-size: var(--canon-font-size-3); - cursor: pointer; - outline: 0; - flex-shrink: 0; - text-decoration: none; - display: flex; - - & .canon-Icon { - color: var(--canon-fg-secondary); - } - - &:first-child { - margin-top: var(--canon-space-1); - } - - &[data-popup-open], &[data-highlighted] { - background-color: var(--canon-gray-3); - - & .canon-Icon { - color: var(--canon-fg-primary); - } - } -} - -.canon-MenuSeparator { - background-color: var(--color-gray-200); - height: 1px; - margin: .375rem 1rem; -} - -.canon-SubmenuComboboxSearch { - padding-inline: var(--canon-space-3); - border: none; - border-bottom: 1px solid var(--canon-border); - background-color: var(--canon-bg-surface-1); - height: 32px; - color: var(--canon-fg-primary); - line-height: 140%; - font-size: var(--canon-font-size-3); - z-index: 1; - outline: none; - position: sticky; - top: 0; - - &::placeholder { - color: var(--canon-fg-secondary); - } - - &:disabled { - opacity: .6; - cursor: not-allowed; - } -} - -.canon-SubmenuComboboxItems { - padding-top: var(--canon-space-2); - outline: none; - flex-direction: column; - display: flex; - overflow-y: auto; -} - -.canon-SubmenuComboboxNoResults { - padding-inline: var(--canon-space-3); - padding-top: var(--canon-space-2); - padding-bottom: var(--canon-space-4); - color: var(--canon-fg-secondary); - font-size: var(--canon-font-size-3); -} - -.canon-SubmenuComboboxItem { - user-select: none; - justify-content: space-between; - align-items: center; - gap: var(--canon-space-2); - height: 32px; - color: var(--canon-fg-primary); - border-radius: var(--canon-radius-2); - margin-inline: var(--canon-space-1); - padding-inline: var(--canon-space-2); - font-size: var(--canon-font-size-3); - cursor: pointer; - outline: 0; - flex-shrink: 0; - text-decoration: none; - display: flex; - - &[data-highlighted] { - background-color: var(--canon-gray-3); - } - - &[data-disabled] { - opacity: .5; - cursor: not-allowed; - } -} - -.canon-SubmenuComboboxItemCheckbox { - width: 16px; - height: 16px; - color: var(--canon-fg-primary); - border-radius: var(--canon-radius-2); - border: 1px solid var(--canon-border); - background: var(--canon-bg-surface-1); - flex-shrink: 0; - justify-content: center; - align-items: center; - display: flex; -} - -.canon-SubmenuComboboxItemLabel { - text-overflow: ellipsis; - white-space: nowrap; - flex: 1; - overflow: hidden; -} - -.canon-Link { - font-family: var(--canon-font-regular); - color: var(--canon-fg-link); - cursor: pointer; - margin: 0; - padding: 0; - text-decoration-line: none; - - &:hover { - color: var(--canon-fg-link-hover); - text-underline-offset: calc(.025em + 2px); - text-decoration-line: underline; - text-decoration-style: solid; - text-decoration-thickness: min(2px, max(1px, .05em)); - text-decoration-color: color-mix(in srgb, var(--canon-fg-link-hover) 30%, transparent); - } -} - -.canon-Link[data-variant="body"] { - font-size: var(--canon-font-size-3); - line-height: 140%; -} - -.canon-Link[data-variant="subtitle"] { - font-size: var(--canon-font-size-4); - line-height: 140%; -} - -.canon-Link[data-variant="caption"] { - font-size: var(--canon-font-size-2); - line-height: 140%; -} - -.canon-Link[data-variant="label"] { - font-size: var(--canon-font-size-1); - line-height: 140%; -} - -.canon-Link[data-weight="regular"] { - font-weight: var(--canon-font-weight-regular); -} - -.canon-Link[data-weight="bold"] { - font-weight: var(--canon-font-weight-bold); + margin-top: var(--canon-space-2); } .canon-TooltipPopup { @@ -1301,3 +1278,61 @@ width: 100%; overflow: hidden; } + +.canon-Switch { + align-items: center; + gap: var(--canon-space-3); + font-size: var(--canon-font-size-3); + color: var(--canon-fg-primary); + cursor: pointer; + display: flex; + position: relative; + + &[data-pressed] .canon-SwitchIndicator { + &:before { + background: var(--canon-fg-solid); + } + } + + &[data-selected] { + & .canon-SwitchIndicator { + background: var(--canon-bg-solid); + + &:before { + background: var(--canon-fg-solid); + transform: translateX(100%); + } + } + + &[data-pressed] { + & .indicator { + background: var(--canon-gray-3); + } + } + } + + &[data-focus-visible] .canon-SwitchIndicator { + outline-offset: 2px; + outline: 2px solid; + } +} + +.canon-SwitchIndicator { + background: var(--canon-gray-3); + border: 2px; + border-radius: 1.143rem; + width: 2rem; + height: 1.143rem; + transition: all .2s; + + &:before { + content: ""; + background: var(--canon-fg-solid); + border-radius: 16px; + width: .857rem; + height: .857rem; + margin: .143rem; + transition: all .2s; + display: block; + } +} diff --git a/packages/canon/css/fieldlabel.css b/packages/canon/css/fieldlabel.css new file mode 100644 index 0000000000..1b708ed580 --- /dev/null +++ b/packages/canon/css/fieldlabel.css @@ -0,0 +1,27 @@ +.canon-FieldLabel { + margin-bottom: var(--canon-space-3); + gap: var(--canon-space-1); + flex-direction: column; + display: flex; +} + +.canon-FieldLabelLabel { + color: var(--canon-fg-primary); + cursor: pointer; + font-weight: var(--canon-font-weight-regular); + font-size: var(--canon-font-size-2); + margin-right: auto; +} + +.canon-FieldLabelSecondaryLabel { + color: var(--canon-fg-secondary); + font-weight: var(--canon-font-weight-regular); + margin-left: var(--canon-space-1); +} + +.canon-FieldLabelDescription { + font-weight: var(--canon-font-weight-regular); + font-size: var(--canon-font-size-2); + color: var(--canon-fg-secondary); + margin: 0; +} diff --git a/packages/canon/css/menu.css b/packages/canon/css/menu.css index 4c9433275c..7035fab12b 100644 --- a/packages/canon/css/menu.css +++ b/packages/canon/css/menu.css @@ -94,6 +94,7 @@ border: none; border-bottom: 1px solid var(--canon-border); background-color: var(--canon-bg-surface-1); + width: 100%; height: 32px; color: var(--canon-fg-primary); line-height: 140%; diff --git a/packages/canon/css/styles.css b/packages/canon/css/styles.css index 43b1cfbc01..b2d111b185 100644 --- a/packages/canon/css/styles.css +++ b/packages/canon/css/styles.css @@ -9368,80 +9368,6 @@ height: 1.25rem; } -.canon-CollapsiblePanel { - height: var(--collapsible-panel-height); - transition: all .15s ease-out; - display: flex; - overflow: hidden; - - &[data-starting-style], &[data-ending-style] { - height: 0; - } -} - -.canon-DataTableRoot { - gap: var(--canon-space-3); - flex-direction: column; - display: flex; -} - -.canon-DataTablePagination { - padding-top: var(--canon-space-5); - justify-content: space-between; - align-items: center; - display: flex; -} - -.canon-DataTablePagination--left { - justify-content: space-between; - align-items: center; - display: flex; -} - -.canon-DataTablePagination--right { - justify-content: space-between; - align-items: center; - gap: var(--canon-space-2); - display: flex; -} - -.canon-DataTablePagination--select { - min-width: 10.5rem; -} - -.canon-Flex { - min-width: 0; - display: flex; -} - -.canon-Grid { - display: grid; -} - -.canon-Container { - max-width: 120rem; - padding-inline: var(--canon-space-4); - margin-inline: auto; - transition: padding .2s ease-in-out; -} - -@media (width >= 640px) { - .canon-Container { - padding-inline: var(--canon-space-8); - } -} - -@media (width >= 1024px) { - .canon-Container { - padding-inline: var(--canon-space-12); - } -} - -.canon-Icon { - width: 1rem; - height: 1rem; -} - .canon-CheckboxRoot { width: 1rem; height: 1rem; @@ -9495,6 +9421,475 @@ display: flex; } +.canon-CollapsiblePanel { + height: var(--collapsible-panel-height); + transition: all .15s ease-out; + display: flex; + overflow: hidden; + + &[data-starting-style], &[data-ending-style] { + height: 0; + } +} + +.canon-Container { + max-width: 120rem; + padding-inline: var(--canon-space-4); + margin-inline: auto; + transition: padding .2s ease-in-out; +} + +@media (width >= 640px) { + .canon-Container { + padding-inline: var(--canon-space-8); + } +} + +@media (width >= 1024px) { + .canon-Container { + padding-inline: var(--canon-space-12); + } +} + +.canon-DataTableRoot { + gap: var(--canon-space-3); + flex-direction: column; + display: flex; +} + +.canon-DataTablePagination { + padding-top: var(--canon-space-5); + justify-content: space-between; + align-items: center; + display: flex; +} + +.canon-DataTablePagination--left { + justify-content: space-between; + align-items: center; + display: flex; +} + +.canon-DataTablePagination--right { + justify-content: space-between; + align-items: center; + gap: var(--canon-space-2); + display: flex; +} + +.canon-DataTablePagination--select { + min-width: 10.5rem; +} + +.canon-FieldLabel { + margin-bottom: var(--canon-space-3); + gap: var(--canon-space-1); + flex-direction: column; + display: flex; +} + +.canon-FieldLabelLabel { + color: var(--canon-fg-primary); + cursor: pointer; + font-weight: var(--canon-font-weight-regular); + font-size: var(--canon-font-size-2); + margin-right: auto; +} + +.canon-FieldLabelSecondaryLabel { + color: var(--canon-fg-secondary); + font-weight: var(--canon-font-weight-regular); + margin-left: var(--canon-space-1); +} + +.canon-FieldLabelDescription { + font-weight: var(--canon-font-weight-regular); + font-size: var(--canon-font-size-2); + color: var(--canon-fg-secondary); + margin: 0; +} + +.canon-Flex { + min-width: 0; + display: flex; +} + +.canon-Grid { + display: grid; +} + +.canon-Heading { + font-family: var(--canon-font-regular); + color: var(--canon-fg-primary); + margin: 0; + padding: 0; + line-height: 100%; +} + +.canon-Heading[data-variant="display"] { + font-size: var(--canon-font-size-10); + font-weight: var(--canon-font-weight-bold); +} + +.canon-Heading[data-variant="title1"] { + font-size: var(--canon-font-size-9); + font-weight: var(--canon-font-weight-bold); +} + +.canon-Heading[data-variant="title2"] { + font-size: var(--canon-font-size-8); + font-weight: var(--canon-font-weight-bold); +} + +.canon-Heading[data-variant="title3"] { + font-size: var(--canon-font-size-7); + font-weight: var(--canon-font-weight-bold); +} + +.canon-Heading[data-variant="title4"] { + font-size: var(--canon-font-size-6); + font-weight: var(--canon-font-weight-bold); +} + +.canon-Heading[data-variant="title5"] { + font-size: var(--canon-font-size-5); + font-weight: var(--canon-font-weight-bold); +} + +.canon-Heading[data-color="primary"] { + color: var(--canon-fg-primary); +} + +.canon-Heading[data-color="secondary"] { + color: var(--canon-fg-secondary); +} + +.canon-Heading[data-truncate] { + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; +} + +.canon-Icon { + width: 1rem; + height: 1rem; +} + +.canon-IconButton { + user-select: none; + font-family: var(--canon-font-regular); + font-weight: var(--canon-font-weight-bold); + cursor: pointer; + border-radius: var(--canon-radius-2); + justify-content: center; + align-items: center; + gap: var(--canon-space-1_5); + border: none; + padding: 0; + display: inline-flex; + + &:disabled { + cursor: not-allowed; + } +} + +.canon-IconButton[data-variant="primary"] { + background-color: var(--canon-bg-solid); + color: var(--canon-fg-solid); + transition: background-color .15s, box-shadow .15s; + + &:hover { + background-color: var(--canon-bg-solid-hover); + } + + &:active { + background-color: var(--canon-bg-solid-pressed); + } + + &:focus-visible { + outline: 2px solid var(--canon-ring); + outline-offset: 2px; + } + + &:disabled { + background-color: var(--canon-bg-solid-disabled); + color: var(--canon-fg-solid-disabled); + } +} + +.canon-IconButton[data-variant="secondary"] { + background-color: var(--canon-bg-surface-1); + box-shadow: inset 0 0 0 1px var(--canon-border); + color: var(--canon-fg-primary); + transition: box-shadow .15s; + + &:hover { + box-shadow: inset 0 0 0 1px var(--canon-border-hover); + } + + &:active { + box-shadow: inset 0 0 0 1px var(--canon-border-pressed); + } + + &:focus-visible { + box-shadow: inset 0 0 0 2px var(--canon-ring); + outline: none; + transition: none; + } + + &:disabled { + box-shadow: inset 0 0 0 1px var(--canon-border-disabled); + color: var(--canon-fg-disabled); + } +} + +.canon-IconButton[data-size="medium"] { + font-size: var(--canon-font-size-4); + width: 40px; + height: 40px; +} + +.canon-IconButton[data-size="small"] { + font-size: var(--canon-font-size-3); + width: 32px; + height: 32px; +} + +.canon-IconButtonIcon[data-size="small"], .canon-IconButtonIcon[data-size="small"] svg { + width: 1rem; + height: 1rem; +} + +.canon-IconButtonIcon[data-size="medium"], .canon-IconButtonIcon[data-size="medium"] svg { + width: 1.25rem; + height: 1.25rem; +} + +.canon-Link { + font-family: var(--canon-font-regular); + color: var(--canon-fg-link); + cursor: pointer; + margin: 0; + padding: 0; + text-decoration-line: none; + + &:hover { + color: var(--canon-fg-link-hover); + text-underline-offset: calc(.025em + 2px); + text-decoration-line: underline; + text-decoration-style: solid; + text-decoration-thickness: min(2px, max(1px, .05em)); + text-decoration-color: color-mix(in srgb, var(--canon-fg-link-hover) 30%, transparent); + } +} + +.canon-Link[data-variant="body"] { + font-size: var(--canon-font-size-3); + line-height: 140%; +} + +.canon-Link[data-variant="subtitle"] { + font-size: var(--canon-font-size-4); + line-height: 140%; +} + +.canon-Link[data-variant="caption"] { + font-size: var(--canon-font-size-2); + line-height: 140%; +} + +.canon-Link[data-variant="label"] { + font-size: var(--canon-font-size-1); + line-height: 140%; +} + +.canon-Link[data-weight="regular"] { + font-weight: var(--canon-font-weight-regular); +} + +.canon-Link[data-weight="bold"] { + font-weight: var(--canon-font-weight-bold); +} + +.canon-MenuPositioner { + outline: 0; +} + +.canon-MenuPopup { + background-color: var(--canon-bg-surface-1); + border: 1px solid var(--canon-border); + color: var(--canon-fg-primary); + transform-origin: var(--transform-origin); + max-width: min(var(--available-width), 340px); + max-height: min(var(--available-height), 500px); + padding-bottom: var(--canon-space-1); + border-radius: .375rem; + outline: none; + flex-direction: column; + transition: transform .15s, opacity .15s; + display: flex; + position: relative; + overflow: auto; + + &[data-starting-style], &[data-ending-style] { + opacity: 0; + transform: scale(.9); + } +} + +.canon-MenuItem { + user-select: none; + align-items: center; + gap: var(--canon-space-2); + height: 32px; + color: var(--canon-fg-primary); + border-radius: var(--canon-radius-2); + margin-inline: var(--canon-space-1); + padding-inline: var(--canon-space-2); + font-size: var(--canon-font-size-3); + cursor: pointer; + outline: 0; + flex-shrink: 0; + text-decoration: none; + display: flex; + + &:first-child { + margin-top: var(--canon-space-1); + } + + &[data-highlighted] { + background-color: var(--canon-gray-3); + } +} + +.canon-MenuSubmenuTrigger { + user-select: none; + justify-content: space-between; + align-items: center; + gap: var(--canon-space-2); + height: 32px; + color: var(--canon-fg-primary); + border-radius: var(--canon-radius-2); + margin-inline: var(--canon-space-1); + padding-inline: var(--canon-space-2); + font-size: var(--canon-font-size-3); + cursor: pointer; + outline: 0; + flex-shrink: 0; + text-decoration: none; + display: flex; + + & .canon-Icon { + color: var(--canon-fg-secondary); + } + + &:first-child { + margin-top: var(--canon-space-1); + } + + &[data-popup-open], &[data-highlighted] { + background-color: var(--canon-gray-3); + + & .canon-Icon { + color: var(--canon-fg-primary); + } + } +} + +.canon-MenuSeparator { + background-color: var(--color-gray-200); + height: 1px; + margin: .375rem 1rem; +} + +.canon-SubmenuComboboxSearch { + padding-inline: var(--canon-space-3); + border: none; + border-bottom: 1px solid var(--canon-border); + background-color: var(--canon-bg-surface-1); + width: 100%; + height: 32px; + color: var(--canon-fg-primary); + line-height: 140%; + font-size: var(--canon-font-size-3); + z-index: 1; + outline: none; + position: sticky; + top: 0; + + &::placeholder { + color: var(--canon-fg-secondary); + } + + &:disabled { + opacity: .6; + cursor: not-allowed; + } +} + +.canon-SubmenuComboboxItems { + padding-top: var(--canon-space-2); + outline: none; + flex-direction: column; + display: flex; + overflow-y: auto; +} + +.canon-SubmenuComboboxNoResults { + padding-inline: var(--canon-space-3); + padding-top: var(--canon-space-2); + padding-bottom: var(--canon-space-4); + color: var(--canon-fg-secondary); + font-size: var(--canon-font-size-3); +} + +.canon-SubmenuComboboxItem { + user-select: none; + justify-content: space-between; + align-items: center; + gap: var(--canon-space-2); + height: 32px; + color: var(--canon-fg-primary); + border-radius: var(--canon-radius-2); + margin-inline: var(--canon-space-1); + padding-inline: var(--canon-space-2); + font-size: var(--canon-font-size-3); + cursor: pointer; + outline: 0; + flex-shrink: 0; + text-decoration: none; + display: flex; + + &[data-highlighted] { + background-color: var(--canon-gray-3); + } + + &[data-disabled] { + opacity: .5; + cursor: not-allowed; + } +} + +.canon-SubmenuComboboxItemCheckbox { + width: 16px; + height: 16px; + color: var(--canon-fg-primary); + border-radius: var(--canon-radius-2); + border: 1px solid var(--canon-border); + background: var(--canon-bg-surface-1); + flex-shrink: 0; + justify-content: center; + align-items: center; + display: flex; +} + +.canon-SubmenuComboboxItemLabel { + text-overflow: ellipsis; + white-space: nowrap; + flex: 1; + overflow: hidden; +} + .canon-TableRoot { caption-side: bottom; border-collapse: collapse; @@ -9711,148 +10106,6 @@ overflow: hidden; } -.canon-Heading { - font-family: var(--canon-font-regular); - color: var(--canon-fg-primary); - margin: 0; - padding: 0; - line-height: 100%; -} - -.canon-Heading[data-variant="display"] { - font-size: var(--canon-font-size-10); - font-weight: var(--canon-font-weight-bold); -} - -.canon-Heading[data-variant="title1"] { - font-size: var(--canon-font-size-9); - font-weight: var(--canon-font-weight-bold); -} - -.canon-Heading[data-variant="title2"] { - font-size: var(--canon-font-size-8); - font-weight: var(--canon-font-weight-bold); -} - -.canon-Heading[data-variant="title3"] { - font-size: var(--canon-font-size-7); - font-weight: var(--canon-font-weight-bold); -} - -.canon-Heading[data-variant="title4"] { - font-size: var(--canon-font-size-6); - font-weight: var(--canon-font-weight-bold); -} - -.canon-Heading[data-variant="title5"] { - font-size: var(--canon-font-size-5); - font-weight: var(--canon-font-weight-bold); -} - -.canon-Heading[data-color="primary"] { - color: var(--canon-fg-primary); -} - -.canon-Heading[data-color="secondary"] { - color: var(--canon-fg-secondary); -} - -.canon-Heading[data-truncate] { - text-overflow: ellipsis; - white-space: nowrap; - overflow: hidden; -} - -.canon-IconButton { - user-select: none; - font-family: var(--canon-font-regular); - font-weight: var(--canon-font-weight-bold); - cursor: pointer; - border-radius: var(--canon-radius-2); - justify-content: center; - align-items: center; - gap: var(--canon-space-1_5); - border: none; - padding: 0; - display: inline-flex; - - &:disabled { - cursor: not-allowed; - } -} - -.canon-IconButton[data-variant="primary"] { - background-color: var(--canon-bg-solid); - color: var(--canon-fg-solid); - transition: background-color .15s, box-shadow .15s; - - &:hover { - background-color: var(--canon-bg-solid-hover); - } - - &:active { - background-color: var(--canon-bg-solid-pressed); - } - - &:focus-visible { - outline: 2px solid var(--canon-ring); - outline-offset: 2px; - } - - &:disabled { - background-color: var(--canon-bg-solid-disabled); - color: var(--canon-fg-solid-disabled); - } -} - -.canon-IconButton[data-variant="secondary"] { - background-color: var(--canon-bg-surface-1); - box-shadow: inset 0 0 0 1px var(--canon-border); - color: var(--canon-fg-primary); - transition: box-shadow .15s; - - &:hover { - box-shadow: inset 0 0 0 1px var(--canon-border-hover); - } - - &:active { - box-shadow: inset 0 0 0 1px var(--canon-border-pressed); - } - - &:focus-visible { - box-shadow: inset 0 0 0 2px var(--canon-ring); - outline: none; - transition: none; - } - - &:disabled { - box-shadow: inset 0 0 0 1px var(--canon-border-disabled); - color: var(--canon-fg-disabled); - } -} - -.canon-IconButton[data-size="medium"] { - font-size: var(--canon-font-size-4); - width: 40px; - height: 40px; -} - -.canon-IconButton[data-size="small"] { - font-size: var(--canon-font-size-3); - width: 32px; - height: 32px; -} - -.canon-IconButtonIcon[data-size="small"], .canon-IconButtonIcon[data-size="small"] svg { - width: 1rem; - height: 1rem; -} - -.canon-IconButtonIcon[data-size="medium"], .canon-IconButtonIcon[data-size="medium"] svg { - width: 1.25rem; - height: 1.25rem; -} - .canon-TextField { font-family: var(--canon-font-regular); flex-direction: column; @@ -9860,48 +10113,26 @@ display: flex; } -.canon-TextFieldLabel { - font-size: var(--canon-font-size-2); - font-weight: var(--canon-font-weight-regular); - color: var(--canon-fg-primary); - margin-bottom: var(--canon-space-1_5); - cursor: pointer; - margin-right: auto; -} - -.canon-TextFieldLabel[data-disabled] { - cursor: default; -} - -.canon-TextFieldDescription { - font-size: var(--canon-font-size-2); - font-weight: var(--canon-font-weight-regular); - color: var(--canon-fg-secondary); - padding-top: var(--canon-space-1_5); - margin: 0; -} - -.canon-TextFieldError { - font-size: var(--canon-font-size-2); - font-weight: var(--canon-font-weight-regular); - color: var(--canon-fg-danger); - padding-top: var(--canon-space-1_5); - margin: 0; -} - .canon-TextFieldInputWrapper { - padding: 0 var(--canon-space-3); - border-radius: var(--canon-radius-3); - border: 1px solid var(--canon-border); - background-color: var(--canon-bg-surface-1); - align-items: center; - display: flex; + position: relative; +} + +.canon-TextFieldInputWrapper[data-size="small"] { + height: 2rem; +} + +.canon-TextFieldInputWrapper[data-size="medium"] { + height: 2.5rem; } .canon-TextFieldIcon { + left: var(--canon-space-3); margin-right: var(--canon-space-1); color: var(--canon-fg-primary); flex-shrink: 0; + position: absolute; + top: 50%; + transform: translateY(-50%); } .canon-TextFieldIcon[data-size="small"], .canon-TextFieldIcon[data-size="small"] svg { @@ -9915,6 +10146,10 @@ } .canon-TextFieldInput { + padding: 0 var(--canon-space-3); + border-radius: var(--canon-radius-3); + border: 1px solid var(--canon-border); + background-color: var(--canon-bg-surface-1); font-size: var(--canon-font-size-3); font-family: var(--canon-font-regular); font-weight: var(--canon-font-weight-regular); @@ -9922,306 +10157,48 @@ width: 100%; height: 100%; cursor: inherit; - background: none; - border: none; - padding: 0; + align-items: center; transition: border-color .2s ease-in-out, outline-color .2s ease-in-out; -} - -.canon-TextFieldInput:not([data-filled]):has( + .canon-TextFieldClearButton) { - padding-right: 1.25rem; -} - -.canon-TextFieldInput[type="search"]::-webkit-search-cancel-button, .canon-TextFieldInput[type="search"]::-webkit-search-decoration { - appearance: none; -} - -.canon-TextFieldClearButton { - margin-left: var(--canon-space-1); - vertical-align: middle; - color: var(--canon-fg-primary); - background: none; - border: none; - padding: 0; - display: none; -} - -.canon-TextFieldInput[data-filled] + .canon-TextFieldClearButton { - display: inline-block; -} - -.canon-TextFieldClearButtonIcon { - display: block; + display: flex; } .canon-TextFieldInput::placeholder { color: var(--canon-fg-secondary); } +.canon-TextFieldInput[data-icon] { + padding-left: var(--canon-space-8); +} + .canon-TextFieldInput[data-focused] { outline-color: var(--canon-border-pressed); outline-width: 0; } -.canon-TextFieldInputWrapper:has( > .canon-TextFieldInput:hover) { +.canon-TextFieldInput[data-hovered] { border-color: var(--canon-border-hover); } -.canon-TextField[data-focused] .canon-TextFieldInputWrapper { +.canon-TextFieldInput[data-focused] { border-color: var(--canon-border-pressed); + outline-width: 0; } -.canon-TextField[data-invalid] .canon-TextFieldInputWrapper { +.canon-TextFieldInput[data-invalid] { border-color: var(--canon-fg-danger); } -.canon-TextField[data-disabled] .canon-TextFieldInputWrapper { +.canon-TextFieldInput[data-disabled] { opacity: .5; cursor: not-allowed; border: 1px solid var(--canon-border-disabled); } -.canon-TextField[data-disabled] .canon-TextFieldClearButton { - cursor: inherit; -} - -.canon-TextFieldInputWrapper[data-size="small"] { - height: 2rem; -} - -.canon-TextFieldInputWrapper[data-size="medium"] { - height: 2.5rem; -} - -.canon-TextFieldRequired { - color: var(--canon-fg-secondary); +.canon-TextFieldError { + color: var(--canon-fg-danger); font-size: var(--canon-font-size-2); font-weight: var(--canon-font-weight-regular); - margin-left: var(--canon-space-1); -} - -.canon-MenuPositioner { - outline: 0; -} - -.canon-MenuPopup { - background-color: var(--canon-bg-surface-1); - border: 1px solid var(--canon-border); - color: var(--canon-fg-primary); - transform-origin: var(--transform-origin); - max-width: min(var(--available-width), 340px); - max-height: min(var(--available-height), 500px); - padding-bottom: var(--canon-space-1); - border-radius: .375rem; - outline: none; - flex-direction: column; - transition: transform .15s, opacity .15s; - display: flex; - position: relative; - overflow: auto; - - &[data-starting-style], &[data-ending-style] { - opacity: 0; - transform: scale(.9); - } -} - -.canon-MenuItem { - user-select: none; - align-items: center; - gap: var(--canon-space-2); - height: 32px; - color: var(--canon-fg-primary); - border-radius: var(--canon-radius-2); - margin-inline: var(--canon-space-1); - padding-inline: var(--canon-space-2); - font-size: var(--canon-font-size-3); - cursor: pointer; - outline: 0; - flex-shrink: 0; - text-decoration: none; - display: flex; - - &:first-child { - margin-top: var(--canon-space-1); - } - - &[data-highlighted] { - background-color: var(--canon-gray-3); - } -} - -.canon-MenuSubmenuTrigger { - user-select: none; - justify-content: space-between; - align-items: center; - gap: var(--canon-space-2); - height: 32px; - color: var(--canon-fg-primary); - border-radius: var(--canon-radius-2); - margin-inline: var(--canon-space-1); - padding-inline: var(--canon-space-2); - font-size: var(--canon-font-size-3); - cursor: pointer; - outline: 0; - flex-shrink: 0; - text-decoration: none; - display: flex; - - & .canon-Icon { - color: var(--canon-fg-secondary); - } - - &:first-child { - margin-top: var(--canon-space-1); - } - - &[data-popup-open], &[data-highlighted] { - background-color: var(--canon-gray-3); - - & .canon-Icon { - color: var(--canon-fg-primary); - } - } -} - -.canon-MenuSeparator { - background-color: var(--color-gray-200); - height: 1px; - margin: .375rem 1rem; -} - -.canon-SubmenuComboboxSearch { - padding-inline: var(--canon-space-3); - border: none; - border-bottom: 1px solid var(--canon-border); - background-color: var(--canon-bg-surface-1); - height: 32px; - color: var(--canon-fg-primary); - line-height: 140%; - font-size: var(--canon-font-size-3); - z-index: 1; - outline: none; - position: sticky; - top: 0; - - &::placeholder { - color: var(--canon-fg-secondary); - } - - &:disabled { - opacity: .6; - cursor: not-allowed; - } -} - -.canon-SubmenuComboboxItems { - padding-top: var(--canon-space-2); - outline: none; - flex-direction: column; - display: flex; - overflow-y: auto; -} - -.canon-SubmenuComboboxNoResults { - padding-inline: var(--canon-space-3); - padding-top: var(--canon-space-2); - padding-bottom: var(--canon-space-4); - color: var(--canon-fg-secondary); - font-size: var(--canon-font-size-3); -} - -.canon-SubmenuComboboxItem { - user-select: none; - justify-content: space-between; - align-items: center; - gap: var(--canon-space-2); - height: 32px; - color: var(--canon-fg-primary); - border-radius: var(--canon-radius-2); - margin-inline: var(--canon-space-1); - padding-inline: var(--canon-space-2); - font-size: var(--canon-font-size-3); - cursor: pointer; - outline: 0; - flex-shrink: 0; - text-decoration: none; - display: flex; - - &[data-highlighted] { - background-color: var(--canon-gray-3); - } - - &[data-disabled] { - opacity: .5; - cursor: not-allowed; - } -} - -.canon-SubmenuComboboxItemCheckbox { - width: 16px; - height: 16px; - color: var(--canon-fg-primary); - border-radius: var(--canon-radius-2); - border: 1px solid var(--canon-border); - background: var(--canon-bg-surface-1); - flex-shrink: 0; - justify-content: center; - align-items: center; - display: flex; -} - -.canon-SubmenuComboboxItemLabel { - text-overflow: ellipsis; - white-space: nowrap; - flex: 1; - overflow: hidden; -} - -.canon-Link { - font-family: var(--canon-font-regular); - color: var(--canon-fg-link); - cursor: pointer; - margin: 0; - padding: 0; - text-decoration-line: none; - - &:hover { - color: var(--canon-fg-link-hover); - text-underline-offset: calc(.025em + 2px); - text-decoration-line: underline; - text-decoration-style: solid; - text-decoration-thickness: min(2px, max(1px, .05em)); - text-decoration-color: color-mix(in srgb, var(--canon-fg-link-hover) 30%, transparent); - } -} - -.canon-Link[data-variant="body"] { - font-size: var(--canon-font-size-3); - line-height: 140%; -} - -.canon-Link[data-variant="subtitle"] { - font-size: var(--canon-font-size-4); - line-height: 140%; -} - -.canon-Link[data-variant="caption"] { - font-size: var(--canon-font-size-2); - line-height: 140%; -} - -.canon-Link[data-variant="label"] { - font-size: var(--canon-font-size-1); - line-height: 140%; -} - -.canon-Link[data-weight="regular"] { - font-weight: var(--canon-font-weight-regular); -} - -.canon-Link[data-weight="bold"] { - font-weight: var(--canon-font-weight-bold); + margin-top: var(--canon-space-2); } .canon-TooltipPopup { @@ -10525,3 +10502,61 @@ width: 100%; overflow: hidden; } + +.canon-Switch { + align-items: center; + gap: var(--canon-space-3); + font-size: var(--canon-font-size-3); + color: var(--canon-fg-primary); + cursor: pointer; + display: flex; + position: relative; + + &[data-pressed] .canon-SwitchIndicator { + &:before { + background: var(--canon-fg-solid); + } + } + + &[data-selected] { + & .canon-SwitchIndicator { + background: var(--canon-bg-solid); + + &:before { + background: var(--canon-fg-solid); + transform: translateX(100%); + } + } + + &[data-pressed] { + & .indicator { + background: var(--canon-gray-3); + } + } + } + + &[data-focus-visible] .canon-SwitchIndicator { + outline-offset: 2px; + outline: 2px solid; + } +} + +.canon-SwitchIndicator { + background: var(--canon-gray-3); + border: 2px; + border-radius: 1.143rem; + width: 2rem; + height: 1.143rem; + transition: all .2s; + + &:before { + content: ""; + background: var(--canon-fg-solid); + border-radius: 16px; + width: .857rem; + height: .857rem; + margin: .143rem; + transition: all .2s; + display: block; + } +} diff --git a/packages/canon/css/switch.css b/packages/canon/css/switch.css new file mode 100644 index 0000000000..ee517543d7 --- /dev/null +++ b/packages/canon/css/switch.css @@ -0,0 +1,57 @@ +.canon-Switch { + align-items: center; + gap: var(--canon-space-3); + font-size: var(--canon-font-size-3); + color: var(--canon-fg-primary); + cursor: pointer; + display: flex; + position: relative; + + &[data-pressed] .canon-SwitchIndicator { + &:before { + background: var(--canon-fg-solid); + } + } + + &[data-selected] { + & .canon-SwitchIndicator { + background: var(--canon-bg-solid); + + &:before { + background: var(--canon-fg-solid); + transform: translateX(100%); + } + } + + &[data-pressed] { + & .indicator { + background: var(--canon-gray-3); + } + } + } + + &[data-focus-visible] .canon-SwitchIndicator { + outline-offset: 2px; + outline: 2px solid; + } +} + +.canon-SwitchIndicator { + background: var(--canon-gray-3); + border: 2px; + border-radius: 1.143rem; + width: 2rem; + height: 1.143rem; + transition: all .2s; + + &:before { + content: ""; + background: var(--canon-fg-solid); + border-radius: 16px; + width: .857rem; + height: .857rem; + margin: .143rem; + transition: all .2s; + display: block; + } +} diff --git a/packages/canon/css/textfield.css b/packages/canon/css/textfield.css index c3c1a88ad6..fdb3621016 100644 --- a/packages/canon/css/textfield.css +++ b/packages/canon/css/textfield.css @@ -5,48 +5,26 @@ display: flex; } -.canon-TextFieldLabel { - font-size: var(--canon-font-size-2); - font-weight: var(--canon-font-weight-regular); - color: var(--canon-fg-primary); - margin-bottom: var(--canon-space-1_5); - cursor: pointer; - margin-right: auto; -} - -.canon-TextFieldLabel[data-disabled] { - cursor: default; -} - -.canon-TextFieldDescription { - font-size: var(--canon-font-size-2); - font-weight: var(--canon-font-weight-regular); - color: var(--canon-fg-secondary); - padding-top: var(--canon-space-1_5); - margin: 0; -} - -.canon-TextFieldError { - font-size: var(--canon-font-size-2); - font-weight: var(--canon-font-weight-regular); - color: var(--canon-fg-danger); - padding-top: var(--canon-space-1_5); - margin: 0; -} - .canon-TextFieldInputWrapper { - padding: 0 var(--canon-space-3); - border-radius: var(--canon-radius-3); - border: 1px solid var(--canon-border); - background-color: var(--canon-bg-surface-1); - align-items: center; - display: flex; + position: relative; +} + +.canon-TextFieldInputWrapper[data-size="small"] { + height: 2rem; +} + +.canon-TextFieldInputWrapper[data-size="medium"] { + height: 2.5rem; } .canon-TextFieldIcon { + left: var(--canon-space-3); margin-right: var(--canon-space-1); color: var(--canon-fg-primary); flex-shrink: 0; + position: absolute; + top: 50%; + transform: translateY(-50%); } .canon-TextFieldIcon[data-size="small"], .canon-TextFieldIcon[data-size="small"] svg { @@ -60,6 +38,10 @@ } .canon-TextFieldInput { + padding: 0 var(--canon-space-3); + border-radius: var(--canon-radius-3); + border: 1px solid var(--canon-border); + background-color: var(--canon-bg-surface-1); font-size: var(--canon-font-size-3); font-family: var(--canon-font-regular); font-weight: var(--canon-font-weight-regular); @@ -67,80 +49,46 @@ width: 100%; height: 100%; cursor: inherit; - background: none; - border: none; - padding: 0; + align-items: center; transition: border-color .2s ease-in-out, outline-color .2s ease-in-out; -} - -.canon-TextFieldInput:not([data-filled]):has( + .canon-TextFieldClearButton) { - padding-right: 1.25rem; -} - -.canon-TextFieldInput[type="search"]::-webkit-search-cancel-button, .canon-TextFieldInput[type="search"]::-webkit-search-decoration { - appearance: none; -} - -.canon-TextFieldClearButton { - margin-left: var(--canon-space-1); - vertical-align: middle; - color: var(--canon-fg-primary); - background: none; - border: none; - padding: 0; - display: none; -} - -.canon-TextFieldInput[data-filled] + .canon-TextFieldClearButton { - display: inline-block; -} - -.canon-TextFieldClearButtonIcon { - display: block; + display: flex; } .canon-TextFieldInput::placeholder { color: var(--canon-fg-secondary); } +.canon-TextFieldInput[data-icon] { + padding-left: var(--canon-space-8); +} + .canon-TextFieldInput[data-focused] { outline-color: var(--canon-border-pressed); outline-width: 0; } -.canon-TextFieldInputWrapper:has( > .canon-TextFieldInput:hover) { +.canon-TextFieldInput[data-hovered] { border-color: var(--canon-border-hover); } -.canon-TextField[data-focused] .canon-TextFieldInputWrapper { +.canon-TextFieldInput[data-focused] { border-color: var(--canon-border-pressed); + outline-width: 0; } -.canon-TextField[data-invalid] .canon-TextFieldInputWrapper { +.canon-TextFieldInput[data-invalid] { border-color: var(--canon-fg-danger); } -.canon-TextField[data-disabled] .canon-TextFieldInputWrapper { +.canon-TextFieldInput[data-disabled] { opacity: .5; cursor: not-allowed; border: 1px solid var(--canon-border-disabled); } -.canon-TextField[data-disabled] .canon-TextFieldClearButton { - cursor: inherit; -} - -.canon-TextFieldInputWrapper[data-size="small"] { - height: 2rem; -} - -.canon-TextFieldInputWrapper[data-size="medium"] { - height: 2.5rem; -} - -.canon-TextFieldRequired { - color: var(--canon-fg-secondary); +.canon-TextFieldError { + color: var(--canon-fg-danger); font-size: var(--canon-font-size-2); font-weight: var(--canon-font-weight-regular); - margin-left: var(--canon-space-1); + margin-top: var(--canon-space-2); } diff --git a/packages/canon/package.json b/packages/canon/package.json index ab9193806a..ba2a595f83 100644 --- a/packages/canon/package.json +++ b/packages/canon/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/canon", - "version": "0.5.0-next.1", + "version": "0.5.0", "backstage": { "role": "web-library" }, @@ -44,7 +44,8 @@ "@base-ui-components/react": "1.0.0-alpha.7", "@remixicon/react": "^4.6.0", "@tanstack/react-table": "^8.21.3", - "clsx": "^2.1.1" + "clsx": "^2.1.1", + "react-aria-components": "^1.10.1" }, "devDependencies": { "@backstage/cli": "workspace:^", diff --git a/packages/canon/report.api.md b/packages/canon/report.api.md index b6ce130ecc..4db3a81bbc 100644 --- a/packages/canon/report.api.md +++ b/packages/canon/report.api.md @@ -8,23 +8,26 @@ import { Breakpoint as Breakpoint_2 } from '@backstage/canon'; import { ChangeEvent } from 'react'; import { Collapsible as Collapsible_2 } from '@base-ui-components/react/collapsible'; import { ComponentProps } from 'react'; +import type { ComponentPropsWithRef } from 'react'; import { Context } from 'react'; import type { CSSProperties } from 'react'; +import type { ElementType } from 'react'; import { FC } from 'react'; import { FocusEvent as FocusEvent_2 } from 'react'; import { ForwardRefExoticComponent } from 'react'; import { HTMLAttributes } from 'react'; import { JSX as JSX_2 } from 'react/jsx-runtime'; import { Menu as Menu_2 } from '@base-ui-components/react/menu'; -import type { MouseEventHandler } from 'react'; import { ReactElement } from 'react'; import { ReactNode } from 'react'; import { RefAttributes } from 'react'; import type { RemixiconComponentType } from '@remixicon/react'; import { ScrollArea as ScrollArea_2 } from '@base-ui-components/react/scroll-area'; +import type { SwitchProps as SwitchProps_2 } from 'react-aria-components'; import { Table as Table_2 } from '@tanstack/react-table'; import { Tabs as Tabs_2 } from '@base-ui-components/react/tabs'; import { TdHTMLAttributes } from 'react'; +import type { TextFieldProps as TextFieldProps_2 } from 'react-aria-components'; import { ThHTMLAttributes } from 'react'; import { Tooltip as Tooltip_2 } from '@base-ui-components/react/tooltip'; import type { useRender } from '@base-ui-components/react/use-render'; @@ -353,6 +356,20 @@ export type EnumPropDef = { required?: boolean; }; +// @public (undocumented) +export const FieldLabel: ForwardRefExoticComponent< + FieldLabelProps & RefAttributes +>; + +// @public (undocumented) +export interface FieldLabelProps { + description?: string | null; + htmlFor?: string; + id?: string; + label?: string | null; + secondaryLabel?: string | null; +} + // @public (undocumented) export const Flex: ForwardRefExoticComponent< FlexProps & RefAttributes @@ -611,25 +628,15 @@ export interface GridProps extends SpaceProps { } // @public (undocumented) -export const Heading: ForwardRefExoticComponent< - Omit & RefAttributes ->; +export const Heading: ( + props: HeadingProps & { + ref?: React.Ref; + }, +) => React.ReactElement | null; // @public (undocumented) -export interface HeadingProps - extends Omit, 'color'> { - // (undocumented) - className?: string; - // (undocumented) - color?: - | 'primary' - | 'secondary' - | Partial>; - // (undocumented) - style?: React.CSSProperties; - // (undocumented) - truncate?: boolean; - // (undocumented) +export type HeadingOwnProps = { + as?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6'; variant?: | 'display' | 'title1' @@ -643,7 +650,18 @@ export interface HeadingProps 'display' | 'title1' | 'title2' | 'title3' | 'title4' | 'title5' > >; -} + color?: + | 'primary' + | 'secondary' + | Partial>; + truncate?: boolean; + className?: string; + style?: React.CSSProperties; +}; + +// @public (undocumented) +export type HeadingProps = HeadingOwnProps & + Omit, keyof HeadingOwnProps>; // @public (undocumented) export const heightPropDefs: { @@ -1159,6 +1177,16 @@ export type StylingPropDef = { parseValue?: (value: string) => string | undefined; }; +// @public (undocumented) +export const Switch: ForwardRefExoticComponent< + SwitchProps & RefAttributes +>; + +// @public (undocumented) +export interface SwitchProps extends SwitchProps_2 { + label?: string; +} + // @public export const Table: { Root: ForwardRefExoticComponent< @@ -1258,9 +1286,11 @@ export interface TabsRootWithoutOrientation > {} // @public (undocumented) -const Text_2: ForwardRefExoticComponent< - Omit & RefAttributes ->; +const Text_2: ( + props: TextProps & { + ref?: React.Ref; + }, +) => React.ReactElement | null; export { Text_2 as Text }; // @public (undocumented) @@ -1270,23 +1300,22 @@ export const TextField: ForwardRefExoticComponent< // @public (undocumented) export interface TextFieldProps - extends Omit, 'size'> { - className?: string; - description?: string; - error?: string | null; + extends TextFieldProps_2, + Omit { icon?: ReactNode; - label?: string; - name: string; - onClear?: MouseEventHandler; size?: 'small' | 'medium' | Partial>; } // @public (undocumented) -export interface TextProps - extends Omit, 'color'> { - // (undocumented) - className?: string; - // (undocumented) +export type TextOwnProps = { + as?: 'p' | 'span' | 'label'; + variant?: + | 'subtitle' + | 'body' + | 'caption' + | 'label' + | Partial>; + weight?: 'regular' | 'bold' | Partial>; color?: | 'primary' | 'secondary' @@ -1299,20 +1328,14 @@ export interface TextProps 'primary' | 'secondary' | 'danger' | 'warning' | 'success' > >; - // (undocumented) - style?: CSSProperties; - // (undocumented) truncate?: boolean; - // (undocumented) - variant?: - | 'subtitle' - | 'body' - | 'caption' - | 'label' - | Partial>; - // (undocumented) - weight?: 'regular' | 'bold' | Partial>; -} + className?: string; + style?: React.CSSProperties; +}; + +// @public (undocumented) +export type TextProps = TextOwnProps & + Omit, keyof TextOwnProps>; // @public (undocumented) export const Tooltip: { diff --git a/packages/canon/src/components/Collapsible/Collapsible.stories.tsx b/packages/canon/src/components/Collapsible/Collapsible.stories.tsx index 175dadba85..8e6a394672 100644 --- a/packages/canon/src/components/Collapsible/Collapsible.stories.tsx +++ b/packages/canon/src/components/Collapsible/Collapsible.stories.tsx @@ -15,7 +15,7 @@ */ import type { Meta, StoryObj } from '@storybook/react'; -import { Collapsible } from './'; +import { Collapsible } from './Collapsible'; import { Button } from '../Button'; import { Box } from '../Box'; import { Text } from '../Text'; diff --git a/packages/canon/src/components/FieldLabel/FieldLabel.stories.tsx b/packages/canon/src/components/FieldLabel/FieldLabel.stories.tsx new file mode 100644 index 0000000000..a82639eca0 --- /dev/null +++ b/packages/canon/src/components/FieldLabel/FieldLabel.stories.tsx @@ -0,0 +1,65 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { Meta, StoryObj } from '@storybook/react'; +import { FieldLabel } from './FieldLabel'; + +const meta = { + title: 'Forms/FieldLabel', + component: FieldLabel, + argTypes: { + label: { + control: 'text', + }, + secondaryLabel: { + control: 'text', + }, + description: { + control: 'text', + }, + }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: { + label: 'Label', + }, +}; + +export const WithSecondaryLabel: Story = { + args: { + ...Default.args, + secondaryLabel: 'Secondary Label', + }, +}; + +export const WithDescription: Story = { + args: { + ...Default.args, + description: 'Description', + }, +}; + +export const WithAllFields: Story = { + args: { + ...Default.args, + secondaryLabel: 'Secondary Label', + description: 'Description', + }, +}; diff --git a/packages/canon/src/components/FieldLabel/FieldLabel.styles.css b/packages/canon/src/components/FieldLabel/FieldLabel.styles.css new file mode 100644 index 0000000000..174e7f7326 --- /dev/null +++ b/packages/canon/src/components/FieldLabel/FieldLabel.styles.css @@ -0,0 +1,27 @@ +.canon-FieldLabel { + display: flex; + flex-direction: column; + margin-bottom: var(--canon-space-3); + gap: var(--canon-space-1); +} + +.canon-FieldLabelLabel { + color: var(--canon-fg-primary); + margin-right: auto; + cursor: pointer; + font-weight: var(--canon-font-weight-regular); + font-size: var(--canon-font-size-2); +} + +.canon-FieldLabelSecondaryLabel { + color: var(--canon-fg-secondary); + font-weight: var(--canon-font-weight-regular); + margin-left: var(--canon-space-1); +} + +.canon-FieldLabelDescription { + font-weight: var(--canon-font-weight-regular); + font-size: var(--canon-font-size-2); + color: var(--canon-fg-secondary); + margin: 0; +} diff --git a/packages/canon/src/components/FieldLabel/FieldLabel.tsx b/packages/canon/src/components/FieldLabel/FieldLabel.tsx new file mode 100644 index 0000000000..8fee7dffed --- /dev/null +++ b/packages/canon/src/components/FieldLabel/FieldLabel.tsx @@ -0,0 +1,50 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { Label } from 'react-aria-components'; +import { forwardRef } from 'react'; +import type { FieldLabelProps } from './types'; + +/** @public */ +export const FieldLabel = forwardRef( + (props: FieldLabelProps, ref) => { + const { label, secondaryLabel, description, htmlFor, id, ...rest } = props; + + if (!label) return null; + + return ( +
+ {label && ( + + )} + {description && ( +
{description}
+ )} +
+ ); + }, +); + +FieldLabel.displayName = 'FieldLabel'; diff --git a/packages/cli/src/modules/info/alpha.ts b/packages/canon/src/components/FieldLabel/index.ts similarity index 54% rename from packages/cli/src/modules/info/alpha.ts rename to packages/canon/src/components/FieldLabel/index.ts index 1e6f761f83..b9cebb1bf7 100644 --- a/packages/cli/src/modules/info/alpha.ts +++ b/packages/canon/src/components/FieldLabel/index.ts @@ -13,21 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import yargs from 'yargs'; -import { createCliPlugin } from '../../wiring/factory'; -export default createCliPlugin({ - pluginId: 'info', - init: async reg => { - reg.addCommand({ - path: ['info'], - description: 'Show helpful information for debugging and reporting bugs', - execute: async ({ args }) => { - yargs().parse(args); - const { default: command } = - require('./commands/info') as typeof import('./commands/info'); - await command(); - }, - }); - }, -}); +export * from './FieldLabel'; +export * from './types'; diff --git a/packages/canon/src/components/FieldLabel/types.ts b/packages/canon/src/components/FieldLabel/types.ts new file mode 100644 index 0000000000..dc4e444133 --- /dev/null +++ b/packages/canon/src/components/FieldLabel/types.ts @@ -0,0 +1,43 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** @public */ +export interface FieldLabelProps { + /** + * The label of the text field + */ + label?: string | null; + + /** + * The secondary label of the text field + */ + secondaryLabel?: string | null; + + /** + * The description of the text field + */ + description?: string | null; + + /** + * The HTML for attribute of the text field + */ + htmlFor?: string; + + /** + * The id of the text field + */ + id?: string; +} diff --git a/packages/canon/src/components/Heading/Heading.stories.tsx b/packages/canon/src/components/Heading/Heading.stories.tsx index 956118ddeb..2e608c09a3 100644 --- a/packages/canon/src/components/Heading/Heading.stories.tsx +++ b/packages/canon/src/components/Heading/Heading.stories.tsx @@ -96,7 +96,7 @@ export const WrappedInLink: Story = { export const CustomRender: Story = { args: { ...Default.args, - render:

, + as: 'h4', }, }; diff --git a/packages/canon/src/components/Heading/Heading.tsx b/packages/canon/src/components/Heading/Heading.tsx index 6ea2fe006b..4df5f85bc9 100644 --- a/packages/canon/src/components/Heading/Heading.tsx +++ b/packages/canon/src/components/Heading/Heading.tsx @@ -14,42 +14,49 @@ * limitations under the License. */ -import { forwardRef, useRef } from 'react'; +import { forwardRef } from 'react'; import clsx from 'clsx'; import { useResponsiveValue } from '../../hooks/useResponsiveValue'; -import { useRender } from '@base-ui-components/react/use-render'; +import type { ElementType } from 'react'; import type { HeadingProps } from './types'; +function HeadingComponent( + { + as, + variant = 'title1', + color = 'primary', + truncate, + className, + style, + ...restProps + }: HeadingProps, + ref: React.Ref, +) { + const Component = as || 'h1'; + + const responsiveVariant = useResponsiveValue(variant); + const responsiveColor = useResponsiveValue(color); + + return ( + + ); +} + +HeadingComponent.displayName = 'Heading'; + /** @public */ -export const Heading = forwardRef( - (props, ref) => { - const { - variant = 'title1', - color = 'primary', - truncate, - className, - render =

, - ...restProps - } = props; +export const Heading = forwardRef(HeadingComponent) as < + T extends ElementType = 'h1', +>( + props: HeadingProps & { ref?: React.Ref }, +) => React.ReactElement | null; - const responsiveVariant = useResponsiveValue(variant); - const responsiveColor = useResponsiveValue(color); - const internalRef = useRef(null); - - const { renderElement } = useRender({ - render, - props: { - className: clsx('canon-Heading', className), - ['data-variant']: responsiveVariant, - ['data-color']: responsiveColor, - ['data-truncate']: truncate, - ...restProps, - }, - refs: [ref, internalRef], - }); - - return renderElement(); - }, -); - -Heading.displayName = 'Heading'; +(Heading as any).displayName = 'Heading'; diff --git a/packages/canon/src/components/Heading/index.ts b/packages/canon/src/components/Heading/index.ts index 69b7c3c1a0..ca9845b122 100644 --- a/packages/canon/src/components/Heading/index.ts +++ b/packages/canon/src/components/Heading/index.ts @@ -14,5 +14,5 @@ * limitations under the License. */ -export { Heading } from './Heading'; -export type { HeadingProps } from './types'; +export * from './Heading'; +export * from './types'; diff --git a/packages/canon/src/components/Heading/types.ts b/packages/canon/src/components/Heading/types.ts index 7a94bdf2a4..f2317462c2 100644 --- a/packages/canon/src/components/Heading/types.ts +++ b/packages/canon/src/components/Heading/types.ts @@ -14,12 +14,12 @@ * limitations under the License. */ -import { Breakpoint } from '../../types'; -import type { useRender } from '@base-ui-components/react/use-render'; +import type { ElementType, ComponentPropsWithRef } from 'react'; +import type { Breakpoint } from '../../types'; /** @public */ -export interface HeadingProps - extends Omit, 'color'> { +export type HeadingOwnProps = { + as?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6'; variant?: | 'display' | 'title1' @@ -40,4 +40,8 @@ export interface HeadingProps truncate?: boolean; className?: string; style?: React.CSSProperties; -} +}; + +/** @public */ +export type HeadingProps = HeadingOwnProps & + Omit, keyof HeadingOwnProps>; diff --git a/packages/canon/src/components/Menu/Menu.styles.css b/packages/canon/src/components/Menu/Menu.styles.css index 07d257f57f..7ccaa7a634 100644 --- a/packages/canon/src/components/Menu/Menu.styles.css +++ b/packages/canon/src/components/Menu/Menu.styles.css @@ -93,6 +93,7 @@ .canon-SubmenuComboboxSearch { padding-inline: var(--canon-space-3); + width: 100%; height: 32px; border: none; border-bottom: 1px solid var(--canon-border); diff --git a/packages/canon/src/components/Switch/Switch.stories.tsx b/packages/canon/src/components/Switch/Switch.stories.tsx new file mode 100644 index 0000000000..165fefc97b --- /dev/null +++ b/packages/canon/src/components/Switch/Switch.stories.tsx @@ -0,0 +1,39 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { Meta, StoryObj } from '@storybook/react'; +import { Switch } from './Switch'; + +const meta = { + title: 'Components/Switch', + component: Switch, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: { + label: 'Switch', + }, +}; + +export const Disabled: Story = { + args: { + ...Default.args, + isDisabled: true, + }, +}; diff --git a/packages/canon/src/components/Switch/Switch.styles.css b/packages/canon/src/components/Switch/Switch.styles.css new file mode 100644 index 0000000000..98368efa13 --- /dev/null +++ b/packages/canon/src/components/Switch/Switch.styles.css @@ -0,0 +1,74 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +.canon-Switch { + display: flex; + /* This is needed so the HiddenInput is positioned correctly */ + position: relative; + align-items: center; + gap: var(--canon-space-3); + font-size: var(--canon-font-size-3); + color: var(--canon-fg-primary); + cursor: pointer; + + &[data-pressed] .canon-SwitchIndicator { + &:before { + background: var(--canon-fg-solid); + } + } + + &[data-selected] { + .canon-SwitchIndicator { + background: var(--canon-bg-solid); + + &:before { + background: var(--canon-fg-solid); + transform: translateX(100%); + } + } + + &[data-pressed] { + .indicator { + background: var(--canon-gray-3); + } + } + } + + &[data-focus-visible] .canon-SwitchIndicator { + outline: 2px solid; + outline-offset: 2px; + } +} + +.canon-SwitchIndicator { + width: 2rem; + height: 1.143rem; + border: 2px; + background: var(--canon-gray-3); + border-radius: 1.143rem; + transition: all 200ms; + + &:before { + content: ''; + display: block; + margin: 0.143rem; + width: 0.857rem; + height: 0.857rem; + background: var(--canon-fg-solid); + border-radius: 16px; + transition: all 200ms; + } +} diff --git a/packages/canon/src/components/Switch/Switch.tsx b/packages/canon/src/components/Switch/Switch.tsx new file mode 100644 index 0000000000..78bbaa3930 --- /dev/null +++ b/packages/canon/src/components/Switch/Switch.tsx @@ -0,0 +1,33 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { forwardRef } from 'react'; +import { Switch as AriaSwitch } from 'react-aria-components'; +import type { SwitchProps } from './types'; + +/** @public */ +export const Switch = forwardRef( + ({ label, ...props }, ref) => { + return ( + +
+ {label} + + ); + }, +); + +Switch.displayName = 'Switch'; diff --git a/packages/canon/src/components/Switch/index.tsx b/packages/canon/src/components/Switch/index.tsx new file mode 100644 index 0000000000..171969809d --- /dev/null +++ b/packages/canon/src/components/Switch/index.tsx @@ -0,0 +1,18 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './Switch'; +export * from './types'; diff --git a/packages/canon/src/components/Switch/types.ts b/packages/canon/src/components/Switch/types.ts new file mode 100644 index 0000000000..725671edd5 --- /dev/null +++ b/packages/canon/src/components/Switch/types.ts @@ -0,0 +1,25 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { SwitchProps as AriaSwitchProps } from 'react-aria-components'; + +/** @public */ +export interface SwitchProps extends AriaSwitchProps { + /** + * The label of the switch + */ + label?: string; +} diff --git a/packages/canon/src/components/Text/Text.stories.tsx b/packages/canon/src/components/Text/Text.stories.tsx index 5fe0c12cb5..5bb918f52e 100644 --- a/packages/canon/src/components/Text/Text.stories.tsx +++ b/packages/canon/src/components/Text/Text.stories.tsx @@ -111,7 +111,7 @@ export const WrappedInLink: Story = { export const CustomRender: Story = { args: { ...Default.args, - render: , + as: 'span', }, }; diff --git a/packages/canon/src/components/Text/Text.tsx b/packages/canon/src/components/Text/Text.tsx index 7e4dc74720..abf03ef0bd 100644 --- a/packages/canon/src/components/Text/Text.tsx +++ b/packages/canon/src/components/Text/Text.tsx @@ -14,47 +14,51 @@ * limitations under the License. */ -import { forwardRef, useRef } from 'react'; +import { forwardRef } from 'react'; import { useResponsiveValue } from '../../hooks/useResponsiveValue'; -import { useRender } from '@base-ui-components/react/use-render'; import clsx from 'clsx'; - +import type { ElementType } from 'react'; import type { TextProps } from './types'; +function TextComponent( + { + as, + variant = 'body', + weight = 'regular', + color = 'primary', + className, + truncate, + style, + ...restProps + }: TextProps, + ref: React.Ref, +) { + const Component = as || 'p'; + + // Get the responsive values for the variant and weight + const responsiveVariant = useResponsiveValue(variant); + const responsiveWeight = useResponsiveValue(weight); + const responsiveColor = useResponsiveValue(color); + + return ( + + ); +} + +TextComponent.displayName = 'Text'; + /** @public */ -export const Text = forwardRef( - (props, ref) => { - const { - variant = 'body', - weight = 'regular', - color = 'primary', - className, - truncate, - render =

, - ...restProps - } = props; +export const Text = forwardRef(TextComponent) as ( + props: TextProps & { ref?: React.Ref }, +) => React.ReactElement | null; - // Get the responsive values for the variant and weight - const responsiveVariant = useResponsiveValue(variant); - const responsiveWeight = useResponsiveValue(weight); - const responsiveColor = useResponsiveValue(color); - const internalRef = useRef(null); - - const { renderElement } = useRender({ - render, - props: { - className: clsx('canon-Text', className), - ['data-variant']: responsiveVariant, - ['data-weight']: responsiveWeight, - ['data-color']: responsiveColor, - ['data-truncate']: truncate, - ...restProps, - }, - refs: [ref, internalRef], - }); - - return renderElement(); - }, -); - -Text.displayName = 'Text'; +(Text as any).displayName = 'Text'; diff --git a/packages/canon/src/components/Text/index.ts b/packages/canon/src/components/Text/index.ts index ae1f532b2c..423288a8a4 100644 --- a/packages/canon/src/components/Text/index.ts +++ b/packages/canon/src/components/Text/index.ts @@ -14,5 +14,5 @@ * limitations under the License. */ -export { Text } from './Text'; -export type { TextProps } from './types'; +export * from './Text'; +export * from './types'; diff --git a/packages/canon/src/components/Text/types.ts b/packages/canon/src/components/Text/types.ts index f9c3c0aaca..ed01956248 100644 --- a/packages/canon/src/components/Text/types.ts +++ b/packages/canon/src/components/Text/types.ts @@ -14,13 +14,12 @@ * limitations under the License. */ -import type { CSSProperties } from 'react'; +import type { ElementType, ComponentPropsWithRef } from 'react'; import type { Breakpoint } from '../../types'; -import type { useRender } from '@base-ui-components/react/use-render'; /** @public */ -export interface TextProps - extends Omit, 'color'> { +export type TextOwnProps = { + as?: 'p' | 'span' | 'label'; variant?: | 'subtitle' | 'body' @@ -42,5 +41,9 @@ export interface TextProps >; truncate?: boolean; className?: string; - style?: CSSProperties; -} + style?: React.CSSProperties; +}; + +/** @public */ +export type TextProps = TextOwnProps & + Omit, keyof TextOwnProps>; diff --git a/packages/canon/src/components/TextField/TextField.stories.tsx b/packages/canon/src/components/TextField/TextField.stories.tsx index 7e625dad24..e07aa6ea05 100644 --- a/packages/canon/src/components/TextField/TextField.stories.tsx +++ b/packages/canon/src/components/TextField/TextField.stories.tsx @@ -16,12 +16,22 @@ import type { Meta, StoryObj } from '@storybook/react'; import { TextField } from './TextField'; -import { Flex } from '../Flex'; +import { Form } from 'react-aria-components'; import { Icon } from '../Icon'; +import { Flex } from '../Flex'; +import { FieldLabel } from '../FieldLabel'; const meta = { - title: 'Components/TextField', + title: 'Forms/TextField', component: TextField, + argTypes: { + isRequired: { + control: 'boolean', + }, + icon: { + control: 'object', + }, + }, } satisfies Meta; export default meta; @@ -30,14 +40,26 @@ type Story = StoryObj; export const Default: Story = { args: { name: 'url', - placeholder: 'Enter a URL', + defaultValue: 'Enter a URL', style: { maxWidth: '300px', }, }, }; -export const Filled: Story = { +export const Sizes: Story = { + args: { + ...Default.args, + }, + render: args => ( + + } /> + } /> + + ), +}; + +export const DefaultValue: Story = { args: { ...Default.args, defaultValue: 'https://example.com', @@ -61,60 +83,21 @@ export const WithDescription: Story = { export const Required: Story = { args: { ...WithLabel.args, - required: true, + isRequired: true, }, }; export const Disabled: Story = { - args: { - ...WithLabel.args, - disabled: true, - }, -}; - -export const Sizes: Story = { args: { ...Default.args, - label: 'Label', - description: 'Description', - }, - render: args => ( - - } /> - } /> - - ), -}; - -export const Responsive: Story = { - args: { - ...WithLabel.args, - size: { - initial: 'small', - sm: 'medium', - }, - }, -}; - -export const WithError: Story = { - args: { - ...WithLabel.args, - error: 'Invalid URL', - }, -}; - -export const WithErrorAndDescription: Story = { - args: { - ...WithLabel.args, - error: 'Invalid URL', - description: 'Description', + isDisabled: true, }, }; export const WithIcon: Story = { args: { - ...WithLabel.args, - placeholder: 'Search...', + ...Default.args, + defaultValue: 'Search...', icon: , }, }; @@ -122,23 +105,42 @@ export const WithIcon: Story = { export const DisabledWithIcon: Story = { args: { ...WithIcon.args, - disabled: true, + isDisabled: true, }, }; -export const WithOnClear: Story = { +export const ShowError: Story = { args: { ...WithLabel.args, - placeholder: 'Search...', - type: 'search', - onClear: () => console.log('Cleared!'), + }, + render: args => ( +

+ + + ), +}; + +export const Validation: Story = { + args: { + ...WithLabel.args, + validate: value => (value === 'admin' ? 'Nice try!' : null), }, }; -export const DisabledWithOnClear: Story = { - args: { - ...WithOnClear.args, - defaultValue: 'Testing', - disabled: true, - }, +export const CustomField: Story = { + render: () => ( + <> + + + + ), }; diff --git a/packages/canon/src/components/TextField/TextField.styles.css b/packages/canon/src/components/TextField/TextField.styles.css index be7ec3379c..9f2039b3af 100644 --- a/packages/canon/src/components/TextField/TextField.styles.css +++ b/packages/canon/src/components/TextField/TextField.styles.css @@ -21,45 +21,23 @@ width: 100%; } -.canon-TextFieldLabel { - font-size: var(--canon-font-size-2); - font-weight: var(--canon-font-weight-regular); - color: var(--canon-fg-primary); - margin-bottom: var(--canon-space-1_5); - margin-right: auto; - cursor: pointer; -} - -.canon-TextFieldLabel[data-disabled] { - cursor: default; -} - -.canon-TextFieldDescription { - font-size: var(--canon-font-size-2); - font-weight: var(--canon-font-weight-regular); - color: var(--canon-fg-secondary); - margin: 0; - padding-top: var(--canon-space-1_5); -} - -.canon-TextFieldError { - font-size: var(--canon-font-size-2); - font-weight: var(--canon-font-weight-regular); - color: var(--canon-fg-danger); - margin: 0; - padding-top: var(--canon-space-1_5); -} - .canon-TextFieldInputWrapper { - display: flex; - align-items: center; - padding: 0 var(--canon-space-3); - border-radius: var(--canon-radius-3); - border: 1px solid var(--canon-border); - background-color: var(--canon-bg-surface-1); + position: relative; +} + +.canon-TextFieldInputWrapper[data-size='small'] { + height: 2rem; +} + +.canon-TextFieldInputWrapper[data-size='medium'] { + height: 2.5rem; } .canon-TextFieldIcon { + position: absolute; + left: var(--canon-space-3); + top: 50%; + transform: translateY(-50%); margin-right: var(--canon-space-1); color: var(--canon-fg-primary); flex-shrink: 0; @@ -78,8 +56,13 @@ } .canon-TextFieldInput { - border: none; - background: none; + display: flex; + align-items: center; + padding: 0 var(--canon-space-3); + border-radius: var(--canon-radius-3); + border: 1px solid var(--canon-border); + background-color: var(--canon-bg-surface-1); + font-size: var(--canon-font-size-3); font-family: var(--canon-font-regular); font-weight: var(--canon-font-weight-regular); @@ -88,78 +71,43 @@ width: 100%; height: 100%; cursor: inherit; - padding: 0; -} - -.canon-TextFieldInput:not([data-filled]):has(+ .canon-TextFieldClearButton) { - padding-right: 1.25rem; -} - -.canon-TextFieldInput[type='search']::-webkit-search-cancel-button, -.canon-TextFieldInput[type='search']::-webkit-search-decoration { - appearance: none; -} - -.canon-TextFieldClearButton { - display: none; - padding: 0; - margin-left: var(--canon-space-1); - background: none; - border: none; - vertical-align: middle; - color: var(--canon-fg-primary); -} - -.canon-TextFieldInput[data-filled] + .canon-TextFieldClearButton { - display: inline-block; -} - -.canon-TextFieldClearButtonIcon { - display: block; } .canon-TextFieldInput::placeholder { color: var(--canon-fg-secondary); } +.canon-TextFieldInput[data-icon] { + padding-left: var(--canon-space-8); +} + .canon-TextFieldInput[data-focused] { outline-color: var(--canon-border-pressed); outline-width: 0px; } -.canon-TextFieldInputWrapper:has(> .canon-TextFieldInput:hover) { +.canon-TextFieldInput[data-hovered] { border-color: var(--canon-border-hover); } -.canon-TextField[data-focused] .canon-TextFieldInputWrapper { +.canon-TextFieldInput[data-focused] { border-color: var(--canon-border-pressed); + outline-width: 0px; } -.canon-TextField[data-invalid] .canon-TextFieldInputWrapper { +.canon-TextFieldInput[data-invalid] { border-color: var(--canon-fg-danger); } -.canon-TextField[data-disabled] .canon-TextFieldInputWrapper { +.canon-TextFieldInput[data-disabled] { opacity: 0.5; cursor: not-allowed; border: 1px solid var(--canon-border-disabled); } -.canon-TextField[data-disabled] .canon-TextFieldClearButton { - cursor: inherit; -} - -.canon-TextFieldInputWrapper[data-size='small'] { - height: 2rem; -} - -.canon-TextFieldInputWrapper[data-size='medium'] { - height: 2.5rem; -} - -.canon-TextFieldRequired { - color: var(--canon-fg-secondary); +.canon-TextFieldError { + color: var(--canon-fg-danger); font-size: var(--canon-font-size-2); font-weight: var(--canon-font-weight-regular); - margin-left: var(--canon-space-1); + margin-top: var(--canon-space-2); } diff --git a/packages/canon/src/components/TextField/TextField.tsx b/packages/canon/src/components/TextField/TextField.tsx index e4cf43a711..444e76e983 100644 --- a/packages/canon/src/components/TextField/TextField.tsx +++ b/packages/canon/src/components/TextField/TextField.tsx @@ -14,88 +14,80 @@ * limitations under the License. */ -import { Field } from '@base-ui-components/react/field'; -import { forwardRef } from 'react'; +import { forwardRef, useEffect } from 'react'; +import { + Input, + TextField as AriaTextField, + FieldError, +} from 'react-aria-components'; import { useResponsiveValue } from '../../hooks/useResponsiveValue'; import clsx from 'clsx'; +import { FieldLabel } from '../FieldLabel'; import type { TextFieldProps } from './types'; -import { Icon } from '../Icon'; /** @public */ export const TextField = forwardRef( - (props: TextFieldProps, ref) => { + (props, ref) => { const { className, + icon, size = 'small', label, + secondaryLabel, description, - error, - required, - style, - disabled, - icon, - onClear, + isRequired, + 'aria-label': ariaLabel, + 'aria-labelledby': ariaLabelledBy, ...rest } = props; + useEffect(() => { + if (!label && !ariaLabel && !ariaLabelledBy) { + console.warn( + 'TextField requires either a visible label, aria-label, or aria-labelledby for accessibility', + ); + } + }, [label, ariaLabel, ariaLabelledBy]); + // Get the responsive value for the variant const responsiveSize = useResponsiveValue(size); + // If a secondary label is provided, use it. Otherwise, use 'Required' if the field is required. + const secondaryLabelText = + secondaryLabel || (isRequired ? 'Required' : null); + return ( - - {label && ( - - {label} - {required && ( - - )} - - )} +
{icon && ( )} - - {onClear && ( - - )}
- {description && ( - - {description} - - )} - {error && ( - - {error} - - )} -
+ + ); }, ); diff --git a/packages/canon/src/components/TextField/index.ts b/packages/canon/src/components/TextField/index.ts index 29df00ccaf..95a838fb46 100644 --- a/packages/canon/src/components/TextField/index.ts +++ b/packages/canon/src/components/TextField/index.ts @@ -15,4 +15,4 @@ */ export * from './TextField'; -export type { TextFieldProps } from './types'; +export * from './types'; diff --git a/packages/canon/src/components/TextField/types.ts b/packages/canon/src/components/TextField/types.ts index 8a37a23efe..92fa077389 100644 --- a/packages/canon/src/components/TextField/types.ts +++ b/packages/canon/src/components/TextField/types.ts @@ -14,49 +14,23 @@ * limitations under the License. */ +import type { TextFieldProps as AriaTextFieldProps } from 'react-aria-components'; +import { ReactNode } from 'react'; import type { Breakpoint } from '../../types'; -import type { ReactNode, MouseEventHandler } from 'react'; +import type { FieldLabelProps } from '../FieldLabel/types'; + /** @public */ export interface TextFieldProps - extends Omit, 'size'> { - /** - * The class name of the text field - */ - className?: string; - - /** - * The size of the text field - * @defaultValue 'medium' - */ - size?: 'small' | 'medium' | Partial>; - - /** - * The label of the text field - */ - label?: string; - - /** - * The description of the text field - */ - description?: string; - - /** - * The name of the text field - */ - name: string; - - /** - * The error message of the text field - */ - error?: string | null; - + extends AriaTextFieldProps, + Omit { /** * An icon to render before the input */ icon?: ReactNode; /** - * Handler to call when the clear button is pressed + * The size of the text field + * @defaultValue 'medium' */ - onClear?: MouseEventHandler; + size?: 'small' | 'medium' | Partial>; } diff --git a/packages/canon/src/css/components.css b/packages/canon/src/css/components.css index 7cee946e3b..c85c1bbdd9 100644 --- a/packages/canon/src/css/components.css +++ b/packages/canon/src/css/components.css @@ -17,14 +17,19 @@ @import '../components/Avatar/Avatar.styles.css'; @import '../components/Box/styles.css'; @import '../components/Button/styles.css'; +@import '../components/Checkbox/styles.css'; @import '../components/Collapsible/Collapsible.styles.css'; +@import '../components/Container/styles.css'; @import '../components/DataTable/Root/DataTableRoot.styles.css'; @import '../components/DataTable/Pagination/DataTablePagination.styles.css'; +@import '../components/FieldLabel/FieldLabel.styles.css'; @import '../components/Flex/styles.css'; @import '../components/Grid/styles.css'; -@import '../components/Container/styles.css'; +@import '../components/Heading/styles.css'; @import '../components/Icon/styles.css'; -@import '../components/Checkbox/styles.css'; +@import '../components/IconButton/styles.css'; +@import '../components/Link/styles.css'; +@import '../components/Menu/Menu.styles.css'; @import '../components/Table/styles.css'; @import '../components/Table/TableCell/TableCell.styles.css'; @import '../components/Table/TableCellText/TableCellText.styles.css'; @@ -32,11 +37,8 @@ @import '../components/Table/TableCellProfile/TableCellProfile.styles.css'; @import '../components/Tabs/Tabs.styles.css'; @import '../components/Text/styles.css'; -@import '../components/Heading/styles.css'; -@import '../components/IconButton/styles.css'; @import '../components/TextField/TextField.styles.css'; -@import '../components/Menu/Menu.styles.css'; -@import '../components/Link/styles.css'; @import '../components/Tooltip/Tooltip.styles.css'; @import '../components/ScrollArea/ScrollArea.styles.css'; @import '../components/Select/Select.styles.css'; +@import '../components/Switch/Switch.styles.css'; diff --git a/packages/canon/src/css/stories.module.css b/packages/canon/src/css/stories.module.css new file mode 100644 index 0000000000..10ed37bb7a --- /dev/null +++ b/packages/canon/src/css/stories.module.css @@ -0,0 +1,16 @@ +.fakeBox { + background: #eaf2fd; + border-radius: 4px; + box-shadow: 0 0 0 1px #2563eb; + height: 48px; + transition-property: background-color, box-shadow, background-image; + transition-duration: 0.2s; + transition-timing-function: ease-in-out; + background-image: url('data:image/svg+xml,%3Csvg%20width%3D%226%22%20height%3D%226%22%20viewBox%3D%220%200%206%206%22%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%3E%3Cg%20fill%3D%22%232563eb%22%20fill-opacity%3D%220.3%22%20fill-rule%3D%22evenodd%22%3E%3Cpath%20d%3D%22M5%200h1L0%206V5zM6%205v1H5z%22/%3E%3C/g%3E%3C/svg%3E'); +} + +[data-theme='dark'] .fakeBox { + background: #1a1a1a; + box-shadow: 0 0 0 1px #4765ff; + background-image: url('data:image/svg+xml,%3Csvg%20width%3D%226%22%20height%3D%226%22%20viewBox%3D%220%200%206%206%22%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%3E%3Cg%20fill%3D%22%234765FF%22%20fill-opacity%3D%221%22%20fill-rule%3D%22evenodd%22%3E%3Cpath%20d%3D%22M5%200h1L0%206V5zM6%205v1H5z%22/%3E%3C/g%3E%3C/svg%3E'); +} diff --git a/packages/canon/src/index.ts b/packages/canon/src/index.ts index cab4cc4acb..9b5a454254 100644 --- a/packages/canon/src/index.ts +++ b/packages/canon/src/index.ts @@ -36,6 +36,7 @@ export * from './components/Avatar'; export * from './components/Button'; export * from './components/Collapsible'; export * from './components/DataTable'; +export * from './components/FieldLabel'; export * from './components/Icon'; export * from './components/IconButton'; export * from './components/Checkbox'; @@ -47,6 +48,7 @@ export * from './components/Menu'; export * from './components/ScrollArea'; export * from './components/Link'; export * from './components/Select'; +export * from './components/Switch'; // Types export * from './types'; diff --git a/packages/canon/src/stories/Form.stories.tsx b/packages/canon/src/stories/Form.stories.tsx deleted file mode 100644 index 3bffca6554..0000000000 --- a/packages/canon/src/stories/Form.stories.tsx +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright 2024 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { useState } from 'react'; -import type { Meta, StoryObj } from '@storybook/react'; -import { useForm, SubmitHandler, Controller } from 'react-hook-form'; -import { TextField } from '../components/TextField'; -import { Button } from '../components/Button'; -import { Select } from '../components/Select'; - -const meta = { - title: 'Examples/Form', -} satisfies Meta; - -export default meta; -type Story = StoryObj; - -type Inputs = { - firstname: string; - lastname: string; - city: string; -}; - -export const Uncontrolled: Story = { - render: () => { - const { - register, - handleSubmit, - control, - formState: { errors }, - } = useForm(); - - const onSubmit: SubmitHandler = data => console.log(data); - - return ( -
- - - { - return ( - - ); - }} - /> - - - ); - }, -}; diff --git a/packages/catalog-client/CHANGELOG.md b/packages/catalog-client/CHANGELOG.md index d521818703..4c30a1465b 100644 --- a/packages/catalog-client/CHANGELOG.md +++ b/packages/catalog-client/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/catalog-client +## 1.10.1 + +### Patch Changes + +- 22fad0d: Fixed `CatalogClient` error responses for `refreshEntity` and `addLocation`. +- Updated dependencies + - @backstage/catalog-model@1.7.4 + - @backstage/errors@1.2.7 + ## 1.10.1-next.0 ### Patch Changes diff --git a/packages/catalog-client/package.json b/packages/catalog-client/package.json index b87a3d4348..9679c33891 100644 --- a/packages/catalog-client/package.json +++ b/packages/catalog-client/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/catalog-client", - "version": "1.10.1-next.0", + "version": "1.10.1", "description": "An isomorphic client for the catalog backend", "backstage": { "role": "common-library" diff --git a/packages/cli/CHANGELOG.md b/packages/cli/CHANGELOG.md index 7e03186e23..99f813b48b 100644 --- a/packages/cli/CHANGELOG.md +++ b/packages/cli/CHANGELOG.md @@ -1,5 +1,75 @@ # @backstage/cli +## 0.33.0 + +### Minor Changes + +- eef0e83: Internal update to promote the modular CLI entrypoint to stable. + +### Patch Changes + +- d07fe35: Added user feedback when opening config docs in browser. The command now clearly indicates what it's doing and provides fallback instructions if the browser fails to open. +- ce70439: The `BACKSTAGE_CLI_EXPERIMENTAL_BUILD_CACHE` flag has been removed. Existing users are encouraged to switch to `EXPERIMENTAL_RSPACK` instead. +- 1d8f00b: Switched to using the `ModuleFederationPlugin` from `@module-federation/enhanced/rspack` for Rspack, rather than the built-in one. +- 2b9633f: The experimental `FORCE_REACT_DEVELOPMENT` flag has been removed. +- d8c4a54: Only use the caching Jest module loader for frontend packages in order to avoid breaking real ESM module imports. +- d6d63c7: Updating the scaffolder action boilerplate to use new `zod` schema +- e36e855: Added `backstage.pluginId` field in `package.json` to all default plugin package templates for the `new` command. +- 1bab255: Internal refactor to combine alpha `build` and `start` modules. +- 713e957: fix: merge eslint reports when using json format +- 8a0164c: Fix an issue where some commands were not usable because of missing dist files +- Updated dependencies + - @backstage/eslint-plugin@0.1.11 + - @backstage/catalog-model@1.7.4 + - @backstage/cli-common@0.1.15 + - @backstage/cli-node@0.2.13 + - @backstage/config@1.3.2 + - @backstage/config-loader@1.10.1 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + - @backstage/release-manifests@0.0.13 + - @backstage/types@1.2.1 + +## 0.33.0-next.2 + +### Patch Changes + +- 8a0164c: Fix an issue where some commands were not usable because of missing dist files +- Updated dependencies + - @backstage/eslint-plugin@0.1.11-next.0 + - @backstage/catalog-model@1.7.4 + - @backstage/cli-common@0.1.15 + - @backstage/cli-node@0.2.13 + - @backstage/config@1.3.2 + - @backstage/config-loader@1.10.1 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + - @backstage/release-manifests@0.0.13 + - @backstage/types@1.2.1 + +## 0.33.0-next.1 + +### Minor Changes + +- eef0e83: Internal update to promote the modular CLI entrypoint to stable. + +### Patch Changes + +- d07fe35: Added user feedback when opening config docs in browser. The command now clearly indicates what it's doing and provides fallback instructions if the browser fails to open. +- d6d63c7: Updating the scaffolder action boilerplate to use new `zod` schema +- e36e855: Added `backstage.pluginId` field in `package.json` to all default plugin package templates for the `new` command. +- Updated dependencies + - @backstage/catalog-model@1.7.4 + - @backstage/cli-common@0.1.15 + - @backstage/cli-node@0.2.13 + - @backstage/config@1.3.2 + - @backstage/config-loader@1.10.1 + - @backstage/errors@1.2.7 + - @backstage/eslint-plugin@0.1.10 + - @backstage/integration@1.17.0 + - @backstage/release-manifests@0.0.13 + - @backstage/types@1.2.1 + ## 0.32.2-next.0 ### Patch Changes diff --git a/packages/cli/cli-report.backstage-cli.md b/packages/cli/cli-report.backstage-cli.md deleted file mode 100644 index ed6ae9049e..0000000000 --- a/packages/cli/cli-report.backstage-cli.md +++ /dev/null @@ -1,521 +0,0 @@ -## CLI Report file for "@backstage/cli" - -> Do not edit this file. It is a report generated by `yarn build:api-reports` - -### `backstage-cli` - -``` -Usage: backstage-cli [options] [command] - -Options: - -V, --version - -h, --help - -Commands: - build-workspace [options] [packages...] - config:check [options] - config:docs [options] - config:print [options] - config:schema [options] - create-github-app - help [command] - info - migrate [command] - new [options] - package [command] - repo [command] - versions:bump [options] - versions:migrate [options] -``` - -### `backstage-cli build-workspace` - -``` -Usage: backstage-cli build-workspace [options] [packages...] - -Options: - --alwaysPack - -h, --help -``` - -### `backstage-cli config:check` - -``` -Usage: backstage-cli config:check [options] - -Options: - --config - --deprecated - --frontend - --lax - --package - --strict - -h, --help -``` - -### `backstage-cli config:docs` - -``` -Usage: backstage-cli config:docs [options] - -Options: - --package - -h, --help -``` - -### `backstage-cli config:print` - -``` -Usage: backstage-cli config:print [options] - -Options: - --config - --format - --frontend - --lax - --package - --with-secrets - -h, --help -``` - -### `backstage-cli config:schema` - -``` -Usage: backstage-cli config:schema [options] - -Options: - --format - --merge - --no-merge - --package - -h, --help -``` - -### `backstage-cli create-github-app` - -``` -Usage: backstage-cli create-github-app [options] - -Options: - -h, --help -``` - -### `backstage-cli info` - -``` -Usage: backstage-cli info [options] - -Options: - -h, --help -``` - -### `backstage-cli migrate` - -``` -Usage: backstage-cli migrate [options] [command] [command] - -Options: - -h, --help - -Commands: - help [command] - package-exports - package-lint-configs - package-roles - package-scripts - react-router-deps -``` - -### `backstage-cli migrate package-exports` - -``` -Usage: backstage-cli migrate package-exports [options] - -Options: - -h, --help -``` - -### `backstage-cli migrate package-lint-configs` - -``` -Usage: backstage-cli migrate package-lint-configs [options] - -Options: - -h, --help -``` - -### `backstage-cli migrate package-roles` - -``` -Usage: backstage-cli migrate package-roles [options] - -Options: - -h, --help -``` - -### `backstage-cli migrate package-scripts` - -``` -Usage: backstage-cli migrate package-scripts [options] - -Options: - -h, --help -``` - -### `backstage-cli migrate react-router-deps` - -``` -Usage: backstage-cli migrate react-router-deps [options] - -Options: - -h, --help -``` - -### `backstage-cli new` - -``` -Usage: backstage-cli new [options] - -Options: - --baseVersion - --license - --no-private - --npm-registry - --option = - --scope - --select - --skip-install - -h, --help -``` - -### `backstage-cli package` - -``` -Usage: backstage-cli package [options] [command] [command] - -Options: - -h, --help - -Commands: - build [options] - clean - help [command] - lint [options] [directories...] - postpack - prepack - start [options] - test -``` - -### `backstage-cli package build` - -``` -Usage: backstage-cli package build [options] - -Options: - --config - --minify - --role - --skip-build-dependencies - --stats - -h, --help -``` - -### `backstage-cli package clean` - -``` -Usage: backstage-cli package clean [options] - -Options: - -h, --help -``` - -### `backstage-cli package lint` - -``` -Usage: backstage-cli package lint [options] [directories...] - -Options: - --fix - --format - --max-warnings - --output-file - -h, --help -``` - -### `backstage-cli package postpack` - -``` -Usage: backstage-cli package postpack [options] - -Options: - -h, --help -``` - -### `backstage-cli package prepack` - -``` -Usage: backstage-cli package prepack [options] - -Options: - -h, --help -``` - -### `backstage-cli package start` - -``` -Usage: backstage-cli package start [options] - -Options: - --check - --config - --inspect [host] - --inspect-brk [host] - --link - --require - --role - -h, --help -``` - -### `backstage-cli package test` - -``` -Usage: backstage-cli [--config=] [TestPathPattern] - -Options: - --all - --automock - --cache - --cacheDirectory - --changedFilesWithAncestor - --changedSince - --ci - --clearCache - --clearMocks - --collectCoverage - --collectCoverageFrom - --color - --colors - --coverage - --coverageDirectory - --coveragePathIgnorePatterns - --coverageProvider - --coverageReporters - --coverageThreshold - --debug - --detectLeaks - --detectOpenHandles - --env - --errorOnDeprecated - --filter - --findRelatedTests - --forceExit - --globalSetup - --globalTeardown - --globals - --haste - --ignoreProjects - --init - --injectGlobals - --json - --lastCommit - --listTests - --logHeapUsage - --maxConcurrency - --moduleDirectories - --moduleFileExtensions - --moduleNameMapper - --modulePathIgnorePatterns - --modulePaths - --noStackTrace - --notify - --notifyMode - --openHandlesTimeout - --outputFile - --passWithNoTests - --preset - --prettierPath - --projects - --randomize - --reporters - --resetMocks - --resetModules - --resolver - --restoreMocks - --rootDir - --roots - --runTestsByPath - --runner - --seed - --selectProjects - --setupFiles - --setupFilesAfterEnv - --shard - --showConfig - --showSeed - --silent - --skipFilter - --snapshotSerializers - --testEnvironment - --testEnvironmentOptions - --testFailureExitCode - --testLocationInResults - --testMatch - --testPathIgnorePatterns - --testPathPattern - --testRegex - --testResultsProcessor - --testRunner - --testSequencer - --testTimeout - --transform - --transformIgnorePatterns - --unmockedModulePathPatterns - --useStderr - --verbose - --version - --watch - --watchAll - --watchPathIgnorePatterns - --watchman - --workerThreads - -b, --bail - -c, --config - -e, --expand - -f, --onlyFailures - -h, --help - -i, --runInBand - -o, --onlyChanged - -t, --testNamePattern - -u, --updateSnapshot - -w, --maxWorkers -``` - -### `backstage-cli repo` - -``` -Usage: backstage-cli repo [options] [command] [command] - -Options: - -h, --help - -Commands: - build [options] - clean - fix [options] - help [command] - lint [options] - list-deprecations [options] - start [options] [packageNameOrPath...] - test [options] -``` - -### `backstage-cli repo build` - -``` -Usage: backstage-cli repo build [options] - -Options: - --all - --minify - --since - -h, --help -``` - -### `backstage-cli repo clean` - -``` -Usage: backstage-cli repo clean [options] - -Options: - -h, --help -``` - -### `backstage-cli repo fix` - -``` -Usage: backstage-cli repo fix [options] - -Options: - --check - --publish - -h, --help -``` - -### `backstage-cli repo lint` - -``` -Usage: backstage-cli repo lint [options] - -Options: - --fix - --format - --max-warnings - --output-file - --since - --successCache - --successCacheDir - -h, --help -``` - -### `backstage-cli repo list-deprecations` - -``` -Usage: backstage-cli repo list-deprecations [options] - -Options: - --json - -h, --help -``` - -### `backstage-cli repo start` - -``` -Usage: backstage-cli repo start [options] [packageNameOrPath...] - -Options: - --config - --inspect [host] - --inspect-brk [host] - --link - --plugin - --require - -h, --help -``` - -### `backstage-cli repo test` - -``` -Usage: backstage-cli repo test [options] - -Options: - --jest-help - --since - --successCache - --successCacheDir - -h, --help -``` - -### `backstage-cli versions:bump` - -``` -Usage: backstage-cli versions:bump [options] - -Options: - --pattern - --release - --skip-install - --skip-migrate - -h, --help -``` - -### `backstage-cli versions:migrate` - -``` -Usage: backstage-cli versions:migrate [options] - -Options: - --pattern - --skip-code-changes - -h, --help -``` diff --git a/packages/cli/cli-report.backstage-cli-alpha.md b/packages/cli/cli-report.md similarity index 79% rename from packages/cli/cli-report.backstage-cli-alpha.md rename to packages/cli/cli-report.md index 331385f6f6..e2f5bb9cc6 100644 --- a/packages/cli/cli-report.backstage-cli-alpha.md +++ b/packages/cli/cli-report.md @@ -2,7 +2,7 @@ > Do not edit this file. It is a report generated by `yarn build:api-reports` -### `backstage-cli-alpha` +### `backstage-cli` ``` Usage: backstage-cli [options] [command] @@ -29,7 +29,7 @@ Commands: versions:migrate ``` -### `backstage-cli-alpha build-workspace` +### `backstage-cli build-workspace` ``` Usage: program [options] [packages...] @@ -39,7 +39,7 @@ Options: -h, --help ``` -### `backstage-cli-alpha config` +### `backstage-cli config` ``` Usage: backstage-cli config [options] [command] [command] @@ -53,7 +53,7 @@ Commands: schema ``` -### `backstage-cli-alpha config docs` +### `backstage-cli config docs` ``` Usage: backstage-cli config docs [options] @@ -63,7 +63,7 @@ Options: -h, --help ``` -### `backstage-cli-alpha config schema` +### `backstage-cli config schema` ``` Usage: @@ -77,7 +77,7 @@ Options: --version ``` -### `backstage-cli-alpha config:check` +### `backstage-cli config:check` ``` Usage: @@ -93,7 +93,7 @@ Options: --version ``` -### `backstage-cli-alpha config:docs` +### `backstage-cli config:docs` ``` Usage: program [options] @@ -103,7 +103,7 @@ Options: -h, --help ``` -### `backstage-cli-alpha config:print` +### `backstage-cli config:print` ``` Usage: @@ -119,7 +119,7 @@ Options: --with-secrets ``` -### `backstage-cli-alpha config:schema` +### `backstage-cli config:schema` ``` Usage: @@ -133,7 +133,7 @@ Options: --version ``` -### `backstage-cli-alpha create-github-app` +### `backstage-cli create-github-app` ``` Usage: program [options] @@ -142,7 +142,7 @@ Options: -h, --help ``` -### `backstage-cli-alpha info` +### `backstage-cli info` ``` Usage: @@ -152,7 +152,7 @@ Options: --version ``` -### `backstage-cli-alpha migrate` +### `backstage-cli migrate` ``` Usage: backstage-cli migrate [options] [command] [command] @@ -169,7 +169,7 @@ Commands: react-router-deps ``` -### `backstage-cli-alpha migrate package-exports` +### `backstage-cli migrate package-exports` ``` Usage: program [options] @@ -178,7 +178,7 @@ Options: -h, --help ``` -### `backstage-cli-alpha migrate package-lint-configs` +### `backstage-cli migrate package-lint-configs` ``` Usage: program [options] @@ -187,7 +187,7 @@ Options: -h, --help ``` -### `backstage-cli-alpha migrate package-roles` +### `backstage-cli migrate package-roles` ``` Usage: program [options] @@ -196,7 +196,7 @@ Options: -h, --help ``` -### `backstage-cli-alpha migrate package-scripts` +### `backstage-cli migrate package-scripts` ``` Usage: program [options] @@ -205,7 +205,7 @@ Options: -h, --help ``` -### `backstage-cli-alpha migrate react-router-deps` +### `backstage-cli migrate react-router-deps` ``` Usage: program [options] @@ -214,7 +214,7 @@ Options: -h, --help ``` -### `backstage-cli-alpha new` +### `backstage-cli new` ``` Usage: program [options] @@ -231,7 +231,7 @@ Options: -h, --help ``` -### `backstage-cli-alpha package` +### `backstage-cli package` ``` Usage: backstage-cli package [options] [command] [command] @@ -250,7 +250,7 @@ Commands: test ``` -### `backstage-cli-alpha package build` +### `backstage-cli package build` ``` Usage: program [options] @@ -264,7 +264,7 @@ Options: -h, --help ``` -### `backstage-cli-alpha package clean` +### `backstage-cli package clean` ``` Usage: program [options] @@ -273,7 +273,7 @@ Options: -h, --help ``` -### `backstage-cli-alpha package lint` +### `backstage-cli package lint` ``` Usage: program [options] [directories...] @@ -286,7 +286,7 @@ Options: -h, --help ``` -### `backstage-cli-alpha package postpack` +### `backstage-cli package postpack` ``` Usage: program [options] @@ -295,7 +295,7 @@ Options: -h, --help ``` -### `backstage-cli-alpha package prepack` +### `backstage-cli package prepack` ``` Usage: program [options] @@ -304,7 +304,7 @@ Options: -h, --help ``` -### `backstage-cli-alpha package start` +### `backstage-cli package start` ``` Usage: program [options] @@ -320,10 +320,10 @@ Options: -h, --help ``` -### `backstage-cli-alpha package test` +### `backstage-cli package test` ``` -Usage: backstage-cli-alpha [--config=] [TestPathPattern] +Usage: backstage-cli [--config=] [TestPathPattern] Options: --all @@ -434,7 +434,7 @@ Options: -w, --maxWorkers ``` -### `backstage-cli-alpha repo` +### `backstage-cli repo` ``` Usage: backstage-cli repo [options] [command] [command] @@ -453,7 +453,7 @@ Commands: test ``` -### `backstage-cli-alpha repo build` +### `backstage-cli repo build` ``` Usage: program [options] [command] @@ -465,7 +465,7 @@ Options: -h, --help ``` -### `backstage-cli-alpha repo clean` +### `backstage-cli repo clean` ``` Usage: program [options] @@ -474,7 +474,7 @@ Options: -h, --help ``` -### `backstage-cli-alpha repo fix` +### `backstage-cli repo fix` ``` Usage: program [options] @@ -485,10 +485,10 @@ Options: -h, --help ``` -### `backstage-cli-alpha repo lint` +### `backstage-cli repo lint` ``` -Usage: program [options] +Usage: program [options] [command] Options: --fix @@ -501,7 +501,7 @@ Options: -h, --help ``` -### `backstage-cli-alpha repo list-deprecations` +### `backstage-cli repo list-deprecations` ``` Usage: program [options] @@ -511,10 +511,10 @@ Options: -h, --help ``` -### `backstage-cli-alpha repo start` +### `backstage-cli repo start` ``` -Usage: program [options] [...packageNameOrPath] +Usage: program [options] [packageNameOrPath...] Options: --config @@ -526,7 +526,7 @@ Options: -h, --help ``` -### `backstage-cli-alpha repo test` +### `backstage-cli repo test` ``` Usage: program [options] @@ -539,7 +539,7 @@ Options: -h, --help ``` -### `backstage-cli-alpha versions:bump` +### `backstage-cli versions:bump` ``` Usage: program [options] @@ -552,7 +552,7 @@ Options: -h, --help ``` -### `backstage-cli-alpha versions:migrate` +### `backstage-cli versions:migrate` ``` Usage: program [options] diff --git a/packages/cli/package.json b/packages/cli/package.json index 603d1a4e1a..1404021078 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/cli", - "version": "0.32.2-next.0", + "version": "0.33.0", "description": "CLI for developing Backstage plugins and apps", "backstage": { "role": "cli" @@ -20,8 +20,7 @@ "license": "Apache-2.0", "main": "dist/index.cjs.js", "bin": { - "backstage-cli": "bin/backstage-cli", - "backstage-cli-alpha": "bin/backstage-cli-alpha" + "backstage-cli": "bin/backstage-cli" }, "files": [ "asset-types", diff --git a/packages/cli/src/alpha.ts b/packages/cli/src/alpha.ts deleted file mode 100644 index f7333073d8..0000000000 --- a/packages/cli/src/alpha.ts +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2024 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { CliInitializer } from './wiring/CliInitializer'; -import chalk from 'chalk'; - -(async () => { - // Logging as stdout to prevent failures from stderr during api-report generation. - console.log( - chalk.yellow( - 'THIS ENTRYPOINT IS IN ALPHA AND MAY CHANGE IN THE FUTURE - DO NOT USE THIS FOR NORMAL DEVELOPMENT', - ), - ); - const initializer = new CliInitializer(); - initializer.add(import('./modules/build/alpha')); - initializer.add(import('./modules/config/alpha')); - initializer.add(import('./modules/create-github-app/alpha')); - initializer.add(import('./modules/info/alpha')); - initializer.add(import('./modules/lint/alpha')); - initializer.add(import('./modules/maintenance/alpha')); - initializer.add(import('./modules/migrate/alpha')); - initializer.add(import('./modules/new/alpha')); - initializer.add(import('./modules/test/alpha')); - await initializer.run(); -})(); diff --git a/packages/cli/src/commands/index.ts b/packages/cli/src/commands/index.ts deleted file mode 100644 index 8cfad48b14..0000000000 --- a/packages/cli/src/commands/index.ts +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2020 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { Command } from 'commander'; -import { registerCommands as registerConfigCommands } from '../modules/config'; -import { - registerPackageCommands as registerPackageBuildCommands, - registerRepoCommands as registerRepoBuildCommands, - registerCommands as registerBuildCommands, -} from '../modules/build'; -import { registerCommands as registerInfoCommands } from '../modules/info'; -import { registerCommands as registerMigrateCommand } from '../modules/migrate'; -import { - registerRepoCommands as registerRepoTestCommands, - registerPackageCommands as registerPackageTestCommands, -} from '../modules/test'; -import { - registerPackageCommands as registerPackageLintCommands, - registerRepoCommands as registerRepoLintCommands, -} from '../modules/lint'; -import { - registerPackageCommands as registerMaintenancePackageCommands, - registerRepoCommands as registerMaintenanceRepoCommands, -} from '../modules/maintenance'; -import { removed } from '../lib/removed'; -import { registerCommands as registerNewCommands } from '../modules/new'; -import { registerCommands as registerCreateGithubAppCommands } from '../modules/create-github-app'; - -export function registerRepoCommand(program: Command) { - const command = program - .command('repo [command]') - .description('Command that run across an entire Backstage project'); - - registerRepoBuildCommands(command); - registerRepoTestCommands(command); - registerRepoLintCommands(command); - registerMaintenanceRepoCommands(command); -} - -export function registerScriptCommand(program: Command) { - const command = program - .command('package [command]') - .description('Lifecycle scripts for individual packages'); - - registerPackageBuildCommands(command); - registerPackageTestCommands(command); - registerMaintenancePackageCommands(command); - registerPackageLintCommands(command); -} - -export function registerCommands(program: Command) { - registerConfigCommands(program); - registerRepoCommand(program); - registerScriptCommand(program); - registerMigrateCommand(program); - registerBuildCommands(program); - registerInfoCommands(program); - registerNewCommands(program); - registerCreateGithubAppCommands(program); - // Notifications for removed commands - - program - .command('plugin:diff') - .allowUnknownOption(true) - .action(removed("use 'backstage-cli fix' instead")); - program - .command('test') - .allowUnknownOption(true) - .action( - removed( - "use 'backstage-cli repo test' or 'backstage-cli package test' instead", - ), - ); - program - .command('clean') - .allowUnknownOption(true) - .action(removed("use 'backstage-cli package clean' instead")); - program - .command('versions:check') - .allowUnknownOption(true) - .action(removed("use 'yarn dedupe' or 'yarn-deduplicate' instead")); - program.command('install').allowUnknownOption(true).action(removed()); - program.command('onboard').allowUnknownOption(true).action(removed()); -} diff --git a/packages/cli/src/index.ts b/packages/cli/src/index.ts index d1ca1bcd04..ece1e413a0 100644 --- a/packages/cli/src/index.ts +++ b/packages/cli/src/index.ts @@ -1,5 +1,5 @@ /* - * Copyright 2020 The Backstage Authors + * Copyright 2024 The Backstage Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,40 +14,18 @@ * limitations under the License. */ -/** - * CLI for developing Backstage plugins and apps - * - * @packageDocumentation - */ +import { CliInitializer } from './wiring/CliInitializer'; -import { program } from 'commander'; -import chalk from 'chalk'; -import { exitWithError } from './lib/errors'; -import { version } from './lib/version'; -import { registerCommands } from './commands'; - -const main = (argv: string[]) => { - program.name('backstage-cli').version(version); - - registerCommands(program); - - program.on('command:*', () => { - console.log(); - console.log(chalk.red(`Invalid command: ${program.args.join(' ')}`)); - console.log(); - program.outputHelp(); - process.exit(1); - }); - - program.parse(argv); -}; - -process.on('unhandledRejection', rejection => { - if (rejection instanceof Error) { - exitWithError(rejection); - } else { - exitWithError(new Error(`Unknown rejection: '${rejection}'`)); - } -}); - -main(process.argv); +(async () => { + const initializer = new CliInitializer(); + initializer.add(import('./modules/build')); + initializer.add(import('./modules/config')); + initializer.add(import('./modules/create-github-app')); + initializer.add(import('./modules/info')); + initializer.add(import('./modules/lint')); + initializer.add(import('./modules/maintenance')); + initializer.add(import('./modules/migrate')); + initializer.add(import('./modules/new')); + initializer.add(import('./modules/test')); + await initializer.run(); +})(); diff --git a/packages/cli/src/modules/build/alpha.ts b/packages/cli/src/modules/build/alpha.ts deleted file mode 100644 index fb9365d7c5..0000000000 --- a/packages/cli/src/modules/build/alpha.ts +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Copyright 2024 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { Command, Option } from 'commander'; -import { createCliPlugin } from '../../wiring/factory'; -import { lazy } from '../../lib/lazy'; -import { registerPackageCommands } from '.'; -import { configOption } from '../config'; - -export const buildPlugin = createCliPlugin({ - pluginId: 'build', - init: async reg => { - reg.addCommand({ - path: ['package', 'build'], - description: 'Build a package for production deployment or publishing', - execute: async ({ args }) => { - const command = new Command(); - - const defaultCommand = command - .option( - '--role ', - 'Run the command with an explicit package role', - ) - .option( - '--minify', - 'Minify the generated code. Does not apply to app package (app is minified by default).', - ) - .option( - '--skip-build-dependencies', - 'Skip the automatic building of local dependencies. Applies to backend packages only.', - ) - .option( - '--stats', - 'If bundle stats are available, write them to the output directory. Applies to app packages only.', - ) - .option( - '--config ', - 'Config files to load instead of app-config.yaml. Applies to app packages only.', - (opt: string, opts: string[]) => (opts ? [...opts, opt] : [opt]), - Array(), - ) - .action(lazy(() => import('./commands/package/build'), 'command')); - await defaultCommand.parseAsync(args, { from: 'user' }); - }, - }); - - reg.addCommand({ - path: ['repo', 'build'], - description: - 'Build packages in the project, excluding bundled app and backend packages.', - execute: async ({ args }) => { - const command = new Command(); - - // This command expect `package build` to be registered, as its used to parse - // individual plugins' package build scripts. - registerPackageCommands(command.command('package')); - - const defaultCommand = command - .option( - '--all', - 'Build all packages, including bundled app and backend packages.', - ) - .option( - '--since ', - 'Only build packages and their dev dependents that changed since the specified ref', - ) - .option( - '--minify', - 'Minify the generated code. Does not apply to app package (app is minified by default).', - ) - .action(lazy(() => import('./commands/repo/build'), 'command')); - await defaultCommand.parseAsync(args, { from: 'user' }); - }, - }); - - reg.addCommand({ - path: ['package', 'start'], - description: 'Start a package for local development', - execute: async ({ args }) => { - const command = new Command(); - - const defaultCommand = command - .option(...configOption) - .option( - '--role ', - 'Run the command with an explicit package role', - ) - .option('--check', 'Enable type checking and linting if available') - .option('--inspect [host]', 'Enable debugger in Node.js environments') - .option( - '--inspect-brk [host]', - 'Enable debugger in Node.js environments, breaking before code starts', - ) - .option( - '--require ', - 'Add a --require argument to the node process', - ) - .option( - '--link ', - 'Link an external workspace for module resolution', - ) - .action(lazy(() => import('./commands/package/start'), 'command')); - - await defaultCommand.parseAsync(args, { from: 'user' }); - }, - }); - - reg.addCommand({ - path: ['repo', 'start'], - description: 'Starts packages in the repo for local development', - execute: async ({ args }) => { - const command = new Command(); - - const defaultCommand = command - .argument( - '[...packageNameOrPath]', - 'Run the specified package instead of the defaults.', - ) - .option( - '--plugin ', - 'Start the dev entry-point for any matching plugin package in the repo', - (opt: string, opts: string[]) => (opts ? [...opts, opt] : [opt]), - Array(), - ) - .option(...configOption) - .option( - '--inspect [host]', - 'Enable debugger in Node.js environments. Applies to backend package only', - ) - .option( - '--inspect-brk [host]', - 'Enable debugger in Node.js environments, breaking before code starts. Applies to backend package only', - ) - .option( - '--require ', - 'Add a --require argument to the node process. Applies to backend package only', - ) - .option( - '--link ', - 'Link an external workspace for module resolution', - ) - .action( - lazy(() => import('../build/commands/repo/start'), 'command'), - ); - - await defaultCommand.parseAsync(args, { from: 'user' }); - }, - }); - - reg.addCommand({ - path: ['build-workspace'], - description: - 'Builds a temporary dist workspace from the provided packages', - execute: async ({ args }) => { - const command = new Command(); - const defaultCommand = command - .arguments(' [packages...]') - .addOption( - new Option( - '--alwaysYarnPack', - 'Alias for --alwaysPack for backwards compatibility.', - ) - .implies({ alwaysPack: true }) - .hideHelp(true), - ) - .option( - '--alwaysPack', - 'Force workspace output to be a result of running `yarn pack` on each package (warning: very slow)', - ) - .action(lazy(() => import('./commands/buildWorkspace'), 'default')); - await defaultCommand.parseAsync(args, { from: 'user' }); - }, - }); - }, -}); - -export default buildPlugin; diff --git a/packages/cli/src/modules/build/index.ts b/packages/cli/src/modules/build/index.ts index c859985975..fd31a6c782 100644 --- a/packages/cli/src/modules/build/index.ts +++ b/packages/cli/src/modules/build/index.ts @@ -13,60 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import { Command, Option } from 'commander'; +import { createCliPlugin } from '../../wiring/factory'; import { lazy } from '../../lib/lazy'; import { configOption } from '../config'; -export function registerRepoCommands(command: Command) { - command - .command('build') - .description( - 'Build packages in the project, excluding bundled app and backend packages.', - ) - .option( - '--all', - 'Build all packages, including bundled app and backend packages.', - ) - .option( - '--since ', - 'Only build packages and their dev dependents that changed since the specified ref', - ) - .option( - '--minify', - 'Minify the generated code. Does not apply to app package (app is minified by default).', - ) - .action(lazy(() => import('./commands/repo/build'), 'command')); - - command - .command('start') - .description('Starts packages in the repo for local development') - .argument( - '[packageNameOrPath...]', - 'Run the specified package instead of the defaults.', - ) - .option( - '--plugin ', - 'Start the dev entry-point for any matching plugin package in the repo', - (opt: string, opts: string[]) => (opts ? [...opts, opt] : [opt]), - Array(), - ) - .option(...configOption) - .option( - '--inspect [host]', - 'Enable debugger in Node.js environments. Applies to backend package only', - ) - .option( - '--inspect-brk [host]', - 'Enable debugger in Node.js environments, breaking before code starts. Applies to backend package only', - ) - .option( - '--require ', - 'Add a --require argument to the node process. Applies to backend package only', - ) - .option('--link ', 'Link an external workspace for module resolution') - .action(lazy(() => import('../build/commands/repo/start'), 'command')); -} - export function registerPackageCommands(command: Command) { command .command('build') @@ -91,41 +43,173 @@ export function registerPackageCommands(command: Command) { Array(), ) .action(lazy(() => import('./commands/package/build'), 'command')); - - command - .command('start') - .description('Start a package for local development') - .option(...configOption) - .option('--role ', 'Run the command with an explicit package role') - .option('--check', 'Enable type checking and linting if available') - .option('--inspect [host]', 'Enable debugger in Node.js environments') - .option( - '--inspect-brk [host]', - 'Enable debugger in Node.js environments, breaking before code starts', - ) - .option( - '--require ', - 'Add a --require argument to the node process', - ) - .option('--link ', 'Link an external workspace for module resolution') - .action(lazy(() => import('./commands/package/start'), 'command')); } -export function registerCommands(program: Command) { - program - .command('build-workspace [packages...]') - .addOption( - new Option( - '--alwaysYarnPack', - 'Alias for --alwaysPack for backwards compatibility.', - ) - .implies({ alwaysPack: true }) - .hideHelp(true), - ) - .option( - '--alwaysPack', - 'Force workspace output to be a result of running `yarn pack` on each package (warning: very slow)', - ) - .description('Builds a temporary dist workspace from the provided packages') - .action(lazy(() => import('./commands/buildWorkspace'), 'default')); -} +export const buildPlugin = createCliPlugin({ + pluginId: 'build', + init: async reg => { + reg.addCommand({ + path: ['package', 'build'], + description: 'Build a package for production deployment or publishing', + execute: async ({ args }) => { + const command = new Command(); + + const defaultCommand = command + .option( + '--role ', + 'Run the command with an explicit package role', + ) + .option( + '--minify', + 'Minify the generated code. Does not apply to app package (app is minified by default).', + ) + .option( + '--skip-build-dependencies', + 'Skip the automatic building of local dependencies. Applies to backend packages only.', + ) + .option( + '--stats', + 'If bundle stats are available, write them to the output directory. Applies to app packages only.', + ) + .option( + '--config ', + 'Config files to load instead of app-config.yaml. Applies to app packages only.', + (opt: string, opts: string[]) => (opts ? [...opts, opt] : [opt]), + Array(), + ) + .action(lazy(() => import('./commands/package/build'), 'command')); + await defaultCommand.parseAsync(args, { from: 'user' }); + }, + }); + + reg.addCommand({ + path: ['repo', 'build'], + description: + 'Build packages in the project, excluding bundled app and backend packages.', + execute: async ({ args }) => { + const command = new Command(); + + // This command expect `package build` to be registered, as its used to parse + // individual plugins' package build scripts. + registerPackageCommands(command.command('package')); + + const defaultCommand = command + .option( + '--all', + 'Build all packages, including bundled app and backend packages.', + ) + .option( + '--since ', + 'Only build packages and their dev dependents that changed since the specified ref', + ) + .option( + '--minify', + 'Minify the generated code. Does not apply to app package (app is minified by default).', + ) + .action(lazy(() => import('./commands/repo/build'), 'command')); + await defaultCommand.parseAsync(args, { from: 'user' }); + }, + }); + + reg.addCommand({ + path: ['package', 'start'], + description: 'Start a package for local development', + execute: async ({ args }) => { + const command = new Command(); + + const defaultCommand = command + .option(...configOption) + .option( + '--role ', + 'Run the command with an explicit package role', + ) + .option('--check', 'Enable type checking and linting if available') + .option('--inspect [host]', 'Enable debugger in Node.js environments') + .option( + '--inspect-brk [host]', + 'Enable debugger in Node.js environments, breaking before code starts', + ) + .option( + '--require ', + 'Add a --require argument to the node process', + ) + .option( + '--link ', + 'Link an external workspace for module resolution', + ) + .action(lazy(() => import('./commands/package/start'), 'command')); + + await defaultCommand.parseAsync(args, { from: 'user' }); + }, + }); + + reg.addCommand({ + path: ['repo', 'start'], + description: 'Starts packages in the repo for local development', + execute: async ({ args }) => { + const command = new Command(); + + const defaultCommand = command + .argument( + '[packageNameOrPath...]', + 'Run the specified package instead of the defaults.', + ) + .option( + '--plugin ', + 'Start the dev entry-point for any matching plugin package in the repo', + (opt: string, opts: string[]) => (opts ? [...opts, opt] : [opt]), + Array(), + ) + .option(...configOption) + .option( + '--inspect [host]', + 'Enable debugger in Node.js environments. Applies to backend package only', + ) + .option( + '--inspect-brk [host]', + 'Enable debugger in Node.js environments, breaking before code starts. Applies to backend package only', + ) + .option( + '--require ', + 'Add a --require argument to the node process. Applies to backend package only', + ) + .option( + '--link ', + 'Link an external workspace for module resolution', + ) + .action( + lazy(() => import('../build/commands/repo/start'), 'command'), + ); + + await defaultCommand.parseAsync(args, { from: 'user' }); + }, + }); + + reg.addCommand({ + path: ['build-workspace'], + description: + 'Builds a temporary dist workspace from the provided packages', + execute: async ({ args }) => { + const command = new Command(); + const defaultCommand = command + .arguments(' [packages...]') + .addOption( + new Option( + '--alwaysYarnPack', + 'Alias for --alwaysPack for backwards compatibility.', + ) + .implies({ alwaysPack: true }) + .hideHelp(true), + ) + .option( + '--alwaysPack', + 'Force workspace output to be a result of running `yarn pack` on each package (warning: very slow)', + ) + .action(lazy(() => import('./commands/buildWorkspace'), 'default')); + await defaultCommand.parseAsync(args, { from: 'user' }); + }, + }); + }, +}); + +export default buildPlugin; diff --git a/packages/cli/src/modules/config/alpha.ts b/packages/cli/src/modules/config/alpha.ts deleted file mode 100644 index 43bce858a1..0000000000 --- a/packages/cli/src/modules/config/alpha.ts +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright 2024 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -import { createCliPlugin } from '../../wiring/factory'; -import yargs from 'yargs'; -import { Command } from 'commander'; -import { lazy } from '../../lib/lazy'; - -export default createCliPlugin({ - pluginId: 'config', - init: async reg => { - reg.addCommand({ - path: ['config:docs'], - description: 'Browse the configuration reference documentation', - execute: async ({ args }) => { - const command = new Command(); - const defaultCommand = command - .option( - '--package ', - 'Only include the schema that applies to the given package', - ) - .description('Browse the configuration reference documentation') - .action(lazy(() => import('./commands/docs'), 'default')); - - await defaultCommand.parseAsync(args, { from: 'user' }); - }, - }); - reg.addCommand({ - path: ['config', 'docs'], - description: 'Browse the configuration reference documentation', - execute: async ({ args, info }) => { - await new Command(info.usage) - .option( - '--package ', - 'Only include the schema that applies to the given package', - ) - .description(info.description) - .action(lazy(() => import('./commands/docs'), 'default')) - .parseAsync(args, { from: 'user' }); - }, - }); - reg.addCommand({ - path: ['config:print'], - description: 'Print the app configuration for the current package', - execute: async ({ args, info }) => { - const argv = await yargs - .options({ - package: { type: 'string' }, - lax: { type: 'boolean' }, - frontend: { type: 'boolean' }, - 'with-secrets': { type: 'boolean' }, - format: { type: 'string' }, - config: { type: 'string', array: true, default: [] }, - }) - .usage('$0', info.description) - .help() - .parse(args); - const m = - (await require('./commands/print')) as typeof import('./commands/print'); - await m.default(argv); - }, - }); - reg.addCommand({ - path: ['config:check'], - description: - 'Validate that the given configuration loads and matches schema', - execute: async ({ args }) => { - const argv = await yargs - .options({ - package: { type: 'string' }, - lax: { type: 'boolean' }, - frontend: { type: 'boolean' }, - deprecated: { type: 'boolean' }, - strict: { type: 'boolean', required: true }, - config: { - type: 'string', - array: true, - default: [], - }, - }) - .help() - .parse(args); - const m = - (await require('./commands/validate')) as typeof import('./commands/validate'); - await m.default(argv); - }, - }); - - reg.addCommand({ - path: ['config:schema'], - description: 'Print the JSON schema for the given configuration', - execute: async ({ args }) => { - const argv = await yargs - .options({ - package: { type: 'string' }, - format: { type: 'string' }, - merge: { type: 'boolean' }, - 'no-merge': { type: 'boolean' }, - }) - .help() - .parse(args); - const m = await import('./commands/schema'); - await m.default(argv); - }, - }); - - reg.addCommand({ - path: ['config', 'schema'], - description: 'Print the JSON schema for the given configuration', - execute: async ({ args }) => { - const argv = await yargs - .options({ - package: { type: 'string' }, - format: { type: 'string' }, - merge: { type: 'boolean' }, - 'no-merge': { type: 'boolean' }, - }) - .help() - .parse(args); - const m = await import('./commands/schema'); - await m.default(argv); - }, - }); - }, -}); diff --git a/packages/cli/src/modules/config/index.ts b/packages/cli/src/modules/config/index.ts index a1436d0c21..d62dbd4d26 100644 --- a/packages/cli/src/modules/config/index.ts +++ b/packages/cli/src/modules/config/index.ts @@ -13,7 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - +import { createCliPlugin } from '../../wiring/factory'; +import yargs from 'yargs'; import { Command } from 'commander'; import { lazy } from '../../lib/lazy'; @@ -24,64 +25,114 @@ export const configOption = [ Array(), ] as const; -export function registerCommands(program: Command) { - program - .command('config:docs') - .option( - '--package ', - 'Only include the schema that applies to the given package', - ) - .description('Browse the configuration reference documentation') - .action(lazy(() => import('./commands/docs'), 'default')); +export default createCliPlugin({ + pluginId: 'config', + init: async reg => { + reg.addCommand({ + path: ['config:docs'], + description: 'Browse the configuration reference documentation', + execute: async ({ args }) => { + const command = new Command(); + const defaultCommand = command + .option( + '--package ', + 'Only include the schema that applies to the given package', + ) + .description('Browse the configuration reference documentation') + .action(lazy(() => import('./commands/docs'), 'default')); - program - .command('config:print') - .option( - '--package ', - 'Only load config schema that applies to the given package', - ) - .option('--lax', 'Do not require environment variables to be set') - .option('--frontend', 'Print only the frontend configuration') - .option('--with-secrets', 'Include secrets in the printed configuration') - .option( - '--format ', - 'Format to print the configuration in, either json or yaml [yaml]', - ) - .option(...configOption) - .description('Print the app configuration for the current package') - .action(lazy(() => import('./commands/print'), 'default')); + await defaultCommand.parseAsync(args, { from: 'user' }); + }, + }); + reg.addCommand({ + path: ['config', 'docs'], + description: 'Browse the configuration reference documentation', + execute: async ({ args, info }) => { + await new Command(info.usage) + .option( + '--package ', + 'Only include the schema that applies to the given package', + ) + .description(info.description) + .action(lazy(() => import('./commands/docs'), 'default')) + .parseAsync(args, { from: 'user' }); + }, + }); + reg.addCommand({ + path: ['config:print'], + description: 'Print the app configuration for the current package', + execute: async ({ args, info }) => { + const argv = await yargs + .options({ + package: { type: 'string' }, + lax: { type: 'boolean' }, + frontend: { type: 'boolean' }, + 'with-secrets': { type: 'boolean' }, + format: { type: 'string' }, + config: { type: 'string', array: true, default: [] }, + }) + .usage('$0', info.description) + .help() + .parse(args); + await lazy(() => import('./commands/print'), 'default')(argv); + }, + }); + reg.addCommand({ + path: ['config:check'], + description: + 'Validate that the given configuration loads and matches schema', + execute: async ({ args }) => { + const argv = await yargs + .options({ + package: { type: 'string' }, + lax: { type: 'boolean' }, + frontend: { type: 'boolean' }, + deprecated: { type: 'boolean' }, + strict: { type: 'boolean' }, + config: { + type: 'string', + array: true, + default: [], + }, + }) + .help() + .parse(args); + await lazy(() => import('./commands/validate'), 'default')(argv); + }, + }); - program - .command('config:check') - .option( - '--package ', - 'Only load config schema that applies to the given package', - ) - .option('--lax', 'Do not require environment variables to be set') - .option('--frontend', 'Only validate the frontend configuration') - .option('--deprecated', 'Output deprecated configuration settings') - .option( - '--strict', - 'Enable strict config validation, forbidding errors and unknown keys', - ) - .option(...configOption) - .description( - 'Validate that the given configuration loads and matches schema', - ) - .action(lazy(() => import('./commands/validate'), 'default')); + reg.addCommand({ + path: ['config:schema'], + description: 'Print the JSON schema for the given configuration', + execute: async ({ args }) => { + const argv = await yargs + .options({ + package: { type: 'string' }, + format: { type: 'string' }, + merge: { type: 'boolean' }, + 'no-merge': { type: 'boolean' }, + }) + .help() + .parse(args); + await lazy(() => import('./commands/schema'), 'default')(argv); + }, + }); - program - .command('config:schema') - .option( - '--package ', - 'Only output config schema that applies to the given package', - ) - .option( - '--format ', - 'Format to print the schema in, either json or yaml [yaml]', - ) - .option('--merge', 'Print the config schemas merged', true) - .option('--no-merge', 'Print the config schemas not merged') - .description('Print configuration schema') - .action(lazy(() => import('./commands/schema'), 'default')); -} + reg.addCommand({ + path: ['config', 'schema'], + description: 'Print the JSON schema for the given configuration', + execute: async ({ args }) => { + const argv = await yargs + .options({ + package: { type: 'string' }, + format: { type: 'string' }, + merge: { type: 'boolean' }, + 'no-merge': { type: 'boolean' }, + }) + .help() + .parse(args); + await lazy(() => import('./commands/schema'), 'default')(argv); + }, + }); + }, +}); diff --git a/packages/cli/src/modules/create-github-app/alpha.ts b/packages/cli/src/modules/create-github-app/alpha.ts deleted file mode 100644 index da1e04aaac..0000000000 --- a/packages/cli/src/modules/create-github-app/alpha.ts +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2025 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -import { createCliPlugin } from '../../wiring/factory'; -import { Command } from 'commander'; -import { lazy } from '../../lib/lazy'; - -export default createCliPlugin({ - pluginId: 'new', - init: async reg => { - reg.addCommand({ - path: ['create-github-app'], - description: 'Create new GitHub App in your organization.', - execute: async ({ args }) => { - const command = new Command(); - const defaultCommand = command - .argument('') - .action( - lazy(() => import('./commands/create-github-app'), 'default'), - ); - - await defaultCommand.parseAsync(args, { from: 'user' }); - }, - }); - }, -}); diff --git a/packages/cli/src/modules/create-github-app/index.ts b/packages/cli/src/modules/create-github-app/index.ts index f69230cd77..da1e04aaac 100644 --- a/packages/cli/src/modules/create-github-app/index.ts +++ b/packages/cli/src/modules/create-github-app/index.ts @@ -13,17 +13,26 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import { createCliPlugin } from '../../wiring/factory'; import { Command } from 'commander'; import { lazy } from '../../lib/lazy'; -export function registerCommands(program: Command) { - program - .command('create-github-app ') - .description('Create new GitHub App in your organization.') - .action( - lazy( - () => import('../create-github-app/commands/create-github-app'), - 'default', - ), - ); -} +export default createCliPlugin({ + pluginId: 'new', + init: async reg => { + reg.addCommand({ + path: ['create-github-app'], + description: 'Create new GitHub App in your organization.', + execute: async ({ args }) => { + const command = new Command(); + const defaultCommand = command + .argument('') + .action( + lazy(() => import('./commands/create-github-app'), 'default'), + ); + + await defaultCommand.parseAsync(args, { from: 'user' }); + }, + }); + }, +}); diff --git a/packages/cli/src/modules/info/index.ts b/packages/cli/src/modules/info/index.ts index af43af652c..1e6f761f83 100644 --- a/packages/cli/src/modules/info/index.ts +++ b/packages/cli/src/modules/info/index.ts @@ -1,5 +1,5 @@ /* - * Copyright 2020 The Backstage Authors + * Copyright 2024 The Backstage Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,13 +13,21 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import yargs from 'yargs'; +import { createCliPlugin } from '../../wiring/factory'; -import { lazy } from '../../lib/lazy'; -import { Command } from 'commander'; - -export function registerCommands(program: Command) { - program - .command('info') - .description('Show helpful information for debugging and reporting bugs') - .action(lazy(() => import('./commands/info'), 'default')); -} +export default createCliPlugin({ + pluginId: 'info', + init: async reg => { + reg.addCommand({ + path: ['info'], + description: 'Show helpful information for debugging and reporting bugs', + execute: async ({ args }) => { + yargs().parse(args); + const { default: command } = + require('./commands/info') as typeof import('./commands/info'); + await command(); + }, + }); + }, +}); diff --git a/packages/cli/src/modules/lint/alpha.ts b/packages/cli/src/modules/lint/alpha.ts deleted file mode 100644 index 617f71d5c9..0000000000 --- a/packages/cli/src/modules/lint/alpha.ts +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2025 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -import { createCliPlugin } from '../../wiring/factory'; -import { Command } from 'commander'; -import { lazy } from '../../lib/lazy'; - -export default createCliPlugin({ - pluginId: 'lint', - init: async reg => { - reg.addCommand({ - path: ['package', 'lint'], - description: 'Lint a package', - execute: async ({ args }) => { - const command = new Command(); - command.arguments('[directories...]'); - command.option('--fix', 'Attempt to automatically fix violations'); - command.option( - '--format ', - 'Lint report output format', - 'eslint-formatter-friendly', - ); - command.option( - '--output-file ', - 'Write the lint report to a file instead of stdout', - ); - command.option( - '--max-warnings ', - 'Fail if more than this number of warnings. -1 allows warnings. (default: -1)', - ); - command.description('Lint a package'); - command.action( - lazy(() => import('./commands/package/lint'), 'default'), - ); - - await command.parseAsync(args, { from: 'user' }); - }, - }); - - reg.addCommand({ - path: ['repo', 'lint'], - description: 'Lint a repository', - execute: async ({ args }) => { - const command = new Command(); - command.option('--fix', 'Attempt to automatically fix violations'); - command.option( - '--format ', - 'Lint report output format', - 'eslint-formatter-friendly', - ); - command.option( - '--output-file ', - 'Write the lint report to a file instead of stdout', - ); - command.option( - '--successCache', - 'Enable success caching, which skips running tests for unchanged packages that were successful in the previous run', - ); - command.option( - '--successCacheDir ', - 'Set the success cache location, (default: node_modules/.cache/backstage-cli)', - ); - command.option( - '--since ', - 'Only lint packages that changed since the specified ref', - ); - command.option( - '--max-warnings ', - 'Fail if more than this number of warnings. -1 allows warnings. (default: -1)', - ); - command.description('Lint a repository'); - command.action(lazy(() => import('./commands/repo/lint'), 'command')); - - await command.parseAsync(args, { from: 'user' }); - }, - }); - }, -}); diff --git a/packages/cli/src/modules/lint/index.ts b/packages/cli/src/modules/lint/index.ts index dfa0916efb..6cba232da9 100644 --- a/packages/cli/src/modules/lint/index.ts +++ b/packages/cli/src/modules/lint/index.ts @@ -13,59 +13,83 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import { createCliPlugin } from '../../wiring/factory'; import { Command } from 'commander'; import { lazy } from '../../lib/lazy'; -export function registerPackageCommands(command: Command) { - command - .command('lint [directories...]') - .option( - '--format ', - 'Lint report output format', - 'eslint-formatter-friendly', - ) - .option( - '--output-file ', - 'Write the lint report to a file instead of stdout', - ) - .option('--fix', 'Attempt to automatically fix violations') - .option( - '--max-warnings ', - 'Fail if more than this number of warnings. -1 allows warnings. (default: -1)', - ) - .description('Lint a package') - .action(lazy(() => import('./commands/package/lint'), 'default')); +export function registerPackageLintCommand(command: Command) { + command.arguments('[directories...]'); + command.option('--fix', 'Attempt to automatically fix violations'); + command.option( + '--format ', + 'Lint report output format', + 'eslint-formatter-friendly', + ); + command.option( + '--output-file ', + 'Write the lint report to a file instead of stdout', + ); + command.option( + '--max-warnings ', + 'Fail if more than this number of warnings. -1 allows warnings. (default: -1)', + ); + command.description('Lint a package'); + command.action(lazy(() => import('./commands/package/lint'), 'default')); } -export function registerRepoCommands(command: Command) { - command - .command('lint') - .description('Lint all packages in the project') - .option( - '--format ', - 'Lint report output format', - 'eslint-formatter-friendly', - ) - .option( - '--output-file ', - 'Write the lint report to a file instead of stdout', - ) - .option( - '--since ', - 'Only lint packages that changed since the specified ref', - ) - .option( - '--successCache', - 'Enable success caching, which skips running tests for unchanged packages that were successful in the previous run', - ) - .option( - '--successCacheDir ', - 'Set the success cache location, (default: node_modules/.cache/backstage-cli)', - ) - .option( - '--max-warnings ', - 'Fail if more than this number of warnings. -1 allows warnings. (default: -1)', - ) - .option('--fix', 'Attempt to automatically fix violations') - .action(lazy(() => import('./commands/repo/lint'), 'command')); -} +export default createCliPlugin({ + pluginId: 'lint', + init: async reg => { + reg.addCommand({ + path: ['package', 'lint'], + description: 'Lint a package', + execute: async ({ args }) => { + const command = new Command(); + registerPackageLintCommand(command); + + await command.parseAsync(args, { from: 'user' }); + }, + }); + + reg.addCommand({ + path: ['repo', 'lint'], + description: 'Lint a repository', + execute: async ({ args }) => { + const command = new Command(); + + registerPackageLintCommand(command.command('package').command('lint')); + + command.option('--fix', 'Attempt to automatically fix violations'); + command.option( + '--format ', + 'Lint report output format', + 'eslint-formatter-friendly', + ); + command.option( + '--output-file ', + 'Write the lint report to a file instead of stdout', + ); + command.option( + '--successCache', + 'Enable success caching, which skips running tests for unchanged packages that were successful in the previous run', + ); + command.option( + '--successCacheDir ', + 'Set the success cache location, (default: node_modules/.cache/backstage-cli)', + ); + command.option( + '--since ', + 'Only lint packages that changed since the specified ref', + ); + command.option( + '--max-warnings ', + 'Fail if more than this number of warnings. -1 allows warnings. (default: -1)', + ); + command.description('Lint a repository'); + command.action(lazy(() => import('./commands/repo/lint'), 'command')); + + await command.parseAsync(args, { from: 'user' }); + }, + }); + }, +}); diff --git a/packages/cli/src/modules/maintenance/alpha.ts b/packages/cli/src/modules/maintenance/alpha.ts deleted file mode 100644 index 41192afdc4..0000000000 --- a/packages/cli/src/modules/maintenance/alpha.ts +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright 2025 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -import { Command } from 'commander'; -import { createCliPlugin } from '../../wiring/factory'; -import { lazy } from '../../lib/lazy'; - -export default createCliPlugin({ - pluginId: 'maintenance', - init: async reg => { - reg.addCommand({ - path: ['package', 'clean'], - description: 'Delete cache directories', - execute: async ({ args }) => { - const command = new Command(); - const defaultCommand = command.action( - lazy(() => import('./commands/package/clean'), 'default'), - ); - - await defaultCommand.parseAsync(args, { from: 'user' }); - }, - }); - - reg.addCommand({ - path: ['package', 'prepack'], - description: 'Prepares a package for packaging before publishing', - execute: async ({ args }) => { - const command = new Command(); - const defaultCommand = command.action( - lazy(() => import('./commands/package/pack'), 'pre'), - ); - - await defaultCommand.parseAsync(args, { from: 'user' }); - }, - }); - - reg.addCommand({ - path: ['package', 'postpack'], - description: 'Restores the changes made by the prepack command', - execute: async ({ args }) => { - const command = new Command(); - const defaultCommand = command.action( - lazy(() => import('./commands/package/pack'), 'post'), - ); - - await defaultCommand.parseAsync(args, { from: 'user' }); - }, - }); - - reg.addCommand({ - path: ['repo', 'fix'], - description: 'Automatically fix packages in the project', - execute: async ({ args }) => { - const command = new Command(); - const defaultCommand = command - .option( - '--publish', - 'Enable additional fixes that only apply when publishing packages', - ) - .option( - '--check', - 'Fail if any packages would have been changed by the command', - ) - .action(lazy(() => import('./commands/repo/fix'), 'command')); - - await defaultCommand.parseAsync(args, { from: 'user' }); - }, - }); - - reg.addCommand({ - path: ['repo', 'clean'], - description: 'Delete cache and output directories', - execute: async ({ args }) => { - const command = new Command(); - const defaultCommand = command.action( - lazy(() => import('./commands/repo/clean'), 'command'), - ); - - await defaultCommand.parseAsync(args, { from: 'user' }); - }, - }); - - reg.addCommand({ - path: ['repo', 'list-deprecations'], - description: 'List deprecations', - execute: async ({ args }) => { - const command = new Command(); - const defaultCommand = command - .option('--json', 'Output as JSON') - .action( - lazy(() => import('./commands/repo/list-deprecations'), 'command'), - ); - - await defaultCommand.parseAsync(args, { from: 'user' }); - }, - }); - }, -}); diff --git a/packages/cli/src/modules/maintenance/index.ts b/packages/cli/src/modules/maintenance/index.ts index 48669e9c34..41192afdc4 100644 --- a/packages/cli/src/modules/maintenance/index.ts +++ b/packages/cli/src/modules/maintenance/index.ts @@ -13,49 +13,98 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - import { Command } from 'commander'; +import { createCliPlugin } from '../../wiring/factory'; import { lazy } from '../../lib/lazy'; -export function registerPackageCommands(command: Command) { - command - .command('clean') - .description('Delete cache directories') - .action(lazy(() => import('./commands/package/clean'), 'default')); +export default createCliPlugin({ + pluginId: 'maintenance', + init: async reg => { + reg.addCommand({ + path: ['package', 'clean'], + description: 'Delete cache directories', + execute: async ({ args }) => { + const command = new Command(); + const defaultCommand = command.action( + lazy(() => import('./commands/package/clean'), 'default'), + ); - command - .command('prepack') - .description('Prepares a package for packaging before publishing') - .action(lazy(() => import('./commands/package/pack'), 'pre')); + await defaultCommand.parseAsync(args, { from: 'user' }); + }, + }); - command - .command('postpack') - .description('Restores the changes made by the prepack command') - .action(lazy(() => import('./commands/package/pack'), 'post')); -} + reg.addCommand({ + path: ['package', 'prepack'], + description: 'Prepares a package for packaging before publishing', + execute: async ({ args }) => { + const command = new Command(); + const defaultCommand = command.action( + lazy(() => import('./commands/package/pack'), 'pre'), + ); -export function registerRepoCommands(command: Command) { - command - .command('fix') - .description('Automatically fix packages in the project') - .option( - '--publish', - 'Enable additional fixes that only apply when publishing packages', - ) - .option( - '--check', - 'Fail if any packages would have been changed by the command', - ) - .action(lazy(() => import('./commands/repo/fix'), 'command')); + await defaultCommand.parseAsync(args, { from: 'user' }); + }, + }); - command - .command('clean') - .description('Delete cache and output directories') - .action(lazy(() => import('./commands/repo/clean'), 'command')); + reg.addCommand({ + path: ['package', 'postpack'], + description: 'Restores the changes made by the prepack command', + execute: async ({ args }) => { + const command = new Command(); + const defaultCommand = command.action( + lazy(() => import('./commands/package/pack'), 'post'), + ); - command - .command('list-deprecations') - .description('List deprecations') - .option('--json', 'Output as JSON') - .action(lazy(() => import('./commands/repo/list-deprecations'), 'command')); -} + await defaultCommand.parseAsync(args, { from: 'user' }); + }, + }); + + reg.addCommand({ + path: ['repo', 'fix'], + description: 'Automatically fix packages in the project', + execute: async ({ args }) => { + const command = new Command(); + const defaultCommand = command + .option( + '--publish', + 'Enable additional fixes that only apply when publishing packages', + ) + .option( + '--check', + 'Fail if any packages would have been changed by the command', + ) + .action(lazy(() => import('./commands/repo/fix'), 'command')); + + await defaultCommand.parseAsync(args, { from: 'user' }); + }, + }); + + reg.addCommand({ + path: ['repo', 'clean'], + description: 'Delete cache and output directories', + execute: async ({ args }) => { + const command = new Command(); + const defaultCommand = command.action( + lazy(() => import('./commands/repo/clean'), 'command'), + ); + + await defaultCommand.parseAsync(args, { from: 'user' }); + }, + }); + + reg.addCommand({ + path: ['repo', 'list-deprecations'], + description: 'List deprecations', + execute: async ({ args }) => { + const command = new Command(); + const defaultCommand = command + .option('--json', 'Output as JSON') + .action( + lazy(() => import('./commands/repo/list-deprecations'), 'command'), + ); + + await defaultCommand.parseAsync(args, { from: 'user' }); + }, + }); + }, +}); diff --git a/packages/cli/src/modules/migrate/alpha.ts b/packages/cli/src/modules/migrate/alpha.ts deleted file mode 100644 index ac56c06b7a..0000000000 --- a/packages/cli/src/modules/migrate/alpha.ts +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright 2024 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -import { createCliPlugin } from '../../wiring/factory'; -import { Command } from 'commander'; -import { lazy } from '../../lib/lazy'; - -export default createCliPlugin({ - pluginId: 'migrate', - init: async reg => { - reg.addCommand({ - path: ['versions:migrate'], - description: - 'Migrate any plugins that have been moved to the @backstage-community namespace automatically', - execute: async ({ args }) => { - const command = new Command(); - const defaultCommand = command - .option( - '--pattern ', - 'Override glob for matching packages to upgrade', - ) - .option( - '--skip-code-changes', - 'Skip code changes and only update package.json files', - ) - .action(lazy(() => import('./commands/versions/migrate'), 'default')); - - await defaultCommand.parseAsync(args, { from: 'user' }); - }, - }); - - reg.addCommand({ - path: ['versions:bump'], - description: 'Bump Backstage packages to the latest versions', - execute: async ({ args }) => { - const command = new Command(); - - const defaultCommand = command - .option( - '--pattern ', - 'Override glob for matching packages to upgrade', - ) - .option( - '--release ', - 'Bump to a specific Backstage release line or version', - 'main', - ) - .option('--skip-install', 'Skips yarn install step') - .option('--skip-migrate', 'Skips migration of any moved packages') - .action(lazy(() => import('./commands/versions/bump'), 'default')); - - await defaultCommand.parseAsync(args, { from: 'user' }); - }, - }); - - reg.addCommand({ - path: ['migrate', 'package-roles'], - description: `Add package role field to packages that don't have it`, - execute: async ({ args }) => { - const command = new Command(); - const defaultCommand = command.action( - lazy(() => import('./commands/packageRole'), 'default'), - ); - - await defaultCommand.parseAsync(args, { from: 'user' }); - }, - }); - - reg.addCommand({ - path: ['migrate', 'package-scripts'], - description: 'Set package scripts according to each package role', - execute: async ({ args }) => { - const command = new Command(); - const defaultCommand = command.action( - lazy(() => import('./commands/packageScripts'), 'command'), - ); - - await defaultCommand.parseAsync(args, { from: 'user' }); - }, - }); - - reg.addCommand({ - path: ['migrate', 'package-exports'], - description: 'Synchronize package subpath export definitions', - execute: async ({ args }) => { - const command = new Command(); - const defaultCommand = command.action( - lazy(() => import('./commands/packageExports'), 'command'), - ); - - await defaultCommand.parseAsync(args, { from: 'user' }); - }, - }); - - reg.addCommand({ - path: ['migrate', 'package-lint-configs'], - description: - 'Migrates all packages to use @backstage/cli/config/eslint-factory', - execute: async ({ args }) => { - const command = new Command(); - const defaultCommand = command.action( - lazy(() => import('./commands/packageLintConfigs'), 'command'), - ); - - await defaultCommand.parseAsync(args, { from: 'user' }); - }, - }); - - reg.addCommand({ - path: ['migrate', 'react-router-deps'], - description: - 'Migrates the react-router dependencies for all packages to be peer dependencies', - execute: async ({ args }) => { - const command = new Command(); - const defaultCommand = command.action( - lazy(() => import('./commands/reactRouterDeps'), 'command'), - ); - - await defaultCommand.parseAsync(args, { from: 'user' }); - }, - }); - }, -}); diff --git a/packages/cli/src/modules/migrate/index.ts b/packages/cli/src/modules/migrate/index.ts index 10e96ad173..ac56c06b7a 100644 --- a/packages/cli/src/modules/migrate/index.ts +++ b/packages/cli/src/modules/migrate/index.ts @@ -1,5 +1,5 @@ /* - * Copyright 2025 The Backstage Authors + * Copyright 2024 The Backstage Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,72 +13,123 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -import { lazy } from '../../lib/lazy'; +import { createCliPlugin } from '../../wiring/factory'; import { Command } from 'commander'; +import { lazy } from '../../lib/lazy'; -export function registerCommands(program: Command) { - program - .command('versions:bump') - .option( - '--pattern ', - 'Override glob for matching packages to upgrade', - ) - .option( - '--release ', - 'Bump to a specific Backstage release line or version', - 'main', - ) - .option('--skip-install', 'Skips yarn install step') - .option('--skip-migrate', 'Skips migration of any moved packages') - .description('Bump Backstage packages to the latest versions') - .action(lazy(() => import('./commands/versions/bump'), 'default')); +export default createCliPlugin({ + pluginId: 'migrate', + init: async reg => { + reg.addCommand({ + path: ['versions:migrate'], + description: + 'Migrate any plugins that have been moved to the @backstage-community namespace automatically', + execute: async ({ args }) => { + const command = new Command(); + const defaultCommand = command + .option( + '--pattern ', + 'Override glob for matching packages to upgrade', + ) + .option( + '--skip-code-changes', + 'Skip code changes and only update package.json files', + ) + .action(lazy(() => import('./commands/versions/migrate'), 'default')); - program - .command('versions:migrate') - .option( - '--pattern ', - 'Override glob for matching packages to upgrade', - ) - .option( - '--skip-code-changes', - 'Skip code changes and only update package.json files', - ) - .description( - 'Migrate any plugins that have been moved to the @backstage-community namespace automatically', - ) - .action(lazy(() => import('./commands/versions/migrate'), 'default')); + await defaultCommand.parseAsync(args, { from: 'user' }); + }, + }); - const command = program - .command('migrate [command]') - .description('Migration utilities'); + reg.addCommand({ + path: ['versions:bump'], + description: 'Bump Backstage packages to the latest versions', + execute: async ({ args }) => { + const command = new Command(); - command - .command('package-roles') - .description(`Add package role field to packages that don't have it`) - .action(lazy(() => import('./commands/packageRole'), 'default')); + const defaultCommand = command + .option( + '--pattern ', + 'Override glob for matching packages to upgrade', + ) + .option( + '--release ', + 'Bump to a specific Backstage release line or version', + 'main', + ) + .option('--skip-install', 'Skips yarn install step') + .option('--skip-migrate', 'Skips migration of any moved packages') + .action(lazy(() => import('./commands/versions/bump'), 'default')); - command - .command('package-scripts') - .description('Set package scripts according to each package role') - .action(lazy(() => import('./commands/packageScripts'), 'command')); + await defaultCommand.parseAsync(args, { from: 'user' }); + }, + }); - command - .command('package-exports') - .description('Synchronize package subpath export definitions') - .action(lazy(() => import('./commands/packageExports'), 'command')); + reg.addCommand({ + path: ['migrate', 'package-roles'], + description: `Add package role field to packages that don't have it`, + execute: async ({ args }) => { + const command = new Command(); + const defaultCommand = command.action( + lazy(() => import('./commands/packageRole'), 'default'), + ); - command - .command('package-lint-configs') - .description( - 'Migrates all packages to use @backstage/cli/config/eslint-factory', - ) - .action(lazy(() => import('./commands/packageLintConfigs'), 'command')); + await defaultCommand.parseAsync(args, { from: 'user' }); + }, + }); - command - .command('react-router-deps') - .description( - 'Migrates the react-router dependencies for all packages to be peer dependencies', - ) - .action(lazy(() => import('./commands/reactRouterDeps'), 'command')); -} + reg.addCommand({ + path: ['migrate', 'package-scripts'], + description: 'Set package scripts according to each package role', + execute: async ({ args }) => { + const command = new Command(); + const defaultCommand = command.action( + lazy(() => import('./commands/packageScripts'), 'command'), + ); + + await defaultCommand.parseAsync(args, { from: 'user' }); + }, + }); + + reg.addCommand({ + path: ['migrate', 'package-exports'], + description: 'Synchronize package subpath export definitions', + execute: async ({ args }) => { + const command = new Command(); + const defaultCommand = command.action( + lazy(() => import('./commands/packageExports'), 'command'), + ); + + await defaultCommand.parseAsync(args, { from: 'user' }); + }, + }); + + reg.addCommand({ + path: ['migrate', 'package-lint-configs'], + description: + 'Migrates all packages to use @backstage/cli/config/eslint-factory', + execute: async ({ args }) => { + const command = new Command(); + const defaultCommand = command.action( + lazy(() => import('./commands/packageLintConfigs'), 'command'), + ); + + await defaultCommand.parseAsync(args, { from: 'user' }); + }, + }); + + reg.addCommand({ + path: ['migrate', 'react-router-deps'], + description: + 'Migrates the react-router dependencies for all packages to be peer dependencies', + execute: async ({ args }) => { + const command = new Command(); + const defaultCommand = command.action( + lazy(() => import('./commands/reactRouterDeps'), 'command'), + ); + + await defaultCommand.parseAsync(args, { from: 'user' }); + }, + }); + }, +}); diff --git a/packages/cli/src/modules/new/alpha.ts b/packages/cli/src/modules/new/alpha.ts deleted file mode 100644 index 6802077507..0000000000 --- a/packages/cli/src/modules/new/alpha.ts +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright 2025 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -import { createCliPlugin } from '../../wiring/factory'; -import { Command } from 'commander'; -import { lazy } from '../../lib/lazy'; -import { removed } from '../../lib/removed'; - -export default createCliPlugin({ - pluginId: 'new', - init: async reg => { - reg.addCommand({ - path: ['new'], - description: - 'Open up an interactive guide to creating new things in your app', - execute: async ({ args }) => { - const command = new Command(); - const defaultCommand = command - .storeOptionsAsProperties(false) - .description( - 'Open up an interactive guide to creating new things in your app', - ) - .option( - '--select ', - 'Select the thing you want to be creating upfront', - ) - .option( - '--option =', - 'Pre-fill options for the creation process', - (opt, arr: string[]) => [...arr, opt], - [], - ) - .option( - '--skip-install', - `Skips running 'yarn install' and 'yarn lint --fix'`, - ) - .option('--scope ', 'The scope to use for new packages') - .option( - '--npm-registry ', - 'The package registry to use for new packages', - ) - .option( - '--baseVersion ', - 'The version to use for any new packages (default: 0.1.0)', - ) - .option( - '--license ', - 'The license to use for any new packages (default: Apache-2.0)', - ) - .option('--no-private', 'Do not mark new packages as private') - .action(lazy(() => import('./commands/new'), 'default')); - - await defaultCommand.parseAsync(args, { from: 'user' }); - }, - }); - - reg.addCommand({ - path: ['create'], - description: 'Create a new Backstage app', - deprecated: true, - execute: async () => { - removed("use 'backstage-cli new' instead")(); - }, - }); - reg.addCommand({ - path: ['create-plugin'], - description: 'Create a new Backstage plugin', - deprecated: true, - execute: async () => { - removed("use 'backstage-cli new' instead")(); - }, - }); - }, -}); diff --git a/packages/cli/src/modules/new/index.ts b/packages/cli/src/modules/new/index.ts index fa288f5f46..6802077507 100644 --- a/packages/cli/src/modules/new/index.ts +++ b/packages/cli/src/modules/new/index.ts @@ -13,53 +13,74 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import { createCliPlugin } from '../../wiring/factory'; import { Command } from 'commander'; import { lazy } from '../../lib/lazy'; import { removed } from '../../lib/removed'; -export function registerCommands(program: Command) { - program - .command('new') - .storeOptionsAsProperties(false) - .description( - 'Open up an interactive guide to creating new things in your app', - ) - .option( - '--select ', - 'Select the thing you want to be creating upfront', - ) - .option( - '--option =', - 'Pre-fill options for the creation process', - (opt, arr: string[]) => [...arr, opt], - [], - ) - .option( - '--skip-install', - `Skips running 'yarn install' and 'yarn lint --fix'`, - ) - .option('--scope ', 'The scope to use for new packages') - .option( - '--npm-registry ', - 'The package registry to use for new packages', - ) - .option( - '--baseVersion ', - 'The version to use for any new packages (default: 0.1.0)', - ) - .option( - '--license ', - 'The license to use for any new packages (default: Apache-2.0)', - ) - .option('--no-private', 'Do not mark new packages as private') - .action(lazy(() => import('./commands/new'), 'default')); +export default createCliPlugin({ + pluginId: 'new', + init: async reg => { + reg.addCommand({ + path: ['new'], + description: + 'Open up an interactive guide to creating new things in your app', + execute: async ({ args }) => { + const command = new Command(); + const defaultCommand = command + .storeOptionsAsProperties(false) + .description( + 'Open up an interactive guide to creating new things in your app', + ) + .option( + '--select ', + 'Select the thing you want to be creating upfront', + ) + .option( + '--option =', + 'Pre-fill options for the creation process', + (opt, arr: string[]) => [...arr, opt], + [], + ) + .option( + '--skip-install', + `Skips running 'yarn install' and 'yarn lint --fix'`, + ) + .option('--scope ', 'The scope to use for new packages') + .option( + '--npm-registry ', + 'The package registry to use for new packages', + ) + .option( + '--baseVersion ', + 'The version to use for any new packages (default: 0.1.0)', + ) + .option( + '--license ', + 'The license to use for any new packages (default: Apache-2.0)', + ) + .option('--no-private', 'Do not mark new packages as private') + .action(lazy(() => import('./commands/new'), 'default')); - program - .command('create') - .allowUnknownOption(true) - .action(removed("use 'backstage-cli new' instead")); - program - .command('create-plugin') - .allowUnknownOption(true) - .action(removed("use 'backstage-cli new' instead")); -} + await defaultCommand.parseAsync(args, { from: 'user' }); + }, + }); + + reg.addCommand({ + path: ['create'], + description: 'Create a new Backstage app', + deprecated: true, + execute: async () => { + removed("use 'backstage-cli new' instead")(); + }, + }); + reg.addCommand({ + path: ['create-plugin'], + description: 'Create a new Backstage plugin', + deprecated: true, + execute: async () => { + removed("use 'backstage-cli new' instead")(); + }, + }); + }, +}); diff --git a/packages/cli/src/modules/test/alpha.ts b/packages/cli/src/modules/test/alpha.ts deleted file mode 100644 index 1583c74997..0000000000 --- a/packages/cli/src/modules/test/alpha.ts +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2024 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -import { createCliPlugin } from '../../wiring/factory'; -import { Command } from 'commander'; -import { lazy } from '../../lib/lazy'; - -export default createCliPlugin({ - pluginId: 'test', - init: async reg => { - reg.addCommand({ - path: ['repo', 'test'], - description: - 'Run tests, forwarding args to Jest, defaulting to watch mode', - execute: async ({ args }) => { - const command = new Command(); - command.allowUnknownOption(true); - command.option( - '--since ', - 'Only test packages that changed since the specified ref', - ); - command.option('--successCache', 'Enable success caching'); - command.option( - '--successCacheDir ', - 'Set the success cache location, (default: node_modules/.cache/backstage-cli)', - ); - command.option( - '--jest-help', - 'Show help for Jest CLI options, which are passed through', - ); - command.action(lazy(() => import('./commands/repo/test'), 'command')); - await command.parseAsync(args, { from: 'user' }); - }, - }); - - reg.addCommand({ - path: ['package', 'test'], - description: - 'Run tests, forwarding args to Jest, defaulting to watch mode', - execute: async ({ args }) => { - const command = new Command(); - - command.allowUnknownOption(true); - command.helpOption(', --backstage-cli-help'); - command.action( - lazy(() => import('./commands/package/test'), 'default'), - ); - await command.parseAsync(args, { from: 'user' }); - }, - }); - }, -}); diff --git a/packages/cli/src/modules/test/index.ts b/packages/cli/src/modules/test/index.ts index 8e4720109f..1583c74997 100644 --- a/packages/cli/src/modules/test/index.ts +++ b/packages/cli/src/modules/test/index.ts @@ -1,5 +1,5 @@ /* - * Copyright 2025 The Backstage Authors + * Copyright 2024 The Backstage Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,39 +13,52 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - +import { createCliPlugin } from '../../wiring/factory'; import { Command } from 'commander'; import { lazy } from '../../lib/lazy'; -export function registerRepoCommands(command: Command) { - command - .command('test') - .allowUnknownOption(true) // Allows the command to run, but we still need to parse raw args - .option( - '--since ', - 'Only test packages that changed since the specified ref', - ) - .option( - '--successCache', - 'Enable success caching, which skips running tests for unchanged packages that were successful in the previous run', - ) - .option( - '--successCacheDir ', - 'Set the success cache location, (default: node_modules/.cache/backstage-cli)', - ) - .option( - '--jest-help', - 'Show help for Jest CLI options, which are passed through', - ) - .description('Run tests, forwarding args to Jest, defaulting to watch mode') - .action(lazy(() => import('./commands/repo/test'), 'command')); -} +export default createCliPlugin({ + pluginId: 'test', + init: async reg => { + reg.addCommand({ + path: ['repo', 'test'], + description: + 'Run tests, forwarding args to Jest, defaulting to watch mode', + execute: async ({ args }) => { + const command = new Command(); + command.allowUnknownOption(true); + command.option( + '--since ', + 'Only test packages that changed since the specified ref', + ); + command.option('--successCache', 'Enable success caching'); + command.option( + '--successCacheDir ', + 'Set the success cache location, (default: node_modules/.cache/backstage-cli)', + ); + command.option( + '--jest-help', + 'Show help for Jest CLI options, which are passed through', + ); + command.action(lazy(() => import('./commands/repo/test'), 'command')); + await command.parseAsync(args, { from: 'user' }); + }, + }); -export function registerPackageCommands(command: Command) { - command - .command('test') - .allowUnknownOption(true) // Allows the command to run, but we still need to parse raw args - .helpOption(', --backstage-cli-help') // Let Jest handle help - .description('Run tests, forwarding args to Jest, defaulting to watch mode') - .action(lazy(() => import('./commands/package/test'), 'default')); -} + reg.addCommand({ + path: ['package', 'test'], + description: + 'Run tests, forwarding args to Jest, defaulting to watch mode', + execute: async ({ args }) => { + const command = new Command(); + + command.allowUnknownOption(true); + command.helpOption(', --backstage-cli-help'); + command.action( + lazy(() => import('./commands/package/test'), 'default'), + ); + await command.parseAsync(args, { from: 'user' }); + }, + }); + }, +}); diff --git a/packages/core-app-api/CHANGELOG.md b/packages/core-app-api/CHANGELOG.md index 6b5a5727e8..1b986bc7b3 100644 --- a/packages/core-app-api/CHANGELOG.md +++ b/packages/core-app-api/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/core-app-api +## 1.17.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.10.8 + - @backstage/config@1.3.2 + - @backstage/types@1.2.1 + - @backstage/version-bridge@1.0.11 + ## 1.17.0 ### Minor Changes diff --git a/packages/core-app-api/package.json b/packages/core-app-api/package.json index 73fef45b06..69c812a445 100644 --- a/packages/core-app-api/package.json +++ b/packages/core-app-api/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/core-app-api", - "version": "1.17.0", + "version": "1.17.1", "description": "Core app API used by Backstage apps", "backstage": { "role": "web-library" diff --git a/packages/core-compat-api/CHANGELOG.md b/packages/core-compat-api/CHANGELOG.md index e1919518ea..9772faf770 100644 --- a/packages/core-compat-api/CHANGELOG.md +++ b/packages/core-compat-api/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/core-compat-api +## 0.4.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.10.8 + - @backstage/frontend-plugin-api@0.10.3 + - @backstage/plugin-catalog-react@1.19.0 + - @backstage/version-bridge@1.0.11 + +## 0.4.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.19.0-next.2 + - @backstage/frontend-plugin-api@0.10.3-next.1 + - @backstage/core-plugin-api@1.10.7 + - @backstage/version-bridge@1.0.11 + ## 0.4.3-next.1 ### Patch Changes diff --git a/packages/core-compat-api/package.json b/packages/core-compat-api/package.json index db865fbec9..bbd9e409fa 100644 --- a/packages/core-compat-api/package.json +++ b/packages/core-compat-api/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/core-compat-api", - "version": "0.4.3-next.1", + "version": "0.4.3", "backstage": { "role": "web-library" }, diff --git a/packages/core-components/CHANGELOG.md b/packages/core-components/CHANGELOG.md index 735fd7b84c..a39152fe8c 100644 --- a/packages/core-components/CHANGELOG.md +++ b/packages/core-components/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/core-components +## 0.17.3 + +### Patch Changes + +- 6232160: table actions header support i18n +- Updated dependencies + - @backstage/core-plugin-api@1.10.8 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/theme@0.6.6 + - @backstage/version-bridge@1.0.11 + +## 0.17.3-next.0 + +### Patch Changes + +- 6232160: table actions header support i18n +- Updated dependencies + - @backstage/config@1.3.2 + - @backstage/core-plugin-api@1.10.7 + - @backstage/errors@1.2.7 + - @backstage/theme@0.6.6 + - @backstage/version-bridge@1.0.11 + ## 0.17.2 ### Patch Changes diff --git a/packages/core-components/package.json b/packages/core-components/package.json index 47641194af..ac2dda270c 100644 --- a/packages/core-components/package.json +++ b/packages/core-components/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/core-components", - "version": "0.17.2", + "version": "0.17.3", "description": "Core components used by Backstage plugins and apps", "backstage": { "role": "web-library" diff --git a/packages/core-plugin-api/CHANGELOG.md b/packages/core-plugin-api/CHANGELOG.md index 6aee788421..9651f37fb1 100644 --- a/packages/core-plugin-api/CHANGELOG.md +++ b/packages/core-plugin-api/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/core-plugin-api +## 1.10.8 + +### Patch Changes + +- c83cd8b: Fixed some circular or otherwise unclear imports +- 0169b23: Internal tweak to avoid circular dependencies +- Updated dependencies + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/version-bridge@1.0.11 + ## 1.10.7 ### Patch Changes diff --git a/packages/core-plugin-api/package.json b/packages/core-plugin-api/package.json index 3671d16609..c4bd3d4b0d 100644 --- a/packages/core-plugin-api/package.json +++ b/packages/core-plugin-api/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/core-plugin-api", - "version": "1.10.7", + "version": "1.10.8", "description": "Core API used by Backstage plugins", "backstage": { "role": "web-library" diff --git a/packages/core-plugin-api/src/analytics/Tracker.ts b/packages/core-plugin-api/src/analytics/Tracker.ts index 130410e2a2..4ae31b43fd 100644 --- a/packages/core-plugin-api/src/analytics/Tracker.ts +++ b/packages/core-plugin-api/src/analytics/Tracker.ts @@ -20,7 +20,7 @@ import { AnalyticsEventAttributes, AnalyticsTracker, } from '../apis'; -import { AnalyticsContextValue } from './'; +import { AnalyticsContextValue } from './types'; type TempGlobalEvents = { /** diff --git a/packages/core-plugin-api/src/apis/definitions/TranslationApi.ts b/packages/core-plugin-api/src/apis/definitions/TranslationApi.ts index 7c3c3f8e83..5cfb14abb2 100644 --- a/packages/core-plugin-api/src/apis/definitions/TranslationApi.ts +++ b/packages/core-plugin-api/src/apis/definitions/TranslationApi.ts @@ -16,7 +16,7 @@ import { ApiRef, createApiRef } from '@backstage/core-plugin-api'; import { Expand, ExpandRecursive, Observable } from '@backstage/types'; -import { TranslationRef } from '../../translation'; +import { TranslationRef } from '../../translation/TranslationRef'; import { JSX } from 'react'; /** diff --git a/packages/create-app/CHANGELOG.md b/packages/create-app/CHANGELOG.md index 2876e57911..6308472870 100644 --- a/packages/create-app/CHANGELOG.md +++ b/packages/create-app/CHANGELOG.md @@ -1,5 +1,35 @@ # @backstage/create-app +## 0.7.0 + +### Minor Changes + +- 30474c4: Add .cache directory to shipped gitignore. + +### Patch Changes + +- d57a6f7: Bumped create-app version. +- f628f44: Bumped create-app version. +- 9c9faf2: Bumped create-app version. +- Updated dependencies + - @backstage/cli-common@0.1.15 + +## 0.7.0-next.3 + +### Patch Changes + +- Bumped create-app version. +- Updated dependencies + - @backstage/cli-common@0.1.15 + +## 0.7.0-next.2 + +### Patch Changes + +- Bumped create-app version. +- Updated dependencies + - @backstage/cli-common@0.1.15 + ## 0.7.0-next.1 ### Patch Changes diff --git a/packages/create-app/package.json b/packages/create-app/package.json index 735d08cc64..91ef375e10 100644 --- a/packages/create-app/package.json +++ b/packages/create-app/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/create-app", - "version": "0.7.0-next.1", + "version": "0.7.0", "description": "A CLI that helps you create your own Backstage app", "backstage": { "role": "cli" diff --git a/packages/dev-utils/CHANGELOG.md b/packages/dev-utils/CHANGELOG.md index 572ba74a94..10a91e10db 100644 --- a/packages/dev-utils/CHANGELOG.md +++ b/packages/dev-utils/CHANGELOG.md @@ -1,5 +1,33 @@ # @backstage/dev-utils +## 1.1.11 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3 + - @backstage/core-plugin-api@1.10.8 + - @backstage/plugin-catalog-react@1.19.0 + - @backstage/app-defaults@1.6.3 + - @backstage/integration-react@1.2.8 + - @backstage/catalog-model@1.7.4 + - @backstage/core-app-api@1.17.1 + - @backstage/theme@0.6.6 + +## 1.1.11-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/plugin-catalog-react@1.19.0-next.2 + - @backstage/app-defaults@1.6.3-next.0 + - @backstage/integration-react@1.2.7 + - @backstage/catalog-model@1.7.4 + - @backstage/core-app-api@1.17.0 + - @backstage/core-plugin-api@1.10.7 + - @backstage/theme@0.6.6 + ## 1.1.11-next.1 ### Patch Changes diff --git a/packages/dev-utils/package.json b/packages/dev-utils/package.json index 545f249f06..1924a43238 100644 --- a/packages/dev-utils/package.json +++ b/packages/dev-utils/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/dev-utils", - "version": "1.1.11-next.1", + "version": "1.1.11", "description": "Utilities for developing Backstage plugins.", "backstage": { "role": "web-library" diff --git a/packages/e2e-test/CHANGELOG.md b/packages/e2e-test/CHANGELOG.md index 4b4da9d410..a097e4bc23 100644 --- a/packages/e2e-test/CHANGELOG.md +++ b/packages/e2e-test/CHANGELOG.md @@ -1,5 +1,32 @@ # e2e-test +## 0.2.29 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.7.0 + - @backstage/cli-common@0.1.15 + - @backstage/errors@1.2.7 + +## 0.2.29-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.7.0-next.3 + - @backstage/cli-common@0.1.15 + - @backstage/errors@1.2.7 + +## 0.2.29-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.7.0-next.2 + - @backstage/cli-common@0.1.15 + - @backstage/errors@1.2.7 + ## 0.2.29-next.1 ### Patch Changes diff --git a/packages/e2e-test/package.json b/packages/e2e-test/package.json index 5f890a8b5e..2ae4912032 100644 --- a/packages/e2e-test/package.json +++ b/packages/e2e-test/package.json @@ -1,6 +1,6 @@ { "name": "e2e-test", - "version": "0.2.29-next.1", + "version": "0.2.29", "description": "E2E test for verifying Backstage packages", "backstage": { "role": "cli" diff --git a/packages/eslint-plugin/CHANGELOG.md b/packages/eslint-plugin/CHANGELOG.md index 12aed8093f..e12e91f97a 100644 --- a/packages/eslint-plugin/CHANGELOG.md +++ b/packages/eslint-plugin/CHANGELOG.md @@ -1,5 +1,28 @@ # @backstage/eslint-plugin +## 0.1.11 + +### Patch Changes + +- 098ef95: Fix custom rules package scanning performance. +- 063b2d3: Added new eslint rule to restrict mixed plugin imports. + + New rule `@backstage/no-mixed-plugin-imports` disallows mixed imports between plugins that are mixing + the backstage architecture. This rule forces that: + + - No imports from frontend plugins to backend plugins or other frontend plugins. + - No imports from backend plugins to frontend plugins or other backend plugins. + - No imports from common plugins to frontend or backend plugins. + + The current recommended configuration is giving a warning for mixed imports. This is to be changed in + the future to an error so please adjust your workspace accordingly. + +## 0.1.11-next.0 + +### Patch Changes + +- 098ef95: Fix custom rules package scanning performance. + ## 0.1.10 ### Patch Changes diff --git a/packages/eslint-plugin/README.md b/packages/eslint-plugin/README.md index 600b3268e1..e30b9e5de3 100644 --- a/packages/eslint-plugin/README.md +++ b/packages/eslint-plugin/README.md @@ -41,3 +41,4 @@ The following rules are provided by this plugin: | [@backstage/no-relative-monorepo-imports](./docs/rules/no-relative-monorepo-imports.md) | Forbid relative imports that reach outside of the package in a monorepo. | | [@backstage/no-undeclared-imports](./docs/rules/no-undeclared-imports.md) | Forbid imports of external packages that have not been declared in the appropriate dependencies field in `package.json`. | | [@backstage/no-top-level-material-ui-4-imports](./docs/rules/no-top-level-material-ui-4-imports.md) | Forbid top level import from Material UI v4 packages. | +| [@backstage/no-mixed-plugin-imports](./docs/rules/no-mixed-plugin-imports.md) | Disallow mixed plugin imports. | diff --git a/packages/eslint-plugin/docs/rules/no-mixed-plugin-imports.md b/packages/eslint-plugin/docs/rules/no-mixed-plugin-imports.md new file mode 100644 index 0000000000..e8570054e4 --- /dev/null +++ b/packages/eslint-plugin/docs/rules/no-mixed-plugin-imports.md @@ -0,0 +1,67 @@ +# @backstage/no-mixed-plugin-imports + +Disallow mixed imports between backstage plugins. + +## Usage + +Add the rules as follows, it has no options: + +```js +"@backstage/no-mixed-plugin-imports": ["error"] +``` + +## Rule Details + +Given the following two target packages: + +```json +{ + "name": "@backstage/plugin-foo", + "backstage": { + "role": "frontend-plugin" + } +} +``` + +```json +{ + "name": "@backstage/plugin-bar", + "backstage": { + "role": "frontend-plugin" + } +} +``` + +### Fail + +```ts +import { FooCard } from '@backstage/plugin-foo'; +``` + +### Pass + +```ts +import { FooCard } from '@backstage/plugin-foo-react'; +``` + +## Options + +You can ignore specific target packages or files by adding them to the options in the `.eslintrc.js` file: + +```js +{ + rules: { + '@backstage/no-mixed-plugin-imports': [ + 'error', + { + excludedTargetPackages: [ + '@backstage/plugin-foo', + ], + excludedFiles: [ + '**/*.{test,spec}.[jt]s?(x)' + ], + } + ] + } +} +``` diff --git a/packages/eslint-plugin/index.js b/packages/eslint-plugin/index.js index af1a8891c3..58b597a438 100644 --- a/packages/eslint-plugin/index.js +++ b/packages/eslint-plugin/index.js @@ -22,6 +22,7 @@ module.exports = { '@backstage/no-forbidden-package-imports': 'error', '@backstage/no-relative-monorepo-imports': 'error', '@backstage/no-undeclared-imports': 'error', + '@backstage/no-mixed-plugin-imports': 'warn', }, }, }, @@ -30,5 +31,6 @@ module.exports = { 'no-relative-monorepo-imports': require('./rules/no-relative-monorepo-imports'), 'no-undeclared-imports': require('./rules/no-undeclared-imports'), 'no-top-level-material-ui-4-imports': require('./rules/no-top-level-material-ui-4-imports'), + 'no-mixed-plugin-imports': require('./rules/no-mixed-plugin-imports'), }, }; diff --git a/packages/eslint-plugin/lib/getPackages.js b/packages/eslint-plugin/lib/getPackages.js index 3b46f41a54..e90536ff52 100644 --- a/packages/eslint-plugin/lib/getPackages.js +++ b/packages/eslint-plugin/lib/getPackages.js @@ -21,7 +21,7 @@ const manypkg = require('@manypkg/get-packages'); /** * @typedef ExtendedPackage - * @type {import('@manypkg/get-packages').Package & { packageJson: { exports?: Record, files?: Array, backstage?: { inline?: boolean } }}} packageJson + * @type {import('@manypkg/get-packages').Package & { packageJson: { exports?: Record, files?: Array, backstage?: { inline?: boolean, role?: string } }}} packageJson */ /** diff --git a/packages/eslint-plugin/package.json b/packages/eslint-plugin/package.json index 3a67ce8cee..8a44cfd1e8 100644 --- a/packages/eslint-plugin/package.json +++ b/packages/eslint-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/eslint-plugin", - "version": "0.1.10", + "version": "0.1.11", "description": "Backstage ESLint plugin", "publishConfig": { "access": "public" diff --git a/packages/eslint-plugin/rules/no-mixed-plugin-imports.js b/packages/eslint-plugin/rules/no-mixed-plugin-imports.js new file mode 100644 index 0000000000..b5e79b509e --- /dev/null +++ b/packages/eslint-plugin/rules/no-mixed-plugin-imports.js @@ -0,0 +1,249 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// @ts-check + +const visitImports = require('../lib/visitImports'); +const getPackages = require('../lib/getPackages'); +const minimatch = require('minimatch'); + +/** @typedef {import('../lib/getPackages.js').ExtendedPackage} ExtendedPackage */ + +/** + * @param {string} pattern + * @param {string} filePath + * @returns {boolean} + */ +const matchesPattern = (pattern, filePath) => { + return new minimatch.Minimatch(pattern).match(filePath); +}; + +const roleRules = [ + { + sourceRole: ['frontend-plugin', 'web-library'], + targetRole: [ + 'backend-plugin', + 'node-library', + 'backend-plugin-module', + 'frontend-plugin', + ], + }, + { + sourceRole: ['backend-plugin', 'node-library', 'backend-plugin-module'], + targetRole: ['frontend-plugin', 'web-library', 'backend-plugin'], + }, + { + sourceRole: ['common-library'], + targetRole: [ + 'frontend-plugin', + 'web-library', + 'backend-plugin', + 'node-library', + 'backend-plugin-module', + ], + }, +]; + +/** @type {import('eslint').Rule.RuleModule} */ +module.exports = { + meta: { + type: 'problem', + messages: { + forbidden: + '{{sourcePackage}} ({{sourceRole}}) uses forbidden import from {{targetPackage}} ({{targetRole}}).', + useReactPlugin: + 'Use web library {{targetPackage}}-react or common library instead.', + useNodePlugin: + 'Use node library {{targetPackage}}-node or common library instead.', + useCommonPlugin: 'Use common library {{targetPackage}}-common instead.', + removeImport: + 'Remove this import to avoid mixed plugin imports. Fix the code by refactoring it to use the correct plugin type.', + }, + docs: { + description: 'Disallow mixed plugin imports.', + url: 'https://github.com/backstage/backstage/blob/master/packages/eslint-plugin/docs/rules/no-mixed-plugin-imports.md', + }, + hasSuggestions: true, + schema: [ + { + type: 'object', + properties: { + excludedTargetPackages: { + type: 'array', + items: { type: 'string' }, + uniqueItems: true, + }, + excludedFiles: { + type: 'array', + items: { type: 'string' }, + uniqueItems: true, + }, + includedFiles: { + type: 'array', + items: { type: 'string' }, + uniqueItems: true, + }, + }, + additionalProperties: false, + }, + ], + }, + create(context) { + const packages = getPackages(context.cwd); + if (!packages) { + return {}; + } + + const filePath = context.physicalFilename + ? context.physicalFilename + : context.filename; + + /** @type {ExtendedPackage | undefined} */ + const pkg = packages.byPath(filePath); + if (!pkg) { + return {}; + } + + const options = context.options[0] || {}; + /** @type {string[]} */ + const ignoreTargetPackages = options.excludedTargetPackages || []; + /** @type {string[]} */ + const excludePatterns = options.excludedFiles || []; + /** @type {string[]} */ + const includePatterns = options.includedFiles || ['**/src/**']; + + if ( + !includePatterns.some(pattern => matchesPattern(pattern, filePath)) || + excludePatterns.some(pattern => matchesPattern(pattern, filePath)) + ) { + return {}; + } + + return visitImports(context, (node, imp) => { + if (imp.type !== 'internal') { + return; + } + + /** @type {ExtendedPackage | undefined} */ + const targetPackage = imp.package; + const targetName = targetPackage?.packageJson.name; + const sourceName = pkg.packageJson.name; + if (sourceName === targetName) { + return; + } + + const sourceRole = pkg.packageJson.backstage?.role; + const targetRole = targetPackage.packageJson.backstage?.role; + if (!sourceRole || !targetRole) { + return; + } + + if ( + roleRules.some( + rule => + rule.sourceRole.includes(sourceRole) && + rule.targetRole.includes(targetRole) && + !ignoreTargetPackages.includes(targetName), + ) + ) { + const suggest = []; + + if ( + (sourceRole === 'frontend-plugin' || sourceRole === 'web-library') && + targetRole === 'frontend-plugin' + ) { + suggest.push({ + messageId: 'useReactPlugin', + data: { + targetPackage: targetName, + }, + /** @param {import('eslint').Rule.RuleFixer} fixer */ + fix(fixer) { + const source = context.sourceCode; + const nodeSource = source.getText(imp.node); + const newImport = nodeSource.replace(/'$/, "-react'"); + return fixer.replaceText(imp.node, newImport); + }, + }); + suggest.push({ + messageId: 'useCommonPlugin', + data: { + targetPackage: targetName, + }, + /** @param {import('eslint').Rule.RuleFixer} fixer */ + fix(fixer) { + const source = context.sourceCode; + const nodeSource = source.getText(imp.node); + const newImport = nodeSource.replace(/'$/, "-common'"); + return fixer.replaceText(imp.node, newImport); + }, + }); + } else if ( + (sourceRole === 'backend-plugin' || + sourceRole === 'backend-plugin-module') && + targetRole === 'backend-plugin' + ) { + suggest.push({ + messageId: 'useNodePlugin', + data: { + targetPackage: targetName, + }, + /** @param {import('eslint').Rule.RuleFixer} fixer */ + fix(fixer) { + const source = context.sourceCode; + const nodeSource = source.getText(imp.node); + const newImport = nodeSource.replace(/-backend'$/, "-node'"); + return fixer.replaceText(imp.node, newImport); + }, + }); + suggest.push({ + messageId: 'useCommonPlugin', + data: { + targetPackage: targetName, + }, + /** @param {import('eslint').Rule.RuleFixer} fixer */ + fix(fixer) { + const source = context.sourceCode; + const nodeSource = source.getText(imp.node); + const newImport = nodeSource.replace(/-backend'$/, '-common'); + return fixer.replaceText(imp.node, newImport); + }, + }); + } else { + suggest.push({ + messageId: 'removeImport', + /** @param {import('eslint').Rule.RuleFixer} _fixer */ + fix(_fixer) { + // Not a fixable case, just give a suggestion to remove the import + }, + }); + } + + context.report({ + node: node, + messageId: 'forbidden', + data: { + sourcePackage: pkg.packageJson.name || imp.package.dir, + sourceRole, + targetPackage: targetPackage.packageJson.name || imp.package.dir, + targetRole, + }, + suggest, + }); + } + }); + }, +}; diff --git a/packages/eslint-plugin/rules/no-undeclared-imports.js b/packages/eslint-plugin/rules/no-undeclared-imports.js index b770ded365..17331d2fce 100644 --- a/packages/eslint-plugin/rules/no-undeclared-imports.js +++ b/packages/eslint-plugin/rules/no-undeclared-imports.js @@ -319,6 +319,7 @@ module.exports = { if (importsToAdd.length > 0) { addMissingImports(importsToAdd, packages, localPkg); + packages.clearCache(); // This switches all import directives back to the original import. for (const added of importsToAdd) { context.report({ @@ -336,6 +337,7 @@ module.exports = { removeInlineImports(importsToInline, localPkg); addForwardedInlineImports(importsToInline, localPkg); + packages.clearCache(); for (const inlined of importsToInline) { context.report({ node: inlined.node, @@ -350,8 +352,6 @@ module.exports = { } importsToInline.length = 0; } - - packages.clearCache(); }, ...visitImports(context, (node, imp) => { // We leave checking of type imports to the repo-tools check, diff --git a/packages/eslint-plugin/src/__fixtures__/monorepo/packages/foo/package.json b/packages/eslint-plugin/src/__fixtures__/monorepo/packages/foo/package.json index 563ec35120..e8e4d4ba70 100644 --- a/packages/eslint-plugin/src/__fixtures__/monorepo/packages/foo/package.json +++ b/packages/eslint-plugin/src/__fixtures__/monorepo/packages/foo/package.json @@ -1,5 +1,12 @@ { "name": "@internal/foo", + "backstage": { + "role": "frontend-plugin" + }, + "files": [ + "dist", + "type-utils" + ], "dependencies": { "@internal/bar": "1.0.0" }, @@ -8,9 +15,5 @@ }, "peerDependencies": { "react": "*" - }, - "files": [ - "dist", - "type-utils" - ] + } } diff --git a/packages/eslint-plugin/src/no-mixed-plugin-imports.test.ts b/packages/eslint-plugin/src/no-mixed-plugin-imports.test.ts new file mode 100644 index 0000000000..45764ca71a --- /dev/null +++ b/packages/eslint-plugin/src/no-mixed-plugin-imports.test.ts @@ -0,0 +1,68 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { RuleTester } from 'eslint'; +import path from 'path'; +import rule from '../rules/no-mixed-plugin-imports'; + +const RULE = 'no-mixed-plugin-imports'; +const FIXTURE = path.resolve(__dirname, '__fixtures__/monorepo'); + +const ERR = ( + sourcePackage: string, + sourceRole: string, + targetPackage: string, + targetRole: string, +) => ({ + message: `${sourcePackage} (${sourceRole}) uses forbidden import from ${targetPackage} (${targetRole}).`, +}); + +// cwd must be restored +const origDir = process.cwd(); +afterAll(() => { + process.chdir(origDir); +}); +process.chdir(FIXTURE); + +const ruleTester = new RuleTester({ + parserOptions: { + sourceType: 'module', + ecmaVersion: 2021, + }, +}); + +ruleTester.run(RULE, rule, { + valid: [ + { + code: `import '@internal/inline'`, + filename: path.join(FIXTURE, 'packages/bar/src/index.ts'), + }, + ], + invalid: [ + { + code: `import '@internal/foo'`, + filename: path.join(FIXTURE, 'packages/bar/src/index.ts'), + errors: [ + ERR( + '@internal/bar', + 'frontend-plugin', + '@internal/foo', + 'frontend-plugin', + ), + ], + }, + ], +}); diff --git a/packages/eslint-plugin/src/no-undeclared-imports.test.ts b/packages/eslint-plugin/src/no-undeclared-imports.test.ts index ee56c34926..7127d2f344 100644 --- a/packages/eslint-plugin/src/no-undeclared-imports.test.ts +++ b/packages/eslint-plugin/src/no-undeclared-imports.test.ts @@ -24,6 +24,7 @@ jest.mock('child_process', () => ({ const RULE = 'no-undeclared-imports'; const FIXTURE = joinPath(__dirname, '__fixtures__/monorepo'); +// const ERR_UNDECLARED = ( name: string, @@ -246,26 +247,14 @@ ruleTester.run(RULE, rule, { }, { code: `import 'react-dom'`, - output: `import 'directive:add-import:dependencies:react-dom'`, + output: `import 'directive:add-import:peerDependencies:react-dom'`, filename: joinPath(FIXTURE, 'packages/foo/src/index.ts'), errors: [ ERR_UNDECLARED( 'react-dom', - 'dependencies', + 'peerDependencies', joinPath('packages', 'foo'), - ), - ], - }, - { - code: `import 'react-dom'`, - output: `import 'directive:add-import:devDependencies:react-dom'`, - filename: joinPath(FIXTURE, 'packages/foo/src/index.test.ts'), - errors: [ - ERR_UNDECLARED( - 'react-dom', - 'devDependencies', - joinPath('packages', 'foo'), - '--dev', + '--peer', ), ], }, diff --git a/packages/frontend-app-api/CHANGELOG.md b/packages/frontend-app-api/CHANGELOG.md index c7e7c4cd46..3b7d7e0c80 100644 --- a/packages/frontend-app-api/CHANGELOG.md +++ b/packages/frontend-app-api/CHANGELOG.md @@ -1,5 +1,35 @@ # @backstage/frontend-app-api +## 0.11.3 + +### Patch Changes + +- 0169b23: Internal tweak to avoid circular dependencies +- c38c9e8: Implemented support for the `plugin.info()` method in specialized apps with a default resolved for `package.json` and `catalog-info.yaml`. The default resolution logic can be overridden via the `pluginInfoResolver` option to `createSpecializedApp`, and plugin-specific overrides can be applied via the new `app.pluginOverrides` key in static configuration. +- Updated dependencies + - @backstage/core-plugin-api@1.10.8 + - @backstage/frontend-plugin-api@0.10.3 + - @backstage/frontend-defaults@0.2.3 + - @backstage/config@1.3.2 + - @backstage/core-app-api@1.17.1 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/version-bridge@1.0.11 + +## 0.11.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.10.3-next.1 + - @backstage/config@1.3.2 + - @backstage/core-app-api@1.17.0 + - @backstage/core-plugin-api@1.10.7 + - @backstage/errors@1.2.7 + - @backstage/frontend-defaults@0.2.3-next.1 + - @backstage/types@1.2.1 + - @backstage/version-bridge@1.0.11 + ## 0.11.3-next.0 ### Patch Changes diff --git a/packages/frontend-app-api/package.json b/packages/frontend-app-api/package.json index cc5a7fd807..ec425b1e9c 100644 --- a/packages/frontend-app-api/package.json +++ b/packages/frontend-app-api/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/frontend-app-api", - "version": "0.11.3-next.0", + "version": "0.11.3", "backstage": { "role": "web-library" }, diff --git a/packages/frontend-app-api/src/routing/collectRouteIds.ts b/packages/frontend-app-api/src/routing/collectRouteIds.ts index 8b23e9e80b..6b0527f670 100644 --- a/packages/frontend-app-api/src/routing/collectRouteIds.ts +++ b/packages/frontend-app-api/src/routing/collectRouteIds.ts @@ -29,7 +29,7 @@ import { toInternalExternalRouteRef } from '../../../frontend-plugin-api/src/rou // eslint-disable-next-line @backstage/no-relative-monorepo-imports import { toInternalSubRouteRef } from '../../../frontend-plugin-api/src/routing/SubRouteRef'; import { OpaqueFrontendPlugin } from '@internal/frontend'; -import { FrontendFeature } from '../wiring'; +import { FrontendFeature } from '../wiring/types'; /** @internal */ export interface RouteRefsById { diff --git a/packages/frontend-defaults/CHANGELOG.md b/packages/frontend-defaults/CHANGELOG.md index a255a1bff7..bf77a9e8a4 100644 --- a/packages/frontend-defaults/CHANGELOG.md +++ b/packages/frontend-defaults/CHANGELOG.md @@ -1,5 +1,28 @@ # @backstage/frontend-defaults +## 0.2.3 + +### Patch Changes + +- fa5650c: Forwarded the new `pluginInfoResolver` option for `createApp`. +- Updated dependencies + - @backstage/plugin-app@0.1.10 + - @backstage/frontend-plugin-api@0.10.3 + - @backstage/frontend-app-api@0.11.3 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + +## 0.2.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.10.3-next.1 + - @backstage/plugin-app@0.1.10-next.1 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/frontend-app-api@0.11.3-next.1 + ## 0.2.3-next.0 ### Patch Changes diff --git a/packages/frontend-defaults/package.json b/packages/frontend-defaults/package.json index a30accf222..91819974d5 100644 --- a/packages/frontend-defaults/package.json +++ b/packages/frontend-defaults/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/frontend-defaults", - "version": "0.2.3-next.0", + "version": "0.2.3", "backstage": { "role": "web-library" }, diff --git a/packages/frontend-dynamic-feature-loader/CHANGELOG.md b/packages/frontend-dynamic-feature-loader/CHANGELOG.md index a93a11364c..fbefcf115e 100644 --- a/packages/frontend-dynamic-feature-loader/CHANGELOG.md +++ b/packages/frontend-dynamic-feature-loader/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/frontend-dynamic-feature-loader +## 0.1.2 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.10.3 + - @backstage/config@1.3.2 + +## 0.1.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.10.3-next.1 + - @backstage/config@1.3.2 + ## 0.1.2-next.0 ### Patch Changes diff --git a/packages/frontend-dynamic-feature-loader/package.json b/packages/frontend-dynamic-feature-loader/package.json index 7c9a7c45bf..1eba5ef9a8 100644 --- a/packages/frontend-dynamic-feature-loader/package.json +++ b/packages/frontend-dynamic-feature-loader/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/frontend-dynamic-feature-loader", - "version": "0.1.2-next.0", + "version": "0.1.2", "backstage": { "role": "web-library" }, diff --git a/packages/frontend-internal/CHANGELOG.md b/packages/frontend-internal/CHANGELOG.md index d3c097ed8b..5132481106 100644 --- a/packages/frontend-internal/CHANGELOG.md +++ b/packages/frontend-internal/CHANGELOG.md @@ -1,5 +1,23 @@ # @internal/frontend +## 0.0.10 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.10.3 + - @backstage/types@1.2.1 + - @backstage/version-bridge@1.0.11 + +## 0.0.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.10.3-next.1 + - @backstage/types@1.2.1 + - @backstage/version-bridge@1.0.11 + ## 0.0.10-next.0 ### Patch Changes diff --git a/packages/frontend-internal/package.json b/packages/frontend-internal/package.json index 931cbc8eb3..e83bce9a75 100644 --- a/packages/frontend-internal/package.json +++ b/packages/frontend-internal/package.json @@ -1,6 +1,6 @@ { "name": "@internal/frontend", - "version": "0.0.10-next.0", + "version": "0.0.10", "backstage": { "role": "web-library", "inline": true diff --git a/packages/frontend-plugin-api/CHANGELOG.md b/packages/frontend-plugin-api/CHANGELOG.md index 4bad433789..d4328babff 100644 --- a/packages/frontend-plugin-api/CHANGELOG.md +++ b/packages/frontend-plugin-api/CHANGELOG.md @@ -1,5 +1,53 @@ # @backstage/frontend-plugin-api +## 0.10.3 + +### Patch Changes + +- 0169b23: Internal tweak to avoid circular dependencies +- 9e3868f: Added a new optional `info` option to `createFrontendPlugin` that lets you provide a loaders for different sources of metadata information about the plugin. + + There are two available loaders. The first one is `info.packageJson`, which can be used to point to a `package.json` file for the plugin. This is recommended for any plugin that is defined within its own package, especially all plugins that are published to a package registry. Typical usage looks like this: + + ```ts + export default createFrontendPlugin({ + pluginId: '...', + info: { + packageJson: () => import('../package.json'), + }, + }); + ``` + + The second loader is `info.manifest`, which can be used to point to an opaque plugin manifest. This **MUST ONLY** be used by plugins that are intended for use within a single organization. Plugins that are published to an open package registry should **NOT** use this loader. The loader is useful for adding additional internal metadata associated with the plugin, and it is up to the Backstage app to decide how these manifests are parsed and used. The default manifest parser in an app created with `createApp` from `@backstage/frontend-defaults` is able to parse the default `catalog-info.yaml` format and built-in fields such as `spec.owner`. + + Typical usage looks like this: + + ```ts + export default createFrontendPlugin({ + pluginId: '...', + info: { + manifest: () => import('../catalog-info.yaml'), + }, + }); + ``` + +- 6f48f71: Added a new `useAppNode` hook, which can be used to get a reference to the `AppNode` from by the closest `ExtensionBoundary`. +- Updated dependencies + - @backstage/core-components@0.17.3 + - @backstage/core-plugin-api@1.10.8 + - @backstage/types@1.2.1 + - @backstage/version-bridge@1.0.11 + +## 0.10.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/core-plugin-api@1.10.7 + - @backstage/types@1.2.1 + - @backstage/version-bridge@1.0.11 + ## 0.10.3-next.0 ### Patch Changes diff --git a/packages/frontend-plugin-api/package.json b/packages/frontend-plugin-api/package.json index bdfd60c39d..c7a155fbaa 100644 --- a/packages/frontend-plugin-api/package.json +++ b/packages/frontend-plugin-api/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/frontend-plugin-api", - "version": "0.10.3-next.0", + "version": "0.10.3", "backstage": { "role": "web-library" }, diff --git a/packages/frontend-plugin-api/report.api.md b/packages/frontend-plugin-api/report.api.md index 9ac89d8331..6101f3e7c9 100644 --- a/packages/frontend-plugin-api/report.api.md +++ b/packages/frontend-plugin-api/report.api.md @@ -8,6 +8,7 @@ import { alertApiRef } from '@backstage/core-plugin-api'; import { AlertMessage } from '@backstage/core-plugin-api'; import { AnyApiFactory } from '@backstage/core-plugin-api'; import { AnyApiRef } from '@backstage/core-plugin-api'; +import { AnyRouteRefParams as AnyRouteRefParams_2 } from '@backstage/frontend-plugin-api'; import { ApiFactory } from '@backstage/core-plugin-api'; import { ApiHolder } from '@backstage/core-plugin-api'; import { ApiRef } from '@backstage/core-plugin-api'; @@ -392,7 +393,7 @@ export const coreExtensionData: { >; routePath: ConfigurableExtensionDataRef; routeRef: ConfigurableExtensionDataRef< - RouteRef, + RouteRef, 'core.routing.ref', {} >; diff --git a/packages/frontend-plugin-api/src/wiring/coreExtensionData.ts b/packages/frontend-plugin-api/src/wiring/coreExtensionData.ts index cb48cb8df3..18466d8196 100644 --- a/packages/frontend-plugin-api/src/wiring/coreExtensionData.ts +++ b/packages/frontend-plugin-api/src/wiring/coreExtensionData.ts @@ -15,7 +15,7 @@ */ import { JSX } from 'react'; -import { RouteRef } from '../routing'; +import { RouteRef } from '../routing/RouteRef'; import { createExtensionDataRef } from './createExtensionDataRef'; /** @public */ diff --git a/packages/frontend-test-utils/CHANGELOG.md b/packages/frontend-test-utils/CHANGELOG.md index 1bc3a595b6..345de5a36b 100644 --- a/packages/frontend-test-utils/CHANGELOG.md +++ b/packages/frontend-test-utils/CHANGELOG.md @@ -1,5 +1,31 @@ # @backstage/frontend-test-utils +## 0.3.3 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-app@0.1.10 + - @backstage/frontend-plugin-api@0.10.3 + - @backstage/frontend-app-api@0.11.3 + - @backstage/config@1.3.2 + - @backstage/test-utils@1.7.9 + - @backstage/types@1.2.1 + - @backstage/version-bridge@1.0.11 + +## 0.3.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.10.3-next.1 + - @backstage/plugin-app@0.1.10-next.1 + - @backstage/config@1.3.2 + - @backstage/frontend-app-api@0.11.3-next.1 + - @backstage/test-utils@1.7.8 + - @backstage/types@1.2.1 + - @backstage/version-bridge@1.0.11 + ## 0.3.3-next.0 ### Patch Changes diff --git a/packages/frontend-test-utils/package.json b/packages/frontend-test-utils/package.json index 607260ed01..a1dfcecfac 100644 --- a/packages/frontend-test-utils/package.json +++ b/packages/frontend-test-utils/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/frontend-test-utils", - "version": "0.3.3-next.0", + "version": "0.3.3", "backstage": { "role": "web-library" }, diff --git a/packages/integration-react/CHANGELOG.md b/packages/integration-react/CHANGELOG.md index 06f8807c4c..2588066fee 100644 --- a/packages/integration-react/CHANGELOG.md +++ b/packages/integration-react/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/integration-react +## 1.2.8 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.10.8 + - @backstage/config@1.3.2 + - @backstage/integration@1.17.0 + ## 1.2.7 ### Patch Changes diff --git a/packages/integration-react/package.json b/packages/integration-react/package.json index 6d0e76aa86..2c31e2a65e 100644 --- a/packages/integration-react/package.json +++ b/packages/integration-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/integration-react", - "version": "1.2.7", + "version": "1.2.8", "description": "Frontend package for managing integrations towards external systems", "backstage": { "role": "web-library" diff --git a/packages/repo-tools/CHANGELOG.md b/packages/repo-tools/CHANGELOG.md index 3ca8db071e..35650d485e 100644 --- a/packages/repo-tools/CHANGELOG.md +++ b/packages/repo-tools/CHANGELOG.md @@ -1,5 +1,39 @@ # @backstage/repo-tools +## 0.14.0 + +### Minor Changes + +- bf9a173: Add support for caching the per-package output from the `package-docs` command. + +### Patch Changes + +- 4bff5d0: Fixed a bug where linting would fail with the generated clients when defining top-level `enum` schema values. +- 2d20024: Fix an issue where errors were not printed to console when running `backstage-repo-tools schema openapi generate` without the `--watch` flag. +- e643ee4: Add missing highlight language for the `package-docs` command. +- c83cd8b: Fixed some circular or otherwise unclear imports +- a372bf1: Updated dependency `@electric-sql/pglite` to `^0.3.0`. +- Updated dependencies + - @backstage/backend-plugin-api@1.4.0 + - @backstage/catalog-model@1.7.4 + - @backstage/cli-common@0.1.15 + - @backstage/cli-node@0.2.13 + - @backstage/config-loader@1.10.1 + - @backstage/errors@1.2.7 + +## 0.14.0-next.2 + +### Patch Changes + +- 4bff5d0: Fixed a bug where linting would fail with the generated clients when defining top-level `enum` schema values. +- Updated dependencies + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/catalog-model@1.7.4 + - @backstage/cli-common@0.1.15 + - @backstage/cli-node@0.2.13 + - @backstage/config-loader@1.10.1 + - @backstage/errors@1.2.7 + ## 0.14.0-next.1 ### Patch Changes diff --git a/packages/repo-tools/package.json b/packages/repo-tools/package.json index 1d266dcb9b..540e7c38d0 100644 --- a/packages/repo-tools/package.json +++ b/packages/repo-tools/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/repo-tools", - "version": "0.14.0-next.1", + "version": "0.14.0", "description": "CLI for Backstage repo tooling ", "backstage": { "role": "cli" @@ -49,7 +49,7 @@ "@backstage/cli-node": "workspace:^", "@backstage/config-loader": "workspace:^", "@backstage/errors": "workspace:^", - "@electric-sql/pglite": "^0.2.15", + "@electric-sql/pglite": "^0.3.0", "@manypkg/get-packages": "^1.1.3", "@microsoft/api-documenter": "^7.25.7", "@microsoft/api-extractor": "^7.47.2", diff --git a/packages/repo-tools/src/commands/package/schema/openapi/generate/server.ts b/packages/repo-tools/src/commands/package/schema/openapi/generate/server.ts index 1a8dd36cab..c51b63cf54 100644 --- a/packages/repo-tools/src/commands/package/schema/openapi/generate/server.ts +++ b/packages/repo-tools/src/commands/package/schema/openapi/generate/server.ts @@ -60,7 +60,7 @@ async function generateSpecFile() { // * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * // ****************************************************************** import {createValidatedOpenApiRouterFromGeneratedEndpointMap} from '@backstage/backend-openapi-utils'; -import {EndpointMap} from './'; +import {EndpointMap} from './apis'; export const spec = ${JSON.stringify(yaml, null, 2)} as const; export const createOpenApiRouter = async ( options?: Parameters['1'], diff --git a/packages/scaffolder-internal/CHANGELOG.md b/packages/scaffolder-internal/CHANGELOG.md index d397fdc00e..edca176087 100644 --- a/packages/scaffolder-internal/CHANGELOG.md +++ b/packages/scaffolder-internal/CHANGELOG.md @@ -1,5 +1,21 @@ # @internal/scaffolder +## 0.0.10 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-react@1.17.0 + - @backstage/frontend-plugin-api@0.10.3 + +## 0.0.10-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.10.3-next.1 + - @backstage/plugin-scaffolder-react@1.16.1-next.2 + ## 0.0.10-next.1 ### Patch Changes diff --git a/packages/scaffolder-internal/package.json b/packages/scaffolder-internal/package.json index d9e9bb54cf..4afd53a9c9 100644 --- a/packages/scaffolder-internal/package.json +++ b/packages/scaffolder-internal/package.json @@ -1,6 +1,6 @@ { "name": "@internal/scaffolder", - "version": "0.0.10-next.1", + "version": "0.0.10", "backstage": { "role": "web-library", "inline": true diff --git a/packages/techdocs-cli-embedded-app/CHANGELOG.md b/packages/techdocs-cli-embedded-app/CHANGELOG.md index 53cabb42bb..a0f05e15d2 100644 --- a/packages/techdocs-cli-embedded-app/CHANGELOG.md +++ b/packages/techdocs-cli-embedded-app/CHANGELOG.md @@ -1,5 +1,62 @@ # techdocs-cli-embedded-app +## 0.2.109 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3 + - @backstage/cli@0.33.0 + - @backstage/plugin-techdocs@1.13.0 + - @backstage/plugin-catalog@1.31.0 + - @backstage/core-plugin-api@1.10.8 + - @backstage/plugin-techdocs-react@1.3.0 + - @backstage/app-defaults@1.6.3 + - @backstage/integration-react@1.2.8 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/core-app-api@1.17.1 + - @backstage/test-utils@1.7.9 + - @backstage/theme@0.6.6 + +## 0.2.109-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.33.0-next.2 + - @backstage/app-defaults@1.6.3-next.0 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/core-app-api@1.17.0 + - @backstage/core-components@0.17.3-next.0 + - @backstage/core-plugin-api@1.10.7 + - @backstage/integration-react@1.2.7 + - @backstage/test-utils@1.7.8 + - @backstage/theme@0.6.6 + - @backstage/plugin-catalog@1.31.0-next.2 + - @backstage/plugin-techdocs@1.13.0-next.2 + - @backstage/plugin-techdocs-react@1.3.0-next.1 + +## 0.2.109-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/cli@0.33.0-next.1 + - @backstage/plugin-catalog@1.31.0-next.2 + - @backstage/plugin-techdocs@1.13.0-next.2 + - @backstage/app-defaults@1.6.3-next.0 + - @backstage/integration-react@1.2.7 + - @backstage/plugin-techdocs-react@1.3.0-next.1 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/core-app-api@1.17.0 + - @backstage/core-plugin-api@1.10.7 + - @backstage/test-utils@1.7.8 + - @backstage/theme@0.6.6 + ## 0.2.109-next.1 ### Patch Changes diff --git a/packages/techdocs-cli-embedded-app/package.json b/packages/techdocs-cli-embedded-app/package.json index 71dc5b6bc2..8b708b362f 100644 --- a/packages/techdocs-cli-embedded-app/package.json +++ b/packages/techdocs-cli-embedded-app/package.json @@ -1,6 +1,6 @@ { "name": "techdocs-cli-embedded-app", - "version": "0.2.109-next.1", + "version": "0.2.109", "backstage": { "role": "frontend" }, diff --git a/packages/techdocs-cli/CHANGELOG.md b/packages/techdocs-cli/CHANGELOG.md index 26179b1e80..799fb72a07 100644 --- a/packages/techdocs-cli/CHANGELOG.md +++ b/packages/techdocs-cli/CHANGELOG.md @@ -1,5 +1,27 @@ # @techdocs/cli +## 1.9.4 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.11.0 + - @backstage/catalog-model@1.7.4 + - @backstage/cli-common@0.1.15 + - @backstage/config@1.3.2 + - @backstage/plugin-techdocs-node@1.13.4 + +## 1.9.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.11.0-next.2 + - @backstage/catalog-model@1.7.4 + - @backstage/cli-common@0.1.15 + - @backstage/config@1.3.2 + - @backstage/plugin-techdocs-node@1.13.4-next.1 + ## 1.9.4-next.1 ### Patch Changes diff --git a/packages/techdocs-cli/package.json b/packages/techdocs-cli/package.json index 96ff8377ad..cbac65a488 100644 --- a/packages/techdocs-cli/package.json +++ b/packages/techdocs-cli/package.json @@ -1,6 +1,6 @@ { "name": "@techdocs/cli", - "version": "1.9.4-next.1", + "version": "1.9.4", "description": "Utility CLI for managing TechDocs sites in Backstage.", "backstage": { "role": "cli" diff --git a/packages/test-utils/CHANGELOG.md b/packages/test-utils/CHANGELOG.md index ebbf6a99ba..e15222be98 100644 --- a/packages/test-utils/CHANGELOG.md +++ b/packages/test-utils/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/test-utils +## 1.7.9 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.10.8 + - @backstage/config@1.3.2 + - @backstage/core-app-api@1.17.1 + - @backstage/theme@0.6.6 + - @backstage/types@1.2.1 + - @backstage/plugin-permission-common@0.9.0 + - @backstage/plugin-permission-react@0.4.35 + ## 1.7.8 ### Patch Changes diff --git a/packages/test-utils/package.json b/packages/test-utils/package.json index c35b80ae46..e2026dcbfd 100644 --- a/packages/test-utils/package.json +++ b/packages/test-utils/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/test-utils", - "version": "1.7.8", + "version": "1.7.9", "description": "Utilities to test Backstage plugins and apps.", "backstage": { "role": "web-library" diff --git a/packages/yarn-plugin/CHANGELOG.md b/packages/yarn-plugin/CHANGELOG.md index 9b8ab91819..5f0c845552 100644 --- a/packages/yarn-plugin/CHANGELOG.md +++ b/packages/yarn-plugin/CHANGELOG.md @@ -1,5 +1,14 @@ # yarn-plugin-backstage +## 0.0.6 + +### Patch Changes + +- a0f9e4e: added functionality so that adding or updating a backstage dependency to a package would maintain the "backstage:^" placeholder for the version. +- Updated dependencies + - @backstage/cli-common@0.1.15 + - @backstage/release-manifests@0.0.13 + ## 0.0.5 ### Patch Changes diff --git a/packages/yarn-plugin/README.md b/packages/yarn-plugin/README.md index 073669b9a5..5c112506e3 100644 --- a/packages/yarn-plugin/README.md +++ b/packages/yarn-plugin/README.md @@ -82,3 +82,12 @@ specific Backstage repository. As such, when publishing packages, all `backstage:^` versions should be removed from the package.json and replaced with the appropriate npm version ranges. This is handled by the `beforeWorkspacePacking` hook. + +### `afterWorkspaceDependencyAddition` hook + +_Replaces npm version ranges with `backstage:^` ranges for `@backstage/*` dependencies added after +the plugin has converted existing dependencies to `backstage:^` range_ + +### `afterWorkspaceDependencyReplacement` hook + +_warns user with console message when running `yarn add` for a `@backstage/*` scoped dependency that is already a dependency in the target package. Doing so will remove the `backstage:^` scope and replace it with the actual npm version range, which may not be desired._ diff --git a/packages/yarn-plugin/package.json b/packages/yarn-plugin/package.json index 978f62fc85..accf567069 100644 --- a/packages/yarn-plugin/package.json +++ b/packages/yarn-plugin/package.json @@ -1,6 +1,6 @@ { "name": "yarn-plugin-backstage", - "version": "0.0.5", + "version": "0.0.6", "description": "Yarn plugin for working with Backstage monorepos", "backstage": { "role": "node-library" @@ -32,8 +32,9 @@ "dependencies": { "@backstage/cli-common": "workspace:^", "@backstage/release-manifests": "workspace:^", - "@yarnpkg/core": "^4.4.0", + "@yarnpkg/core": "^4.4.1", "@yarnpkg/fslib": "^3.1.2", + "@yarnpkg/plugin-essentials": "^4.4.0", "@yarnpkg/plugin-npm": "patch:@yarnpkg/plugin-npm@npm%3A3.1.0#~/.yarn/patches/@yarnpkg-plugin-npm-npm-3.1.0-6533d0f5a1.patch", "@yarnpkg/plugin-pack": "^4.0.1", "semver": "^7.6.0" diff --git a/packages/yarn-plugin/report.api.md b/packages/yarn-plugin/report.api.md index 620bbbb567..b9425282b4 100644 --- a/packages/yarn-plugin/report.api.md +++ b/packages/yarn-plugin/report.api.md @@ -4,10 +4,11 @@ ```ts import { Hooks } from '@yarnpkg/core'; -import { Hooks as Hooks_2 } from '@yarnpkg/plugin-pack'; +import { Hooks as Hooks_2 } from '@yarnpkg/plugin-essentials'; +import { Hooks as Hooks_3 } from '@yarnpkg/plugin-pack'; import { Plugin as Plugin_2 } from '@yarnpkg/core'; // @public (undocumented) -const plugin: Plugin_2; +const plugin: Plugin_2; export default plugin; ``` diff --git a/packages/yarn-plugin/src/handlers/afterWorkspaceDependencyAddition.test.ts b/packages/yarn-plugin/src/handlers/afterWorkspaceDependencyAddition.test.ts new file mode 100644 index 0000000000..ae575a8b02 --- /dev/null +++ b/packages/yarn-plugin/src/handlers/afterWorkspaceDependencyAddition.test.ts @@ -0,0 +1,119 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { + Descriptor, + DescriptorHash, + IdentHash, + Workspace, +} from '@yarnpkg/core'; +import { suggestUtils } from '@yarnpkg/plugin-essentials'; +import { getPackageVersion } from '../util'; +import { afterWorkspaceDependencyAddition } from './afterWorkspaceDependencyAddition'; + +jest.mock('../util', () => ({ + getPackageVersion: jest.fn(), +})); + +describe('afterWorkspaceDependencyAddition', () => { + const workspace = { + project: { + configuration: {}, + }, + } as Workspace; + const target = {} as suggestUtils.Target; + const strategies: Array = []; + const mockGetPackageVersion = getPackageVersion as jest.MockedFunction< + typeof getPackageVersion + >; + + beforeEach(() => { + mockGetPackageVersion.mockReset(); + }); + + it('should replace the range for a backstage scoped dependency', async () => { + const input: Descriptor = { + scope: 'backstage', + name: 'test-package', + range: '^1.0.0', + descriptorHash: {} as DescriptorHash, + identHash: {} as IdentHash, + }; + + mockGetPackageVersion.mockImplementation(() => Promise.resolve('success')); + + await afterWorkspaceDependencyAddition( + workspace, + target, + input, + strategies, + ); + + expect(input.range).toBe('backstage:^'); + expect(mockGetPackageVersion).toHaveBeenCalledTimes(1); + expect(mockGetPackageVersion).toHaveBeenCalledWith( + input, + workspace.project.configuration, + ); + }); + + it('should not replace the range for a backstage scoped dependency where it cant find a version from remote', async () => { + const input: Descriptor = { + scope: 'backstage', + name: 'test-package', + range: '^1.0.0', + descriptorHash: {} as DescriptorHash, + identHash: {} as IdentHash, + }; + + mockGetPackageVersion.mockImplementation(() => + Promise.reject(new Error('test error')), + ); + + await afterWorkspaceDependencyAddition( + workspace, + target, + input, + strategies, + ); + + expect(input.range).toBe('^1.0.0'); + expect(mockGetPackageVersion).toHaveBeenCalledTimes(1); + expect(mockGetPackageVersion).toHaveBeenCalledWith( + input, + workspace.project.configuration, + ); + }); + + it('should not replace the range for a non-backstage scoped dependency', async () => { + const input: Descriptor = { + scope: 'backstage-community', + name: 'test-package', + range: '^1.0.0', + descriptorHash: {} as DescriptorHash, + identHash: {} as IdentHash, + }; + + await afterWorkspaceDependencyAddition( + workspace, + target, + input, + strategies, + ); + + expect(input.range).toBe('^1.0.0'); + expect(mockGetPackageVersion).not.toHaveBeenCalled(); + }); +}); diff --git a/packages/yarn-plugin/src/handlers/afterWorkspaceDependencyAddition.ts b/packages/yarn-plugin/src/handlers/afterWorkspaceDependencyAddition.ts new file mode 100644 index 0000000000..219830a8c9 --- /dev/null +++ b/packages/yarn-plugin/src/handlers/afterWorkspaceDependencyAddition.ts @@ -0,0 +1,46 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Descriptor, structUtils, Workspace } from '@yarnpkg/core'; +import { suggestUtils } from '@yarnpkg/plugin-essentials'; +import { getPackageVersion } from '../util'; +import { PROTOCOL } from '../constants'; + +export const afterWorkspaceDependencyAddition = async ( + workspace: Workspace, + _target: suggestUtils.Target, + descriptor: Descriptor, + _strategies: Array, +) => { + const descriptorRange = structUtils.parseRange(descriptor.range); + + if ( + descriptor.scope === 'backstage' && + descriptorRange.protocol !== PROTOCOL + ) { + try { + await getPackageVersion(descriptor, workspace.project.configuration); + console.info( + `Setting ${descriptor.scope}/${descriptor.name} to ${PROTOCOL}^`, + ); + descriptor.range = `${PROTOCOL}^`; + } catch (_error: any) { + // if there's no found version then this is likely a deprecated package + // or otherwise the plugin won't be able to resolve the real version + // and we should leave the desired range as is + } + } +}; diff --git a/packages/yarn-plugin/src/handlers/afterWorkspaceDependencyReplacement.test.ts b/packages/yarn-plugin/src/handlers/afterWorkspaceDependencyReplacement.test.ts new file mode 100644 index 0000000000..7bf9c77554 --- /dev/null +++ b/packages/yarn-plugin/src/handlers/afterWorkspaceDependencyReplacement.test.ts @@ -0,0 +1,138 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { + Descriptor, + DescriptorHash, + IdentHash, + Workspace, +} from '@yarnpkg/core'; +import { suggestUtils } from '@yarnpkg/plugin-essentials'; +import { getPackageVersion } from '../util'; +import { afterWorkspaceDependencyReplacement } from './afterWorkspaceDependencyReplacement'; + +jest.mock('../util', () => ({ + getPackageVersion: jest.fn(), +})); + +describe('afterWorkspaceDependencyReplacement.test', () => { + const workspace = { + project: { + configuration: {}, + }, + } as Workspace; + const target = {} as suggestUtils.Target; + const mockGetPackageVersion = getPackageVersion as jest.MockedFunction< + typeof getPackageVersion + >; + + beforeEach(() => { + mockGetPackageVersion.mockReset(); + }); + + it('should warn that the range is being changed for a backstage scoped dependency', async () => { + const fromDescriptor: Descriptor = { + scope: 'backstage', + name: 'test-package', + range: 'backstage:^', + descriptorHash: {} as DescriptorHash, + identHash: {} as IdentHash, + }; + const toDescriptor: Descriptor = { + scope: 'backstage', + name: 'test-package', + range: '^1.0.0', + descriptorHash: {} as DescriptorHash, + identHash: {} as IdentHash, + }; + + mockGetPackageVersion.mockImplementation(() => Promise.resolve('success')); + + await afterWorkspaceDependencyReplacement( + workspace, + target, + fromDescriptor, + toDescriptor, + ); + + expect(toDescriptor.range).toBe('^1.0.0'); + expect(mockGetPackageVersion).toHaveBeenCalledTimes(1); + expect(mockGetPackageVersion).toHaveBeenCalledWith( + toDescriptor, + workspace.project.configuration, + ); + }); + + it('should not warn that the range is being changed for a backstage scoped dependency where it cant find a version from remote', async () => { + const fromDescriptor: Descriptor = { + scope: 'backstage', + name: 'test-package', + range: 'backstage:^', + descriptorHash: {} as DescriptorHash, + identHash: {} as IdentHash, + }; + const toDescriptor: Descriptor = { + scope: 'backstage', + name: 'test-package', + range: '^1.0.0', + descriptorHash: {} as DescriptorHash, + identHash: {} as IdentHash, + }; + + mockGetPackageVersion.mockImplementation(() => + Promise.reject(new Error('test error')), + ); + + await afterWorkspaceDependencyReplacement( + workspace, + target, + fromDescriptor, + toDescriptor, + ); + + expect(toDescriptor.range).toBe('^1.0.0'); + expect(mockGetPackageVersion).toHaveBeenCalledTimes(1); + expect(mockGetPackageVersion).toHaveBeenCalledWith( + toDescriptor, + workspace.project.configuration, + ); + }); + + it('should ignore that the range is being changed for a non-backstage scoped dependency', async () => { + const fromDescriptor: Descriptor = { + scope: 'backstage-community', + name: 'test-package', + range: 'backstage:^', + descriptorHash: {} as DescriptorHash, + identHash: {} as IdentHash, + }; + const toDescriptor: Descriptor = { + scope: 'backstage-community', + name: 'test-package', + range: '^1.0.0', + descriptorHash: {} as DescriptorHash, + identHash: {} as IdentHash, + }; + await afterWorkspaceDependencyReplacement( + workspace, + target, + fromDescriptor, + toDescriptor, + ); + + expect(toDescriptor.range).toBe('^1.0.0'); + expect(mockGetPackageVersion).not.toHaveBeenCalled(); + }); +}); diff --git a/packages/yarn-plugin/src/handlers/afterWorkspaceDependencyReplacement.ts b/packages/yarn-plugin/src/handlers/afterWorkspaceDependencyReplacement.ts new file mode 100644 index 0000000000..55a11086fd --- /dev/null +++ b/packages/yarn-plugin/src/handlers/afterWorkspaceDependencyReplacement.ts @@ -0,0 +1,45 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Descriptor, structUtils, Workspace } from '@yarnpkg/core'; +import { suggestUtils } from '@yarnpkg/plugin-essentials'; +import { getPackageVersion } from '../util'; +import { PROTOCOL } from '../constants'; + +export const afterWorkspaceDependencyReplacement = async ( + workspace: Workspace, + _target: suggestUtils.Target, + _fromDescriptor: Descriptor, + toDescriptor: Descriptor, +) => { + const toDescriptorRange = structUtils.parseRange(toDescriptor.range); + + if ( + toDescriptor.scope === 'backstage' && + toDescriptorRange.protocol !== PROTOCOL + ) { + try { + await getPackageVersion(toDescriptor, workspace.project.configuration); + console.warn( + `${toDescriptor.name} should be set to "${PROTOCOL}^" instead of "${toDescriptor.range}". Make sure this change is intentional and not a mistake.`, + ); + } catch (_error: any) { + // if there's no found version then this is likely a deprecated package + // or otherwise the plugin won't be able to resolve the real version + // and we should not warn them. + } + } +}; diff --git a/packages/yarn-plugin/src/handlers/index.ts b/packages/yarn-plugin/src/handlers/index.ts index baa144b36f..fe8f05c935 100644 --- a/packages/yarn-plugin/src/handlers/index.ts +++ b/packages/yarn-plugin/src/handlers/index.ts @@ -16,3 +16,5 @@ export { beforeWorkspacePacking } from './beforeWorkspacePacking'; export { reduceDependency } from './reduceDependency'; +export { afterWorkspaceDependencyAddition } from './afterWorkspaceDependencyAddition'; +export { afterWorkspaceDependencyReplacement } from './afterWorkspaceDependencyReplacement'; diff --git a/packages/yarn-plugin/src/index.ts b/packages/yarn-plugin/src/index.ts index ad18deb0ff..b08d98eae7 100644 --- a/packages/yarn-plugin/src/index.ts +++ b/packages/yarn-plugin/src/index.ts @@ -23,7 +23,13 @@ import { Plugin, Hooks, semverUtils, YarnVersion } from '@yarnpkg/core'; import { Hooks as PackHooks } from '@yarnpkg/plugin-pack'; -import { beforeWorkspacePacking, reduceDependency } from './handlers'; +import { Hooks as EssentialHooks } from '@yarnpkg/plugin-essentials'; +import { + afterWorkspaceDependencyAddition, + afterWorkspaceDependencyReplacement, + beforeWorkspacePacking, + reduceDependency, +} from './handlers'; import { BackstageNpmResolver } from './resolvers'; // All dependencies of the yarn plugin are bundled during the build. Chalk @@ -44,8 +50,10 @@ if (!semverUtils.satisfiesWithPrereleases(YarnVersion, '^4.1.1')) { /** * @public */ -const plugin: Plugin = { +const plugin: Plugin = { hooks: { + afterWorkspaceDependencyAddition, + afterWorkspaceDependencyReplacement, reduceDependency, beforeWorkspacePacking, }, diff --git a/plugins/api-docs/CHANGELOG.md b/plugins/api-docs/CHANGELOG.md index 960b46abf2..87a8b1020d 100644 --- a/plugins/api-docs/CHANGELOG.md +++ b/plugins/api-docs/CHANGELOG.md @@ -1,5 +1,36 @@ # @backstage/plugin-api-docs +## 0.12.8 + +### Patch Changes + +- 18c64e9: Added the `info.packageJson` option to the plugin instance for the new frontend system. +- Updated dependencies + - @backstage/core-components@0.17.3 + - @backstage/plugin-catalog@1.31.0 + - @backstage/core-plugin-api@1.10.8 + - @backstage/frontend-plugin-api@0.10.3 + - @backstage/plugin-catalog-react@1.19.0 + - @backstage/catalog-model@1.7.4 + - @backstage/core-compat-api@0.4.3 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-permission-react@0.4.35 + +## 0.12.8-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/plugin-catalog@1.31.0-next.2 + - @backstage/plugin-catalog-react@1.19.0-next.2 + - @backstage/frontend-plugin-api@0.10.3-next.1 + - @backstage/catalog-model@1.7.4 + - @backstage/core-compat-api@0.4.3-next.2 + - @backstage/core-plugin-api@1.10.7 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-permission-react@0.4.34 + ## 0.12.8-next.1 ### Patch Changes diff --git a/plugins/api-docs/package.json b/plugins/api-docs/package.json index ade2c0530b..8d7e99e781 100644 --- a/plugins/api-docs/package.json +++ b/plugins/api-docs/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-api-docs", - "version": "0.12.8-next.1", + "version": "0.12.8", "description": "A Backstage plugin that helps represent API entities in the frontend", "backstage": { "role": "frontend-plugin", diff --git a/plugins/app-backend/CHANGELOG.md b/plugins/app-backend/CHANGELOG.md index 42beb0377f..14a64c0fca 100644 --- a/plugins/app-backend/CHANGELOG.md +++ b/plugins/app-backend/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-app-backend +## 0.5.3 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/config-loader@1.10.1 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/plugin-app-node@0.1.34 + ## 0.5.3-next.1 ### Patch Changes diff --git a/plugins/app-backend/package.json b/plugins/app-backend/package.json index 6a2a2ea09b..3eede984bd 100644 --- a/plugins/app-backend/package.json +++ b/plugins/app-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-app-backend", - "version": "0.5.3-next.1", + "version": "0.5.3", "description": "A Backstage backend plugin that serves the Backstage frontend app", "backstage": { "role": "backend-plugin", diff --git a/plugins/app-node/CHANGELOG.md b/plugins/app-node/CHANGELOG.md index 4052664edc..215f6543be 100644 --- a/plugins/app-node/CHANGELOG.md +++ b/plugins/app-node/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-app-node +## 0.1.34 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config-loader@1.10.1 + ## 0.1.34-next.1 ### Patch Changes diff --git a/plugins/app-node/package.json b/plugins/app-node/package.json index 83d0009c1b..355bd5b127 100644 --- a/plugins/app-node/package.json +++ b/plugins/app-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-app-node", - "version": "0.1.34-next.1", + "version": "0.1.34", "description": "Node.js library for the app plugin", "backstage": { "role": "node-library", diff --git a/plugins/app-visualizer/CHANGELOG.md b/plugins/app-visualizer/CHANGELOG.md index e5ca9aab39..26727d2729 100644 --- a/plugins/app-visualizer/CHANGELOG.md +++ b/plugins/app-visualizer/CHANGELOG.md @@ -1,5 +1,24 @@ # @backstage/plugin-app-visualizer +## 0.1.20 + +### Patch Changes + +- 18c64e9: Added the `info.packageJson` option to the plugin instance for the new frontend system. +- Updated dependencies + - @backstage/core-components@0.17.3 + - @backstage/core-plugin-api@1.10.8 + - @backstage/frontend-plugin-api@0.10.3 + +## 0.1.20-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/frontend-plugin-api@0.10.3-next.1 + - @backstage/core-plugin-api@1.10.7 + ## 0.1.20-next.0 ### Patch Changes diff --git a/plugins/app-visualizer/package.json b/plugins/app-visualizer/package.json index 7f3d005c0e..8440070487 100644 --- a/plugins/app-visualizer/package.json +++ b/plugins/app-visualizer/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-app-visualizer", - "version": "0.1.20-next.0", + "version": "0.1.20", "description": "Visualizes the Backstage app structure", "backstage": { "role": "frontend-plugin", diff --git a/plugins/app/CHANGELOG.md b/plugins/app/CHANGELOG.md index 7ef336e214..528736c655 100644 --- a/plugins/app/CHANGELOG.md +++ b/plugins/app/CHANGELOG.md @@ -1,5 +1,32 @@ # @backstage/plugin-app +## 0.1.10 + +### Patch Changes + +- 18c64e9: Added the `info.packageJson` option to the plugin instance for the new frontend system. +- Updated dependencies + - @backstage/core-components@0.17.3 + - @backstage/core-plugin-api@1.10.8 + - @backstage/frontend-plugin-api@0.10.3 + - @backstage/integration-react@1.2.8 + - @backstage/theme@0.6.6 + - @backstage/types@1.2.1 + - @backstage/plugin-permission-react@0.4.35 + +## 0.1.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/frontend-plugin-api@0.10.3-next.1 + - @backstage/integration-react@1.2.7 + - @backstage/core-plugin-api@1.10.7 + - @backstage/theme@0.6.6 + - @backstage/types@1.2.1 + - @backstage/plugin-permission-react@0.4.34 + ## 0.1.10-next.0 ### Patch Changes diff --git a/plugins/app/package.json b/plugins/app/package.json index 717a4cc2c4..a788a9372a 100644 --- a/plugins/app/package.json +++ b/plugins/app/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-app", - "version": "0.1.10-next.0", + "version": "0.1.10", "backstage": { "role": "frontend-plugin", "pluginId": "app", diff --git a/plugins/auth-backend-module-atlassian-provider/CHANGELOG.md b/plugins/auth-backend-module-atlassian-provider/CHANGELOG.md index 3ff30201af..5bd8d12ed7 100644 --- a/plugins/auth-backend-module-atlassian-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-atlassian-provider/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-auth-backend-module-atlassian-provider +## 0.4.4 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-plugin-api@1.4.0 + ## 0.4.4-next.1 ### Patch Changes diff --git a/plugins/auth-backend-module-atlassian-provider/package.json b/plugins/auth-backend-module-atlassian-provider/package.json index c146a3a551..b27c995d14 100644 --- a/plugins/auth-backend-module-atlassian-provider/package.json +++ b/plugins/auth-backend-module-atlassian-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-atlassian-provider", - "version": "0.4.4-next.1", + "version": "0.4.4", "description": "The atlassian-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-auth0-provider/CHANGELOG.md b/plugins/auth-backend-module-auth0-provider/CHANGELOG.md index 22cec4e289..dfd6475e55 100644 --- a/plugins/auth-backend-module-auth0-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-auth0-provider/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-auth-backend-module-auth0-provider +## 0.2.4 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-plugin-api@1.4.0 + ## 0.2.4-next.1 ### Patch Changes diff --git a/plugins/auth-backend-module-auth0-provider/package.json b/plugins/auth-backend-module-auth0-provider/package.json index 3e18951293..6918506ece 100644 --- a/plugins/auth-backend-module-auth0-provider/package.json +++ b/plugins/auth-backend-module-auth0-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-auth0-provider", - "version": "0.2.4-next.1", + "version": "0.2.4", "description": "The auth0-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-aws-alb-provider/CHANGELOG.md b/plugins/auth-backend-module-aws-alb-provider/CHANGELOG.md index a681992dc8..b26a474c1e 100644 --- a/plugins/auth-backend-module-aws-alb-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-aws-alb-provider/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-auth-backend-module-aws-alb-provider +## 0.4.4 + +### Patch Changes + +- c83cd8b: Fixed some circular or otherwise unclear imports +- Updated dependencies + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/errors@1.2.7 + - @backstage/plugin-auth-backend@0.25.1 + ## 0.4.4-next.1 ### Patch Changes diff --git a/plugins/auth-backend-module-aws-alb-provider/package.json b/plugins/auth-backend-module-aws-alb-provider/package.json index 4382931db3..ca6fbdd8e2 100644 --- a/plugins/auth-backend-module-aws-alb-provider/package.json +++ b/plugins/auth-backend-module-aws-alb-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-aws-alb-provider", - "version": "0.4.4-next.1", + "version": "0.4.4", "description": "The aws-alb provider module for the Backstage auth backend.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-aws-alb-provider/report.api.md b/plugins/auth-backend-module-aws-alb-provider/report.api.md index ebb3e8e24a..e809ae0fe3 100644 --- a/plugins/auth-backend-module-aws-alb-provider/report.api.md +++ b/plugins/auth-backend-module-aws-alb-provider/report.api.md @@ -6,7 +6,7 @@ import { BackendFeature } from '@backstage/backend-plugin-api'; import { JWTHeaderParameters } from 'jose'; import { KeyObject } from 'crypto'; -import type { PassportProfile } from '@backstage/plugin-auth-node/'; +import type { PassportProfile } from '@backstage/plugin-auth-node'; import { ProxyAuthenticator } from '@backstage/plugin-auth-node'; import { SignInResolverFactory } from '@backstage/plugin-auth-node'; diff --git a/plugins/auth-backend-module-aws-alb-provider/src/types.ts b/plugins/auth-backend-module-aws-alb-provider/src/types.ts index b4c792a5f9..fd3b3dd80b 100644 --- a/plugins/auth-backend-module-aws-alb-provider/src/types.ts +++ b/plugins/auth-backend-module-aws-alb-provider/src/types.ts @@ -14,7 +14,8 @@ * limitations under the License. */ -import type { PassportProfile } from '@backstage/plugin-auth-node/'; +import type { PassportProfile } from '@backstage/plugin-auth-node'; + /** * JWT header extraction result, containing the raw value and the parsed JWT * payload. @@ -26,6 +27,7 @@ export type AwsAlbResult = { expiresInSeconds?: number; accessToken: string; }; + /** * @public */ @@ -39,6 +41,7 @@ export type AwsAlbClaims = { exp: number; iss: string; }; + /** * @internal */ diff --git a/plugins/auth-backend-module-azure-easyauth-provider/CHANGELOG.md b/plugins/auth-backend-module-azure-easyauth-provider/CHANGELOG.md index f0359b1e55..ca0bd0749c 100644 --- a/plugins/auth-backend-module-azure-easyauth-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-azure-easyauth-provider/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-auth-backend-module-azure-easyauth-provider +## 0.2.9 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/catalog-model@1.7.4 + - @backstage/errors@1.2.7 + ## 0.2.9-next.1 ### Patch Changes diff --git a/plugins/auth-backend-module-azure-easyauth-provider/package.json b/plugins/auth-backend-module-azure-easyauth-provider/package.json index 39ebf38dd6..7d767f178a 100644 --- a/plugins/auth-backend-module-azure-easyauth-provider/package.json +++ b/plugins/auth-backend-module-azure-easyauth-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-azure-easyauth-provider", - "version": "0.2.9-next.1", + "version": "0.2.9", "description": "The azure-easyauth-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-bitbucket-provider/CHANGELOG.md b/plugins/auth-backend-module-bitbucket-provider/CHANGELOG.md index a9c90e8a05..ba52bd40a3 100644 --- a/plugins/auth-backend-module-bitbucket-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-bitbucket-provider/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-auth-backend-module-bitbucket-provider +## 0.3.4 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-plugin-api@1.4.0 + ## 0.3.4-next.1 ### Patch Changes diff --git a/plugins/auth-backend-module-bitbucket-provider/package.json b/plugins/auth-backend-module-bitbucket-provider/package.json index edd1d811da..e55d5eb81c 100644 --- a/plugins/auth-backend-module-bitbucket-provider/package.json +++ b/plugins/auth-backend-module-bitbucket-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-bitbucket-provider", - "version": "0.3.4-next.1", + "version": "0.3.4", "description": "The bitbucket-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-bitbucket-server-provider/CHANGELOG.md b/plugins/auth-backend-module-bitbucket-server-provider/CHANGELOG.md index 7f2c2eac5c..3eb70f352b 100644 --- a/plugins/auth-backend-module-bitbucket-server-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-bitbucket-server-provider/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-auth-backend-module-bitbucket-server-provider +## 0.2.4 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-plugin-api@1.4.0 + ## 0.2.4-next.1 ### Patch Changes diff --git a/plugins/auth-backend-module-bitbucket-server-provider/package.json b/plugins/auth-backend-module-bitbucket-server-provider/package.json index 7c2060a6df..4fa29994bb 100644 --- a/plugins/auth-backend-module-bitbucket-server-provider/package.json +++ b/plugins/auth-backend-module-bitbucket-server-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-bitbucket-server-provider", - "version": "0.2.4-next.1", + "version": "0.2.4", "description": "The bitbucket-server-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-cloudflare-access-provider/CHANGELOG.md b/plugins/auth-backend-module-cloudflare-access-provider/CHANGELOG.md index 1e206cdbaa..adc4bcb53a 100644 --- a/plugins/auth-backend-module-cloudflare-access-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-cloudflare-access-provider/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-auth-backend-module-cloudflare-access-provider +## 0.4.4 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + ## 0.4.4-next.1 ### Patch Changes diff --git a/plugins/auth-backend-module-cloudflare-access-provider/package.json b/plugins/auth-backend-module-cloudflare-access-provider/package.json index fc9334f958..8da1cf4482 100644 --- a/plugins/auth-backend-module-cloudflare-access-provider/package.json +++ b/plugins/auth-backend-module-cloudflare-access-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-cloudflare-access-provider", - "version": "0.4.4-next.1", + "version": "0.4.4", "description": "The cloudflare-access-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-gcp-iap-provider/CHANGELOG.md b/plugins/auth-backend-module-gcp-iap-provider/CHANGELOG.md index 63b30dba1f..4b8cfea2d9 100644 --- a/plugins/auth-backend-module-gcp-iap-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-gcp-iap-provider/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-auth-backend-module-gcp-iap-provider +## 0.4.4 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + ## 0.4.4-next.1 ### Patch Changes diff --git a/plugins/auth-backend-module-gcp-iap-provider/package.json b/plugins/auth-backend-module-gcp-iap-provider/package.json index bbdeca08a3..2ce13ba30e 100644 --- a/plugins/auth-backend-module-gcp-iap-provider/package.json +++ b/plugins/auth-backend-module-gcp-iap-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-gcp-iap-provider", - "version": "0.4.4-next.1", + "version": "0.4.4", "description": "A GCP IAP auth provider module for the Backstage auth backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-github-provider/CHANGELOG.md b/plugins/auth-backend-module-github-provider/CHANGELOG.md index ec3305ddca..1d446c4ac9 100644 --- a/plugins/auth-backend-module-github-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-github-provider/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-auth-backend-module-github-provider +## 0.3.4 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-plugin-api@1.4.0 + ## 0.3.4-next.1 ### Patch Changes diff --git a/plugins/auth-backend-module-github-provider/package.json b/plugins/auth-backend-module-github-provider/package.json index 92352dd8aa..3e97640ca3 100644 --- a/plugins/auth-backend-module-github-provider/package.json +++ b/plugins/auth-backend-module-github-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-github-provider", - "version": "0.3.4-next.1", + "version": "0.3.4", "description": "The github-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-gitlab-provider/CHANGELOG.md b/plugins/auth-backend-module-gitlab-provider/CHANGELOG.md index 94c6a8a63c..c7466f1ed2 100644 --- a/plugins/auth-backend-module-gitlab-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-gitlab-provider/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-auth-backend-module-gitlab-provider +## 0.3.4 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-plugin-api@1.4.0 + ## 0.3.4-next.1 ### Patch Changes diff --git a/plugins/auth-backend-module-gitlab-provider/package.json b/plugins/auth-backend-module-gitlab-provider/package.json index 8db0c5f881..a0951a2089 100644 --- a/plugins/auth-backend-module-gitlab-provider/package.json +++ b/plugins/auth-backend-module-gitlab-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-gitlab-provider", - "version": "0.3.4-next.1", + "version": "0.3.4", "description": "The gitlab-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-google-provider/CHANGELOG.md b/plugins/auth-backend-module-google-provider/CHANGELOG.md index 451746eb0a..88123e5154 100644 --- a/plugins/auth-backend-module-google-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-google-provider/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-auth-backend-module-google-provider +## 0.3.4 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-plugin-api@1.4.0 + ## 0.3.4-next.1 ### Patch Changes diff --git a/plugins/auth-backend-module-google-provider/package.json b/plugins/auth-backend-module-google-provider/package.json index d0c77c3bde..417ca82ddc 100644 --- a/plugins/auth-backend-module-google-provider/package.json +++ b/plugins/auth-backend-module-google-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-google-provider", - "version": "0.3.4-next.1", + "version": "0.3.4", "description": "A Google auth provider module for the Backstage auth backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-guest-provider/CHANGELOG.md b/plugins/auth-backend-module-guest-provider/CHANGELOG.md index c9117fb1e2..45bac195d6 100644 --- a/plugins/auth-backend-module-guest-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-guest-provider/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-auth-backend-module-guest-provider +## 0.2.9 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/catalog-model@1.7.4 + - @backstage/errors@1.2.7 + ## 0.2.9-next.1 ### Patch Changes diff --git a/plugins/auth-backend-module-guest-provider/package.json b/plugins/auth-backend-module-guest-provider/package.json index 92368c3364..c7c97ac242 100644 --- a/plugins/auth-backend-module-guest-provider/package.json +++ b/plugins/auth-backend-module-guest-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-guest-provider", - "version": "0.2.9-next.1", + "version": "0.2.9", "description": "The guest-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-microsoft-provider/CHANGELOG.md b/plugins/auth-backend-module-microsoft-provider/CHANGELOG.md index 3ddacc4be9..0286289724 100644 --- a/plugins/auth-backend-module-microsoft-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-microsoft-provider/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-auth-backend-module-microsoft-provider +## 0.3.4 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-plugin-api@1.4.0 + ## 0.3.4-next.1 ### Patch Changes diff --git a/plugins/auth-backend-module-microsoft-provider/package.json b/plugins/auth-backend-module-microsoft-provider/package.json index d3ecdcbc4d..ffe2a45cef 100644 --- a/plugins/auth-backend-module-microsoft-provider/package.json +++ b/plugins/auth-backend-module-microsoft-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-microsoft-provider", - "version": "0.3.4-next.1", + "version": "0.3.4", "description": "The microsoft-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-oauth2-provider/CHANGELOG.md b/plugins/auth-backend-module-oauth2-provider/CHANGELOG.md index 67fcf5686d..4833e43a4d 100644 --- a/plugins/auth-backend-module-oauth2-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-oauth2-provider/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-auth-backend-module-oauth2-provider +## 0.4.4 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-plugin-api@1.4.0 + ## 0.4.4-next.1 ### Patch Changes diff --git a/plugins/auth-backend-module-oauth2-provider/package.json b/plugins/auth-backend-module-oauth2-provider/package.json index 33c221ce42..f15e6c68e0 100644 --- a/plugins/auth-backend-module-oauth2-provider/package.json +++ b/plugins/auth-backend-module-oauth2-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-oauth2-provider", - "version": "0.4.4-next.1", + "version": "0.4.4", "description": "The oauth2-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-oauth2-proxy-provider/CHANGELOG.md b/plugins/auth-backend-module-oauth2-proxy-provider/CHANGELOG.md index 6da4b2529d..76c048d5b2 100644 --- a/plugins/auth-backend-module-oauth2-proxy-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-oauth2-proxy-provider/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-auth-backend-module-oauth2-proxy-provider +## 0.2.9 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/errors@1.2.7 + ## 0.2.9-next.1 ### Patch Changes diff --git a/plugins/auth-backend-module-oauth2-proxy-provider/package.json b/plugins/auth-backend-module-oauth2-proxy-provider/package.json index 2df01732ac..883cf11f2c 100644 --- a/plugins/auth-backend-module-oauth2-proxy-provider/package.json +++ b/plugins/auth-backend-module-oauth2-proxy-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-oauth2-proxy-provider", - "version": "0.2.9-next.1", + "version": "0.2.9", "description": "The oauth2-proxy-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-oidc-provider/CHANGELOG.md b/plugins/auth-backend-module-oidc-provider/CHANGELOG.md index 37f529cbbc..5d524429c6 100644 --- a/plugins/auth-backend-module-oidc-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-oidc-provider/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-auth-backend-module-oidc-provider +## 0.4.4 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/types@1.2.1 + - @backstage/plugin-auth-backend@0.25.1 + ## 0.4.4-next.1 ### Patch Changes diff --git a/plugins/auth-backend-module-oidc-provider/package.json b/plugins/auth-backend-module-oidc-provider/package.json index 621726e6c4..8f7ebe91be 100644 --- a/plugins/auth-backend-module-oidc-provider/package.json +++ b/plugins/auth-backend-module-oidc-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-oidc-provider", - "version": "0.4.4-next.1", + "version": "0.4.4", "description": "The oidc-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-okta-provider/CHANGELOG.md b/plugins/auth-backend-module-okta-provider/CHANGELOG.md index 2c4022fc73..073a944e1d 100644 --- a/plugins/auth-backend-module-okta-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-okta-provider/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-auth-backend-module-okta-provider +## 0.2.4 + +### Patch Changes + +- b25977f: Updated dependency `@davidzemon/passport-okta-oauth` to `^0.0.6`. +- Updated dependencies + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-plugin-api@1.4.0 + ## 0.2.4-next.1 ### Patch Changes diff --git a/plugins/auth-backend-module-okta-provider/package.json b/plugins/auth-backend-module-okta-provider/package.json index 2780942fe8..c70e1043dd 100644 --- a/plugins/auth-backend-module-okta-provider/package.json +++ b/plugins/auth-backend-module-okta-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-okta-provider", - "version": "0.2.4-next.1", + "version": "0.2.4", "description": "The okta-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", @@ -36,7 +36,7 @@ "dependencies": { "@backstage/backend-plugin-api": "workspace:^", "@backstage/plugin-auth-node": "workspace:^", - "@davidzemon/passport-okta-oauth": "^0.0.5", + "@davidzemon/passport-okta-oauth": "^0.0.6", "express": "^4.18.2", "passport": "^0.7.0", "zod": "^3.22.4" diff --git a/plugins/auth-backend-module-okta-provider/src/types.d.ts b/plugins/auth-backend-module-okta-provider/src/types.d.ts index 58cfb74173..7ca3645e3e 100644 --- a/plugins/auth-backend-module-okta-provider/src/types.d.ts +++ b/plugins/auth-backend-module-okta-provider/src/types.d.ts @@ -23,3 +23,87 @@ declare module 'passport-okta2' { authenticate(this: StrategyCreated, req: Request, options?: any): any; } } + +// NOTE(freben): This entire block is here because version 0.0.6 of this library +// accidentally didn't include types. It did, however, include a scope fix that +// is interesting for Backstage to get in. +// See https://github.com/backstage/backstage/pull/29529 +// See https://github.com/DavidZemon/passport-okta-oauth/pull/1 +declare module '@davidzemon/passport-okta-oauth' { + import OAuth2Strategy = require('passport-oauth2'); + + type OktaStrategyOptions = UniqueOktaStrategyOptions & + Omit< + import('passport-oauth2')._StrategyOptionsBase, + 'authorizationURL' | 'tokenURL' + >; + type UniqueOktaStrategyOptions = { + /** + * audience is the Okta Domain, e.g. `https://example.okta.com`, + * `https://example.oktapreview.com` + */ + audience: string; + /** + * authServerID is the authorization server ID. If it is defined, the token + * URL might be something like `https://example.okta.com/oauth2/authServerID/v1/token` + */ + authServerID: string | undefined; + /** + * idp is the Identity Provider (id). This is an optional field. it's a 20 character + * alphanumeric string, e.g. `qOp8aaJmCEhvep5Il6ZJ` (generated example) + */ + idp: string | undefined; + /** + * With this option enabled, `req` will be passed as the first argument to the + * verify callback. + */ + passReqToCallback: boolean | undefined; + /** + * Set this to 'code' + */ + response_type: 'code'; + }; + + class Strategy extends OAuth2Strategy { + /** + * @param {OktaStrategyOptions | undefined} options + * @param {import("passport-oauth2").VerifyFunction | import("passport-oauth2").VerifyFunctionWithRequest} verify + */ + constructor( + options: OktaStrategyOptions | undefined, + verify: + | import('passport-oauth2').VerifyFunction + | import('passport-oauth2').VerifyFunctionWithRequest, + ); + _userInfoUrl: string; + _idp: string; + _state: any; + /** + * Retrieve user profile from Okta. + * Further references at http://developer.okta.com/docs/api/resources/oidc.html#get-user-information + * + * This function constructs a normalized profile, with the following properties: + * + * - `provider` always set to `okta` + * - `id` + * - `username` + * - `displayName` + * + * @param {String} accessToken + * @param {Function} done + * @api protected + */ + userProfile(accessToken: string, done: Function): void; + /** + * Return extra Okta-specific parameters to be included in the authorization + * request. + * + * @param {Object} option + * @return {Object} + * @api protected + */ + authorizationParams(option: any): any; + } + + export { Strategy }; +} diff --git a/plugins/auth-backend-module-onelogin-provider/CHANGELOG.md b/plugins/auth-backend-module-onelogin-provider/CHANGELOG.md index dce3cd0c6c..00ae875f18 100644 --- a/plugins/auth-backend-module-onelogin-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-onelogin-provider/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-auth-backend-module-onelogin-provider +## 0.3.4 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-plugin-api@1.4.0 + ## 0.3.4-next.1 ### Patch Changes diff --git a/plugins/auth-backend-module-onelogin-provider/package.json b/plugins/auth-backend-module-onelogin-provider/package.json index 58f5489bbc..bf3ccefe98 100644 --- a/plugins/auth-backend-module-onelogin-provider/package.json +++ b/plugins/auth-backend-module-onelogin-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-onelogin-provider", - "version": "0.3.4-next.1", + "version": "0.3.4", "description": "The onelogin-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-pinniped-provider/CHANGELOG.md b/plugins/auth-backend-module-pinniped-provider/CHANGELOG.md index 0c31e3d28e..2bbf9687cd 100644 --- a/plugins/auth-backend-module-pinniped-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-pinniped-provider/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-auth-backend-module-pinniped-provider +## 0.3.4 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/types@1.2.1 + ## 0.3.4-next.1 ### Patch Changes diff --git a/plugins/auth-backend-module-pinniped-provider/package.json b/plugins/auth-backend-module-pinniped-provider/package.json index 4cde024617..17fec7e87e 100644 --- a/plugins/auth-backend-module-pinniped-provider/package.json +++ b/plugins/auth-backend-module-pinniped-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-pinniped-provider", - "version": "0.3.4-next.1", + "version": "0.3.4", "description": "The pinniped-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-vmware-cloud-provider/CHANGELOG.md b/plugins/auth-backend-module-vmware-cloud-provider/CHANGELOG.md index e8e5ac6a05..8b432b873e 100644 --- a/plugins/auth-backend-module-vmware-cloud-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-vmware-cloud-provider/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-auth-backend-module-vmware-cloud-provider +## 0.5.4 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/catalog-model@1.7.4 + ## 0.5.4-next.1 ### Patch Changes diff --git a/plugins/auth-backend-module-vmware-cloud-provider/package.json b/plugins/auth-backend-module-vmware-cloud-provider/package.json index 2aa4cc56bc..3ee9835ace 100644 --- a/plugins/auth-backend-module-vmware-cloud-provider/package.json +++ b/plugins/auth-backend-module-vmware-cloud-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-vmware-cloud-provider", - "version": "0.5.4-next.1", + "version": "0.5.4", "description": "The vmware-cloud-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend/CHANGELOG.md b/plugins/auth-backend/CHANGELOG.md index 0c97d879ae..bd54646ed6 100644 --- a/plugins/auth-backend/CHANGELOG.md +++ b/plugins/auth-backend/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-auth-backend +## 0.25.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + ## 0.25.1-next.1 ### Patch Changes diff --git a/plugins/auth-backend/package.json b/plugins/auth-backend/package.json index 9ba97ee8ac..925469b7ea 100644 --- a/plugins/auth-backend/package.json +++ b/plugins/auth-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend", - "version": "0.25.1-next.1", + "version": "0.25.1", "description": "A Backstage backend plugin that handles authentication", "backstage": { "role": "backend-plugin", diff --git a/plugins/auth-node/CHANGELOG.md b/plugins/auth-node/CHANGELOG.md index 5745219625..cd4b5b58bf 100644 --- a/plugins/auth-node/CHANGELOG.md +++ b/plugins/auth-node/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-auth-node +## 0.6.4 + +### Patch Changes + +- 0169b23: Internal tweak to avoid circular dependencies +- Updated dependencies + - @backstage/catalog-client@1.10.1 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + ## 0.6.4-next.1 ### Patch Changes diff --git a/plugins/auth-node/package.json b/plugins/auth-node/package.json index fe24d798d6..b5ec590eb3 100644 --- a/plugins/auth-node/package.json +++ b/plugins/auth-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-node", - "version": "0.6.4-next.1", + "version": "0.6.4", "backstage": { "role": "node-library", "pluginId": "auth", diff --git a/plugins/auth-node/report.api.md b/plugins/auth-node/report.api.md index 090f981636..69e953cf13 100644 --- a/plugins/auth-node/report.api.md +++ b/plugins/auth-node/report.api.md @@ -3,8 +3,6 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts -import { BackstageIdentityResponse as BackstageIdentityResponse_2 } from '@backstage/plugin-auth-node'; -import { BackstageSignInResult as BackstageSignInResult_2 } from '@backstage/plugin-auth-node'; import { Config } from '@backstage/config'; import { DiscoveryService } from '@backstage/backend-plugin-api'; import { Entity } from '@backstage/catalog-model'; @@ -575,8 +573,8 @@ export type PassportProfile = Profile & { // @public export function prepareBackstageIdentityResponse( - result: BackstageSignInResult_2, -): BackstageIdentityResponse_2; + result: BackstageSignInResult, +): BackstageIdentityResponse; // @public export type ProfileInfo = { diff --git a/plugins/auth-node/src/identity/prepareBackstageIdentityResponse.ts b/plugins/auth-node/src/identity/prepareBackstageIdentityResponse.ts index a1de4e365c..aa827cef3f 100644 --- a/plugins/auth-node/src/identity/prepareBackstageIdentityResponse.ts +++ b/plugins/auth-node/src/identity/prepareBackstageIdentityResponse.ts @@ -15,10 +15,7 @@ */ import { InputError } from '@backstage/errors'; -import { - BackstageIdentityResponse, - BackstageSignInResult, -} from '@backstage/plugin-auth-node'; +import { BackstageIdentityResponse, BackstageSignInResult } from '../types'; function parseJwtPayload(token: string) { const [_header, payload, _signature] = token.split('.'); diff --git a/plugins/auth-react/CHANGELOG.md b/plugins/auth-react/CHANGELOG.md index e0380a9fa9..da56041530 100644 --- a/plugins/auth-react/CHANGELOG.md +++ b/plugins/auth-react/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-auth-react +## 0.1.16 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3 + - @backstage/core-plugin-api@1.10.8 + - @backstage/errors@1.2.7 + +## 0.1.16-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/core-plugin-api@1.10.7 + - @backstage/errors@1.2.7 + ## 0.1.15 ### Patch Changes diff --git a/plugins/auth-react/package.json b/plugins/auth-react/package.json index f668c95c06..50296070ea 100644 --- a/plugins/auth-react/package.json +++ b/plugins/auth-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-react", - "version": "0.1.15", + "version": "0.1.16", "description": "Web library for the auth plugin", "backstage": { "role": "web-library", diff --git a/plugins/catalog-backend-module-aws/CHANGELOG.md b/plugins/catalog-backend-module-aws/CHANGELOG.md index 95417d8073..bdaf217a08 100644 --- a/plugins/catalog-backend-module-aws/CHANGELOG.md +++ b/plugins/catalog-backend-module-aws/CHANGELOG.md @@ -1,5 +1,37 @@ # @backstage/plugin-catalog-backend-module-aws +## 0.4.12 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.11.0 + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + - @backstage/integration-aws-node@0.1.16 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-kubernetes-common@0.9.5 + +## 0.4.12-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.11.0-next.2 + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + - @backstage/integration-aws-node@0.1.16 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-catalog-node@1.17.1-next.1 + - @backstage/plugin-kubernetes-common@0.9.5 + ## 0.4.12-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-aws/package.json b/plugins/catalog-backend-module-aws/package.json index e1259daa7c..f5b56f705a 100644 --- a/plugins/catalog-backend-module-aws/package.json +++ b/plugins/catalog-backend-module-aws/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-aws", - "version": "0.4.12-next.1", + "version": "0.4.12", "description": "A Backstage catalog backend module that helps integrate towards AWS", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-azure/CHANGELOG.md b/plugins/catalog-backend-module-azure/CHANGELOG.md index c59dfea5b3..c68daded70 100644 --- a/plugins/catalog-backend-module-azure/CHANGELOG.md +++ b/plugins/catalog-backend-module-azure/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-catalog-backend-module-azure +## 0.3.6 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/integration@1.17.0 + - @backstage/plugin-catalog-common@1.1.4 + ## 0.3.6-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-azure/package.json b/plugins/catalog-backend-module-azure/package.json index cfc5f2a30d..6892b859fe 100644 --- a/plugins/catalog-backend-module-azure/package.json +++ b/plugins/catalog-backend-module-azure/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-azure", - "version": "0.3.6-next.1", + "version": "0.3.6", "description": "A Backstage catalog backend module that helps integrate towards Azure", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-backstage-openapi/CHANGELOG.md b/plugins/catalog-backend-module-backstage-openapi/CHANGELOG.md index f2282c7796..283b8d22ec 100644 --- a/plugins/catalog-backend-module-backstage-openapi/CHANGELOG.md +++ b/plugins/catalog-backend-module-backstage-openapi/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-catalog-backend-module-backstage-openapi +## 0.5.3 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/backend-openapi-utils@0.5.4 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + ## 0.5.3-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-backstage-openapi/package.json b/plugins/catalog-backend-module-backstage-openapi/package.json index b3669aa611..b81797fbf9 100644 --- a/plugins/catalog-backend-module-backstage-openapi/package.json +++ b/plugins/catalog-backend-module-backstage-openapi/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-backstage-openapi", - "version": "0.5.3-next.1", + "version": "0.5.3", "backstage": { "role": "backend-plugin-module", "pluginId": "catalog", diff --git a/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md b/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md index bbab017765..66e8f9a5c2 100644 --- a/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md +++ b/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md @@ -1,5 +1,43 @@ # @backstage/plugin-catalog-backend-module-bitbucket-cloud +## 0.5.0 + +### Minor Changes + +- 8a150bf: **BREAKING**: `BitbucketCloudEntityProvider` now accepts a `CatalogService` instead of a `CatalogApi`. + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.10.1 + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/integration@1.17.0 + - @backstage/plugin-bitbucket-cloud-common@0.3.0 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-events-node@0.4.12 + +## 0.5.0-next.2 + +### Minor Changes + +- 8a150bf: **BREAKING**: `BitbucketCloudEntityProvider` now accepts a `CatalogService` instead of a `CatalogApi`. + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/catalog-client@1.10.1-next.0 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/integration@1.17.0 + - @backstage/plugin-bitbucket-cloud-common@0.3.0 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-catalog-node@1.17.1-next.1 + - @backstage/plugin-events-node@0.4.12-next.1 + ## 0.4.9-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-bitbucket-cloud/package.json b/plugins/catalog-backend-module-bitbucket-cloud/package.json index b0f4c08403..2fdc1ba5c7 100644 --- a/plugins/catalog-backend-module-bitbucket-cloud/package.json +++ b/plugins/catalog-backend-module-bitbucket-cloud/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-bitbucket-cloud", - "version": "0.4.9-next.1", + "version": "0.5.0", "description": "A Backstage catalog backend module that helps integrate towards Bitbucket Cloud", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-bitbucket-server/CHANGELOG.md b/plugins/catalog-backend-module-bitbucket-server/CHANGELOG.md index 7506f728cf..5bc457524c 100644 --- a/plugins/catalog-backend-module-bitbucket-server/CHANGELOG.md +++ b/plugins/catalog-backend-module-bitbucket-server/CHANGELOG.md @@ -1,5 +1,24 @@ # @backstage/plugin-catalog-backend-module-bitbucket-server +## 0.5.0 + +### Minor Changes + +- eb8b3aa: Add validateLocationsExist option to avoid generating locations for catalog-info.yaml files that do not exist in the source repository. + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.10.1 + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-events-node@0.4.12 + ## 0.4.2-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-bitbucket-server/config.d.ts b/plugins/catalog-backend-module-bitbucket-server/config.d.ts index 0f6889efa7..d57a15a736 100644 --- a/plugins/catalog-backend-module-bitbucket-server/config.d.ts +++ b/plugins/catalog-backend-module-bitbucket-server/config.d.ts @@ -51,6 +51,11 @@ export interface Config { */ skipArchivedRepos?: boolean; }; + /** + * (Optional) Whether to validate locations that exist before emitting them. + * Default: `false`. + */ + validateLocationsExist?: boolean; /** * (Optional) TaskScheduleDefinition for the refresh. */ @@ -83,6 +88,11 @@ export interface Config { */ skipArchivedRepos?: boolean; }; + /** + * (Optional) Whether to validate locations that exist before emitting them. + * Default: `false`. + */ + validateLocationsExist?: boolean; /** * (Optional) TaskScheduleDefinition for the refresh. */ diff --git a/plugins/catalog-backend-module-bitbucket-server/package.json b/plugins/catalog-backend-module-bitbucket-server/package.json index de7fb993e9..67f25e1ada 100644 --- a/plugins/catalog-backend-module-bitbucket-server/package.json +++ b/plugins/catalog-backend-module-bitbucket-server/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-bitbucket-server", - "version": "0.4.2-next.1", + "version": "0.5.0", "backstage": { "role": "backend-plugin-module", "pluginId": "catalog", diff --git a/plugins/catalog-backend-module-bitbucket-server/src/lib/BitbucketServerClient.ts b/plugins/catalog-backend-module-bitbucket-server/src/lib/BitbucketServerClient.ts index fa0c455b04..7bf6480f33 100644 --- a/plugins/catalog-backend-module-bitbucket-server/src/lib/BitbucketServerClient.ts +++ b/plugins/catalog-backend-module-bitbucket-server/src/lib/BitbucketServerClient.ts @@ -70,8 +70,11 @@ export class BitbucketServerClient { repo: string; path: string; }): Promise { + const normalizedPath = options.path.startsWith('/') + ? options.path.substring(1) + : options.path; return fetch( - `${this.config.apiBaseUrl}/projects/${options.projectKey}/repos/${options.repo}/raw/${options.path}`, + `${this.config.apiBaseUrl}/projects/${options.projectKey}/repos/${options.repo}/raw/${normalizedPath}`, getBitbucketServerRequestOptions(this.config), ); } diff --git a/plugins/catalog-backend-module-bitbucket-server/src/providers/BitbucketServerEntityProvider.test.ts b/plugins/catalog-backend-module-bitbucket-server/src/providers/BitbucketServerEntityProvider.test.ts index ba4e3e0411..790bef7939 100644 --- a/plugins/catalog-backend-module-bitbucket-server/src/providers/BitbucketServerEntityProvider.test.ts +++ b/plugins/catalog-backend-module-bitbucket-server/src/providers/BitbucketServerEntityProvider.test.ts @@ -668,6 +668,97 @@ describe('BitbucketServerEntityProvider', () => { }); }); + it('do not add locations when validateLocationsExist and catalog-info does not exist', async () => { + server.use( + rest.get( + `https://${host}/rest/api/1.0/projects/project-test/repos/repo-test/raw/catalog-info.yaml`, + (_, res, ctx) => { + return res(ctx.status(404)); + }, + ), + rest.get( + `https://${host}/rest/api/1.0/projects/other-project/repos/other-repo/raw/catalog-info.yaml`, + (_, res, ctx) => { + return res(ctx.status(200)); + }, + ), + ); + const config = new ConfigReader({ + integrations: { + bitbucketServer: [ + { + host: host, + }, + ], + }, + catalog: { + providers: { + bitbucketServer: { + mainProvider: { + host: host, + validateLocationsExist: true, + }, + }, + }, + }, + }); + const schedule = new PersistingTaskRunner(); + const entityProviderConnection: EntityProviderConnection = { + applyMutation: jest.fn(), + refresh: jest.fn(), + }; + const provider = BitbucketServerEntityProvider.fromConfig(config, { + logger, + schedule, + })[0]; + expect(provider.getProviderName()).toEqual( + 'bitbucketServer-provider:mainProvider', + ); + + setupStubs( + [ + { key: 'project-test', repos: [{ name: 'repo-test' }] }, + { key: 'other-project', repos: [{ name: 'other-repo' }] }, + ], + `https://${host}`, + 'master', + ); + await provider.connect(entityProviderConnection); + + const taskDef = schedule.getTasks()[0]; + expect(taskDef.id).toEqual('bitbucketServer-provider:mainProvider:refresh'); + await (taskDef.fn as () => Promise)(); + + const expectedEntities = [ + { + entity: { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Location', + metadata: { + annotations: { + 'backstage.io/managed-by-location': `url:https://${host}/projects/other-project/repos/other-repo/browse/catalog-info.yaml`, + 'backstage.io/managed-by-origin-location': `url:https://${host}/projects/other-project/repos/other-repo/browse/catalog-info.yaml`, + 'bitbucket.org/default-branch': 'master', + }, + name: 'generated-d8d4944c30c2906dfee172ddda9537f9893b2c0f', + }, + spec: { + presence: 'optional', + target: `https://${host}/projects/other-project/repos/other-repo/browse/catalog-info.yaml`, + type: 'url', + }, + }, + locationKey: 'bitbucketServer-provider:mainProvider', + }, + ]; + + expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes(1); + expect(entityProviderConnection.applyMutation).toHaveBeenCalledWith({ + type: 'full', + entities: expectedEntities, + }); + }); + it('Multiple location entities to deferred entities', async () => { const schedule = new PersistingTaskRunner(); const config = new ConfigReader({ diff --git a/plugins/catalog-backend-module-bitbucket-server/src/providers/BitbucketServerEntityProvider.ts b/plugins/catalog-backend-module-bitbucket-server/src/providers/BitbucketServerEntityProvider.ts index b462f8756a..4b02632892 100644 --- a/plugins/catalog-backend-module-bitbucket-server/src/providers/BitbucketServerEntityProvider.ts +++ b/plugins/catalog-backend-module-bitbucket-server/src/providers/BitbucketServerEntityProvider.ts @@ -253,6 +253,37 @@ export class BitbucketServerEntityProvider implements EntityProvider { if (this.config?.filters?.skipArchivedRepos && repository.archived) { continue; } + if (this.config.validateLocationsExist) { + try { + const response = await client.getFile({ + projectKey: project.key, + repo: repository.slug, + path: this.config.catalogPath, + }); + if (!response.ok) { + if (response.status === 404) { + this.logger.debug( + `Skipping repository ${repository.slug} in project ${project.key} because the catalog file does not exist.`, + ); + } else { + this.logger.warn( + `Unexpected response code ${ + response.status + } while fetching the catalog file from repository ${ + repository.slug + } in project ${ + project.key + }. Response details: ${JSON.stringify(response)}`, + ); + } + continue; + } + } catch (error) { + this.logger.error( + `An error occurred while fetching the catalog file from repository ${repository.slug} in project ${project.key}: ${error}`, + ); + } + } for await (const entity of this.parser({ client, logger: this.logger, diff --git a/plugins/catalog-backend-module-bitbucket-server/src/providers/BitbucketServerEntityProviderConfig.test.ts b/plugins/catalog-backend-module-bitbucket-server/src/providers/BitbucketServerEntityProviderConfig.test.ts index 755fa4b58a..cd39f0659b 100644 --- a/plugins/catalog-backend-module-bitbucket-server/src/providers/BitbucketServerEntityProviderConfig.test.ts +++ b/plugins/catalog-backend-module-bitbucket-server/src/providers/BitbucketServerEntityProviderConfig.test.ts @@ -49,6 +49,8 @@ describe('readProviderConfigs', () => { repoSlug: undefined, skipArchivedRepos: undefined, }, + schedule: undefined, + validateLocationsExist: false, }); }); @@ -89,6 +91,8 @@ describe('readProviderConfigs', () => { repoSlug: undefined, skipArchivedRepos: undefined, }, + schedule: undefined, + validateLocationsExist: false, }); expect(providerConfigs[1]).toEqual({ id: 'secondaryProvider', @@ -99,6 +103,8 @@ describe('readProviderConfigs', () => { repoSlug: undefined, skipArchivedRepos: undefined, }, + schedule: undefined, + validateLocationsExist: false, }); expect(providerConfigs[2]).toEqual({ id: 'thirdProvider', @@ -109,6 +115,7 @@ describe('readProviderConfigs', () => { repoSlug: undefined, skipArchivedRepos: undefined, }, + validateLocationsExist: false, schedule: { frequency: { minutes: 30 }, timeout: { @@ -147,6 +154,36 @@ describe('readProviderConfigs', () => { repoSlug: /.*/, skipArchivedRepos: true, }, + schedule: undefined, + validateLocationsExist: false, + }); + }); + + it('single simple provider config with validateLocationsExist', () => { + const config = new ConfigReader({ + catalog: { + providers: { + bitbucketServer: { + host: 'bitbucket.mycompany.com', + validateLocationsExist: true, + }, + }, + }, + }); + const providerConfigs = readProviderConfigs(config); + + expect(providerConfigs).toHaveLength(1); + expect(providerConfigs[0]).toEqual({ + id: 'default', + catalogPath: '/catalog-info.yaml', + host: 'bitbucket.mycompany.com', + filters: { + projectKey: undefined, + repoSlug: undefined, + skipArchivedRepos: undefined, + }, + schedule: undefined, + validateLocationsExist: true, }); }); }); diff --git a/plugins/catalog-backend-module-bitbucket-server/src/providers/BitbucketServerEntityProviderConfig.ts b/plugins/catalog-backend-module-bitbucket-server/src/providers/BitbucketServerEntityProviderConfig.ts index 3b921b6bab..1a224536a7 100644 --- a/plugins/catalog-backend-module-bitbucket-server/src/providers/BitbucketServerEntityProviderConfig.ts +++ b/plugins/catalog-backend-module-bitbucket-server/src/providers/BitbucketServerEntityProviderConfig.ts @@ -32,6 +32,7 @@ export type BitbucketServerEntityProviderConfig = { repoSlug?: RegExp; skipArchivedRepos?: boolean; }; + validateLocationsExist: boolean; schedule?: SchedulerServiceTaskScheduleDefinition; }; @@ -66,7 +67,8 @@ function readProviderConfig( const skipArchivedReposFlag = config.getOptionalBoolean( 'filters.skipArchivedRepos', ); - + const validateLocationsExistFlag = + config?.getOptionalBoolean('validateLocationsExist') ?? false; const schedule = config.has('schedule') ? readSchedulerServiceTaskScheduleDefinitionFromConfig( config.getConfig('schedule'), @@ -82,6 +84,7 @@ function readProviderConfig( repoSlug: repoSlugPattern ? new RegExp(repoSlugPattern) : undefined, skipArchivedRepos: skipArchivedReposFlag, }, + validateLocationsExist: validateLocationsExistFlag, schedule, }; } diff --git a/plugins/catalog-backend-module-gcp/CHANGELOG.md b/plugins/catalog-backend-module-gcp/CHANGELOG.md index 99df738894..1831056e4e 100644 --- a/plugins/catalog-backend-module-gcp/CHANGELOG.md +++ b/plugins/catalog-backend-module-gcp/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-catalog-backend-module-gcp +## 0.3.9 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/plugin-kubernetes-common@0.9.5 + ## 0.3.9-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-gcp/package.json b/plugins/catalog-backend-module-gcp/package.json index dbcd8c8249..71d9a82e01 100644 --- a/plugins/catalog-backend-module-gcp/package.json +++ b/plugins/catalog-backend-module-gcp/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-gcp", - "version": "0.3.9-next.1", + "version": "0.3.9", "description": "A Backstage catalog backend module that helps integrate towards GCP", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-gerrit/CHANGELOG.md b/plugins/catalog-backend-module-gerrit/CHANGELOG.md index 104a13390d..f82bccfecb 100644 --- a/plugins/catalog-backend-module-gerrit/CHANGELOG.md +++ b/plugins/catalog-backend-module-gerrit/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-catalog-backend-module-gerrit +## 0.3.3 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + - @backstage/plugin-catalog-common@1.1.4 + ## 0.3.3-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-gerrit/package.json b/plugins/catalog-backend-module-gerrit/package.json index 5568702238..aada0b8773 100644 --- a/plugins/catalog-backend-module-gerrit/package.json +++ b/plugins/catalog-backend-module-gerrit/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-gerrit", - "version": "0.3.3-next.1", + "version": "0.3.3", "backstage": { "role": "backend-plugin-module", "pluginId": "catalog", diff --git a/plugins/catalog-backend-module-gitea/CHANGELOG.md b/plugins/catalog-backend-module-gitea/CHANGELOG.md index 849f8205b4..bea863224c 100644 --- a/plugins/catalog-backend-module-gitea/CHANGELOG.md +++ b/plugins/catalog-backend-module-gitea/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-catalog-backend-module-gitea +## 0.1.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + - @backstage/plugin-catalog-common@1.1.4 + ## 0.1.1-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-gitea/package.json b/plugins/catalog-backend-module-gitea/package.json index 714252d43a..13b806f0d9 100644 --- a/plugins/catalog-backend-module-gitea/package.json +++ b/plugins/catalog-backend-module-gitea/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-gitea", - "version": "0.1.1-next.1", + "version": "0.1.1", "license": "Apache-2.0", "description": "The gitea backend module for the catalog plugin.", "main": "src/index.ts", diff --git a/plugins/catalog-backend-module-github-org/CHANGELOG.md b/plugins/catalog-backend-module-github-org/CHANGELOG.md index 8e0cb68570..1892a829e4 100644 --- a/plugins/catalog-backend-module-github-org/CHANGELOG.md +++ b/plugins/catalog-backend-module-github-org/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-catalog-backend-module-github-org +## 0.3.11 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/plugin-catalog-backend-module-github@0.10.0 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/plugin-events-node@0.4.12 + +## 0.3.11-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/config@1.3.2 + - @backstage/plugin-catalog-backend-module-github@0.9.1-next.2 + - @backstage/plugin-catalog-node@1.17.1-next.1 + - @backstage/plugin-events-node@0.4.12-next.1 + ## 0.3.11-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-github-org/package.json b/plugins/catalog-backend-module-github-org/package.json index 438ec45dcf..8bf5977b2e 100644 --- a/plugins/catalog-backend-module-github-org/package.json +++ b/plugins/catalog-backend-module-github-org/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-github-org", - "version": "0.3.11-next.1", + "version": "0.3.11", "description": "The github-org backend module for the catalog plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-github/CHANGELOG.md b/plugins/catalog-backend-module-github/CHANGELOG.md index 11ff006b82..c67c3a3ded 100644 --- a/plugins/catalog-backend-module-github/CHANGELOG.md +++ b/plugins/catalog-backend-module-github/CHANGELOG.md @@ -1,5 +1,39 @@ # @backstage/plugin-catalog-backend-module-github +## 0.10.0 + +### Minor Changes + +- 7c0dfb0: GitHub organization now matches in a case-insensitive manner when processing events. + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.10.1 + - @backstage/plugin-catalog-backend@2.1.0 + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/integration@1.17.0 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-events-node@0.4.12 + +## 0.9.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@2.0.1-next.2 + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/catalog-client@1.10.1-next.0 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/integration@1.17.0 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-catalog-node@1.17.1-next.1 + - @backstage/plugin-events-node@0.4.12-next.1 + ## 0.9.1-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-github/package.json b/plugins/catalog-backend-module-github/package.json index 95fae59471..5a445be46c 100644 --- a/plugins/catalog-backend-module-github/package.json +++ b/plugins/catalog-backend-module-github/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-github", - "version": "0.9.1-next.1", + "version": "0.10.0", "description": "A Backstage catalog backend module that helps integrate towards GitHub", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-github/src/providers/GithubEntityProvider.test.ts b/plugins/catalog-backend-module-github/src/providers/GithubEntityProvider.test.ts index b7df19c296..4032e1d368 100644 --- a/plugins/catalog-backend-module-github/src/providers/GithubEntityProvider.test.ts +++ b/plugins/catalog-backend-module-github/src/providers/GithubEntityProvider.test.ts @@ -940,6 +940,27 @@ describe('GithubEntityProvider', () => { expect(entityProviderConnection.refresh).toHaveBeenCalledTimes(0); expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes(0); }); + + it('should process when orgs case-insensitive match', async () => { + const config = createSingleProviderConfig({ + providerConfig: { + organization: 'test-org', + }, + }); + const provider = createProviders(config)[0]; + + const entityProviderConnection: EntityProviderConnection = { + applyMutation: jest.fn(), + refresh: jest.fn(), + }; + await provider.connect(entityProviderConnection); + + const event = createPushEvent({ org: 'Test-Org' }); + + await provider.onEvent(event); + + expect(entityProviderConnection.refresh).toHaveBeenCalledTimes(1); + }); }); describe('on repository event', () => { @@ -1189,6 +1210,36 @@ describe('GithubEntityProvider', () => { 0, ); }); + + it('applies update when orgs case-insensitive match', async () => { + const config = createSingleProviderConfig({ + providerConfig: { + organization: 'test-org', + filters: { + topic: { + include: ['backstage-include'], + }, + }, + }, + }); + + const provider = createProviders(config)[0]; + + const entityProviderConnection: EntityProviderConnection = { + applyMutation: jest.fn(), + refresh: jest.fn(), + }; + await provider.connect(entityProviderConnection); + + const event = createRepoEvent('edited'); + event.eventPayload.organization!.login = 'Test-Org'; + + await provider.onEvent(event); + + expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes( + 1, + ); + }); }); describe('on repository privatized event', () => { diff --git a/plugins/catalog-backend-module-github/src/providers/GithubEntityProvider.ts b/plugins/catalog-backend-module-github/src/providers/GithubEntityProvider.ts index 131237c581..5f3c652cb9 100644 --- a/plugins/catalog-backend-module-github/src/providers/GithubEntityProvider.ts +++ b/plugins/catalog-backend-module-github/src/providers/GithubEntityProvider.ts @@ -323,7 +323,13 @@ export class GithubEntityProvider implements EntityProvider, EventSubscriber { } private async onPush(event: PushEvent) { - if (this.config.organization !== event.organization?.login) { + const configOrganization = this.config.organization; + const eventOrganization = event.organization?.login; + + if ( + configOrganization.toLocaleLowerCase('en-US') !== + eventOrganization?.toLocaleLowerCase('en-US') + ) { this.logger.debug( `skipping push event from organization ${event.organization?.login}`, ); @@ -406,7 +412,13 @@ export class GithubEntityProvider implements EntityProvider, EventSubscriber { } private async onRepoChange(event: RepositoryEvent) { - if (this.config.organization !== event.organization?.login) { + const configOrganization = this.config.organization; + const eventOrganization = event.organization?.login; + + if ( + configOrganization.toLocaleLowerCase('en-US') !== + eventOrganization?.toLocaleLowerCase('en-US') + ) { this.logger.debug( `skipping repository event from organization ${event.organization?.login}`, ); diff --git a/plugins/catalog-backend-module-gitlab-org/CHANGELOG.md b/plugins/catalog-backend-module-gitlab-org/CHANGELOG.md index 87609736c4..fa25b06614 100644 --- a/plugins/catalog-backend-module-gitlab-org/CHANGELOG.md +++ b/plugins/catalog-backend-module-gitlab-org/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/plugin-catalog-backend-module-gitlab-org +## 0.2.10 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend-module-gitlab@0.7.0 + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/plugin-events-node@0.4.12 + +## 0.2.10-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend-module-gitlab@0.7.0-next.2 + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/plugin-catalog-node@1.17.1-next.1 + - @backstage/plugin-events-node@0.4.12-next.1 + ## 0.2.10-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-gitlab-org/package.json b/plugins/catalog-backend-module-gitlab-org/package.json index 6240674608..1d455b84a5 100644 --- a/plugins/catalog-backend-module-gitlab-org/package.json +++ b/plugins/catalog-backend-module-gitlab-org/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-gitlab-org", - "version": "0.2.10-next.1", + "version": "0.2.10", "description": "The gitlab-org backend module for the catalog plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-gitlab/CHANGELOG.md b/plugins/catalog-backend-module-gitlab/CHANGELOG.md index 790d906cd9..5725caf17a 100644 --- a/plugins/catalog-backend-module-gitlab/CHANGELOG.md +++ b/plugins/catalog-backend-module-gitlab/CHANGELOG.md @@ -1,5 +1,42 @@ # @backstage/plugin-catalog-backend-module-gitlab +## 0.7.0 + +### Minor Changes + +- 42bb3b8: **BREAKING CHANGE**: User and Group discovery will default to ingesting all users in sub groups that belong to the specified root group in config. Disable by setting `restrictUsersToGroup: true` in app-config under your module settings. + +### Patch Changes + +- 57a0bad: Implement retry for GitLab API calls to handle rate limiting +- Updated dependencies + - @backstage/backend-defaults@0.11.0 + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/integration@1.17.0 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-events-node@0.4.12 + +## 0.7.0-next.2 + +### Minor Changes + +- 42bb3b8: **BREAKING CHANGE**: User and Group discovery will default to ingesting all users in sub groups that belong to the specified root group in config. Disable by setting `restrictUsersToGroup: true` in app-config under your module settings. + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.11.0-next.2 + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/integration@1.17.0 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-catalog-node@1.17.1-next.1 + - @backstage/plugin-events-node@0.4.12-next.1 + ## 0.6.7-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-gitlab/package.json b/plugins/catalog-backend-module-gitlab/package.json index 6dea628d79..3cc3862610 100644 --- a/plugins/catalog-backend-module-gitlab/package.json +++ b/plugins/catalog-backend-module-gitlab/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-gitlab", - "version": "0.6.7-next.1", + "version": "0.7.0", "description": "A Backstage catalog backend module that helps integrate towards GitLab", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-incremental-ingestion/CHANGELOG.md b/plugins/catalog-backend-module-incremental-ingestion/CHANGELOG.md index 1bb1971898..a31aadc3b8 100644 --- a/plugins/catalog-backend-module-incremental-ingestion/CHANGELOG.md +++ b/plugins/catalog-backend-module-incremental-ingestion/CHANGELOG.md @@ -1,5 +1,37 @@ # @backstage/plugin-catalog-backend-module-incremental-ingestion +## 0.7.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.11.0 + - @backstage/plugin-catalog-backend@2.1.0 + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/plugin-events-node@0.4.12 + - @backstage/plugin-permission-common@0.9.0 + +## 0.7.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.11.0-next.2 + - @backstage/plugin-catalog-backend@2.0.1-next.2 + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/plugin-catalog-node@1.17.1-next.1 + - @backstage/plugin-events-node@0.4.12-next.1 + - @backstage/plugin-permission-common@0.9.0 + ## 0.7.1-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-incremental-ingestion/package.json b/plugins/catalog-backend-module-incremental-ingestion/package.json index b4cb22eb36..fd29be61ea 100644 --- a/plugins/catalog-backend-module-incremental-ingestion/package.json +++ b/plugins/catalog-backend-module-incremental-ingestion/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-incremental-ingestion", - "version": "0.7.1-next.1", + "version": "0.7.1", "description": "An entity provider for streaming large asset sources into the catalog", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-ldap/CHANGELOG.md b/plugins/catalog-backend-module-ldap/CHANGELOG.md index 53039b1260..1486c92d05 100644 --- a/plugins/catalog-backend-module-ldap/CHANGELOG.md +++ b/plugins/catalog-backend-module-ldap/CHANGELOG.md @@ -1,5 +1,54 @@ # @backstage/plugin-catalog-backend-module-ldap +## 0.11.6 + +### Patch Changes + +- 087d51d: Export LDAP vendor types and instances for testing custom transformers +- f07b0ad: Added the ability to configure disabling one side of the relations tree with LDAP. + + Groups have a `member` attribute and users have a `memberOf` attribute, however these can drift out of sync in some LDAP installations, leaving weird states in the Catalog as we collate these results together and deduplicate them. + + You can chose to optionally disable one side of these relationships, or even both by setting the respective mapping to `null` in your `app-config.yaml` for your groups and/or users: + + ```yaml + catalog: + providers: + ldapOrg: + default: + target: ldaps://ds.example.net + bind: + dn: uid=ldap-reader-user,ou=people,ou=example,dc=example,dc=net + secret: ${LDAP_SECRET} + users: + - dn: ou=people,ou=example,dc=example,dc=net + options: + filter: (uid=*) + map: + # this ensures that outgoing memberships from users is ignored + memberOf: null + groups: + - dn: ou=access,ou=groups,ou=example,dc=example,dc=net + options: + filter: (&(objectClass=some-group-class)(!(groupType=email))) + map: + description: l + set: + metadata.customField: 'hello' + map: + # this ensures that outgoing memberships from groups is ignored + members: null + ``` + +- Updated dependencies + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/plugin-catalog-common@1.1.4 + ## 0.11.6-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-ldap/config.d.ts b/plugins/catalog-backend-module-ldap/config.d.ts index 8bd8623891..f9b49eabee 100644 --- a/plugins/catalog-backend-module-ldap/config.d.ts +++ b/plugins/catalog-backend-module-ldap/config.d.ts @@ -141,7 +141,7 @@ export interface Config { * The name of the attribute that shall be used for the values of * the spec.memberOf field of the entity. Defaults to "memberOf". */ - memberOf?: string; + memberOf?: string | null; }; } | Array<{ @@ -221,7 +221,7 @@ export interface Config { * The name of the attribute that shall be used for the values of * the spec.memberOf field of the entity. Defaults to "memberOf". */ - memberOf?: string; + memberOf?: string | null; }; }>; @@ -311,12 +311,12 @@ export interface Config { * The name of the attribute that shall be used for the values of * the spec.parent field of the entity. Defaults to "memberOf". */ - memberOf?: string; + memberOf?: string | null; /** * The name of the attribute that shall be used for the values of * the spec.children field of the entity. Defaults to "member". */ - members?: string; + members?: string | null; }; } | Array<{ @@ -401,12 +401,12 @@ export interface Config { * The name of the attribute that shall be used for the values of * the spec.parent field of the entity. Defaults to "memberOf". */ - memberOf?: string; + memberOf?: string | null; /** * The name of the attribute that shall be used for the values of * the spec.children field of the entity. Defaults to "member". */ - members?: string; + members?: string | null; }; }>; /** @@ -556,7 +556,7 @@ export interface Config { * The name of the attribute that shall be used for the values of * the spec.memberOf field of the entity. Defaults to "memberOf". */ - memberOf?: string; + memberOf?: string | null; }; } | Array<{ @@ -588,6 +588,7 @@ export interface Config { pagePause?: boolean; }; }; + /** * JSON paths (on a.b.c form) and hard coded values to set on those * paths. @@ -636,7 +637,7 @@ export interface Config { * The name of the attribute that shall be used for the values of * the spec.memberOf field of the entity. Defaults to "memberOf". */ - memberOf?: string; + memberOf?: string | null; }; }>; @@ -726,12 +727,12 @@ export interface Config { * The name of the attribute that shall be used for the values of * the spec.parent field of the entity. Defaults to "memberOf". */ - memberOf?: string; + memberOf?: string | null; /** * The name of the attribute that shall be used for the values of * the spec.children field of the entity. Defaults to "member". */ - members?: string; + members?: string | null; }; } | Array<{ @@ -816,12 +817,12 @@ export interface Config { * The name of the attribute that shall be used for the values of * the spec.parent field of the entity. Defaults to "memberOf". */ - memberOf?: string; + memberOf?: string | null; /** * The name of the attribute that shall be used for the values of * the spec.children field of the entity. Defaults to "member". */ - members?: string; + members?: string | null; }; }>; @@ -926,7 +927,6 @@ export interface Config { * paths. * * This can be useful for example if you want to hard code a - * namespace or similar on the generated entities. */ set?: { [key: string]: JsonValue }; /** @@ -969,7 +969,7 @@ export interface Config { * The name of the attribute that shall be used for the values of * the spec.memberOf field of the entity. Defaults to "memberOf". */ - memberOf?: string; + memberOf?: string | null; }; }; @@ -1006,6 +1006,7 @@ export interface Config { }; }; /** + * @default false * JSON paths (on a.b.c form) and hard coded values to set on those * paths. * @@ -1058,12 +1059,12 @@ export interface Config { * The name of the attribute that shall be used for the values of * the spec.parent field of the entity. Defaults to "memberOf". */ - memberOf?: string; + memberOf?: string | null; /** * The name of the attribute that shall be used for the values of * the spec.children field of the entity. Defaults to "member". */ - members?: string; + members?: string | null; }; }; /** diff --git a/plugins/catalog-backend-module-ldap/package.json b/plugins/catalog-backend-module-ldap/package.json index a5d22ba3f5..cae1834b8d 100644 --- a/plugins/catalog-backend-module-ldap/package.json +++ b/plugins/catalog-backend-module-ldap/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-ldap", - "version": "0.11.6-next.1", + "version": "0.11.6", "description": "A Backstage catalog backend module that helps integrate towards LDAP", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-ldap/report.api.md b/plugins/catalog-backend-module-ldap/report.api.md index 16546cb773..c5eddd8778 100644 --- a/plugins/catalog-backend-module-ldap/report.api.md +++ b/plugins/catalog-backend-module-ldap/report.api.md @@ -63,8 +63,8 @@ export type GroupConfig = { displayName: string; email?: string; picture?: string; - memberOf: string; - members: string; + memberOf: string | null; + members: string | null; }; }; @@ -259,7 +259,7 @@ export type UserConfig = { displayName: string; email: string; picture?: string; - memberOf: string; + memberOf: string | null; }; }; @@ -275,4 +275,14 @@ export type VendorConfig = { dnAttributeName?: string; uuidAttributeName?: string; }; + +// @public +export const vendors: { + readonly activeDirectory: LdapVendor; + readonly aeDir: LdapVendor; + readonly freeIpa: LdapVendor; + readonly googleLdap: LdapVendor; + readonly lldap: LdapVendor; + readonly default: LdapVendor; +}; ``` diff --git a/plugins/catalog-backend-module-ldap/src/ldap/config.ts b/plugins/catalog-backend-module-ldap/src/ldap/config.ts index 6fdf682b42..8c7fd0dda5 100644 --- a/plugins/catalog-backend-module-ldap/src/ldap/config.ts +++ b/plugins/catalog-backend-module-ldap/src/ldap/config.ts @@ -90,6 +90,7 @@ export type UserConfig = { // Only the scope, filter, attributes, and paged fields are supported. The // default is scope "one" and attributes "*" and "+". options: SearchOptions; + // JSON paths (on a.b.c form) and hard coded values to set on those paths set?: { [path: string]: JsonValue }; // Mappings from well known entity fields, to LDAP attribute names @@ -114,7 +115,7 @@ export type UserConfig = { picture?: string; // The name of the attribute that shall be used for the values of the // spec.memberOf field of the entity. Defaults to "memberOf". - memberOf: string; + memberOf: string | null; }; }; @@ -129,6 +130,7 @@ export type GroupConfig = { // The search options to use. // Only the scope, filter, attributes, and paged fields are supported. options: SearchOptions; + // JSON paths (on a.b.c form) and hard coded values to set on those paths set?: { [path: string]: JsonValue }; // Mappings from well known entity fields, to LDAP attribute names @@ -156,10 +158,10 @@ export type GroupConfig = { picture?: string; // The name of the attribute that shall be used for the values of the // spec.parent field of the entity. Defaults to "memberOf". - memberOf: string; + memberOf: string | null; // The name of the attribute that shall be used for the values of the // spec.children field of the entity. Defaults to "member". - members: string; + members: string | null; }; }; diff --git a/plugins/catalog-backend-module-ldap/src/ldap/index.ts b/plugins/catalog-backend-module-ldap/src/ldap/index.ts index 6d8fbd06d6..800ebec316 100644 --- a/plugins/catalog-backend-module-ldap/src/ldap/index.ts +++ b/plugins/catalog-backend-module-ldap/src/ldap/index.ts @@ -13,6 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import { + ActiveDirectoryVendor, + AEDirVendor, + DefaultLdapVendor, + FreeIpaVendor, + GoogleLdapVendor, + LdapVendor, + LLDAPVendor, +} from './vendors'; export { LdapClient } from './client'; export { mapStringAttr } from './util'; @@ -37,3 +46,16 @@ export { readLdapOrg, } from './read'; export type { GroupTransformer, UserTransformer } from './types'; +/** + * An LDAP Vendor types. + * + * @public + */ +export const vendors = { + activeDirectory: ActiveDirectoryVendor as LdapVendor, + aeDir: AEDirVendor as LdapVendor, + freeIpa: FreeIpaVendor as LdapVendor, + googleLdap: GoogleLdapVendor as LdapVendor, + lldap: LLDAPVendor as LdapVendor, + default: DefaultLdapVendor as LdapVendor, +} as const; diff --git a/plugins/catalog-backend-module-ldap/src/ldap/read.test.ts b/plugins/catalog-backend-module-ldap/src/ldap/read.test.ts index 4e4f4f7cfd..374cc2afd0 100644 --- a/plugins/catalog-backend-module-ldap/src/ldap/read.test.ts +++ b/plugins/catalog-backend-module-ldap/src/ldap/read.test.ts @@ -210,6 +210,53 @@ describe('readLdapUsers', () => { ); }); + it('should allow skipping memberOf', async () => { + client.getVendor.mockResolvedValue(DefaultLdapVendor); + client.searchStreaming.mockImplementation(async (_dn, _opts, fn) => { + await fn(searchEntry({ memberOf: ['x', 'y', 'z'] })); + }); + + client.getVendor.mockResolvedValue(DefaultLdapVendor); + client.searchStreaming.mockImplementation(async (_dn, _opts, fn) => { + await fn( + searchEntry({ + uid: ['uid-value'], + description: ['description-value'], + cn: ['cn-value'], + mail: ['mail-value'], + avatarUrl: ['avatarUrl-value'], + memberOf: ['x', 'y', 'z'], + customDN: ['dn-value'], + customUUID: ['uuid-value'], + }), + ); + }); + const config: UserConfig[] = [ + { + dn: 'ddd', + options: {}, + + map: { + rdn: 'uid', + name: 'uid', + description: 'description', + displayName: 'cn', + email: 'mail', + picture: 'avatarUrl', + memberOf: null, + }, + }, + ]; + + const vendorConfig: VendorConfig = { + dnAttributeName: 'customDN', + uuidAttributeName: 'customUUID', + }; + + const { userMemberOf } = await readLdapUsers(client, config, vendorConfig); + expect(userMemberOf.size).toBe(0); + }); + it('transfers all attributes from Microsoft Active Directory', async () => { client.getVendor.mockResolvedValue(ActiveDirectoryVendor); client.searchStreaming.mockImplementation(async (_dn, _opts, fn) => { @@ -729,6 +776,51 @@ describe('readLdapGroups', () => { ); }); + it('should allow skipping members', async () => { + client.getVendor.mockResolvedValue(DefaultLdapVendor); + client.searchStreaming.mockImplementation(async (_dn, _opts, fn) => { + await fn( + searchEntry({ + cn: ['cn-value'], + description: ['description-value'], + tt: ['type-value'], + mail: ['mail-value'], + avatarUrl: ['avatarUrl-value'], + memberOf: ['x', 'y', 'z'], + member: ['e', 'f', 'g'], + customDN: ['dn-value'], + customUUID: ['uuid-value'], + }), + ); + }); + const config: GroupConfig[] = [ + { + dn: 'ddd', + options: {}, + map: { + rdn: 'cn', + name: 'cn', + description: 'description', + displayName: 'cn', + email: 'mail', + picture: 'avatarUrl', + type: 'tt', + memberOf: 'memberOf', + members: null, + }, + }, + ]; + + const vendorConfig: VendorConfig = { + dnAttributeName: 'customDN', + uuidAttributeName: 'customUUID', + }; + + const { groupMember } = await readLdapGroups(client, config, vendorConfig); + + expect(groupMember.size).toBe(0); + }); + it('can process a list of GroupConfigs', async () => { client.getVendor.mockResolvedValue(DefaultLdapVendor); client.searchStreaming.mockImplementation(async (_dn, _opts, fn) => { diff --git a/plugins/catalog-backend-module-ldap/src/ldap/read.ts b/plugins/catalog-backend-module-ldap/src/ldap/read.ts index 9b9041913d..a3f3ce1e75 100644 --- a/plugins/catalog-backend-module-ldap/src/ldap/read.ts +++ b/plugins/catalog-backend-module-ldap/src/ldap/read.ts @@ -146,6 +146,7 @@ export async function readLdapUsers( mapReferencesAttr(user, vendor, map.memberOf, (myDn, vs) => { ensureItems(userMemberOf, myDn, vs); }); + entities.push(entity); }); } @@ -277,6 +278,7 @@ export async function readLdapGroups( mapReferencesAttr(entry, vendor, map.memberOf, (myDn, vs) => { ensureItems(groupMemberOf, myDn, vs); }); + mapReferencesAttr(entry, vendor, map.members, (myDn, vs) => { ensureItems(groupMember, myDn, vs); }); @@ -349,7 +351,7 @@ export async function readLdapOrg( function mapReferencesAttr( entry: SearchEntry, vendor: LdapVendor, - attributeName: string | undefined, + attributeName: string | undefined | null, setter: (sourceDn: string, targets: string[]) => void, ) { if (attributeName) { diff --git a/plugins/catalog-backend-module-logs/CHANGELOG.md b/plugins/catalog-backend-module-logs/CHANGELOG.md index 5795eb8023..16aa0436e0 100644 --- a/plugins/catalog-backend-module-logs/CHANGELOG.md +++ b/plugins/catalog-backend-module-logs/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-catalog-backend-module-logs +## 0.1.11 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@2.1.0 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/plugin-events-node@0.4.12 + +## 0.1.11-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@2.0.1-next.2 + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/plugin-events-node@0.4.12-next.1 + ## 0.1.11-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-logs/package.json b/plugins/catalog-backend-module-logs/package.json index c21f08cfa5..fa0b89de25 100644 --- a/plugins/catalog-backend-module-logs/package.json +++ b/plugins/catalog-backend-module-logs/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-logs", - "version": "0.1.11-next.1", + "version": "0.1.11", "description": "A module that subscribes to catalog related events and logs them.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-msgraph/CHANGELOG.md b/plugins/catalog-backend-module-msgraph/CHANGELOG.md index 9e495277c3..b844e52e5b 100644 --- a/plugins/catalog-backend-module-msgraph/CHANGELOG.md +++ b/plugins/catalog-backend-module-msgraph/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-catalog-backend-module-msgraph +## 0.7.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/plugin-catalog-common@1.1.4 + ## 0.7.1-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-msgraph/package.json b/plugins/catalog-backend-module-msgraph/package.json index 67285b2897..34b472b500 100644 --- a/plugins/catalog-backend-module-msgraph/package.json +++ b/plugins/catalog-backend-module-msgraph/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-msgraph", - "version": "0.7.1-next.1", + "version": "0.7.1", "description": "A Backstage catalog backend module that helps integrate towards Microsoft Graph", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-openapi/CHANGELOG.md b/plugins/catalog-backend-module-openapi/CHANGELOG.md index 0db664e8c8..5fe46b66d9 100644 --- a/plugins/catalog-backend-module-openapi/CHANGELOG.md +++ b/plugins/catalog-backend-module-openapi/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-catalog-backend-module-openapi +## 0.2.11 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/catalog-model@1.7.4 + - @backstage/integration@1.17.0 + - @backstage/types@1.2.1 + - @backstage/plugin-catalog-common@1.1.4 + ## 0.2.11-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-openapi/package.json b/plugins/catalog-backend-module-openapi/package.json index 742cf6e796..34acb98afb 100644 --- a/plugins/catalog-backend-module-openapi/package.json +++ b/plugins/catalog-backend-module-openapi/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-openapi", - "version": "0.2.11-next.1", + "version": "0.2.11", "description": "A Backstage catalog backend module that helps with OpenAPI specifications", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-puppetdb/CHANGELOG.md b/plugins/catalog-backend-module-puppetdb/CHANGELOG.md index f1c0618cc8..db9f89b5d3 100644 --- a/plugins/catalog-backend-module-puppetdb/CHANGELOG.md +++ b/plugins/catalog-backend-module-puppetdb/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-catalog-backend-module-puppetdb +## 0.2.11 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + ## 0.2.11-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-puppetdb/package.json b/plugins/catalog-backend-module-puppetdb/package.json index 0df55cbbe0..04f83433e9 100644 --- a/plugins/catalog-backend-module-puppetdb/package.json +++ b/plugins/catalog-backend-module-puppetdb/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-puppetdb", - "version": "0.2.11-next.1", + "version": "0.2.11", "description": "A Backstage catalog backend module that helps integrate towards PuppetDB", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-scaffolder-entity-model/CHANGELOG.md b/plugins/catalog-backend-module-scaffolder-entity-model/CHANGELOG.md index 1eacdb3f61..ac96e7a98c 100644 --- a/plugins/catalog-backend-module-scaffolder-entity-model/CHANGELOG.md +++ b/plugins/catalog-backend-module-scaffolder-entity-model/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-catalog-backend-module-scaffolder-entity-model +## 0.2.9 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/catalog-model@1.7.4 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-scaffolder-common@1.5.11 + ## 0.2.9-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-scaffolder-entity-model/package.json b/plugins/catalog-backend-module-scaffolder-entity-model/package.json index 2c78f3f07c..3e01eb7b24 100644 --- a/plugins/catalog-backend-module-scaffolder-entity-model/package.json +++ b/plugins/catalog-backend-module-scaffolder-entity-model/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-scaffolder-entity-model", - "version": "0.2.9-next.1", + "version": "0.2.9", "description": "Adds support for the scaffolder specific entity model (e.g. the Template kind) to the catalog backend plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-unprocessed/CHANGELOG.md b/plugins/catalog-backend-module-unprocessed/CHANGELOG.md index 87e43914b0..519f0542d0 100644 --- a/plugins/catalog-backend-module-unprocessed/CHANGELOG.md +++ b/plugins/catalog-backend-module-unprocessed/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-catalog-backend-module-unprocessed +## 0.6.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/catalog-model@1.7.4 + - @backstage/errors@1.2.7 + - @backstage/plugin-catalog-unprocessed-entities-common@0.0.8 + - @backstage/plugin-permission-common@0.9.0 + ## 0.6.1-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-unprocessed/package.json b/plugins/catalog-backend-module-unprocessed/package.json index f8a7d529b1..0c14e41a28 100644 --- a/plugins/catalog-backend-module-unprocessed/package.json +++ b/plugins/catalog-backend-module-unprocessed/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-unprocessed", - "version": "0.6.1-next.1", + "version": "0.6.1", "description": "Backstage Catalog module to view unprocessed entities", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend/CHANGELOG.md b/plugins/catalog-backend/CHANGELOG.md index e09921bb01..5bdf7ce965 100644 --- a/plugins/catalog-backend/CHANGELOG.md +++ b/plugins/catalog-backend/CHANGELOG.md @@ -1,5 +1,51 @@ # @backstage/plugin-catalog-backend +## 2.1.0 + +### Minor Changes + +- 2e7adf0: Implement the action `get-catalog-entity` with the `ActionsRegistry` + +### Patch Changes + +- 2cac8b0: You can now specify an optional value when applying the `HAS_LABEL` permission rule, similar to the `HAS_ANNOTATION` permission rule. +- c83cd8b: Fixed some circular or otherwise unclear imports +- 4654a78: Update `refresh_state_references.id` to be a big int +- Updated dependencies + - @backstage/catalog-client@1.10.1 + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/backend-openapi-utils@0.5.4 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + - @backstage/types@1.2.1 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-events-node@0.4.12 + - @backstage/plugin-permission-common@0.9.0 + - @backstage/plugin-permission-node@0.10.1 + +## 2.0.1-next.2 + +### Patch Changes + +- 2cac8b0: You can now specify an optional value when applying the `HAS_LABEL` permission rule, similar to the `HAS_ANNOTATION` permission rule. +- Updated dependencies + - @backstage/backend-openapi-utils@0.5.4-next.1 + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/catalog-client@1.10.1-next.0 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + - @backstage/types@1.2.1 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-catalog-node@1.17.1-next.1 + - @backstage/plugin-events-node@0.4.12-next.1 + - @backstage/plugin-permission-common@0.9.0 + - @backstage/plugin-permission-node@0.10.1-next.1 + ## 2.0.1-next.1 ### Patch Changes diff --git a/plugins/catalog-backend/package.json b/plugins/catalog-backend/package.json index 8547858f65..aac1b0779c 100644 --- a/plugins/catalog-backend/package.json +++ b/plugins/catalog-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend", - "version": "2.0.1-next.1", + "version": "2.1.0", "description": "The Backstage backend plugin that provides the Backstage catalog", "backstage": { "role": "backend-plugin", diff --git a/plugins/catalog-backend/src/actions/createGetCatalogEntityAction.test.ts b/plugins/catalog-backend/src/actions/createGetCatalogEntityAction.test.ts new file mode 100644 index 0000000000..ed8aec264d --- /dev/null +++ b/plugins/catalog-backend/src/actions/createGetCatalogEntityAction.test.ts @@ -0,0 +1,78 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { createGetCatalogEntityAction } from './createGetCatalogEntityAction'; +import { catalogServiceMock } from '@backstage/plugin-catalog-node/testUtils'; +import { actionsRegistryServiceMock } from '@backstage/backend-test-utils/alpha'; + +describe('createGetCatalogEntityAction', () => { + it('should throw an error if the entity is not found', async () => { + const mockActionsRegistry = actionsRegistryServiceMock(); + const mockCatalog = catalogServiceMock(); + + createGetCatalogEntityAction({ + catalog: mockCatalog, + actionsRegistry: mockActionsRegistry, + }); + + await expect( + mockActionsRegistry.invoke({ + id: 'test:get-catalog-entity', + input: { name: 'test' }, + }), + ).rejects.toThrow(`No entity found with name "test"`); + }); + + it('should throw an error if theres multiple entities found', async () => { + const mockActionsRegistry = actionsRegistryServiceMock(); + const mockCatalog = catalogServiceMock({ + entities: [ + { + kind: 'Component', + apiVersion: 'backstage.io/v1alpha1', + metadata: { + name: 'test', + namespace: 'default', + }, + spec: { + type: 'component', + }, + }, + { + kind: 'API', + apiVersion: 'backstage.io/v1alpha1', + metadata: { + name: 'test', + namespace: 'default', + }, + }, + ], + }); + + createGetCatalogEntityAction({ + catalog: mockCatalog, + actionsRegistry: mockActionsRegistry, + }); + + await expect( + mockActionsRegistry.invoke({ + id: 'test:get-catalog-entity', + input: { name: 'test' }, + }), + ).rejects.toThrow( + `Multiple entities found with name "test", please provide more specific filters. Entities found: "component:default/test", "api:default/test"`, + ); + }); +}); diff --git a/plugins/catalog-backend/src/actions/createGetCatalogEntityAction.ts b/plugins/catalog-backend/src/actions/createGetCatalogEntityAction.ts new file mode 100644 index 0000000000..da33064c08 --- /dev/null +++ b/plugins/catalog-backend/src/actions/createGetCatalogEntityAction.ts @@ -0,0 +1,95 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { ActionsRegistryService } from '@backstage/backend-plugin-api/alpha'; +import { stringifyEntityRef } from '@backstage/catalog-model'; +import { InputError } from '@backstage/errors'; +import { CatalogService } from '@backstage/plugin-catalog-node'; + +export const createGetCatalogEntityAction = ({ + catalog, + actionsRegistry, +}: { + catalog: CatalogService; + actionsRegistry: ActionsRegistryService; +}) => { + actionsRegistry.register({ + name: 'get-catalog-entity', + title: 'Get Catalog Entity', + description: ` +This allows you to get a single entity from the software catalog. +Each entity in the software catalog has a unique name, kind, and namespace. The default namespace is "default". +Each entity is identified by a unique entity reference, which is a string of the form "kind:namespace/name". + `, + schema: { + input: z => + z.object({ + kind: z + .string() + .describe( + 'The kind of the entity to query. If the kind is unknown it can be omitted.', + ) + .optional(), + namespace: z + .string() + .describe( + 'The namespace of the entity to query. If the namespace is unknown it can be omitted.', + ) + .optional(), + name: z.string().describe('The name of the entity to query'), + }), + // TODO: is there a better way to do this? + output: z => z.object({}).passthrough(), + }, + action: async ({ input, credentials }) => { + const filter: Record = { 'metadata.name': input.name }; + + if (input.kind) { + filter.kind = input.kind; + } + + if (input.namespace) { + filter['metadata.namespace'] = input.namespace; + } + + const { items } = await catalog.queryEntities( + { filter }, + { + credentials, + }, + ); + + if (items.length === 0) { + throw new InputError(`No entity found with name "${input.name}"`); + } + + if (items.length > 1) { + throw new Error( + `Multiple entities found with name "${ + input.name + }", please provide more specific filters. Entities found: ${items + .map(item => `"${stringifyEntityRef(item)}"`) + .join(', ')}`, + ); + } + + const [entity] = items; + + return { + output: entity, + }; + }, + }); +}; diff --git a/plugins/catalog-backend/src/schema/openapi/generated/router.ts b/plugins/catalog-backend/src/schema/openapi/generated/router.ts index 67eb1a699e..d32ef0a4de 100644 --- a/plugins/catalog-backend/src/schema/openapi/generated/router.ts +++ b/plugins/catalog-backend/src/schema/openapi/generated/router.ts @@ -18,7 +18,7 @@ // * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * // ****************************************************************** import { createValidatedOpenApiRouterFromGeneratedEndpointMap } from '@backstage/backend-openapi-utils'; -import { EndpointMap } from './'; +import { EndpointMap } from './apis'; export const spec = { openapi: '3.0.3', diff --git a/plugins/catalog-backend/src/service/CatalogPlugin.ts b/plugins/catalog-backend/src/service/CatalogPlugin.ts index 9925f11c7b..a9bb2c9285 100644 --- a/plugins/catalog-backend/src/service/CatalogPlugin.ts +++ b/plugins/catalog-backend/src/service/CatalogPlugin.ts @@ -22,6 +22,7 @@ import { ForwardedError } from '@backstage/errors'; import { CatalogProcessor, CatalogProcessorParser, + catalogServiceRef, EntityProvider, LocationAnalyzer, PlaceholderResolver, @@ -43,6 +44,8 @@ import { eventsServiceRef } from '@backstage/plugin-events-node'; import { Permission } from '@backstage/plugin-permission-common'; import { merge } from 'lodash'; import { CatalogBuilder } from './CatalogBuilder'; +import { actionsRegistryServiceRef } from '@backstage/backend-plugin-api/alpha'; +import { createGetCatalogEntityAction } from '../actions/createGetCatalogEntityAction'; class CatalogLocationsExtensionPointImpl implements CatalogLocationsExtensionPoint @@ -237,6 +240,8 @@ export const catalogPlugin = createBackendPlugin({ httpAuth: coreServices.httpAuth, auditor: coreServices.auditor, events: eventsServiceRef, + catalog: catalogServiceRef, + actionsRegistry: actionsRegistryServiceRef, }, async init({ logger, @@ -250,6 +255,8 @@ export const catalogPlugin = createBackendPlugin({ scheduler, auth, httpAuth, + catalog, + actionsRegistry, auditor, events, }) { @@ -313,6 +320,11 @@ export const catalogPlugin = createBackendPlugin({ } httpRouter.use(router); + + createGetCatalogEntityAction({ + catalog, + actionsRegistry, + }); }, }); }, diff --git a/plugins/catalog-backend/src/service/createRouter.test.ts b/plugins/catalog-backend/src/service/createRouter.test.ts index b0dddbdef0..193d5b5b52 100644 --- a/plugins/catalog-backend/src/service/createRouter.test.ts +++ b/plugins/catalog-backend/src/service/createRouter.test.ts @@ -56,7 +56,7 @@ describe('createRouter readonly disabled', () => { let app: express.Express | Server; let refreshService: RefreshService; let locationAnalyzer: jest.Mocked; - const permissionsService = mockServices.permissions.mock(); + const permissionsService = mockServices.permissions(); beforeEach(async () => { entitiesCatalog = { @@ -799,12 +799,6 @@ describe('createRouter readonly disabled', () => { metadata: { name: 'n' }, }; - permissionsService.authorize.mockResolvedValueOnce([ - { - result: AuthorizeResult.ALLOW, - }, - ]); - orchestrator.process.mockResolvedValueOnce({ ok: true, state: {}, @@ -845,12 +839,6 @@ describe('createRouter readonly disabled', () => { metadata: { name: 'invalid*name' }, }; - permissionsService.authorize.mockResolvedValueOnce([ - { - result: AuthorizeResult.ALLOW, - }, - ]); - orchestrator.process.mockResolvedValueOnce({ ok: false, errors: [new Error('Invalid entity name')], @@ -888,12 +876,6 @@ describe('createRouter readonly disabled', () => { metadata: { name: 'n' }, }; - permissionsService.authorize.mockResolvedValueOnce([ - { - result: AuthorizeResult.ALLOW, - }, - ]); - const response = await request(app) .post('/validate-entity') .send({ entity, location: null }); @@ -940,7 +922,7 @@ describe('createRouter readonly and raw json enabled', () => { let entitiesCatalog: jest.Mocked; let app: express.Express; let locationService: jest.Mocked; - const permissionsService = mockServices.permissions.mock(); + const permissionsService = mockServices.permissions(); beforeAll(async () => { entitiesCatalog = { @@ -1144,7 +1126,7 @@ describe('NextRouter permissioning', () => { let locationService: jest.Mocked; let app: express.Express; let refreshService: RefreshService; - const permissionsService = mockServices.permissions.mock(); + const permissionsService = mockServices.permissions(); const fakeRule = createPermissionRule({ name: 'FAKE_RULE', diff --git a/plugins/catalog-graph/CHANGELOG.md b/plugins/catalog-graph/CHANGELOG.md index c1be6d3076..3b55716ecc 100644 --- a/plugins/catalog-graph/CHANGELOG.md +++ b/plugins/catalog-graph/CHANGELOG.md @@ -1,5 +1,34 @@ # @backstage/plugin-catalog-graph +## 0.4.20 + +### Patch Changes + +- 18c64e9: Added the `info.packageJson` option to the plugin instance for the new frontend system. +- Updated dependencies + - @backstage/core-components@0.17.3 + - @backstage/catalog-client@1.10.1 + - @backstage/core-plugin-api@1.10.8 + - @backstage/frontend-plugin-api@0.10.3 + - @backstage/plugin-catalog-react@1.19.0 + - @backstage/catalog-model@1.7.4 + - @backstage/core-compat-api@0.4.3 + - @backstage/types@1.2.1 + +## 0.4.20-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/plugin-catalog-react@1.19.0-next.2 + - @backstage/frontend-plugin-api@0.10.3-next.1 + - @backstage/catalog-client@1.10.1-next.0 + - @backstage/catalog-model@1.7.4 + - @backstage/core-compat-api@0.4.3-next.2 + - @backstage/core-plugin-api@1.10.7 + - @backstage/types@1.2.1 + ## 0.4.20-next.1 ### Patch Changes diff --git a/plugins/catalog-graph/package.json b/plugins/catalog-graph/package.json index f7cdb8c4bc..019ce8421d 100644 --- a/plugins/catalog-graph/package.json +++ b/plugins/catalog-graph/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-graph", - "version": "0.4.20-next.1", + "version": "0.4.20", "backstage": { "role": "frontend-plugin", "pluginId": "catalog-graph", diff --git a/plugins/catalog-import/CHANGELOG.md b/plugins/catalog-import/CHANGELOG.md index dfb001c4d7..1fb4f81f6d 100644 --- a/plugins/catalog-import/CHANGELOG.md +++ b/plugins/catalog-import/CHANGELOG.md @@ -1,5 +1,44 @@ # @backstage/plugin-catalog-import +## 0.13.1 + +### Patch Changes + +- 18c64e9: Added the `info.packageJson` option to the plugin instance for the new frontend system. +- 5d7c539: Catalog import plugin full support i18n +- Updated dependencies + - @backstage/core-components@0.17.3 + - @backstage/catalog-client@1.10.1 + - @backstage/core-plugin-api@1.10.8 + - @backstage/frontend-plugin-api@0.10.3 + - @backstage/plugin-catalog-react@1.19.0 + - @backstage/integration-react@1.2.8 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/core-compat-api@0.4.3 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + - @backstage/plugin-catalog-common@1.1.4 + +## 0.13.1-next.2 + +### Patch Changes + +- 5d7c539: Catalog import plugin full support i18n +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/plugin-catalog-react@1.19.0-next.2 + - @backstage/frontend-plugin-api@0.10.3-next.1 + - @backstage/integration-react@1.2.7 + - @backstage/catalog-client@1.10.1-next.0 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/core-compat-api@0.4.3-next.2 + - @backstage/core-plugin-api@1.10.7 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + - @backstage/plugin-catalog-common@1.1.4 + ## 0.13.1-next.1 ### Patch Changes diff --git a/plugins/catalog-import/package.json b/plugins/catalog-import/package.json index b20568c9f1..5598f2930c 100644 --- a/plugins/catalog-import/package.json +++ b/plugins/catalog-import/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-import", - "version": "0.13.1-next.1", + "version": "0.13.1", "description": "A Backstage plugin the helps you import entities into your catalog", "backstage": { "role": "frontend-plugin", diff --git a/plugins/catalog-import/src/components/StepInitAnalyzeUrl/StepInitAnalyzeUrl.test.tsx b/plugins/catalog-import/src/components/StepInitAnalyzeUrl/StepInitAnalyzeUrl.test.tsx index ed6fb5683f..e351acb28a 100644 --- a/plugins/catalog-import/src/components/StepInitAnalyzeUrl/StepInitAnalyzeUrl.test.tsx +++ b/plugins/catalog-import/src/components/StepInitAnalyzeUrl/StepInitAnalyzeUrl.test.tsx @@ -19,8 +19,8 @@ import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; import { act, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { ReactNode } from 'react'; -import { AnalyzeResult, catalogImportApiRef } from '../../api/'; import { StepInitAnalyzeUrl } from './StepInitAnalyzeUrl'; +import { AnalyzeResult, catalogImportApiRef } from '../../api/CatalogImportApi'; describe('', () => { const catalogImportApi: jest.Mocked = { diff --git a/plugins/catalog-node/CHANGELOG.md b/plugins/catalog-node/CHANGELOG.md index b42bb83c6f..648648167d 100644 --- a/plugins/catalog-node/CHANGELOG.md +++ b/plugins/catalog-node/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-catalog-node +## 1.17.1 + +### Patch Changes + +- 0169b23: Internal tweak to avoid circular dependencies +- Updated dependencies + - @backstage/catalog-client@1.10.1 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/catalog-model@1.7.4 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-permission-common@0.9.0 + - @backstage/plugin-permission-node@0.10.1 + ## 1.17.1-next.1 ### Patch Changes diff --git a/plugins/catalog-node/package.json b/plugins/catalog-node/package.json index bfe1bb218f..3bf8741b08 100644 --- a/plugins/catalog-node/package.json +++ b/plugins/catalog-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-node", - "version": "1.17.1-next.1", + "version": "1.17.1", "description": "The plugin-catalog-node module for @backstage/plugin-catalog-backend", "backstage": { "role": "node-library", diff --git a/plugins/catalog-node/src/api/provider.ts b/plugins/catalog-node/src/api/provider.ts index a576f32022..63f3f0bd09 100644 --- a/plugins/catalog-node/src/api/provider.ts +++ b/plugins/catalog-node/src/api/provider.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { DeferredEntity } from '../processing'; +import { DeferredEntity } from '../processing/types'; /** * A 'full' mutation replaces all existing entities created by this entity provider with new ones. diff --git a/plugins/catalog-node/src/processing/types.ts b/plugins/catalog-node/src/processing/types.ts index 625effc4df..d4255c1c51 100644 --- a/plugins/catalog-node/src/processing/types.ts +++ b/plugins/catalog-node/src/processing/types.ts @@ -21,7 +21,7 @@ import { AnalyzeLocationResponse, } from '@backstage/plugin-catalog-common'; import { JsonValue } from '@backstage/types'; -import { CatalogProcessorEmit } from '../api'; +import { CatalogProcessorEmit } from '../api/processor'; import { BackstageCredentials } from '@backstage/backend-plugin-api'; /** diff --git a/plugins/catalog-react/CHANGELOG.md b/plugins/catalog-react/CHANGELOG.md index 3caa6d7959..8ed8a2059b 100644 --- a/plugins/catalog-react/CHANGELOG.md +++ b/plugins/catalog-react/CHANGELOG.md @@ -1,5 +1,141 @@ # @backstage/plugin-catalog-react +## 1.19.0 + +### Minor Changes + +- 406acb6: Introduces a new `EntityIconLinkBlueprint` that customizes the `About` card icon links on the `Catalog` entity page. + + The blueprint currently accepts a `useProps` hook as `param` and this function returns the following props that will be passed to the icon link component: + + | Name | Description | Type | Default Value | + | ---------- | --------------------------------------------------- | ------------- | ------------- | + | `icon` | The icon to display. | `JSX.Element` | N/A | + | `label` | The label for the element. | `string` | N/A | + | `title` | The title for the element. | `string` | N/A | + | `disabled` | Whether the element is disabled. | `boolean` | `false` | + | `href` | The URL to navigate to when the element is clicked. | `string` | N/A | + | `onClick` | A function to call when the element is clicked. | `() => void` | N/A | + + Here is an usage example: + + ```tsx + import { EntityIconLinkBlueprint } from '@backstage/plugin-catalog-react/alpha'; + //... + + EntityIconLinkBlueprint.make({ + name: 'my-icon-link', + params: { + useProps() { + const { t } = useTranslationRef(myIconLinkTranslationRef); + return { + label: t('myIconLink.label'), + icon: , + href: '/my-plugin', + }; + }, + }, + }); + ``` + + Additionally, the `app-config.yaml` file allows you to override some of the default icon link parameters, including `label` and `title` values. Here's how to set them: + + ```yaml + app: + extensions: + - entity-icon-link:my-plugin/my-icon-link: + config: + label: 'My Custom Icon Link label' + ``` + + Finally, you can disable all links if you want to hide the About card header completely (useful, for example, when links are displayed on separate cards). The header is hidden when no icon links extensions are enabled. + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3 + - @backstage/catalog-client@1.10.1 + - @backstage/core-plugin-api@1.10.8 + - @backstage/frontend-plugin-api@0.10.3 + - @backstage/integration-react@1.2.8 + - @backstage/catalog-model@1.7.4 + - @backstage/core-compat-api@0.4.3 + - @backstage/errors@1.2.7 + - @backstage/frontend-test-utils@0.3.3 + - @backstage/types@1.2.1 + - @backstage/version-bridge@1.0.11 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-permission-common@0.9.0 + - @backstage/plugin-permission-react@0.4.35 + +## 1.19.0-next.2 + +### Minor Changes + +- 406acb6: Introduces a new `EntityIconLinkBlueprint` that customizes the `About` card icon links on the `Catalog` entity page. + + The blueprint currently accepts a `useProps` hook as `param` and this function returns the following props that will be passed to the icon link component: + + | Name | Description | Type | Default Value | + | ---------- | --------------------------------------------------- | ------------- | ------------- | + | `icon` | The icon to display. | `JSX.Element` | N/A | + | `label` | The label for the element. | `string` | N/A | + | `title` | The title for the element. | `string` | N/A | + | `disabled` | Whether the element is disabled. | `boolean` | `false` | + | `href` | The URL to navigate to when the element is clicked. | `string` | N/A | + | `onClick` | A function to call when the element is clicked. | `() => void` | N/A | + + Here is an usage example: + + ```tsx + import { EntityIconLinkBlueprint } from '@backstage/plugin-catalog-react/alpha'; + //... + + EntityIconLinkBlueprint.make({ + name: 'my-icon-link', + params: { + useProps() { + const { t } = useTranslationRef(myIconLinkTranslationRef); + return { + label: t('myIconLink.label'), + icon: , + href: '/my-plugin', + }; + }, + }, + }); + ``` + + Additionally, the `app-config.yaml` file allows you to override some of the default icon link parameters, including `label` and `title` values. Here's how to set them: + + ```yaml + app: + extensions: + - entity-icon-link:my-plugin/my-icon-link: + config: + label: 'My Custom Icon Link label' + ``` + + Finally, you can disable all links if you want to hide the About card header completely (useful, for example, when links are displayed on separate cards). The header is hidden when no icon links extensions are enabled. + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/frontend-plugin-api@0.10.3-next.1 + - @backstage/integration-react@1.2.7 + - @backstage/catalog-client@1.10.1-next.0 + - @backstage/catalog-model@1.7.4 + - @backstage/core-compat-api@0.4.3-next.2 + - @backstage/core-plugin-api@1.10.7 + - @backstage/errors@1.2.7 + - @backstage/frontend-test-utils@0.3.3-next.1 + - @backstage/types@1.2.1 + - @backstage/version-bridge@1.0.11 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-permission-common@0.9.0 + - @backstage/plugin-permission-react@0.4.34 + ## 1.18.1-next.1 ### Patch Changes diff --git a/plugins/catalog-react/package.json b/plugins/catalog-react/package.json index 9f5b7d7b3c..401067ca9b 100644 --- a/plugins/catalog-react/package.json +++ b/plugins/catalog-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-react", - "version": "1.18.1-next.1", + "version": "1.19.0", "description": "A frontend library that helps other Backstage plugins interact with the catalog", "backstage": { "role": "web-library", diff --git a/plugins/catalog-unprocessed-entities/CHANGELOG.md b/plugins/catalog-unprocessed-entities/CHANGELOG.md index cc82f793d5..407c1599b4 100644 --- a/plugins/catalog-unprocessed-entities/CHANGELOG.md +++ b/plugins/catalog-unprocessed-entities/CHANGELOG.md @@ -1,5 +1,30 @@ # @backstage/plugin-catalog-unprocessed-entities +## 0.2.18 + +### Patch Changes + +- 18c64e9: Added the `info.packageJson` option to the plugin instance for the new frontend system. +- Updated dependencies + - @backstage/core-components@0.17.3 + - @backstage/core-plugin-api@1.10.8 + - @backstage/frontend-plugin-api@0.10.3 + - @backstage/catalog-model@1.7.4 + - @backstage/core-compat-api@0.4.3 + - @backstage/errors@1.2.7 + +## 0.2.18-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/frontend-plugin-api@0.10.3-next.1 + - @backstage/catalog-model@1.7.4 + - @backstage/core-compat-api@0.4.3-next.2 + - @backstage/core-plugin-api@1.10.7 + - @backstage/errors@1.2.7 + ## 0.2.18-next.1 ### Patch Changes diff --git a/plugins/catalog-unprocessed-entities/package.json b/plugins/catalog-unprocessed-entities/package.json index 95ef6bc065..45fcc6f9a1 100644 --- a/plugins/catalog-unprocessed-entities/package.json +++ b/plugins/catalog-unprocessed-entities/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-unprocessed-entities", - "version": "0.2.18-next.1", + "version": "0.2.18", "backstage": { "role": "frontend-plugin", "pluginId": "catalog-unprocessed-entities", diff --git a/plugins/catalog/CHANGELOG.md b/plugins/catalog/CHANGELOG.md index d5f981432c..0b74c17faa 100644 --- a/plugins/catalog/CHANGELOG.md +++ b/plugins/catalog/CHANGELOG.md @@ -1,5 +1,72 @@ # @backstage/plugin-catalog +## 1.31.0 + +### Minor Changes + +- 406acb6: Add support to customize the about card icon links via `EntityIconLinkBlueprint` and provide a default catalog view catalog source, launch scaffolder template and read techdocs docs icon links extensions. + + **BREAKING ALPHA** + + The `Scaffolder` launch template and `TechDocs` read documentation icons have been extracted from the default `Catalog` about card links and are now provided respectively by the `Scaffolder` and `TechDocs` plugins in the new frontend system. It means that they will not be available unless you install the `TechDocs` and `Scaffolder` plugins. Also If you are using translation for these icon link titles other than the default, you should now translate them using the scaffolder translation reference or the TechDocs translation reference (the translation keys are still the same, `aboutCard.viewTechdocs` and `aboutCard.launchTemplate`). + +- ec7b35d: Introduced `backstage.io/techdocs-entity-path` annotation which allows deep linking into another entities TechDocs in conjunction with `backstage.io/techdocs-entity`. + +### Patch Changes + +- 18c64e9: Added the `info.packageJson` option to the plugin instance for the new frontend system. +- Updated dependencies + - @backstage/core-components@0.17.3 + - @backstage/catalog-client@1.10.1 + - @backstage/core-plugin-api@1.10.8 + - @backstage/frontend-plugin-api@0.10.3 + - @backstage/plugin-catalog-react@1.19.0 + - @backstage/plugin-techdocs-react@1.3.0 + - @backstage/plugin-techdocs-common@0.1.1 + - @backstage/plugin-search-react@1.9.1 + - @backstage/integration-react@1.2.8 + - @backstage/catalog-model@1.7.4 + - @backstage/core-compat-api@0.4.3 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/version-bridge@1.0.11 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-permission-react@0.4.35 + - @backstage/plugin-scaffolder-common@1.5.11 + - @backstage/plugin-search-common@1.2.18 + +## 1.31.0-next.2 + +### Minor Changes + +- 406acb6: Add support to customize the about card icon links via `EntityIconLinkBlueprint` and provide a default catalog view catalog source, launch scaffolder template and read techdocs docs icon links extensions. + + **BREAKING ALPHA** + + The `Scaffolder` launch template and `TechDocs` read documentation icons have been extracted from the default `Catalog` about card links and are now provided respectively by the `Scaffolder` and `TechDocs` plugins in the new frontend system. It means that they will not be available unless you install the `TechDocs` and `Scaffolder` plugins. Also If you are using translation for these icon link titles other than the default, you should now translate them using the scaffolder translation reference or the TechDocs translation reference (the translation keys are still the same, `aboutCard.viewTechdocs` and `aboutCard.launchTemplate`). + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/plugin-catalog-react@1.19.0-next.2 + - @backstage/plugin-search-react@1.9.1-next.1 + - @backstage/frontend-plugin-api@0.10.3-next.1 + - @backstage/integration-react@1.2.7 + - @backstage/plugin-techdocs-react@1.3.0-next.1 + - @backstage/catalog-client@1.10.1-next.0 + - @backstage/catalog-model@1.7.4 + - @backstage/core-compat-api@0.4.3-next.2 + - @backstage/core-plugin-api@1.10.7 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/version-bridge@1.0.11 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-permission-react@0.4.34 + - @backstage/plugin-scaffolder-common@1.5.11 + - @backstage/plugin-search-common@1.2.18 + - @backstage/plugin-techdocs-common@0.1.1-next.0 + ## 1.31.0-next.1 ### Patch Changes diff --git a/plugins/catalog/package.json b/plugins/catalog/package.json index 1e78d40306..f9f9e4f95d 100644 --- a/plugins/catalog/package.json +++ b/plugins/catalog/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog", - "version": "1.31.0-next.1", + "version": "1.31.0", "description": "The Backstage plugin for browsing the Backstage catalog", "backstage": { "role": "frontend-plugin", diff --git a/plugins/config-schema/CHANGELOG.md b/plugins/config-schema/CHANGELOG.md index ff063bd996..9a59f81d91 100644 --- a/plugins/config-schema/CHANGELOG.md +++ b/plugins/config-schema/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/plugin-config-schema +## 0.1.69 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3 + - @backstage/core-plugin-api@1.10.8 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + +## 0.1.69-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/core-plugin-api@1.10.7 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + ## 0.1.68 ### Patch Changes diff --git a/plugins/config-schema/package.json b/plugins/config-schema/package.json index 4450aec9db..f640ac6b07 100644 --- a/plugins/config-schema/package.json +++ b/plugins/config-schema/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-config-schema", - "version": "0.1.68", + "version": "0.1.69", "description": "A Backstage plugin that lets you browse the configuration schema of your app", "backstage": { "role": "frontend-plugin", diff --git a/plugins/devtools-backend/CHANGELOG.md b/plugins/devtools-backend/CHANGELOG.md index 0a11e19ddb..15a3b5efab 100644 --- a/plugins/devtools-backend/CHANGELOG.md +++ b/plugins/devtools-backend/CHANGELOG.md @@ -1,5 +1,38 @@ # @backstage/plugin-devtools-backend +## 0.5.6 + +### Patch Changes + +- 9a99735: Removed the usage of `permissionIntegrationRouter` in favor of using the new `coreServices.permissionsRegistry` +- Updated dependencies + - @backstage/backend-defaults@0.11.0 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/cli-common@0.1.15 + - @backstage/config@1.3.2 + - @backstage/config-loader@1.10.1 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/plugin-devtools-common@0.1.16 + - @backstage/plugin-permission-common@0.9.0 + - @backstage/plugin-permission-node@0.10.1 + +## 0.5.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.11.0-next.2 + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/cli-common@0.1.15 + - @backstage/config@1.3.2 + - @backstage/config-loader@1.10.1 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/plugin-devtools-common@0.1.16 + - @backstage/plugin-permission-common@0.9.0 + - @backstage/plugin-permission-node@0.10.1-next.1 + ## 0.5.6-next.1 ### Patch Changes diff --git a/plugins/devtools-backend/package.json b/plugins/devtools-backend/package.json index 0547b8bc9a..b4d5411046 100644 --- a/plugins/devtools-backend/package.json +++ b/plugins/devtools-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-devtools-backend", - "version": "0.5.6-next.1", + "version": "0.5.6", "backstage": { "role": "backend-plugin", "pluginId": "devtools", diff --git a/plugins/devtools-backend/src/plugin.ts b/plugins/devtools-backend/src/plugin.ts index ee7bf369f5..d3fefda343 100644 --- a/plugins/devtools-backend/src/plugin.ts +++ b/plugins/devtools-backend/src/plugin.ts @@ -19,6 +19,7 @@ import { createBackendPlugin, } from '@backstage/backend-plugin-api'; import { createRouter } from './service/router'; +import { devToolsPermissions } from '@backstage/plugin-devtools-common'; /** * DevTools backend plugin @@ -36,6 +37,7 @@ export const devtoolsPlugin = createBackendPlugin({ httpRouter: coreServices.httpRouter, discovery: coreServices.discovery, httpAuth: coreServices.httpAuth, + permissionsRegistry: coreServices.permissionsRegistry, }, async init({ config, @@ -44,6 +46,7 @@ export const devtoolsPlugin = createBackendPlugin({ httpRouter, discovery, httpAuth, + permissionsRegistry, }) { httpRouter.use( await createRouter({ @@ -58,6 +61,7 @@ export const devtoolsPlugin = createBackendPlugin({ path: '/health', allow: 'unauthenticated', }); + permissionsRegistry.addPermissions(devToolsPermissions); }, }); }, diff --git a/plugins/devtools-backend/src/service/router.ts b/plugins/devtools-backend/src/service/router.ts index ad77495b36..caba2185fc 100644 --- a/plugins/devtools-backend/src/service/router.ts +++ b/plugins/devtools-backend/src/service/router.ts @@ -19,13 +19,11 @@ import { devToolsConfigReadPermission, devToolsExternalDependenciesReadPermission, devToolsInfoReadPermission, - devToolsPermissions, } from '@backstage/plugin-devtools-common'; import { DevToolsBackendApi } from '../api'; import { NotAllowedError } from '@backstage/errors'; import Router from 'express-promise-router'; import express from 'express'; -import { createPermissionIntegrationRouter } from '@backstage/plugin-permission-node'; import { DiscoveryService, HttpAuthService, @@ -59,11 +57,6 @@ export async function createRouter( const router = Router(); router.use(express.json()); - router.use( - createPermissionIntegrationRouter({ - permissions: devToolsPermissions, - }), - ); router.get('/health', (_req, res) => { res.status(200).json({ status: 'ok' }); diff --git a/plugins/devtools/CHANGELOG.md b/plugins/devtools/CHANGELOG.md index 7ae5262c69..5197c8b90d 100644 --- a/plugins/devtools/CHANGELOG.md +++ b/plugins/devtools/CHANGELOG.md @@ -1,5 +1,32 @@ # @backstage/plugin-devtools +## 0.1.28 + +### Patch Changes + +- 18c64e9: Added the `info.packageJson` option to the plugin instance for the new frontend system. +- Updated dependencies + - @backstage/core-components@0.17.3 + - @backstage/core-plugin-api@1.10.8 + - @backstage/frontend-plugin-api@0.10.3 + - @backstage/core-compat-api@0.4.3 + - @backstage/errors@1.2.7 + - @backstage/plugin-devtools-common@0.1.16 + - @backstage/plugin-permission-react@0.4.35 + +## 0.1.28-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/frontend-plugin-api@0.10.3-next.1 + - @backstage/core-compat-api@0.4.3-next.2 + - @backstage/core-plugin-api@1.10.7 + - @backstage/errors@1.2.7 + - @backstage/plugin-devtools-common@0.1.16 + - @backstage/plugin-permission-react@0.4.34 + ## 0.1.28-next.1 ### Patch Changes diff --git a/plugins/devtools/package.json b/plugins/devtools/package.json index 32ac310d53..815c2451bd 100644 --- a/plugins/devtools/package.json +++ b/plugins/devtools/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-devtools", - "version": "0.1.28-next.1", + "version": "0.1.28", "backstage": { "role": "frontend-plugin", "pluginId": "devtools", diff --git a/plugins/events-backend-module-aws-sqs/CHANGELOG.md b/plugins/events-backend-module-aws-sqs/CHANGELOG.md index 6372fb6b46..dab40a9419 100644 --- a/plugins/events-backend-module-aws-sqs/CHANGELOG.md +++ b/plugins/events-backend-module-aws-sqs/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-events-backend-module-aws-sqs +## 0.4.12 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/types@1.2.1 + - @backstage/plugin-events-node@0.4.12 + ## 0.4.12-next.1 ### Patch Changes diff --git a/plugins/events-backend-module-aws-sqs/package.json b/plugins/events-backend-module-aws-sqs/package.json index 7cd59759cc..5fa5d43d6a 100644 --- a/plugins/events-backend-module-aws-sqs/package.json +++ b/plugins/events-backend-module-aws-sqs/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-aws-sqs", - "version": "0.4.12-next.1", + "version": "0.4.12", "backstage": { "role": "backend-plugin-module", "pluginId": "events", diff --git a/plugins/events-backend-module-azure/CHANGELOG.md b/plugins/events-backend-module-azure/CHANGELOG.md index 791a72a413..76b66181ad 100644 --- a/plugins/events-backend-module-azure/CHANGELOG.md +++ b/plugins/events-backend-module-azure/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-events-backend-module-azure +## 0.2.21 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.0 + - @backstage/plugin-events-node@0.4.12 + ## 0.2.21-next.1 ### Patch Changes diff --git a/plugins/events-backend-module-azure/package.json b/plugins/events-backend-module-azure/package.json index 3ccc5436db..04eb908a12 100644 --- a/plugins/events-backend-module-azure/package.json +++ b/plugins/events-backend-module-azure/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-azure", - "version": "0.2.21-next.1", + "version": "0.2.21", "backstage": { "role": "backend-plugin-module", "pluginId": "events", diff --git a/plugins/events-backend-module-bitbucket-cloud/CHANGELOG.md b/plugins/events-backend-module-bitbucket-cloud/CHANGELOG.md index c56b358dfa..45d8d2230b 100644 --- a/plugins/events-backend-module-bitbucket-cloud/CHANGELOG.md +++ b/plugins/events-backend-module-bitbucket-cloud/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-events-backend-module-bitbucket-cloud +## 0.2.21 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.0 + - @backstage/plugin-events-node@0.4.12 + ## 0.2.21-next.1 ### Patch Changes diff --git a/plugins/events-backend-module-bitbucket-cloud/package.json b/plugins/events-backend-module-bitbucket-cloud/package.json index 68d6823859..b44fba658e 100644 --- a/plugins/events-backend-module-bitbucket-cloud/package.json +++ b/plugins/events-backend-module-bitbucket-cloud/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-bitbucket-cloud", - "version": "0.2.21-next.1", + "version": "0.2.21", "backstage": { "role": "backend-plugin-module", "pluginId": "events", diff --git a/plugins/events-backend-module-bitbucket-server/CHANGELOG.md b/plugins/events-backend-module-bitbucket-server/CHANGELOG.md index 7e285f28f8..32b0e55e7a 100644 --- a/plugins/events-backend-module-bitbucket-server/CHANGELOG.md +++ b/plugins/events-backend-module-bitbucket-server/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-events-backend-module-bitbucket-server +## 0.1.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.0 + - @backstage/plugin-events-node@0.4.12 + ## 0.1.2-next.1 ### Patch Changes diff --git a/plugins/events-backend-module-bitbucket-server/package.json b/plugins/events-backend-module-bitbucket-server/package.json index 501088fd74..7045b0fa3e 100644 --- a/plugins/events-backend-module-bitbucket-server/package.json +++ b/plugins/events-backend-module-bitbucket-server/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-bitbucket-server", - "version": "0.1.2-next.1", + "version": "0.1.2", "backstage": { "role": "backend-plugin-module", "pluginId": "events", diff --git a/plugins/events-backend-module-gerrit/CHANGELOG.md b/plugins/events-backend-module-gerrit/CHANGELOG.md index b0e7a64255..d6a78b0c4d 100644 --- a/plugins/events-backend-module-gerrit/CHANGELOG.md +++ b/plugins/events-backend-module-gerrit/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-events-backend-module-gerrit +## 0.2.21 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.0 + - @backstage/plugin-events-node@0.4.12 + ## 0.2.21-next.1 ### Patch Changes diff --git a/plugins/events-backend-module-gerrit/package.json b/plugins/events-backend-module-gerrit/package.json index 33dfe31b19..b613407c59 100644 --- a/plugins/events-backend-module-gerrit/package.json +++ b/plugins/events-backend-module-gerrit/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-gerrit", - "version": "0.2.21-next.1", + "version": "0.2.21", "backstage": { "role": "backend-plugin-module", "pluginId": "events", diff --git a/plugins/events-backend-module-github/CHANGELOG.md b/plugins/events-backend-module-github/CHANGELOG.md index 1521413713..ced999124e 100644 --- a/plugins/events-backend-module-github/CHANGELOG.md +++ b/plugins/events-backend-module-github/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-events-backend-module-github +## 0.4.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/integration@1.17.0 + - @backstage/types@1.2.1 + - @backstage/plugin-events-node@0.4.12 + ## 0.4.1-next.1 ### Patch Changes diff --git a/plugins/events-backend-module-github/package.json b/plugins/events-backend-module-github/package.json index ebfefa8965..8506063943 100644 --- a/plugins/events-backend-module-github/package.json +++ b/plugins/events-backend-module-github/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-github", - "version": "0.4.1-next.1", + "version": "0.4.1", "backstage": { "role": "backend-plugin-module", "pluginId": "events", diff --git a/plugins/events-backend-module-gitlab/CHANGELOG.md b/plugins/events-backend-module-gitlab/CHANGELOG.md index 7941142c71..2b5daa381b 100644 --- a/plugins/events-backend-module-gitlab/CHANGELOG.md +++ b/plugins/events-backend-module-gitlab/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-events-backend-module-gitlab +## 0.3.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/plugin-events-node@0.4.12 + ## 0.3.2-next.1 ### Patch Changes diff --git a/plugins/events-backend-module-gitlab/package.json b/plugins/events-backend-module-gitlab/package.json index 23b90b6832..b02ece2332 100644 --- a/plugins/events-backend-module-gitlab/package.json +++ b/plugins/events-backend-module-gitlab/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-gitlab", - "version": "0.3.2-next.1", + "version": "0.3.2", "backstage": { "role": "backend-plugin-module", "pluginId": "events", diff --git a/plugins/events-backend-module-google-pubsub/CHANGELOG.md b/plugins/events-backend-module-google-pubsub/CHANGELOG.md index aee8ff1327..24ab6b3969 100644 --- a/plugins/events-backend-module-google-pubsub/CHANGELOG.md +++ b/plugins/events-backend-module-google-pubsub/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-events-backend-module-google-pubsub +## 0.1.1 + +### Patch Changes + +- f983e99: Add an `EventConsumingGooglePubSubPublisher`, for pushing Backstage events to pubsub +- Updated dependencies + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/plugin-events-node@0.4.12 + ## 0.1.1-next.1 ### Patch Changes diff --git a/plugins/events-backend-module-google-pubsub/README.md b/plugins/events-backend-module-google-pubsub/README.md index 67ddcfacb4..9752fa30c6 100644 --- a/plugins/events-backend-module-google-pubsub/README.md +++ b/plugins/events-backend-module-google-pubsub/README.md @@ -19,11 +19,24 @@ events: # The fully qualified name of the subscription subscriptionName: 'projects/my-google-project/subscriptions/github-enterprise-events' # The event system topic to transfer to. This can also be just a plain string - targetTopic: - # This example picks the topic name from a message attribute + a prefix - fromMessageAttribute: - attributeName: 'x-github-event' - withPrefix: 'github.' + targetTopic: 'github.{{ event.attributes.x-github-event }}' +``` + +The following configuration enables the transfer of events from a Backstage events topic into a Google +Pub/Sub topic. + +```yaml +events: + modules: + googlePubSub: + eventConsumingGooglePubSubPublisher: + subscriptions: + # A unique key for your subscription, to be used in logging and metrics + mySubscription: + # The source topic (or array of topics) + sourceTopic: 'github' + # The fully qualified name of the target topic + targetTopicName: 'projects/my-google-project/topics/github-enterprise-events' ``` ## Installation diff --git a/plugins/events-backend-module-google-pubsub/config.d.ts b/plugins/events-backend-module-google-pubsub/config.d.ts index 3e70489b9d..1097b71e00 100644 --- a/plugins/events-backend-module-google-pubsub/config.d.ts +++ b/plugins/events-backend-module-google-pubsub/config.d.ts @@ -90,6 +90,68 @@ export interface Config { }; }; }; + + /** + * Configuration for `EventConsumingGooglePubSubPublisher`, which + * consumes messages from the Backstage events system and forwards them + * into Google Pub/Sub topics. + */ + eventConsumingGooglePubSubPublisher?: { + subscriptions: { + [name: string]: { + /** + * The name of the events backend topic(s) that messages are + * consumed from. + */ + sourceTopic: string | string[]; + + /** + * The complete name of the Google Pub/Sub subscription to forward + * events to, on the form + * `projects/PROJECT_ID/topics/TOPIC_ID`. + * + * The value can contain placeholders on the form `{{ + * message.attributes.foo }}`, to mirror attribute `foo` as the + * whole or part of the topic name. + * + * @example + * + * This example expects the events topic to contain GitHub + * webhook events where the HTTP headers were mapped into + * event metadata fields. The outcome should be that messages + * end up on event topics such as `github.push`, + * `github.repository` etc which matches the [`@backstage/plugin-events-backend-module-github`](https://github.com/backstage/backstage/tree/master/plugins/events-backend-module-github) structure. + * + * ```yaml + * targetTopic: 'projects/my-project/topics/github.{{ event.metadata.x-github-event }}' + * ``` + */ + targetTopicName: string; + + /** + * Event metadata fields are by default copied to the Pub/Sub + * message attribute. This setting allows you to override or amend + * those attributes. + * + * @remarks + * + * The values can contain placeholders on the form `{{ event.metadata.foo }}`, + * to mirror metadata field `foo` as the whole or part of a + * message attribute value. + * + * @example + * + * ```yaml + * messageAttributes: + * x-gitHub-event: '{{ event.metadata.event }}' + * ``` + */ + messageAttributes?: { + [key: string]: string; + }; + }; + }; + }; }; }; }; diff --git a/plugins/events-backend-module-google-pubsub/dev/index.ts b/plugins/events-backend-module-google-pubsub/dev/index.ts index 752217e6db..78a7e775cf 100644 --- a/plugins/events-backend-module-google-pubsub/dev/index.ts +++ b/plugins/events-backend-module-google-pubsub/dev/index.ts @@ -28,20 +28,21 @@ backend.add(import('../src')); backend.add( createBackendPlugin({ - pluginId: 'example-event-consumer', + pluginId: 'example-event-drivers', register(reg) { reg.registerInit({ deps: { events: eventsServiceRef, logger: coreServices.logger, + scheduler: coreServices.scheduler, }, - async init({ events, logger }) { - events.subscribe({ - id: 'example-subscription', - topics: ['example-topic'], + async init({ events, logger, scheduler }) { + await events.subscribe({ + id: 'inbox-subscription', + topics: ['inbox-topic'], async onEvent(event) { logger.info( - `Received event: ${JSON.stringify( + `Received inbox event: ${JSON.stringify( { topic: event.topic, payload: event.eventPayload, @@ -53,6 +54,24 @@ backend.add( ); }, }); + + await scheduler.scheduleTask({ + id: 'outbox-task', + scope: 'local', + frequency: { seconds: 5 }, + timeout: { seconds: 5 }, + fn: async () => { + await events.publish({ + topic: 'outbox-topic', + eventPayload: { + message: 'Hello, world!', + }, + metadata: { + source: 'outbox-task', + }, + }); + }, + }); }, }); }, diff --git a/plugins/events-backend-module-google-pubsub/package.json b/plugins/events-backend-module-google-pubsub/package.json index 591067de48..36a7468173 100644 --- a/plugins/events-backend-module-google-pubsub/package.json +++ b/plugins/events-backend-module-google-pubsub/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-google-pubsub", - "version": "0.1.1-next.1", + "version": "0.1.1", "description": "The google-pubsub backend module for the events plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/events-backend-module-google-pubsub/report.api.md b/plugins/events-backend-module-google-pubsub/report.api.md index bdb057d7fc..b42c1f80ff 100644 --- a/plugins/events-backend-module-google-pubsub/report.api.md +++ b/plugins/events-backend-module-google-pubsub/report.api.md @@ -6,6 +6,6 @@ import { BackendFeature } from '@backstage/backend-plugin-api'; // @public -const eventsModuleGooglePubsubConsumingEventPublisher: BackendFeature; -export default eventsModuleGooglePubsubConsumingEventPublisher; +const _default: BackendFeature; +export default _default; ``` diff --git a/plugins/events-backend-module-google-pubsub/src/EventConsumingGooglePubSubPublisher/EventConsumingGooglePubSubPublisher.test.ts b/plugins/events-backend-module-google-pubsub/src/EventConsumingGooglePubSubPublisher/EventConsumingGooglePubSubPublisher.test.ts new file mode 100644 index 0000000000..e5af68add7 --- /dev/null +++ b/plugins/events-backend-module-google-pubsub/src/EventConsumingGooglePubSubPublisher/EventConsumingGooglePubSubPublisher.test.ts @@ -0,0 +1,111 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { mockServices } from '@backstage/backend-test-utils'; +import { EventParams } from '@backstage/plugin-events-node'; +import { PubSub } from '@google-cloud/pubsub'; +import waitFor from 'wait-for-expect'; +import { EventConsumingGooglePubSubPublisher } from './EventConsumingGooglePubSubPublisher'; + +describe('EventConsumingGooglePubSubPublisher', () => { + const logger = mockServices.logger.mock(); + const events = mockServices.events.mock(); + + let onEvent: undefined | ((event: EventParams) => void); + events.subscribe.mockImplementation(async options => { + onEvent = options.onEvent; + }); + + const topic = { + publishMessage: jest.fn(), + }; + const pubSub = { + close: jest.fn(), + topic: jest.fn(() => topic), + }; + const pubSubFactory = jest.fn(() => pubSub as unknown as PubSub); + + beforeEach(() => { + onEvent = undefined; + jest.clearAllMocks(); + }); + + it('should go though the expected registration and flows', async () => { + const publisher = new EventConsumingGooglePubSubPublisher({ + logger, + events, + tasks: [ + { + id: 'my-id', + sourceTopics: ['my-topic'], + targetTopicPattern: 'projects/my-project/topics/my-topic', + mapToTopic: () => ({ project: 'my-project', topic: 'my-topic' }), + mapToAttributes: m => ({ ...m.metadata, more: 'yes' }), + }, + ], + pubSubFactory, + }); + + // Start up + + await publisher.start(); + + expect(events.subscribe).toHaveBeenCalledWith({ + id: 'EventConsumingGooglePubSubPublisher.my-id', + topics: ['my-topic'], + onEvent: expect.any(Function), + }); + + // Publish successfully + + onEvent!({ + topic: 'my-topic', + eventPayload: { foo: 'bar' }, + metadata: { extra: 'data', more: 'yes' }, + }); + + await waitFor(() => { + expect(pubSubFactory).toHaveBeenCalledWith('my-project'); + expect(pubSub.topic).toHaveBeenCalledWith('my-topic'); + expect(topic.publishMessage).toHaveBeenCalledWith({ + json: { foo: 'bar' }, + attributes: { extra: 'data', more: 'yes' }, + }); + }); + + // Simulate a failed publish + + topic.publishMessage.mockRejectedValueOnce(new Error('Failed to publish')); + + await expect( + onEvent!({ + topic: 'my-topic', + eventPayload: { foo: 'bar' }, + metadata: { extra: 'data', more: 'yes' }, + }), + ).rejects.toThrowErrorMatchingInlineSnapshot(`"Failed to publish"`); + + expect(logger.error).toHaveBeenCalledWith( + 'Error publishing Google Pub/Sub message', + new Error('Failed to publish'), + ); + + // Shut down + + await publisher.stop(); + expect(pubSub.close).toHaveBeenCalled(); + }); +}); diff --git a/plugins/events-backend-module-google-pubsub/src/EventConsumingGooglePubSubPublisher/EventConsumingGooglePubSubPublisher.ts b/plugins/events-backend-module-google-pubsub/src/EventConsumingGooglePubSubPublisher/EventConsumingGooglePubSubPublisher.ts new file mode 100644 index 0000000000..4a88bc2e79 --- /dev/null +++ b/plugins/events-backend-module-google-pubsub/src/EventConsumingGooglePubSubPublisher/EventConsumingGooglePubSubPublisher.ts @@ -0,0 +1,153 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + LoggerService, + RootConfigService, + RootLifecycleService, +} from '@backstage/backend-plugin-api'; +import { EventsService } from '@backstage/plugin-events-node'; +import { PubSub } from '@google-cloud/pubsub'; +import { Counter, metrics } from '@opentelemetry/api'; +import { readSubscriptionTasksFromConfig } from './config'; +import { SubscriptionTask } from './types'; + +/** + * Reads messages off of the events system and forwards them into Google Pub/Sub + * topics. + */ +export class EventConsumingGooglePubSubPublisher { + readonly #logger: LoggerService; + readonly #events: EventsService; + readonly #tasks: SubscriptionTask[]; + readonly #pubSubFactory: (projectId: string) => PubSub; + readonly #metrics: { messages: Counter }; + #activeClientsByProjectId: Map; + + static create(options: { + config: RootConfigService; + logger: LoggerService; + rootLifecycle: RootLifecycleService; + events: EventsService; + }) { + const publisher = new EventConsumingGooglePubSubPublisher({ + logger: options.logger, + events: options.events, + tasks: readSubscriptionTasksFromConfig(options.config), + pubSubFactory: projectId => new PubSub({ projectId }), + }); + + options.rootLifecycle.addStartupHook(async () => { + await publisher.start(); + }); + + options.rootLifecycle.addBeforeShutdownHook(async () => { + await publisher.stop(); + }); + + return publisher; + } + + constructor(options: { + logger: LoggerService; + events: EventsService; + tasks: SubscriptionTask[]; + pubSubFactory: (projectId: string) => PubSub; + }) { + this.#logger = options.logger; + this.#events = options.events; + this.#tasks = options.tasks; + this.#pubSubFactory = options.pubSubFactory; + + const meter = metrics.getMeter('default'); + this.#metrics = { + messages: meter.createCounter( + 'events.google.pubsub.publisher.messages.total', + { + description: + 'Number of Pub/Sub messages sent by EventConsumingGooglePubSubPublisher', + unit: 'short', + }, + ), + }; + + this.#activeClientsByProjectId = new Map(); + } + + async start() { + for (const task of this.#tasks) { + this.#logger.info( + `Starting publisher: id=${ + task.id + } sourceTopics=${task.sourceTopics.join(',')} targetTopic=${ + task.targetTopicPattern + }`, + ); + + await this.#events.subscribe({ + id: `EventConsumingGooglePubSubPublisher.${task.id}`, + topics: task.sourceTopics, + onEvent: async event => { + let status: 'success' | 'failed' | 'ignored' = 'failed'; + try { + const topic = task.mapToTopic(event); + if (!topic) { + status = 'ignored'; + return; + } + + let pubsub = this.#activeClientsByProjectId.get(topic.project); + if (!pubsub) { + pubsub = this.#pubSubFactory(topic.project); + this.#activeClientsByProjectId.set(topic.project, pubsub); + } + + await pubsub.topic(topic.topic).publishMessage({ + json: event.eventPayload, + attributes: task.mapToAttributes(event), + }); + + status = 'success'; + } catch (error) { + this.#logger.error( + 'Error publishing Google Pub/Sub message', + error, + ); + status = 'failed'; + throw error; + } finally { + this.#metrics.messages.add(1, { + subscription: task.id, + status: status, + }); + } + }, + }); + } + } + + async stop() { + const clients = Array.from(this.#activeClientsByProjectId.values()); + this.#activeClientsByProjectId = new Map(); + + await Promise.allSettled( + clients.map(async client => { + this.#logger.info(`Closing Google Pub/Sub client: ${client.projectId}`); + await client.close(); + }), + ); + } +} diff --git a/plugins/events-backend-module-google-pubsub/src/EventConsumingGooglePubSubPublisher/config.test.ts b/plugins/events-backend-module-google-pubsub/src/EventConsumingGooglePubSubPublisher/config.test.ts new file mode 100644 index 0000000000..c3a5c1a5bb --- /dev/null +++ b/plugins/events-backend-module-google-pubsub/src/EventConsumingGooglePubSubPublisher/config.test.ts @@ -0,0 +1,196 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { mockServices } from '@backstage/backend-test-utils'; +import { readSubscriptionTasksFromConfig } from './config'; + +describe('readSubscriptionTasksFromConfig', () => { + it('reads with basic targetTopic', () => { + const data = { + events: { + modules: { + googlePubSub: { + eventConsumingGooglePubSubPublisher: { + subscriptions: { + subKey1: { + sourceTopic: 'my-topic', + targetTopicName: 'projects/pid/topics/tid', + }, + subKey2: { + sourceTopic: ['my-topic-1', 'my-topic-2'], + targetTopicName: 'projects/pid/topics/tid.{{ event.topic }}', + }, + }, + }, + }, + }, + }, + }; + + const result = readSubscriptionTasksFromConfig( + mockServices.rootConfig({ data }), + ); + + expect(result).toEqual([ + { + id: 'subKey1', + sourceTopics: ['my-topic'], + targetTopicPattern: 'projects/pid/topics/tid', + mapToTopic: expect.any(Function), + mapToAttributes: expect.any(Function), + }, + { + id: 'subKey2', + sourceTopics: ['my-topic-1', 'my-topic-2'], + targetTopicPattern: 'projects/pid/topics/tid.{{ event.topic }}', + mapToTopic: expect.any(Function), + mapToAttributes: expect.any(Function), + }, + ]); + + expect( + result[0].mapToTopic({ + topic: 'a', + eventPayload: { foo: 'bar' }, + metadata: { attr: 'yes' }, + }), + ).toEqual({ project: 'pid', topic: 'tid' }); + expect( + result[0].mapToAttributes({ + topic: 'a', + eventPayload: { foo: 'bar' }, + metadata: { attr: 'yes' }, + }), + ).toEqual({ attr: 'yes' }); + }); + + it('fills in placeholders', () => { + const data = { + events: { + modules: { + googlePubSub: { + eventConsumingGooglePubSubPublisher: { + subscriptions: { + sub1: { + sourceTopic: 'my-topic', + targetTopicName: 'projects/pid/topics/tid.{{ event.topic }}', + messageAttributes: { + attr1: 'updated.{{ event.metadata.exists }}', + attr2: 'updated.{{ event.metadata.missing }}', + }, + }, + sub2: { + sourceTopic: 'my-topic', + targetTopicName: + 'projects/pid/topics/tid.{{ event.metadata.missing }}', + messageAttributes: { + attr3: 'new', + }, + }, + }, + }, + }, + }, + }, + }; + + const result = readSubscriptionTasksFromConfig( + mockServices.rootConfig({ data }), + ); + + expect(result).toEqual([ + { + id: 'sub1', + sourceTopics: ['my-topic'], + targetTopicPattern: 'projects/pid/topics/tid.{{ event.topic }}', + mapToTopic: expect.any(Function), + mapToAttributes: expect.any(Function), + }, + { + id: 'sub2', + sourceTopics: ['my-topic'], + targetTopicPattern: + 'projects/pid/topics/tid.{{ event.metadata.missing }}', + mapToTopic: expect.any(Function), + mapToAttributes: expect.any(Function), + }, + ]); + + expect( + result[0].mapToTopic({ + topic: 'a', + eventPayload: { foo: 'bar' }, + metadata: { exists: 'exists', attr1: 'original1', attr2: 'original2' }, + }), + ).toEqual({ project: 'pid', topic: 'tid.a' }); // Message attribute existed, successfully routed + expect( + result[0].mapToAttributes({ + topic: 'a', + eventPayload: { foo: 'bar' }, + metadata: { exists: 'exists', attr1: 'original1', attr2: 'original2' }, + }), + ).toEqual({ + exists: 'exists', + attr1: 'updated.exists', // message attribute existed, was replaced + attr2: 'original2', // message attribute did not exist, was not replaced + }); + + expect( + result[1].mapToTopic({ + topic: 'a', + eventPayload: { foo: 'bar' }, + metadata: { exists: 'exists', attr1: 'original1', attr2: 'original2' }, + }), + ).toBeUndefined(); // Message attribute did not exist, could not be routed + expect( + result[1].mapToAttributes({ + topic: 'a', + eventPayload: { foo: 'bar' }, + metadata: { exists: 'exists', attr1: 'original1', attr2: 'original2' }, + }), + ).toEqual({ + exists: 'exists', + attr1: 'original1', + attr2: 'original2', + attr3: 'new', + }); + }); + + it('rejects malformed subscription name', () => { + const data = { + events: { + modules: { + googlePubSub: { + eventConsumingGooglePubSubPublisher: { + subscriptions: { + subKey: { + sourceTopic: 'sid', + targetTopicName: 'foo', + }, + }, + }, + }, + }, + }, + }; + + expect(() => + readSubscriptionTasksFromConfig(mockServices.rootConfig({ data })), + ).toThrowErrorMatchingInlineSnapshot( + `"Expected Google Pub/Sub 'targetTopicName' to be on the form 'projects/PROJECT_ID/topics/TOPIC_ID' but got 'foo'"`, + ); + }); +}); diff --git a/plugins/events-backend-module-google-pubsub/src/EventConsumingGooglePubSubPublisher/config.ts b/plugins/events-backend-module-google-pubsub/src/EventConsumingGooglePubSubPublisher/config.ts new file mode 100644 index 0000000000..7ccd78cfcb --- /dev/null +++ b/plugins/events-backend-module-google-pubsub/src/EventConsumingGooglePubSubPublisher/config.ts @@ -0,0 +1,146 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { RootConfigService } from '@backstage/backend-plugin-api'; +import { Config } from '@backstage/config'; +import { InputError } from '@backstage/errors'; +import { EventParams } from '@backstage/plugin-events-node'; +import { createPatternResolver } from '../util/createPatternResolver'; +import { SubscriptionTask } from './types'; + +export function readSubscriptionTasksFromConfig( + rootConfig: RootConfigService, +): SubscriptionTask[] { + const subscriptionsConfig = rootConfig.getOptionalConfig( + 'events.modules.googlePubSub.eventConsumingGooglePubSubPublisher.subscriptions', + ); + if (!subscriptionsConfig) { + return []; + } + + return subscriptionsConfig.keys().map(subscriptionId => { + if (!subscriptionId.match(/^[-_\w]+$/)) { + throw new InputError( + `Expected Google Pub/Sub subscription ID to consist of letters, numbers, dashes and underscores, but got '${subscriptionId}'`, + ); + } + + const config = subscriptionsConfig.getConfig(subscriptionId); + const sourceTopics = readSourceTopics(config); + const mapToTopic = readTopicMapper(config); + const mapToAttributes = readAttributeMapper(config); + + return { + id: subscriptionId, + sourceTopics: sourceTopics, + targetTopicPattern: config.getString('targetTopicName'), + mapToTopic, + mapToAttributes, + }; + }); +} + +function readSourceTopics(config: Config): string[] { + if (Array.isArray(config.getOptional('sourceTopic'))) { + return config.getStringArray('sourceTopic'); + } + return [config.getString('sourceTopic')]; +} + +/** + * Handles the `targetTopicName` configuration field. + */ +function readTopicMapper( + config: Config, +): (event: EventParams) => { project: string; topic: string } | undefined { + const regex = /^projects\/([^/]+)\/topics\/(.+)$/; + + const targetTopicPattern = config.getString('targetTopicName'); + let parts = targetTopicPattern.match(regex); + if (!parts) { + throw new InputError( + `Expected Google Pub/Sub 'targetTopicName' to be on the form 'projects/PROJECT_ID/topics/TOPIC_ID' but got '${targetTopicPattern}'`, + ); + } + + const patternResolver = createPatternResolver(targetTopicPattern); + + return event => { + try { + parts = patternResolver({ event }).match(regex); + if (!parts) { + return undefined; + } + return { + project: parts[1], + topic: parts[2], + }; + } catch { + // could not map to a topic + return undefined; + } + }; +} + +/** + * Handles the `messageAttributes` configuration field. + */ +function readAttributeMapper( + config: Config, +): (event: EventParams) => Record { + const setters = new Array< + (options: { + event: EventParams; + attributes: Record; + }) => void + >(); + + const eventMetadata = config.getOptionalConfig('messageAttributes'); + if (eventMetadata) { + for (const key of eventMetadata?.keys() ?? []) { + const valuePattern = eventMetadata.getString(key); + const patternResolver = createPatternResolver(valuePattern); + setters.push(({ event, attributes }) => { + try { + const value = patternResolver({ event }); + if (value) { + attributes[key] = value; + } + } catch { + // ignore silently, keep original + } + }); + } + } + + return event => { + const result: Record = {}; + for (const [key, value] of Object.entries(event.metadata ?? {})) { + if (value) { + if (typeof value === 'string') { + result[key] = value; + } else if (Array.isArray(value) && value.length > 0) { + // Google Pub/Sub does not support array values + result[key] = value.join(','); + } + } + } + for (const setter of setters) { + setter({ event, attributes: result }); + } + return result; + }; +} diff --git a/plugins/events-backend-module-google-pubsub/src/EventConsumingGooglePubSubPublisher/index.ts b/plugins/events-backend-module-google-pubsub/src/EventConsumingGooglePubSubPublisher/index.ts new file mode 100644 index 0000000000..3e5713a28d --- /dev/null +++ b/plugins/events-backend-module-google-pubsub/src/EventConsumingGooglePubSubPublisher/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { eventsModuleEventConsumingGooglePubSubPublisher } from './module'; diff --git a/plugins/events-backend-module-google-pubsub/src/EventConsumingGooglePubSubPublisher/module.ts b/plugins/events-backend-module-google-pubsub/src/EventConsumingGooglePubSubPublisher/module.ts new file mode 100644 index 0000000000..498996fee0 --- /dev/null +++ b/plugins/events-backend-module-google-pubsub/src/EventConsumingGooglePubSubPublisher/module.ts @@ -0,0 +1,52 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + coreServices, + createBackendModule, +} from '@backstage/backend-plugin-api'; +import { eventsServiceRef } from '@backstage/plugin-events-node'; +import { EventConsumingGooglePubSubPublisher } from './EventConsumingGooglePubSubPublisher'; + +/** + * Reads messages off of the events system and forwards them into Google Pub/Sub + * topics. + * + * @public + */ +export const eventsModuleEventConsumingGooglePubSubPublisher = + createBackendModule({ + pluginId: 'events', + moduleId: 'event-consuming-google-pubsub-publisher', + register(reg) { + reg.registerInit({ + deps: { + config: coreServices.rootConfig, + logger: coreServices.logger, + rootLifecycle: coreServices.rootLifecycle, + events: eventsServiceRef, + }, + async init({ config, logger, rootLifecycle, events }) { + EventConsumingGooglePubSubPublisher.create({ + config, + logger, + rootLifecycle, + events, + }); + }, + }); + }, + }); diff --git a/plugins/events-backend-module-google-pubsub/src/EventConsumingGooglePubSubPublisher/types.ts b/plugins/events-backend-module-google-pubsub/src/EventConsumingGooglePubSubPublisher/types.ts new file mode 100644 index 0000000000..36b3aeaa78 --- /dev/null +++ b/plugins/events-backend-module-google-pubsub/src/EventConsumingGooglePubSubPublisher/types.ts @@ -0,0 +1,30 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { EventParams } from '@backstage/plugin-events-node'; + +/** + * A configured subscription task. + */ +export interface SubscriptionTask { + id: string; + sourceTopics: string[]; + targetTopicPattern: string; + mapToTopic: ( + event: EventParams, + ) => { project: string; topic: string } | undefined; + mapToAttributes: (event: EventParams) => Record; +} diff --git a/plugins/events-backend-module-google-pubsub/src/GooglePubSubConsumingEventPublisher/config.test.ts b/plugins/events-backend-module-google-pubsub/src/GooglePubSubConsumingEventPublisher/config.test.ts index bfe3c20773..b4034123f0 100644 --- a/plugins/events-backend-module-google-pubsub/src/GooglePubSubConsumingEventPublisher/config.test.ts +++ b/plugins/events-backend-module-google-pubsub/src/GooglePubSubConsumingEventPublisher/config.test.ts @@ -188,7 +188,7 @@ describe('readSubscriptionTasksFromConfig', () => { expect(() => readSubscriptionTasksFromConfig(mockServices.rootConfig({ data })), ).toThrowErrorMatchingInlineSnapshot( - `"Expected Googoe Pub/Sub 'subscriptionName' to be on the form 'projects/PROJECT_ID/subscriptions/SUBSCRIPTION_ID' but got 'sid'"`, + `"Expected Google Pub/Sub 'subscriptionName' to be on the form 'projects/PROJECT_ID/subscriptions/SUBSCRIPTION_ID' but got 'sid'"`, ); }); }); diff --git a/plugins/events-backend-module-google-pubsub/src/GooglePubSubConsumingEventPublisher/config.ts b/plugins/events-backend-module-google-pubsub/src/GooglePubSubConsumingEventPublisher/config.ts index fdcab2e2e5..d8dfb2ada2 100644 --- a/plugins/events-backend-module-google-pubsub/src/GooglePubSubConsumingEventPublisher/config.ts +++ b/plugins/events-backend-module-google-pubsub/src/GooglePubSubConsumingEventPublisher/config.ts @@ -34,7 +34,7 @@ export function readSubscriptionTasksFromConfig( return subscriptionsConfig.keys().map(subscriptionId => { if (!subscriptionId.match(/^[-_\w]+$/)) { throw new InputError( - `Expected Googoe Pub/Sub subscription ID to consist of letters, numbers, dashes and underscores, but got '${subscriptionId}'`, + `Expected Google Pub/Sub subscription ID to consist of letters, numbers, dashes and underscores, but got '${subscriptionId}'`, ); } @@ -63,7 +63,7 @@ function readSubscriptionName(config: Config): { ); if (!parts) { throw new InputError( - `Expected Googoe Pub/Sub 'subscriptionName' to be on the form 'projects/PROJECT_ID/subscriptions/SUBSCRIPTION_ID' but got '${subscriptionName}'`, + `Expected Google Pub/Sub 'subscriptionName' to be on the form 'projects/PROJECT_ID/subscriptions/SUBSCRIPTION_ID' but got '${subscriptionName}'`, ); } return { diff --git a/plugins/events-backend-module-google-pubsub/src/GooglePubSubConsumingEventPublisher/module.ts b/plugins/events-backend-module-google-pubsub/src/GooglePubSubConsumingEventPublisher/module.ts index 14cfdd2bd8..3d5fce14ee 100644 --- a/plugins/events-backend-module-google-pubsub/src/GooglePubSubConsumingEventPublisher/module.ts +++ b/plugins/events-backend-module-google-pubsub/src/GooglePubSubConsumingEventPublisher/module.ts @@ -24,8 +24,6 @@ import { GooglePubSubConsumingEventPublisher } from './GooglePubSubConsumingEven /** * Reads messages off of Google Pub/Sub subscriptions and forwards them into the * Backstage events system. - * - * @public */ export const eventsModuleGooglePubsubConsumingEventPublisher = createBackendModule({ diff --git a/plugins/events-backend-module-google-pubsub/src/index.ts b/plugins/events-backend-module-google-pubsub/src/index.ts index 2b79fcb9a1..0dcbe3c5d8 100644 --- a/plugins/events-backend-module-google-pubsub/src/index.ts +++ b/plugins/events-backend-module-google-pubsub/src/index.ts @@ -14,10 +14,19 @@ * limitations under the License. */ +import { createBackendFeatureLoader } from '@backstage/backend-plugin-api'; +import { eventsModuleEventConsumingGooglePubSubPublisher } from './EventConsumingGooglePubSubPublisher'; +import { eventsModuleGooglePubsubConsumingEventPublisher } from './GooglePubSubConsumingEventPublisher'; + /** * The google-pubsub backend module for the events plugin. * * @packageDocumentation */ -export { eventsModuleGooglePubsubConsumingEventPublisher as default } from './GooglePubSubConsumingEventPublisher'; +export default createBackendFeatureLoader({ + *loader() { + yield eventsModuleGooglePubsubConsumingEventPublisher; + yield eventsModuleEventConsumingGooglePubSubPublisher; + }, +}); diff --git a/plugins/events-backend-module-kafka/.eslintrc.js b/plugins/events-backend-module-kafka/.eslintrc.js new file mode 100644 index 0000000000..e2a53a6ad2 --- /dev/null +++ b/plugins/events-backend-module-kafka/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/plugins/events-backend-module-kafka/CHANGELOG.md b/plugins/events-backend-module-kafka/CHANGELOG.md new file mode 100644 index 0000000000..a259c90614 --- /dev/null +++ b/plugins/events-backend-module-kafka/CHANGELOG.md @@ -0,0 +1,33 @@ +# @backstage/plugin-events-backend-module-kafka + +## 0.1.0 + +### Minor Changes + +- b034b9d: Adds a new module `kafka` for plugin-events-backend + + The module introduces the `KafkaConsumerClient` which creates a Kafka client used to establish consumer connections. It also provides the `KafkaConsumingEventPublisher`, a consumer that subscribes to configured Kafka topics and publishes received messages to the Event Service. + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/types@1.2.1 + - @backstage/plugin-events-node@0.4.12 + +## 0.1.0-next.0 + +### Minor Changes + +- b034b9d: Adds a new module `kafka` for plugin-events-backend + + The module introduces the `KafkaConsumerClient` which creates a Kafka client used to establish consumer connections. It also provides the `KafkaConsumingEventPublisher`, a consumer that subscribes to configured Kafka topics and publishes received messages to the Event Service. + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/config@1.3.2 + - @backstage/types@1.2.1 + - @backstage/plugin-events-node@0.4.12-next.1 diff --git a/plugins/events-backend-module-kafka/README.md b/plugins/events-backend-module-kafka/README.md new file mode 100644 index 0000000000..dbc5bf5607 --- /dev/null +++ b/plugins/events-backend-module-kafka/README.md @@ -0,0 +1,78 @@ +# @backstage/backstage-plugin-events-backend-module-kafka + +Welcome to the `events-backend-module-kafka` backend module! + +This package is a module for the `events-backend` backend plugin and extends the events system with an `KafkaConsumingEventPublisher.` + +This event publisher will allow you to receive events from an Kafka queue and will publish these to the used `EventsService` implementation. + +## Configuration + +To set up Kafka queues, you need to configure the following values: + +```yaml +events: + modules: + kafka: + kafkaConsumingEventPublisher: + clientId: your-client-id # (Required) Client ID used by Backstage to identify when connecting to the Kafka cluster. + brokers: # (Required) List of brokers in the Kafka cluster to connect to. + - broker1 + - broker2 + topics: + - topic: 'backstage.topic' # (Required) Replace with actual topic name as expected by subscribers + kafka: + topics: # (Required) The Kafka topics to subscribe to. + - topic1 + groupId: your-group-id # (Required) The GroupId to be used by the topic consumers. +``` + +For a complete list of all available fields that can be configured, refer to the [config.d.ts file](./config.d.ts). + +### Optional SSL Configuration + +If your Kafka cluster requires SSL, you can configure it as follows: + +```yaml +events: + modules: + kafka: + kafkaConsumingEventPublisher: + ssl: + rejectUnauthorized: true # (Optional) If true, the server certificate is verified against the list of supplied CAs. + ca: [path/to/ca-cert] # (Optional) Array of trusted certificates in PEM format. + key: path/to/client-key # (Optional) Private key in PEM format. + cert: path/to/client-cert # (Optional) Public x509 certificate in PEM format. +``` + +### Optional SASL Authentication Configuration + +If your Kafka cluster requires `SASL` authentication, you can configure it as follows: + +```yaml +events: + modules: + kafka: + kafkaConsumingEventPublisher: + sasl: + mechanism: 'plain' # SASL mechanism ('plain', 'scram-sha-256' or 'scram-sha-512') + username: your-username # SASL username + password: your-password # SASL password +``` + +This section includes optional `SSL` and `SASL` authentication configuration for enhanced security. + +## Installation + +1. Install this module +2. Add your configuration. + +```bash +# From your Backstage root directory +yarn --cwd packages/backend add @backstage/plugin-events-backend-module-kafka +``` + +```typescript +// packages/backend/src/index.ts +backend.add(import('@backstage/plugin-events-backend-module-kafka')); +``` diff --git a/plugins/events-backend-module-kafka/catalog-info.yaml b/plugins/events-backend-module-kafka/catalog-info.yaml new file mode 100644 index 0000000000..72358ec3c3 --- /dev/null +++ b/plugins/events-backend-module-kafka/catalog-info.yaml @@ -0,0 +1,10 @@ +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: backstage-plugin-events-backend-module-kafka + title: '@backstage/plugin-events-backend-module-kafka' + description: The kafka backend module for the events plugin. +spec: + lifecycle: experimental + type: backstage-backend-plugin-module + owner: maintainers diff --git a/plugins/events-backend-module-kafka/config.d.ts b/plugins/events-backend-module-kafka/config.d.ts new file mode 100644 index 0000000000..49c417098c --- /dev/null +++ b/plugins/events-backend-module-kafka/config.d.ts @@ -0,0 +1,205 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { HumanDuration } from '@backstage/types'; + +export interface Config { + events?: { + modules?: { + /** + * events-backend-module-kafka plugin configuration. + */ + kafka?: { + /** + * Configuration for KafkaConsumingEventPublisher + */ + kafkaConsumingEventPublisher?: { + /** + * (Required) Client ID used by Backstage to identify when connecting to the Kafka cluster. + */ + clientId: string; + /** + * (Required) List of brokers in the Kafka cluster to connect to. + */ + brokers: string[]; + /** + * Optional SSL connection parameters to connect to the cluster. Passed directly to Node tls.connect. + * See https://nodejs.org/dist/latest-v8.x/docs/api/tls.html#tls_tls_createsecurecontext_options + */ + ssl?: + | { + ca?: string[]; + /** @visibility secret */ + key?: string; + cert?: string; + rejectUnauthorized?: boolean; + } + | boolean; + /** + * Optional SASL connection parameters. + */ + sasl?: { + mechanism: 'plain' | 'scram-sha-256' | 'scram-sha-512'; + username: string; + /** @visibility secret */ + password: string; + }; + + /** + * Optional retry connection parameters. + */ + retry: { + /** + * (Optional) Maximum wait time for a retry + * Default: 30000 ms. + */ + maxRetryTime: HumanDuration | string; + + /** + * (Optional) Initial value used to calculate the retry (This is still randomized following the randomization factor) + * Default: 300 ms. + */ + initialRetryTime: HumanDuration | string; + + /** + * (Optional) Randomization factor + * Default: 0.2. + */ + factor: number; + + /** + * (Optional) Exponential factor + * Default: 2. + */ + multiplier: number; + + /** + * (Optional) Max number of retries per call + * Default: 5. + */ + retries: number; + }; + + /** + * (Optional) Timeout for authentication requests. + * Default: 10000 ms. + */ + authenticationTimeout: HumanDuration | string; + + /** + * (Optional) Time to wait for a successful connection. + * Default: 1000 ms. + */ + connectionTimeout: HumanDuration | string; + + /** + * (Optional) Time to wait for a successful request. + * Default: 30000 ms. + */ + requestTimeout: HumanDuration | string; + + /** + * (Optional) The request timeout can be disabled by setting enforceRequestTimeout to false. + * Default: true + */ + enforceRequestTimeout: boolean; + + /** + * Contains a object per topic for which an Kafka queue + * should be used as source of events. + */ + topics: Array<{ + /** + * (Required) The Backstage topic to publish to + */ + topic: string; + /** + * (Required) KafkaConsumer-related configuration. + */ + kafka: { + /** + * (Required) The Kafka topics to subscribe to + */ + topics: string[]; + /** + * (Required) The GroupId to be used by the topic consumers + */ + groupId: string; + + /** + * (Optional) Timeout used to detect failures. + * The consumer sends periodic heartbeats to indicate its liveness to the broker. + * If no heartbeats are received by the broker before the expiration of this session timeout, + * then the broker will remove this consumer from the group and initiate a rebalance + * Default: 30000 ms. + */ + sessionTimeout: HumanDuration | string; + + /** + * (Optional) The maximum time that the coordinator will wait for each member to rejoin when rebalancing the group + * Default: 60000 ms. + */ + rebalanceTimeout: HumanDuration | string; + + /** + * (Optional) The expected time between heartbeats to the consumer coordinator. + * Heartbeats are used to ensure that the consumer's session stays active. + * The value must be set lower than session timeout + * Default: 3000 ms. + */ + heartbeatInterval: HumanDuration | string; + + /** + * (Optional) The period of time after which we force a refresh of metadata + * even if we haven't seen any partition leadership changes to proactively discover any new brokers or partitions + * Default: 300000 ms (5 minutes). + */ + metadataMaxAge: HumanDuration | string; + + /** + * (Optional) The maximum amount of data per-partition the server will return. + * This size must be at least as large as the maximum message size the server allows + * or else it is possible for the producer to send messages larger than the consumer can fetch. + * If that happens, the consumer can get stuck trying to fetch a large message on a certain partition + * Default: 1048576 (1MB) + */ + maxBytesPerPartition: number; + + /** + * (Optional) Minimum amount of data the server should return for a fetch request, otherwise wait up to maxWaitTime for more data to accumulate. + * Default: 1 + */ + minBytes: number; + + /** + * (Optional) Maximum amount of bytes to accumulate in the response. Supported by Kafka >= 0.10.1.0 + * Default: 10485760 (10MB) + */ + maxBytes: number; + + /** + * (Optional) The maximum amount of time the server will block before answering the fetch request + * if there isn’t sufficient data to immediately satisfy the requirement given by minBytes + * Default: 5000 + */ + maxWaitTime: HumanDuration | string; + }; + }>; + }; + }; + }; + }; +} diff --git a/plugins/events-backend-module-kafka/package.json b/plugins/events-backend-module-kafka/package.json new file mode 100644 index 0000000000..9e92ef1345 --- /dev/null +++ b/plugins/events-backend-module-kafka/package.json @@ -0,0 +1,51 @@ +{ + "name": "@backstage/plugin-events-backend-module-kafka", + "version": "0.1.0", + "description": "The kafka backend module for the events plugin.", + "backstage": { + "role": "backend-plugin-module", + "pluginId": "events", + "pluginPackage": "@backstage/plugin-events-backend" + }, + "publishConfig": { + "access": "public", + "main": "dist/index.cjs.js", + "types": "dist/index.d.ts" + }, + "homepage": "https://backstage.io", + "repository": { + "type": "git", + "url": "https://github.com/backstage/backstage", + "directory": "plugins/events-backend-module-kafka" + }, + "license": "Apache-2.0", + "main": "src/index.ts", + "types": "src/index.ts", + "files": [ + "dist", + "config.d.ts" + ], + "scripts": { + "build": "backstage-cli package build", + "clean": "backstage-cli package clean", + "lint": "backstage-cli package lint", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "start": "backstage-cli package start", + "test": "backstage-cli package test" + }, + "dependencies": { + "@backstage/backend-plugin-api": "workspace:^", + "@backstage/config": "workspace:^", + "@backstage/plugin-events-node": "workspace:^", + "@backstage/types": "workspace:^", + "kafkajs": "^2.2.4", + "luxon": "^3.0.0" + }, + "devDependencies": { + "@backstage/backend-test-utils": "workspace:^", + "@backstage/cli": "workspace:^", + "@backstage/plugin-events-backend-test-utils": "workspace:^" + }, + "configSchema": "config.d.ts" +} diff --git a/plugins/events-backend-module-kafka/report.api.md b/plugins/events-backend-module-kafka/report.api.md new file mode 100644 index 0000000000..a6b129b82e --- /dev/null +++ b/plugins/events-backend-module-kafka/report.api.md @@ -0,0 +1,11 @@ +## API Report File for "@backstage/plugin-events-backend-module-kafka" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { BackendFeature } from '@backstage/backend-plugin-api'; + +// @public +const eventsModuleKafkaConsumingEventPublisher: BackendFeature; +export default eventsModuleKafkaConsumingEventPublisher; +``` diff --git a/plugins/events-backend-module-kafka/src/index.ts b/plugins/events-backend-module-kafka/src/index.ts new file mode 100644 index 0000000000..3ba6207d7d --- /dev/null +++ b/plugins/events-backend-module-kafka/src/index.ts @@ -0,0 +1,26 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * The module "kafka" for the Backstage backend plugin "events" + * adding an Kafka-based publisher, + * receiving events from an Kafka topic and passing it to the + * internal event broker. + * + * @packageDocumentation + */ + +export { eventsModuleKafkaConsumingEventPublisher as default } from './service/eventsModuleKafkaConsumingEventPublisher'; diff --git a/plugins/events-backend-module-kafka/src/publisher/KafkaConsumerClient.test.ts b/plugins/events-backend-module-kafka/src/publisher/KafkaConsumerClient.test.ts new file mode 100644 index 0000000000..5824bf4d41 --- /dev/null +++ b/plugins/events-backend-module-kafka/src/publisher/KafkaConsumerClient.test.ts @@ -0,0 +1,132 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { KafkaConsumerClient } from './KafkaConsumerClient'; +import { ConfigReader } from '@backstage/config'; +import { KafkaConsumingEventPublisher } from './KafkaConsumingEventPublisher'; +import { mockServices } from '@backstage/backend-test-utils'; + +jest.mock('kafkajs'); +jest.mock('./KafkaConsumingEventPublisher'); + +describe('KafkaConsumerClient', () => { + const mockLogger = mockServices.logger.mock(); + const mockEvents = mockServices.events.mock(); + + const mockConfig = new ConfigReader({ + events: { + modules: { + kafka: { + kafkaConsumingEventPublisher: { + clientId: 'backstage-events', + brokers: ['kafka1:9092', 'kafka2:9092'], + topics: [ + { + topic: 'fake1', + kafka: { + topics: ['topic-A'], + groupId: 'my-group', + }, + }, + { + topic: 'fake2', + kafka: { + topics: ['topic-B'], + groupId: 'my-group', + }, + }, + ], + }, + }, + }, + }, + }); + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('should create an instance from config', () => { + const client = KafkaConsumerClient.fromConfig({ + config: mockConfig, + events: mockEvents, + logger: mockLogger, + }); + + expect(client).toBeInstanceOf(KafkaConsumerClient); + }); + + it('should not create an instance from config', () => { + const client = KafkaConsumerClient.fromConfig({ + config: new ConfigReader({}), + events: mockEvents, + logger: mockLogger, + }); + + expect(client).toBeUndefined(); + }); + + it('should create a consumer for each topic from config', () => { + KafkaConsumerClient.fromConfig({ + config: mockConfig, + events: mockEvents, + logger: mockLogger, + }); + + expect(KafkaConsumingEventPublisher.fromConfig).toHaveBeenCalledTimes(2); + }); + + it('should start all consumers', async () => { + const mockConsumer = { + start: jest.fn().mockResolvedValue(undefined), + }; + (KafkaConsumingEventPublisher.fromConfig as jest.Mock).mockReturnValue( + mockConsumer, + ); + + const client = KafkaConsumerClient.fromConfig({ + config: mockConfig, + events: mockEvents, + logger: mockLogger, + }); + + expect(client).toBeDefined(); + + await client?.start(); + + expect(mockConsumer.start).toHaveBeenCalled(); + }); + + it('should shutdown all consumers', async () => { + const mockConsumer = { + shutdown: jest.fn().mockResolvedValue(undefined), + }; + (KafkaConsumingEventPublisher.fromConfig as jest.Mock).mockReturnValue( + mockConsumer, + ); + + const client = KafkaConsumerClient.fromConfig({ + config: mockConfig, + events: mockEvents, + logger: mockLogger, + }); + + expect(client).toBeDefined(); + + await client?.shutdown(); + + expect(mockConsumer.shutdown).toHaveBeenCalled(); + }); +}); diff --git a/plugins/events-backend-module-kafka/src/publisher/KafkaConsumerClient.ts b/plugins/events-backend-module-kafka/src/publisher/KafkaConsumerClient.ts new file mode 100644 index 0000000000..735b0fc224 --- /dev/null +++ b/plugins/events-backend-module-kafka/src/publisher/KafkaConsumerClient.ts @@ -0,0 +1,79 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { LoggerService } from '@backstage/backend-plugin-api'; +import { Config } from '@backstage/config'; +import { EventsService } from '@backstage/plugin-events-node'; +import { Kafka } from 'kafkajs'; +import { KafkaEventSourceConfig, readConfig } from './config'; +import { KafkaConsumingEventPublisher } from './KafkaConsumingEventPublisher'; +import { loggerServiceAdapter } from './LoggerServiceAdapter'; + +/** + * KafkaConsumerClient + * + * This class creates the Kafka client that will be used to create the KafkaConsumingEventPublisher + * + * @public + */ +export class KafkaConsumerClient { + private readonly kafka: Kafka; + private readonly consumers: KafkaConsumingEventPublisher[]; + + static fromConfig(options: { + config: Config; + events: EventsService; + logger: LoggerService; + }): KafkaConsumerClient | undefined { + const kafkaConfig = readConfig(options.config); + + if (!kafkaConfig) { + options.logger.info( + 'Kafka consumer not configured, skipping initialization', + ); + return undefined; + } + + return new KafkaConsumerClient(options.logger, options.events, kafkaConfig); + } + + private constructor( + logger: LoggerService, + events: EventsService, + config: KafkaEventSourceConfig, + ) { + this.kafka = new Kafka({ + ...config.kafkaConfig, + logCreator: loggerServiceAdapter(logger), + }); + + this.consumers = config.kafkaConsumerConfigs.map(consumerConfig => + KafkaConsumingEventPublisher.fromConfig({ + kafkaClient: this.kafka, + config: consumerConfig, + logger, + events, + }), + ); + } + + async start(): Promise { + this.consumers.map(async consumer => await consumer.start()); + } + + async shutdown(): Promise { + this.consumers.map(async consumer => await consumer.shutdown()); + } +} diff --git a/plugins/events-backend-module-kafka/src/publisher/KafkaConsumingEventPublisher.test.ts b/plugins/events-backend-module-kafka/src/publisher/KafkaConsumingEventPublisher.test.ts new file mode 100644 index 0000000000..64c53595ad --- /dev/null +++ b/plugins/events-backend-module-kafka/src/publisher/KafkaConsumingEventPublisher.test.ts @@ -0,0 +1,92 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { KafkaConsumingEventPublisher } from './KafkaConsumingEventPublisher'; +import { Kafka } from 'kafkajs'; +import { KafkaConsumerConfig } from './config'; +import { mockServices } from '@backstage/backend-test-utils'; + +jest.mock('kafkajs'); + +describe('KafkaConsumingEventPublisher', () => { + const mockLogger = mockServices.logger.mock(); + const mockEvents = mockServices.events.mock(); + + const mockConsumer = { + connect: jest.fn(), + disconnect: jest.fn(), + subscribe: jest.fn(), + run: jest.fn(), + }; + + const mockKafkaClient = { + consumer: jest.fn().mockReturnValue(mockConsumer), + } as unknown as Kafka; + + const kafkaConsumerConfig: KafkaConsumerConfig = { + consumerConfig: { + groupId: 'test-group', + }, + consumerSubscribeTopics: { + topics: ['test-topic'], + }, + backstageTopic: 'backstage-topic', + }; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('should create an instance from config', () => { + const consumer = KafkaConsumingEventPublisher.fromConfig({ + kafkaClient: mockKafkaClient, + config: kafkaConsumerConfig, + events: mockEvents, + logger: mockLogger, + }); + + expect(consumer).toBeInstanceOf(KafkaConsumingEventPublisher); + }); + + it('should start the consumer', async () => { + const consumer = KafkaConsumingEventPublisher.fromConfig({ + kafkaClient: mockKafkaClient, + config: kafkaConsumerConfig, + events: mockEvents, + logger: mockLogger, + }); + + await consumer.start(); + + expect(mockConsumer.connect).toHaveBeenCalled(); + expect(mockConsumer.subscribe).toHaveBeenCalledWith( + kafkaConsumerConfig.consumerSubscribeTopics, + ); + expect(mockConsumer.run).toHaveBeenCalled(); + }); + + it('should shutdown the consumer', async () => { + const consumer = KafkaConsumingEventPublisher.fromConfig({ + kafkaClient: mockKafkaClient, + config: kafkaConsumerConfig, + events: mockEvents, + logger: mockLogger, + }); + + await consumer.shutdown(); + + expect(mockConsumer.disconnect).toHaveBeenCalled(); + }); +}); diff --git a/plugins/events-backend-module-kafka/src/publisher/KafkaConsumingEventPublisher.ts b/plugins/events-backend-module-kafka/src/publisher/KafkaConsumingEventPublisher.ts new file mode 100644 index 0000000000..223e4e99ac --- /dev/null +++ b/plugins/events-backend-module-kafka/src/publisher/KafkaConsumingEventPublisher.ts @@ -0,0 +1,109 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { LoggerService } from '@backstage/backend-plugin-api'; +import { EventParams, EventsService } from '@backstage/plugin-events-node'; +import { Consumer, ConsumerSubscribeTopics, IHeaders, Kafka } from 'kafkajs'; +import { KafkaConsumerConfig } from './config'; + +type EventMetadata = EventParams['metadata']; + +/** + * + * This class subscribes to Kafka topics and publishes events received to the registered subscriber. + * The message payload will be used as the event payload and passed to the subscribers. + * + * @public + */ +export class KafkaConsumingEventPublisher { + private readonly kafkaConsumer: Consumer; + private readonly consumerSubscribeTopics: ConsumerSubscribeTopics; + private readonly backstageTopic: string; + private readonly logger: LoggerService; + + static fromConfig(env: { + kafkaClient: Kafka; + config: KafkaConsumerConfig; + events: EventsService; + logger: LoggerService; + }): KafkaConsumingEventPublisher { + return new KafkaConsumingEventPublisher( + env.kafkaClient, + env.logger, + env.events, + env.config, + ); + } + + private constructor( + kafkaClient: Kafka, + logger: LoggerService, + private readonly events: EventsService, + config: KafkaConsumerConfig, + ) { + this.kafkaConsumer = kafkaClient.consumer(config.consumerConfig); + this.consumerSubscribeTopics = config.consumerSubscribeTopics; + this.backstageTopic = config.backstageTopic; + const id = `events.kafka.publisher:${this.backstageTopic}`; + this.logger = logger.child({ + class: KafkaConsumingEventPublisher.prototype.constructor.name, + groupId: config.consumerConfig.groupId, + kafkaTopics: config.consumerSubscribeTopics.topics.toString(), + backstageTopic: config.backstageTopic, + taskId: id, + }); + } + + async start(): Promise { + try { + await this.kafkaConsumer.connect(); + + await this.kafkaConsumer.subscribe(this.consumerSubscribeTopics); + + await this.kafkaConsumer.run({ + eachMessage: async ({ message }) => { + this.events.publish({ + topic: this.backstageTopic, + eventPayload: JSON.parse(message.value?.toString()!), + metadata: this.convertHeadersToMetadata(message.headers), + }); + }, + }); + } catch (error: any) { + this.logger.error('Kafka consumer connection failed ', error); + } + } + + async shutdown(): Promise { + await this.kafkaConsumer.disconnect(); + } + + private convertHeadersToMetadata = ( + headers: IHeaders | undefined, + ): EventParams['metadata'] => { + if (!headers) return undefined; + + const metadata: EventMetadata = {}; + + Object.entries(headers).forEach(([key, value]) => { + // If value is an array use toString() on all values converting any Buffer types to valid strings + if (Array.isArray(value)) metadata[key] = value.map(v => v.toString()); + // Always return the values using toString() to catch all Buffer types that should be converted to strings + else metadata[key] = value?.toString(); + }); + + return metadata; + }; +} diff --git a/plugins/events-backend-module-kafka/src/publisher/LoggerServiceAdapter.ts b/plugins/events-backend-module-kafka/src/publisher/LoggerServiceAdapter.ts new file mode 100644 index 0000000000..b9e9379104 --- /dev/null +++ b/plugins/events-backend-module-kafka/src/publisher/LoggerServiceAdapter.ts @@ -0,0 +1,45 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { LoggerService } from '@backstage/backend-plugin-api'; +import { LogEntry, logLevel } from 'kafkajs'; + +export const loggerServiceAdapter = + (loggerService: LoggerService) => (_level: logLevel) => { + return (entry: LogEntry) => { + const { namespace, level, log } = entry; + const { message, ...extra } = log; + + const logMethods: Record< + logLevel, + (message: string, meta?: object) => void + > = { + [logLevel.ERROR]: loggerService.error, + [logLevel.WARN]: loggerService.warn, + [logLevel.INFO]: loggerService.info, + [logLevel.DEBUG]: loggerService.debug, + [logLevel.NOTHING]: () => {}, + }; + + // Use loggerService method that matches the level + logMethods[level].call( + loggerService, + `Kafka ${namespace} ${log.message}`, + { + ...extra, + }, + ); + }; + }; diff --git a/plugins/events-backend-module-kafka/src/publisher/config.test.ts b/plugins/events-backend-module-kafka/src/publisher/config.test.ts new file mode 100644 index 0000000000..fc7e3049b0 --- /dev/null +++ b/plugins/events-backend-module-kafka/src/publisher/config.test.ts @@ -0,0 +1,250 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { ConfigReader } from '@backstage/config'; +import { readConfig } from './config'; + +describe('readConfig', () => { + it('not configured', () => { + const publisherConfigs = readConfig(new ConfigReader({})); + + expect(publisherConfigs).toBeUndefined(); + }); + + it('only required fields configured', () => { + const config = new ConfigReader({ + events: { + modules: { + kafka: { + kafkaConsumingEventPublisher: { + clientId: 'backstage-events', + brokers: ['kafka1:9092', 'kafka2:9092'], + topics: [ + { + topic: 'fake1', + kafka: { + topics: ['topic-A'], + groupId: 'my-group', + }, + }, + { + topic: 'fake2', + kafka: { + topics: ['topic-B'], + groupId: 'my-group', + }, + }, + ], + }, + }, + }, + }, + }); + + const publisherConfigs = readConfig(config); + + expect(publisherConfigs).toBeDefined(); + + expect(publisherConfigs?.kafkaConsumerConfigs.length).toBe(2); + + expect(publisherConfigs?.kafkaConfig.clientId).toEqual('backstage-events'); + expect(publisherConfigs?.kafkaConfig.brokers).toEqual([ + 'kafka1:9092', + 'kafka2:9092', + ]); + expect(publisherConfigs?.kafkaConsumerConfigs[0].backstageTopic).toEqual( + 'fake1', + ); + expect( + publisherConfigs?.kafkaConsumerConfigs[0].consumerConfig.groupId, + ).toEqual('my-group'); + expect( + publisherConfigs?.kafkaConsumerConfigs[0].consumerSubscribeTopics.topics, + ).toEqual(['topic-A']); + }); + + it('all fields configured', () => { + const config = new ConfigReader({ + events: { + modules: { + kafka: { + kafkaConsumingEventPublisher: { + clientId: 'backstage-events', + brokers: ['kafka1:9092', 'kafka2:9092'], + ssl: true, + sasl: { + mechanism: 'plain', + username: 'username', + password: 'password', + }, + retry: { + maxRetryTime: { milliseconds: 20000 }, + initialRetryTime: { milliseconds: 200 }, + factor: '0.4', + multiplier: '4', + retries: '10', + }, + authenticationTimeout: { milliseconds: 20000 }, + connectionTimeout: { milliseconds: 1500 }, + requestTimeout: { milliseconds: 20000 }, + enforceRequestTimeout: false, + topics: [ + { + topic: 'fake1', + kafka: { + topics: ['topic-A'], + groupId: 'my-group', + sessionTimeout: { milliseconds: 20000 }, + rebalanceTimeout: { milliseconds: 50000 }, + heartbeatInterval: { milliseconds: 2000 }, + metadataMaxAge: { milliseconds: 400000 }, + maxBytesPerPartition: 50000, + minBytes: 2, + maxBytes: 500000, + maxWaitTime: { milliseconds: 4000 }, + }, + }, + { + topic: 'fake2', + kafka: { + topics: ['topic-B'], + groupId: 'my-group', + }, + }, + ], + }, + }, + }, + }, + }); + + const publisherConfigs = readConfig(config); + + expect(publisherConfigs).toBeDefined(); + + // Client configuration + expect(publisherConfigs?.kafkaConfig.clientId).toEqual('backstage-events'); + expect(publisherConfigs?.kafkaConfig.brokers).toEqual([ + 'kafka1:9092', + 'kafka2:9092', + ]); + expect(publisherConfigs?.kafkaConfig.ssl).toBeTruthy(); + expect(publisherConfigs?.kafkaConfig.sasl).toStrictEqual({ + mechanism: 'plain', + username: 'username', + password: 'password', + }); + expect(publisherConfigs?.kafkaConfig.authenticationTimeout).toBe(20000); + expect(publisherConfigs?.kafkaConfig.connectionTimeout).toBe(1500); + expect(publisherConfigs?.kafkaConfig.requestTimeout).toBe(20000); + expect(publisherConfigs?.kafkaConfig.enforceRequestTimeout).toBeFalsy(); + expect(publisherConfigs?.kafkaConfig.retry).toStrictEqual({ + maxRetryTime: 20000, + initialRetryTime: 200, + factor: 0.4, + multiplier: 4, + retries: 10, + }); + + // Consumer configuration + expect(publisherConfigs?.kafkaConsumerConfigs.length).toBe(2); + expect(publisherConfigs?.kafkaConsumerConfigs[0].backstageTopic).toEqual( + 'fake1', + ); + expect( + publisherConfigs?.kafkaConsumerConfigs[0].consumerConfig.groupId, + ).toEqual('my-group'); + expect( + publisherConfigs?.kafkaConsumerConfigs[0].consumerSubscribeTopics.topics, + ).toEqual(['topic-A']); + + expect( + publisherConfigs?.kafkaConsumerConfigs[0].consumerConfig.sessionTimeout, + ).toBe(20000); + expect( + publisherConfigs?.kafkaConsumerConfigs[0].consumerConfig.rebalanceTimeout, + ).toBe(50000); + expect( + publisherConfigs?.kafkaConsumerConfigs[0].consumerConfig + .heartbeatInterval, + ).toBe(2000); + expect( + publisherConfigs?.kafkaConsumerConfigs[0].consumerConfig.metadataMaxAge, + ).toBe(400000); + expect( + publisherConfigs?.kafkaConsumerConfigs[0].consumerConfig + .maxBytesPerPartition, + ).toBe(50000); + expect( + publisherConfigs?.kafkaConsumerConfigs[0].consumerConfig.minBytes, + ).toBe(2); + expect( + publisherConfigs?.kafkaConsumerConfigs[0].consumerConfig.maxBytes, + ).toBe(500000); + expect( + publisherConfigs?.kafkaConsumerConfigs[0].consumerConfig.maxWaitTimeInMs, + ).toBe(4000); + }); + + it('should handle HumanDuration and string values for durations and timeouts', () => { + const config = new ConfigReader({ + events: { + modules: { + kafka: { + kafkaConsumingEventPublisher: { + clientId: 'backstage-events', + brokers: ['kafka1:9092', 'kafka2:9092'], + retry: { + maxRetryTime: { seconds: 1 }, + initialRetryTime: { minutes: 1 }, + factor: 0.4, + multiplier: 4, + retries: 10, + }, + authenticationTimeout: { hours: 1 }, + connectionTimeout: { days: 1 }, + topics: [], + requestTimeout: '1m', + }, + }, + }, + }, + }); + + const publisherConfigs = readConfig(config); + + expect(publisherConfigs).toBeDefined(); + + // Client configuration + expect(publisherConfigs?.kafkaConfig.clientId).toEqual('backstage-events'); + expect(publisherConfigs?.kafkaConfig.brokers).toEqual([ + 'kafka1:9092', + 'kafka2:9092', + ]); + expect(publisherConfigs?.kafkaConfig.authenticationTimeout).toBe(3600000); + expect(publisherConfigs?.kafkaConfig.connectionTimeout).toBe(86400000); + expect(publisherConfigs?.kafkaConfig.requestTimeout).toBe(60000); + expect(publisherConfigs?.kafkaConfig.retry).toStrictEqual({ + maxRetryTime: 1000, + initialRetryTime: 60000, + factor: 0.4, + multiplier: 4, + retries: 10, + }); + + // Consumer configuration + expect(publisherConfigs?.kafkaConsumerConfigs.length).toBe(0); + }); +}); diff --git a/plugins/events-backend-module-kafka/src/publisher/config.ts b/plugins/events-backend-module-kafka/src/publisher/config.ts new file mode 100644 index 0000000000..aa5921a7f3 --- /dev/null +++ b/plugins/events-backend-module-kafka/src/publisher/config.ts @@ -0,0 +1,159 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { Config, readDurationFromConfig } from '@backstage/config'; +import { ConsumerConfig, ConsumerSubscribeTopics, KafkaConfig } from 'kafkajs'; +import { Duration } from 'luxon'; + +/** + * @public + */ +export interface KafkaConsumerConfig { + backstageTopic: string; + consumerConfig: ConsumerConfig; + consumerSubscribeTopics: ConsumerSubscribeTopics; +} + +/** + * @public + */ +export interface KafkaEventSourceConfig { + kafkaConfig: KafkaConfig; + kafkaConsumerConfigs: KafkaConsumerConfig[]; +} + +const CONFIG_PREFIX_PUBLISHER = + 'events.modules.kafka.kafkaConsumingEventPublisher'; + +/** + * Reads an optional HumanDuration from the config and returns the value in milliseconds if the key is defined. + * + * @param config - The configuration object to read from. + * @param key - The key to look up in the configuration. + * @returns The duration in milliseconds, or undefined if the key is not defined. + */ +const readOptionalHumanDurationInMs = ( + config: Config, + key: string, +): number | undefined => { + const humanDuration = config.has(key) + ? readDurationFromConfig(config, { key }) + : undefined; + + if (!humanDuration) return undefined; + + return Duration.fromObject(humanDuration).as('milliseconds'); +}; + +export const readConfig = ( + config: Config, +): KafkaEventSourceConfig | undefined => { + const kafkaConfig = config.getOptionalConfig(CONFIG_PREFIX_PUBLISHER); + + if (!kafkaConfig) { + return undefined; + } + + const clientId = kafkaConfig.getString('clientId'); + const brokers = kafkaConfig.getStringArray('brokers'); + + const authenticationTimeout = readOptionalHumanDurationInMs( + kafkaConfig, + 'authenticationTimeout', + ); + + const connectionTimeout = readOptionalHumanDurationInMs( + kafkaConfig, + 'connectionTimeout', + ); + const requestTimeout = readOptionalHumanDurationInMs( + kafkaConfig, + 'requestTimeout', + ); + const enforceRequestTimeout = kafkaConfig.getOptionalBoolean( + 'enforceRequestTimeout', + ); + + const ssl = kafkaConfig.getOptional('ssl') as KafkaConfig['ssl']; + const sasl = kafkaConfig.getOptional('sasl') as KafkaConfig['sasl']; + + const retry: KafkaConfig['retry'] = { + maxRetryTime: readOptionalHumanDurationInMs( + kafkaConfig, + 'retry.maxRetryTime', + ), + initialRetryTime: readOptionalHumanDurationInMs( + kafkaConfig, + 'retry.initialRetryTime', + ), + factor: kafkaConfig.getOptionalNumber('retry.factor'), + multiplier: kafkaConfig.getOptionalNumber('retry.multiplier'), + retries: kafkaConfig.getOptionalNumber('retry.retries'), + }; + + const kafkaConsumerConfigs: KafkaConsumerConfig[] = kafkaConfig + .getConfigArray('topics') + .map(topic => { + return { + backstageTopic: topic.getString('topic'), + consumerConfig: { + groupId: topic.getString('kafka.groupId'), + sessionTimeout: readOptionalHumanDurationInMs( + topic, + 'kafka.sessionTimeout', + ), + rebalanceTimeout: readOptionalHumanDurationInMs( + topic, + 'kafka.rebalanceTimeout', + ), + heartbeatInterval: readOptionalHumanDurationInMs( + topic, + 'kafka.heartbeatInterval', + ), + metadataMaxAge: readOptionalHumanDurationInMs( + topic, + 'kafka.metadataMaxAge', + ), + maxBytesPerPartition: topic.getOptionalNumber( + 'kafka.maxBytesPerPartition', + ), + minBytes: topic.getOptionalNumber('kafka.minBytes'), + maxBytes: topic.getOptionalNumber('kafka.maxBytes'), + maxWaitTimeInMs: readOptionalHumanDurationInMs( + topic, + 'kafka.maxWaitTime', + ), + }, + consumerSubscribeTopics: { + topics: topic.getStringArray('kafka.topics'), + }, + }; + }); + + return { + kafkaConfig: { + clientId, + brokers, + ssl, + sasl, + authenticationTimeout, + connectionTimeout, + requestTimeout, + enforceRequestTimeout, + retry, + }, + kafkaConsumerConfigs, + }; +}; diff --git a/plugins/events-backend-module-kafka/src/service/eventsModuleKafkaConsumingEventPublisher.test.ts b/plugins/events-backend-module-kafka/src/service/eventsModuleKafkaConsumingEventPublisher.test.ts new file mode 100644 index 0000000000..816793f635 --- /dev/null +++ b/plugins/events-backend-module-kafka/src/service/eventsModuleKafkaConsumingEventPublisher.test.ts @@ -0,0 +1,85 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { createServiceFactory } from '@backstage/backend-plugin-api'; +import { mockServices, startTestBackend } from '@backstage/backend-test-utils'; +import { eventsServiceRef } from '@backstage/plugin-events-node'; +import { TestEventsService } from '@backstage/plugin-events-backend-test-utils'; +import { eventsModuleKafkaConsumingEventPublisher } from './eventsModuleKafkaConsumingEventPublisher'; +import { KafkaConsumerClient } from '../publisher/KafkaConsumerClient'; + +jest.mock('../publisher/KafkaConsumerClient'); + +describe('eventsModuleKafkaConsumingEventPublisher', () => { + it('should be correctly wired and set up', async () => { + const events = new TestEventsService(); + const eventsServiceFactory = createServiceFactory({ + service: eventsServiceRef, + deps: {}, + async factory({}) { + return events; + }, + }); + + const mockKafkaConsumerClient = { + start: jest.fn(), + shutdown: jest.fn(), + }; + (KafkaConsumerClient.fromConfig as jest.Mock).mockReturnValue( + mockKafkaConsumerClient, + ); + + await startTestBackend({ + features: [ + eventsServiceFactory, + eventsModuleKafkaConsumingEventPublisher, + mockServices.rootConfig.factory({ + data: { + events: { + modules: { + kafka: { + kafkaConsumingEventPublisher: { + clientId: 'backstage-events', + brokers: ['kafka1:9092', 'kafka2:9092'], + topics: { + fake1: { + kafka: { + topics: ['topic-A'], + groupId: 'my-group', + }, + }, + fake2: { + kafka: { + topics: ['topic-B'], + groupId: 'my-group', + }, + }, + }, + }, + }, + }, + }, + }, + }), + ], + }); + + // Verify that the Kafka consumer client was started + expect(mockKafkaConsumerClient.start).toHaveBeenCalled(); + + // Verify that the shutdown hook was registered + expect(mockKafkaConsumerClient.shutdown).not.toHaveBeenCalled(); + }); +}); diff --git a/plugins/events-backend-module-kafka/src/service/eventsModuleKafkaConsumingEventPublisher.ts b/plugins/events-backend-module-kafka/src/service/eventsModuleKafkaConsumingEventPublisher.ts new file mode 100644 index 0000000000..b524454ca0 --- /dev/null +++ b/plugins/events-backend-module-kafka/src/service/eventsModuleKafkaConsumingEventPublisher.ts @@ -0,0 +1,56 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { + coreServices, + createBackendModule, +} from '@backstage/backend-plugin-api'; +import { KafkaConsumerClient } from '../publisher/KafkaConsumerClient'; +import { eventsServiceRef } from '@backstage/plugin-events-node'; + +/** + * Kafka module for the Events plugin. + * + * @public + */ +export const eventsModuleKafkaConsumingEventPublisher = createBackendModule({ + pluginId: 'events', + moduleId: 'kafka-consuming-event-publisher', + register(env) { + env.registerInit({ + deps: { + config: coreServices.rootConfig, + events: eventsServiceRef, + logger: coreServices.logger, + lifecycle: coreServices.lifecycle, + }, + async init({ config, logger, events, lifecycle }) { + const kafka = KafkaConsumerClient.fromConfig({ + config, + events, + logger, + }); + + if (!kafka) { + return; + } + + await kafka.start(); + + lifecycle.addShutdownHook(async () => await kafka.shutdown()); + }, + }); + }, +}); diff --git a/plugins/events-backend-test-utils/CHANGELOG.md b/plugins/events-backend-test-utils/CHANGELOG.md index 0acf569d83..e9a355c610 100644 --- a/plugins/events-backend-test-utils/CHANGELOG.md +++ b/plugins/events-backend-test-utils/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/plugin-events-backend-test-utils +## 0.1.45 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.4.12 + ## 0.1.45-next.1 ### Patch Changes diff --git a/plugins/events-backend-test-utils/package.json b/plugins/events-backend-test-utils/package.json index 1662f4f943..6cdb45110f 100644 --- a/plugins/events-backend-test-utils/package.json +++ b/plugins/events-backend-test-utils/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-test-utils", - "version": "0.1.45-next.1", + "version": "0.1.45", "description": "The plugin-events-backend-test-utils for @backstage/plugin-events-node", "backstage": { "role": "node-library", diff --git a/plugins/events-backend/CHANGELOG.md b/plugins/events-backend/CHANGELOG.md index 90f5f6009f..e0a28c935a 100644 --- a/plugins/events-backend/CHANGELOG.md +++ b/plugins/events-backend/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-events-backend +## 0.5.3 + +### Patch Changes + +- c83cd8b: Fixed some circular or otherwise unclear imports +- Updated dependencies + - @backstage/backend-plugin-api@1.4.0 + - @backstage/backend-openapi-utils@0.5.4 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/plugin-events-node@0.4.12 + ## 0.5.3-next.1 ### Patch Changes diff --git a/plugins/events-backend/package.json b/plugins/events-backend/package.json index 0f57e0da5a..79cee20cda 100644 --- a/plugins/events-backend/package.json +++ b/plugins/events-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend", - "version": "0.5.3-next.1", + "version": "0.5.3", "backstage": { "role": "backend-plugin", "pluginId": "events", diff --git a/plugins/events-backend/src/schema/openapi/generated/router.ts b/plugins/events-backend/src/schema/openapi/generated/router.ts index 3c43880170..d2cedd2166 100644 --- a/plugins/events-backend/src/schema/openapi/generated/router.ts +++ b/plugins/events-backend/src/schema/openapi/generated/router.ts @@ -18,7 +18,7 @@ // * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * // ****************************************************************** import { createValidatedOpenApiRouterFromGeneratedEndpointMap } from '@backstage/backend-openapi-utils'; -import { EndpointMap } from './'; +import { EndpointMap } from './apis'; export const spec = { openapi: '3.0.3', diff --git a/plugins/events-backend/src/service/EventsPlugin.test.ts b/plugins/events-backend/src/service/EventsPlugin.test.ts index 12a0f63002..2c3fb3b909 100644 --- a/plugins/events-backend/src/service/EventsPlugin.test.ts +++ b/plugins/events-backend/src/service/EventsPlugin.test.ts @@ -34,6 +34,8 @@ import { TestEventsService } from '@backstage/plugin-events-backend-test-utils'; import request from 'supertest'; import { eventsPlugin } from './EventsPlugin'; +jest.setTimeout(60_000); + describe('eventsPlugin', () => { it('should be initialized properly', async () => { const eventsService = new TestEventsService(); diff --git a/plugins/events-backend/src/service/hub/DatabaseEventBusStore.test.ts b/plugins/events-backend/src/service/hub/DatabaseEventBusStore.test.ts index 959341cbc0..5664475851 100644 --- a/plugins/events-backend/src/service/hub/DatabaseEventBusStore.test.ts +++ b/plugins/events-backend/src/service/hub/DatabaseEventBusStore.test.ts @@ -21,6 +21,8 @@ import { } from '@backstage/backend-test-utils'; import { DatabaseEventBusStore } from './DatabaseEventBusStore'; +jest.setTimeout(60_000); + const logger = mockServices.logger.mock(); const databases = TestDatabases.create({ diff --git a/plugins/events-node/CHANGELOG.md b/plugins/events-node/CHANGELOG.md index 06960faf33..235b37dcc2 100644 --- a/plugins/events-node/CHANGELOG.md +++ b/plugins/events-node/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-events-node +## 0.4.12 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.0 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + ## 0.4.12-next.1 ### Patch Changes diff --git a/plugins/events-node/package.json b/plugins/events-node/package.json index c60bb7ded1..92c7bb3b37 100644 --- a/plugins/events-node/package.json +++ b/plugins/events-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-node", - "version": "0.4.12-next.1", + "version": "0.4.12", "description": "The plugin-events-node module for @backstage/plugin-events-backend", "backstage": { "role": "node-library", diff --git a/plugins/example-todo-list-backend/CHANGELOG.md b/plugins/example-todo-list-backend/CHANGELOG.md index eb0f46dc95..13b66a91d0 100644 --- a/plugins/example-todo-list-backend/CHANGELOG.md +++ b/plugins/example-todo-list-backend/CHANGELOG.md @@ -1,5 +1,13 @@ # @internal/plugin-todo-list-backend +## 1.0.40 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.0 + - @backstage/errors@1.2.7 + ## 1.0.40-next.1 ### Patch Changes diff --git a/plugins/example-todo-list-backend/package.json b/plugins/example-todo-list-backend/package.json index 1e8152f632..508b70af1f 100644 --- a/plugins/example-todo-list-backend/package.json +++ b/plugins/example-todo-list-backend/package.json @@ -1,6 +1,6 @@ { "name": "@internal/plugin-todo-list-backend", - "version": "1.0.40-next.1", + "version": "1.0.40", "backstage": { "role": "backend-plugin", "pluginId": "todo-list", diff --git a/plugins/example-todo-list/CHANGELOG.md b/plugins/example-todo-list/CHANGELOG.md index 219f418b6e..10d2ab94ba 100644 --- a/plugins/example-todo-list/CHANGELOG.md +++ b/plugins/example-todo-list/CHANGELOG.md @@ -1,5 +1,21 @@ # @internal/plugin-todo-list +## 1.0.40 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3 + - @backstage/core-plugin-api@1.10.8 + +## 1.0.40-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/core-plugin-api@1.10.7 + ## 1.0.39 ### Patch Changes diff --git a/plugins/example-todo-list/package.json b/plugins/example-todo-list/package.json index 3fbdf8fe9d..f42ccd267d 100644 --- a/plugins/example-todo-list/package.json +++ b/plugins/example-todo-list/package.json @@ -1,6 +1,6 @@ { "name": "@internal/plugin-todo-list", - "version": "1.0.39", + "version": "1.0.40", "backstage": { "role": "frontend-plugin", "pluginId": "todo-list", diff --git a/plugins/gateway-backend/CHANGELOG.md b/plugins/gateway-backend/CHANGELOG.md index 5521af45d0..a75b886136 100644 --- a/plugins/gateway-backend/CHANGELOG.md +++ b/plugins/gateway-backend/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/plugin-gateway-backend +## 1.0.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.0 + ## 1.0.2-next.1 ### Patch Changes diff --git a/plugins/gateway-backend/package.json b/plugins/gateway-backend/package.json index c7efdbfaec..f33b9041e7 100644 --- a/plugins/gateway-backend/package.json +++ b/plugins/gateway-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-gateway-backend", - "version": "1.0.2-next.1", + "version": "1.0.2", "backstage": { "role": "backend-plugin", "pluginId": "gateway", diff --git a/plugins/home-react/CHANGELOG.md b/plugins/home-react/CHANGELOG.md index 42b7f67b3b..829ec3eea2 100644 --- a/plugins/home-react/CHANGELOG.md +++ b/plugins/home-react/CHANGELOG.md @@ -1,5 +1,24 @@ # @backstage/plugin-home-react +## 0.1.27 + +### Patch Changes + +- c83cd8b: Fixed some circular or otherwise unclear imports +- cef60db: Home plugin support i18n +- Updated dependencies + - @backstage/core-components@0.17.3 + - @backstage/core-plugin-api@1.10.8 + - @backstage/frontend-plugin-api@0.10.3 + +## 0.1.27-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/core-plugin-api@1.10.7 + ## 0.1.26 ### Patch Changes diff --git a/plugins/home-react/package.json b/plugins/home-react/package.json index 37180110fe..47466e61e8 100644 --- a/plugins/home-react/package.json +++ b/plugins/home-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-home-react", - "version": "0.1.26", + "version": "0.1.27", "description": "A Backstage plugin that contains react components helps you build a home page", "backstage": { "role": "web-library", @@ -11,9 +11,7 @@ ] }, "publishConfig": { - "access": "public", - "main": "dist/index.esm.js", - "types": "dist/index.d.ts" + "access": "public" }, "keywords": [ "backstage", @@ -27,8 +25,23 @@ }, "license": "Apache-2.0", "sideEffects": false, + "exports": { + ".": "./src/index.ts", + "./alpha": "./src/alpha.ts", + "./package.json": "./package.json" + }, "main": "src/index.ts", "types": "src/index.ts", + "typesVersions": { + "*": { + "alpha": [ + "src/alpha.ts" + ], + "package.json": [ + "package.json" + ] + } + }, "files": [ "dist" ], @@ -44,6 +57,7 @@ "dependencies": { "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", + "@backstage/frontend-plugin-api": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@rjsf/utils": "5.23.2" diff --git a/plugins/home-react/report-alpha.api.md b/plugins/home-react/report-alpha.api.md new file mode 100644 index 0000000000..fad4c5a2bc --- /dev/null +++ b/plugins/home-react/report-alpha.api.md @@ -0,0 +1,19 @@ +## API Report File for "@backstage/plugin-home-react" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { TranslationRef } from '@backstage/frontend-plugin-api'; + +// @alpha (undocumented) +export const homeReactTranslationRef: TranslationRef< + 'home-react', + { + readonly 'settingsModal.title': 'Settings'; + readonly 'settingsModal.closeButtonTitle': 'Close'; + readonly 'cardExtension.settingsButtonTitle': 'Settings'; + } +>; + +// (No @packageDocumentation comment for this package) +``` diff --git a/plugins/home-react/src/alpha.ts b/plugins/home-react/src/alpha.ts new file mode 100644 index 0000000000..3a08699f66 --- /dev/null +++ b/plugins/home-react/src/alpha.ts @@ -0,0 +1,16 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export { homeReactTranslationRef } from './translation'; diff --git a/plugins/home-react/src/components/SettingsModal.tsx b/plugins/home-react/src/components/SettingsModal.tsx index 4a6aa46198..37b8d103c2 100644 --- a/plugins/home-react/src/components/SettingsModal.tsx +++ b/plugins/home-react/src/components/SettingsModal.tsx @@ -14,11 +14,13 @@ * limitations under the License. */ +import { useTranslationRef } from '@backstage/frontend-plugin-api'; import Button from '@material-ui/core/Button'; import Dialog from '@material-ui/core/Dialog'; import DialogActions from '@material-ui/core/DialogActions'; import DialogContent from '@material-ui/core/DialogContent'; import DialogTitle from '@material-ui/core/DialogTitle'; +import { homeReactTranslationRef } from '../translation'; /** @public */ export const SettingsModal = (props: { @@ -28,16 +30,18 @@ export const SettingsModal = (props: { children: JSX.Element; }) => { const { open, close, componentName, children } = props; - + const { t } = useTranslationRef(homeReactTranslationRef); return ( close()}> - {componentName ? `Settings - ${componentName}` : 'Settings'} + {componentName + ? `${t('settingsModal.title')} - ${componentName}` + : t('settingsModal.title')} {children} diff --git a/plugins/home-react/src/extensions.tsx b/plugins/home-react/src/extensions.tsx index 610c76bb0e..7795e20c73 100644 --- a/plugins/home-react/src/extensions.tsx +++ b/plugins/home-react/src/extensions.tsx @@ -21,6 +21,8 @@ import { InfoCard } from '@backstage/core-components'; import { SettingsModal } from './components'; import { createReactExtension, useApp } from '@backstage/core-plugin-api'; import { RJSFSchema, UiSchema } from '@rjsf/utils'; +import { useTranslationRef } from '@backstage/frontend-plugin-api'; +import { homeReactTranslationRef } from './translation'; /** * @public @@ -133,6 +135,7 @@ function CardExtension(props: CardExtensionComponentProps) { const app = useApp(); const { Progress } = app.getComponents(); const [settingsOpen, setSettingsOpen] = useState(false); + const { t } = useTranslationRef(homeReactTranslationRef); if (Renderer) { return ( @@ -158,7 +161,9 @@ function CardExtension(props: CardExtensionComponentProps) { ? { action: ( setSettingsOpen(true)}> - Settings + + {t('cardExtension.settingsButtonTitle')} + ), } diff --git a/plugins/home-react/src/overridableComponents.ts b/plugins/home-react/src/overridableComponents.ts index 8a88fd5c94..3653257507 100644 --- a/plugins/home-react/src/overridableComponents.ts +++ b/plugins/home-react/src/overridableComponents.ts @@ -16,7 +16,7 @@ import { Overrides } from '@material-ui/core/styles/overrides'; import { StyleRules } from '@material-ui/core/styles/withStyles'; -import { PluginHomeContentModalClassKey } from './'; +import { PluginHomeContentModalClassKey } from './components/ContentModal'; /** @public */ export type PluginHomeComponentsNameToClassKey = { diff --git a/plugins/home-react/src/translation.ts b/plugins/home-react/src/translation.ts new file mode 100644 index 0000000000..8de5bb1ff1 --- /dev/null +++ b/plugins/home-react/src/translation.ts @@ -0,0 +1,32 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { createTranslationRef } from '@backstage/frontend-plugin-api'; + +/** + * @alpha + */ +export const homeReactTranslationRef = createTranslationRef({ + id: 'home-react', + messages: { + settingsModal: { + title: 'Settings', + closeButtonTitle: 'Close', + }, + cardExtension: { + settingsButtonTitle: 'Settings', + }, + }, +}); diff --git a/plugins/home/CHANGELOG.md b/plugins/home/CHANGELOG.md index 3b4972c087..c28c6528a0 100644 --- a/plugins/home/CHANGELOG.md +++ b/plugins/home/CHANGELOG.md @@ -1,5 +1,43 @@ # @backstage/plugin-home +## 0.8.9 + +### Patch Changes + +- 18c64e9: Added the `info.packageJson` option to the plugin instance for the new frontend system. +- 0ebad54: Fixed the `WelcomeTitle` to properly default to the previous value of `inherit` +- cef60db: Home plugin support i18n +- Updated dependencies + - @backstage/core-components@0.17.3 + - @backstage/catalog-client@1.10.1 + - @backstage/core-plugin-api@1.10.8 + - @backstage/plugin-home-react@0.1.27 + - @backstage/frontend-plugin-api@0.10.3 + - @backstage/plugin-catalog-react@1.19.0 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/core-app-api@1.17.1 + - @backstage/core-compat-api@0.4.3 + - @backstage/theme@0.6.6 + +## 0.8.9-next.2 + +### Patch Changes + +- 0ebad54: Fixed the `WelcomeTitle` to properly default to the previous value of `inherit` +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/plugin-catalog-react@1.19.0-next.2 + - @backstage/frontend-plugin-api@0.10.3-next.1 + - @backstage/plugin-home-react@0.1.27-next.0 + - @backstage/catalog-client@1.10.1-next.0 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/core-app-api@1.17.0 + - @backstage/core-compat-api@0.4.3-next.2 + - @backstage/core-plugin-api@1.10.7 + - @backstage/theme@0.6.6 + ## 0.8.9-next.1 ### Patch Changes diff --git a/plugins/home/package.json b/plugins/home/package.json index e6550137fc..203a670ed9 100644 --- a/plugins/home/package.json +++ b/plugins/home/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-home", - "version": "0.8.9-next.1", + "version": "0.8.9", "description": "A Backstage plugin that helps you build a home page", "backstage": { "role": "frontend-plugin", diff --git a/plugins/home/report-alpha.api.md b/plugins/home/report-alpha.api.md index 5e43163e31..f36589ea51 100644 --- a/plugins/home/report-alpha.api.md +++ b/plugins/home/report-alpha.api.md @@ -10,6 +10,7 @@ import { ExtensionInput } from '@backstage/frontend-plugin-api'; import { FrontendPlugin } from '@backstage/frontend-plugin-api'; import { JSX as JSX_2 } from 'react'; import { RouteRef } from '@backstage/frontend-plugin-api'; +import { TranslationRef } from '@backstage/frontend-plugin-api'; // @alpha (undocumented) const _default: FrontendPlugin< @@ -69,6 +70,38 @@ const _default: FrontendPlugin< >; export default _default; +// @alpha (undocumented) +export const homeTranslationRef: TranslationRef< + 'home', + { + readonly 'starredEntities.noStarredEntitiesMessage': 'Click the star beside an entity name to add it to this list!'; + readonly 'addWidgetDialog.title': 'Add new widget to dashboard'; + readonly 'customHomepageButtons.clearAll': 'Clear all'; + readonly 'customHomepageButtons.edit': 'Edit'; + readonly 'customHomepageButtons.restoreDefaults': 'Restore defaults'; + readonly 'customHomepageButtons.addWidget': 'Add widget'; + readonly 'customHomepageButtons.save': 'Save'; + readonly 'customHomepage.noWidgets': "No widgets added. Start by clicking the 'Add widget' button."; + readonly 'widgetSettingsOverlay.cancelButtonTitle': 'Cancel'; + readonly 'widgetSettingsOverlay.editSettingsTooptip': 'Edit settings'; + readonly 'widgetSettingsOverlay.deleteWidgetTooltip': 'Delete widget'; + readonly 'widgetSettingsOverlay.submitButtonTitle': 'Submit'; + readonly 'starredEntityListItem.removeFavoriteEntityTitle': 'Remove entity from favorites'; + readonly 'visitList.empty.title': 'There are no visits to show yet.'; + readonly 'visitList.empty.description': 'Once you start using Backstage, your visits will appear here as a quick link to carry on where you left off.'; + readonly 'visitList.few.title': 'The more pages you visit, the more pages will appear here.'; + readonly 'quickStart.title': 'Onboarding'; + readonly 'quickStart.description': 'Get started with Backstage'; + readonly 'quickStart.learnMoreLinkTitle': 'Learn more'; + readonly 'visitedByType.action.viewMore': 'View more'; + readonly 'visitedByType.action.viewLess': 'View less'; + readonly 'featuredDocsCard.empty.title': 'No documents to show'; + readonly 'featuredDocsCard.empty.description': 'Create your own document. Check out our Getting Started Information'; + readonly 'featuredDocsCard.empty.learnMoreLinkTitle': 'DOCS'; + readonly 'featuredDocsCard.learnMoreTitle': 'LEARN MORE'; + } +>; + // @alpha (undocumented) export const titleExtensionDataRef: ConfigurableExtensionDataRef< string, diff --git a/plugins/home/src/alpha.tsx b/plugins/home/src/alpha.tsx index 854a8a7dd3..fc34c6e806 100644 --- a/plugins/home/src/alpha.tsx +++ b/plugins/home/src/alpha.tsx @@ -74,3 +74,5 @@ export default createFrontendPlugin({ root: rootRouteRef, }, }); + +export { homeTranslationRef } from './translation'; diff --git a/plugins/home/src/components/CustomHomepage/AddWidgetDialog.tsx b/plugins/home/src/components/CustomHomepage/AddWidgetDialog.tsx index 6519bfe901..4763401fe5 100644 --- a/plugins/home/src/components/CustomHomepage/AddWidgetDialog.tsx +++ b/plugins/home/src/components/CustomHomepage/AddWidgetDialog.tsx @@ -23,6 +23,8 @@ import ListItemAvatar from '@material-ui/core/ListItemAvatar'; import AddIcon from '@material-ui/icons/Add'; import ListItemText from '@material-ui/core/ListItemText'; import Typography from '@material-ui/core/Typography'; +import { useTranslationRef } from '@backstage/frontend-plugin-api'; +import { homeTranslationRef } from '../../translation'; interface AddWidgetDialogProps { widgets: Widget[]; @@ -35,9 +37,10 @@ const getTitle = (widget: Widget) => { export const AddWidgetDialog = (props: AddWidgetDialogProps) => { const { widgets, handleAdd } = props; + const { t } = useTranslationRef(homeTranslationRef); return ( <> - Add new widget to dashboard + {t('addWidgetDialog.title')} {widgets.map(widget => { diff --git a/plugins/home/src/components/CustomHomepage/CustomHomepageButtons.tsx b/plugins/home/src/components/CustomHomepage/CustomHomepageButtons.tsx index d586f94d20..0496e923de 100644 --- a/plugins/home/src/components/CustomHomepage/CustomHomepageButtons.tsx +++ b/plugins/home/src/components/CustomHomepage/CustomHomepageButtons.tsx @@ -20,6 +20,8 @@ import DeleteIcon from '@material-ui/icons/Delete'; import AddIcon from '@material-ui/icons/Add'; import EditIcon from '@material-ui/icons/Edit'; import CancelIcon from '@material-ui/icons/Cancel'; +import { useTranslationRef } from '@backstage/frontend-plugin-api'; +import { homeTranslationRef } from '../../translation'; const useStyles = makeStyles((theme: Theme) => createStyles({ @@ -55,6 +57,7 @@ export const CustomHomepageButtons = (props: CustomHomepageButtonsProps) => { restoreDefault, } = props; const styles = useStyles(); + const { t } = useTranslationRef(homeTranslationRef); return ( <> @@ -66,7 +69,7 @@ export const CustomHomepageButtons = (props: CustomHomepageButtonsProps) => { size="small" startIcon={} > - Edit + {t('customHomepageButtons.edit')} ) : ( <> @@ -78,7 +81,7 @@ export const CustomHomepageButtons = (props: CustomHomepageButtonsProps) => { size="small" startIcon={} > - Restore defaults + {t('customHomepageButtons.restoreDefaults')} )} {numWidgets > 0 && ( @@ -90,7 +93,7 @@ export const CustomHomepageButtons = (props: CustomHomepageButtonsProps) => { size="small" startIcon={} > - Clear all + {t('customHomepageButtons.clearAll')} )} {numWidgets > 0 && ( )} diff --git a/plugins/home/src/components/CustomHomepage/CustomHomepageGrid.tsx b/plugins/home/src/components/CustomHomepage/CustomHomepageGrid.tsx index 675e17357e..4b3d35ed62 100644 --- a/plugins/home/src/components/CustomHomepage/CustomHomepageGrid.tsx +++ b/plugins/home/src/components/CustomHomepage/CustomHomepageGrid.tsx @@ -50,6 +50,8 @@ import { WidgetSchema, } from './types'; import { CardConfig } from '@backstage/plugin-home-react'; +import { useTranslationRef } from '@backstage/frontend-plugin-api'; +import { homeTranslationRef } from '../../translation'; // eslint-disable-next-line new-cap const ResponsiveGrid = WidthProvider(Responsive); @@ -222,6 +224,7 @@ export const CustomHomepageGrid = (props: CustomHomepageGridProps) => { const getWidgetNameFromKey = (key: string) => { return key.split('__')[0]; }; + const { t } = useTranslationRef(homeTranslationRef); const handleAdd = (widget: Widget) => { const widgetId = `${widget.name}__${widgets.length + 1}${Math.random() @@ -340,7 +343,7 @@ export const CustomHomepageGrid = (props: CustomHomepageGridProps) => { {!editMode && widgets.length === 0 && ( - No widgets added. Start by clicking the 'Add widget' button. + {t('customHomepage.noWidgets')} )} { const styles = useStyles(); const onClose = () => setSettingsDialogOpen(false); + const { t } = useTranslationRef(homeTranslationRef); return (
@@ -98,10 +101,10 @@ export const WidgetSettingsOverlay = (props: WidgetSettingsOverlayProps) => { > @@ -116,7 +119,7 @@ export const WidgetSettingsOverlay = (props: WidgetSettingsOverlayProps) => { > {widget.settingsSchema && ( - + setSettingsDialogOpen(true)} @@ -128,7 +131,7 @@ export const WidgetSettingsOverlay = (props: WidgetSettingsOverlayProps) => { )} {deletable !== false && ( - + handleRemove(id)}> diff --git a/plugins/home/src/components/StarredEntityListItem/StarredEntityListItem.tsx b/plugins/home/src/components/StarredEntityListItem/StarredEntityListItem.tsx index 28f199978d..60433fbddf 100644 --- a/plugins/home/src/components/StarredEntityListItem/StarredEntityListItem.tsx +++ b/plugins/home/src/components/StarredEntityListItem/StarredEntityListItem.tsx @@ -26,6 +26,8 @@ import { entityRouteRef } from '@backstage/plugin-catalog-react'; import { useRouteRef } from '@backstage/core-plugin-api'; import { FavoriteToggle } from '@backstage/core-components'; import { makeStyles } from '@material-ui/core/styles'; +import { useTranslationRef } from '@backstage/frontend-plugin-api'; +import { homeTranslationRef } from '../../translation'; type EntityListItemProps = { entity: Entity; @@ -50,6 +52,7 @@ export const StarredEntityListItem = ({ }: EntityListItemProps) => { const classes = useStyles(); const catalogEntityRoute = useRouteRef(entityRouteRef); + const { t } = useTranslationRef(homeTranslationRef); let secondaryText = ''; if (showKind) { @@ -80,7 +83,7 @@ export const StarredEntityListItem = ({ > onToggleStarredEntity(entity)} /> diff --git a/plugins/home/src/components/VisitList/VisitListEmpty.tsx b/plugins/home/src/components/VisitList/VisitListEmpty.tsx index e8b6d369d2..144c9a2066 100644 --- a/plugins/home/src/components/VisitList/VisitListEmpty.tsx +++ b/plugins/home/src/components/VisitList/VisitListEmpty.tsx @@ -14,16 +14,20 @@ * limitations under the License. */ +import { useTranslationRef } from '@backstage/frontend-plugin-api'; import Typography from '@material-ui/core/Typography'; +import { homeTranslationRef } from '../../translation'; -export const VisitListEmpty = () => ( - <> - - There are no visits to show yet. - - - Once you start using Backstage, your visits will appear here as a quick - link to carry on where you left off. - - -); +export const VisitListEmpty = () => { + const { t } = useTranslationRef(homeTranslationRef); + return ( + <> + + {t('visitList.empty.title')} + + + {t('visitList.empty.description')} + + + ); +}; diff --git a/plugins/home/src/components/VisitList/VisitListFew.tsx b/plugins/home/src/components/VisitList/VisitListFew.tsx index 26fdb92293..7f741f3af5 100644 --- a/plugins/home/src/components/VisitList/VisitListFew.tsx +++ b/plugins/home/src/components/VisitList/VisitListFew.tsx @@ -14,12 +14,17 @@ * limitations under the License. */ +import { useTranslationRef } from '@backstage/frontend-plugin-api'; import Typography from '@material-ui/core/Typography'; +import { homeTranslationRef } from '../../translation'; -export const VisitListFew = () => ( - <> - - The more pages you visit, the more pages will appear here. - - -); +export const VisitListFew = () => { + const { t } = useTranslationRef(homeTranslationRef); + return ( + <> + + {t('visitList.few.title')} + + + ); +}; diff --git a/plugins/home/src/homePageComponents/FeaturedDocsCard/Content.tsx b/plugins/home/src/homePageComponents/FeaturedDocsCard/Content.tsx index 475ef4b47e..a854203fdb 100644 --- a/plugins/home/src/homePageComponents/FeaturedDocsCard/Content.tsx +++ b/plugins/home/src/homePageComponents/FeaturedDocsCard/Content.tsx @@ -33,6 +33,8 @@ import { EntityFilterQuery } from '@backstage/catalog-client'; import Typography from '@material-ui/core/Typography'; import { makeStyles } from '@material-ui/core/styles'; import { stringifyEntityRef } from '@backstage/catalog-model'; +import { useTranslationRef } from '@backstage/frontend-plugin-api'; +import { homeTranslationRef } from '../../translation'; /** * Props customizing the component. @@ -88,7 +90,8 @@ const useStyles = makeStyles( export const Content = (props: FeaturedDocsCardProps): JSX.Element => { const { emptyState, filter, linkDestination, responseLimit, subLinkText } = props; - const linkText = subLinkText || 'LEARN MORE'; + const { t } = useTranslationRef(homeTranslationRef); + const linkText = subLinkText || t('featuredDocsCard.learnMoreTitle'); const styles = useStyles(); const catalogApi = useApi(catalogApiRef); const { @@ -153,14 +156,14 @@ export const Content = (props: FeaturedDocsCardProps): JSX.Element => { emptyState || ( - DOCS + {t('featuredDocsCard.empty.learnMoreLinkTitle')} } /> diff --git a/plugins/home/src/homePageComponents/QuickStart/Content.tsx b/plugins/home/src/homePageComponents/QuickStart/Content.tsx index b923970888..5317312626 100644 --- a/plugins/home/src/homePageComponents/QuickStart/Content.tsx +++ b/plugins/home/src/homePageComponents/QuickStart/Content.tsx @@ -20,6 +20,8 @@ import Typography from '@material-ui/core/Typography'; import Grid from '@material-ui/core/Grid'; import { ContentModal } from '@backstage/plugin-home-react'; import { useStyles } from './styles'; +import { useTranslationRef } from '@backstage/frontend-plugin-api'; +import { homeTranslationRef } from '../../translation'; /** * Props customizing the component. @@ -54,14 +56,15 @@ export type QuickStartCardProps = { */ export const Content = (props: QuickStartCardProps): JSX.Element => { const styles = useStyles(); + const { t } = useTranslationRef(homeTranslationRef); return ( <> - {props.cardDescription || 'Get started with Backstage'} + {props.cardDescription || t('quickStart.description')} { variant="h6" className={styles.link} > - {props.docsLinkTitle || 'Learn more'} + {props.docsLinkTitle || t('quickStart.learnMoreLinkTitle')} diff --git a/plugins/home/src/homePageComponents/StarredEntities/Content.tsx b/plugins/home/src/homePageComponents/StarredEntities/Content.tsx index 80f5ee74b5..ffe1b36b36 100644 --- a/plugins/home/src/homePageComponents/StarredEntities/Content.tsx +++ b/plugins/home/src/homePageComponents/StarredEntities/Content.tsx @@ -29,6 +29,8 @@ import { ReactNode, useState } from 'react'; import useAsync from 'react-use/esm/useAsync'; import { StarredEntityListItem } from '../../components/StarredEntityListItem/StarredEntityListItem'; import { makeStyles } from '@material-ui/core/styles'; +import { useTranslationRef } from '@backstage/frontend-plugin-api'; +import { homeTranslationRef } from '../../translation'; const useStyles = makeStyles(theme => ({ tabs: { @@ -63,6 +65,7 @@ export const Content = ({ const catalogApi = useApi(catalogApiRef); const { starredEntities, toggleStarredEntity } = useStarredEntities(); const [activeTab, setActiveTab] = useState(0); + const { t } = useTranslationRef(homeTranslationRef); // Grab starred entities from catalog to ensure they still exist and also retrieve display titles const entities = useAsync(async () => { @@ -89,7 +92,7 @@ export const Content = ({ return ( {noStarredEntitiesMessage || - 'Click the star beside an entity name to add it to this list!'} + t('starredEntities.noStarredEntitiesMessage')} ); diff --git a/plugins/home/src/homePageComponents/VisitedByType/Actions.tsx b/plugins/home/src/homePageComponents/VisitedByType/Actions.tsx index a8e8bf7722..4c874f93a7 100644 --- a/plugins/home/src/homePageComponents/VisitedByType/Actions.tsx +++ b/plugins/home/src/homePageComponents/VisitedByType/Actions.tsx @@ -17,6 +17,8 @@ import { useCallback } from 'react'; import Button from '@material-ui/core/Button'; import { useContext } from './Context'; +import { useTranslationRef } from '@backstage/frontend-plugin-api'; +import { homeTranslationRef } from '../../translation'; export const Actions = () => { const { collapsed, setCollapsed, visits, numVisitsOpen, loading } = @@ -25,7 +27,10 @@ export const Actions = () => { () => setCollapsed(prevCollapsed => !prevCollapsed), [setCollapsed], ); - const label = collapsed ? 'View More' : 'View Less'; + const { t } = useTranslationRef(homeTranslationRef); + const label = collapsed + ? t('visitedByType.action.viewMore') + : t('visitedByType.action.viewLess'); if (!loading && visits.length <= numVisitsOpen) return <>; diff --git a/plugins/home/src/translation.ts b/plugins/home/src/translation.ts new file mode 100644 index 0000000000..4070dde28c --- /dev/null +++ b/plugins/home/src/translation.ts @@ -0,0 +1,81 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { createTranslationRef } from '@backstage/frontend-plugin-api'; + +/** + * @alpha + */ +export const homeTranslationRef = createTranslationRef({ + id: 'home', + messages: { + addWidgetDialog: { + title: 'Add new widget to dashboard', + }, + customHomepageButtons: { + edit: 'Edit', + restoreDefaults: 'Restore defaults', + clearAll: 'Clear all', + addWidget: 'Add widget', + save: 'Save', + }, + customHomepage: { + noWidgets: "No widgets added. Start by clicking the 'Add widget' button.", + }, + widgetSettingsOverlay: { + editSettingsTooptip: 'Edit settings', + deleteWidgetTooltip: 'Delete widget', + submitButtonTitle: 'Submit', + cancelButtonTitle: 'Cancel', + }, + starredEntityListItem: { + removeFavoriteEntityTitle: 'Remove entity from favorites', + }, + visitList: { + empty: { + title: 'There are no visits to show yet.', + description: + 'Once you start using Backstage, your visits will appear here as a quick link to carry on where you left off.', + }, + few: { + title: 'The more pages you visit, the more pages will appear here.', + }, + }, + quickStart: { + title: 'Onboarding', + description: 'Get started with Backstage', + learnMoreLinkTitle: 'Learn more', + }, + starredEntities: { + noStarredEntitiesMessage: + 'Click the star beside an entity name to add it to this list!', + }, + visitedByType: { + action: { + viewMore: 'View more', + viewLess: 'View less', + }, + }, + featuredDocsCard: { + learnMoreTitle: 'LEARN MORE', + empty: { + title: 'No documents to show', + description: + 'Create your own document. Check out our Getting Started Information', + learnMoreLinkTitle: 'DOCS', + }, + }, + }, +}); diff --git a/plugins/kubernetes-backend/CHANGELOG.md b/plugins/kubernetes-backend/CHANGELOG.md index eab166f2b5..656321d450 100644 --- a/plugins/kubernetes-backend/CHANGELOG.md +++ b/plugins/kubernetes-backend/CHANGELOG.md @@ -1,5 +1,24 @@ # @backstage/plugin-kubernetes-backend +## 0.19.7 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.10.1 + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration-aws-node@0.1.16 + - @backstage/types@1.2.1 + - @backstage/plugin-kubernetes-common@0.9.5 + - @backstage/plugin-kubernetes-node@0.3.1 + - @backstage/plugin-permission-common@0.9.0 + - @backstage/plugin-permission-node@0.10.1 + ## 0.19.7-next.1 ### Patch Changes diff --git a/plugins/kubernetes-backend/package.json b/plugins/kubernetes-backend/package.json index bbd01f2c45..820804974a 100644 --- a/plugins/kubernetes-backend/package.json +++ b/plugins/kubernetes-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-kubernetes-backend", - "version": "0.19.7-next.1", + "version": "0.19.7", "description": "A Backstage backend plugin that integrates towards Kubernetes", "backstage": { "role": "backend-plugin", diff --git a/plugins/kubernetes-backend/src/routes/resourceRoutes.test.ts b/plugins/kubernetes-backend/src/routes/resourceRoutes.test.ts index 462312a404..50c50d7ffa 100644 --- a/plugins/kubernetes-backend/src/routes/resourceRoutes.test.ts +++ b/plugins/kubernetes-backend/src/routes/resourceRoutes.test.ts @@ -18,30 +18,18 @@ import request from 'supertest'; import { mockCredentials, mockServices, - type ServiceMock, startTestBackend, } from '@backstage/backend-test-utils'; import { kubernetesObjectsProviderExtensionPoint } from '@backstage/plugin-kubernetes-node'; -import { - createBackendModule, - type PermissionsService, -} from '@backstage/backend-plugin-api'; +import { createBackendModule } from '@backstage/backend-plugin-api'; import { Entity } from '@backstage/catalog-model'; import { ExtendedHttpServer } from '@backstage/backend-defaults/rootHttpRouter'; import { AuthorizeResult } from '@backstage/plugin-permission-common'; describe('resourcesRoutes', () => { let app: ExtendedHttpServer; - const permissionsMock: ServiceMock = - mockServices.permissions.mock({ - authorize: jest.fn(), - authorizeConditional: jest.fn(), - }); const startPermissionDeniedTestServer = async () => { - permissionsMock.authorize.mockResolvedValue([ - { result: AuthorizeResult.DENY }, - ]); const { server } = await startTestBackend({ features: [ mockServices.rootConfig.factory({ @@ -52,7 +40,7 @@ describe('resourcesRoutes', () => { }, }, }), - permissionsMock.factory, + mockServices.permissions.factory({ result: AuthorizeResult.DENY }), import('@backstage/plugin-kubernetes-backend'), ], }); diff --git a/plugins/kubernetes-backend/src/service/KubernetesBuilder.test.ts b/plugins/kubernetes-backend/src/service/KubernetesBuilder.test.ts index 3046232bad..a3353eec43 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesBuilder.test.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesBuilder.test.ts @@ -35,7 +35,6 @@ import { } from './KubernetesProxy'; import { setupServer } from 'msw/node'; import { - ServiceMock, mockCredentials, mockServices, registerMswTestHooks, @@ -43,10 +42,7 @@ import { } from '@backstage/backend-test-utils'; import { rest } from 'msw'; import { AuthorizeResult } from '@backstage/plugin-permission-common'; -import { - PermissionsService, - createBackendModule, -} from '@backstage/backend-plugin-api'; +import { createBackendModule } from '@backstage/backend-plugin-api'; import { AuthMetadata, KubernetesObjectsProvider, @@ -64,11 +60,6 @@ describe('API integration tests', () => { const happyK8SResult = { items: [{ clusterOne: { pods: [{ metadata: { name: 'pod1' } }] } }], }; - const permissionsMock: ServiceMock = - mockServices.permissions.mock({ - authorize: jest.fn(), - authorizeConditional: jest.fn(), - }); const minimalValidConfigService = mockServices.rootConfig.factory({ data: { kubernetes: { @@ -93,13 +84,10 @@ describe('API integration tests', () => { }, }); const startPermissionDeniedTestServer = async () => { - permissionsMock.authorize.mockResolvedValue([ - { result: AuthorizeResult.DENY }, - ]); const { server } = await startTestBackend({ features: [ minimalValidConfigService, - permissionsMock.factory, + mockServices.permissions.factory({ result: AuthorizeResult.DENY }), import('@backstage/plugin-kubernetes-backend'), ], }); diff --git a/plugins/kubernetes-backend/src/service/KubernetesProxy.test.ts b/plugins/kubernetes-backend/src/service/KubernetesProxy.test.ts index 3ed8b25c56..3ef7f95b7d 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesProxy.test.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesProxy.test.ts @@ -22,7 +22,6 @@ import { registerMswTestHooks, } from '@backstage/backend-test-utils'; import { NotFoundError } from '@backstage/errors'; -import { AuthorizeResult } from '@backstage/plugin-permission-common'; import { ANNOTATION_KUBERNETES_AUTH_PROVIDER, KubernetesRequestAuth, @@ -78,7 +77,7 @@ describe('KubernetesProxy', () => { >(), }; - const permissionApi = mockServices.permissions.mock(); + const permissionApi = mockServices.permissions(); const mockDisocveryApi = mockServices.discovery.mock(); registerMswTestHooks(worker); @@ -156,9 +155,6 @@ describe('KubernetesProxy', () => { authStrategy, discovery: mockDisocveryApi, }); - permissionApi.authorize.mockResolvedValue([ - { result: AuthorizeResult.ALLOW }, - ]); }); it('should return a ERROR_NOT_FOUND if no clusters are found', async () => { diff --git a/plugins/kubernetes-cluster/CHANGELOG.md b/plugins/kubernetes-cluster/CHANGELOG.md index bb7a443367..fef1236d13 100644 --- a/plugins/kubernetes-cluster/CHANGELOG.md +++ b/plugins/kubernetes-cluster/CHANGELOG.md @@ -1,5 +1,31 @@ # @backstage/plugin-kubernetes-cluster +## 0.0.26 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3 + - @backstage/plugin-kubernetes-react@0.5.8 + - @backstage/core-plugin-api@1.10.8 + - @backstage/plugin-catalog-react@1.19.0 + - @backstage/catalog-model@1.7.4 + - @backstage/plugin-kubernetes-common@0.9.5 + - @backstage/plugin-permission-react@0.4.35 + +## 0.0.26-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/plugin-catalog-react@1.19.0-next.2 + - @backstage/plugin-kubernetes-react@0.5.8-next.0 + - @backstage/catalog-model@1.7.4 + - @backstage/core-plugin-api@1.10.7 + - @backstage/plugin-kubernetes-common@0.9.5 + - @backstage/plugin-permission-react@0.4.34 + ## 0.0.26-next.1 ### Patch Changes diff --git a/plugins/kubernetes-cluster/package.json b/plugins/kubernetes-cluster/package.json index bb31ebeceb..634532e6df 100644 --- a/plugins/kubernetes-cluster/package.json +++ b/plugins/kubernetes-cluster/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-kubernetes-cluster", - "version": "0.0.26-next.1", + "version": "0.0.26", "description": "A Backstage plugin that shows details of Kubernetes clusters", "backstage": { "role": "frontend-plugin", diff --git a/plugins/kubernetes-node/CHANGELOG.md b/plugins/kubernetes-node/CHANGELOG.md index 887629d69a..c11e7078e2 100644 --- a/plugins/kubernetes-node/CHANGELOG.md +++ b/plugins/kubernetes-node/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-kubernetes-node +## 0.3.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.0 + - @backstage/catalog-model@1.7.4 + - @backstage/types@1.2.1 + - @backstage/plugin-kubernetes-common@0.9.5 + ## 0.3.1-next.1 ### Patch Changes diff --git a/plugins/kubernetes-node/package.json b/plugins/kubernetes-node/package.json index 598c3e4a7f..2a0997fa44 100644 --- a/plugins/kubernetes-node/package.json +++ b/plugins/kubernetes-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-kubernetes-node", - "version": "0.3.1-next.1", + "version": "0.3.1", "description": "Node.js library for the kubernetes plugin", "backstage": { "role": "node-library", diff --git a/plugins/kubernetes-react/CHANGELOG.md b/plugins/kubernetes-react/CHANGELOG.md index 497439cf10..aed2c7522e 100644 --- a/plugins/kubernetes-react/CHANGELOG.md +++ b/plugins/kubernetes-react/CHANGELOG.md @@ -1,5 +1,30 @@ # @backstage/plugin-kubernetes-react +## 0.5.8 + +### Patch Changes + +- 3ea5d1b: chore(deps): Update deprecated xterm to new package under @xterm +- Updated dependencies + - @backstage/core-components@0.17.3 + - @backstage/core-plugin-api@1.10.8 + - @backstage/catalog-model@1.7.4 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/plugin-kubernetes-common@0.9.5 + +## 0.5.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/catalog-model@1.7.4 + - @backstage/core-plugin-api@1.10.7 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/plugin-kubernetes-common@0.9.5 + ## 0.5.7 ### Patch Changes diff --git a/plugins/kubernetes-react/package.json b/plugins/kubernetes-react/package.json index 28dd746e3b..7050a19f36 100644 --- a/plugins/kubernetes-react/package.json +++ b/plugins/kubernetes-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-kubernetes-react", - "version": "0.5.7", + "version": "0.5.8", "description": "Web library for the kubernetes-react plugin", "backstage": { "role": "web-library", @@ -66,15 +66,15 @@ "@material-ui/core": "^4.9.13", "@material-ui/icons": "^4.11.3", "@material-ui/lab": "^4.0.0-alpha.61", + "@xterm/addon-attach": "^0.11.0", + "@xterm/addon-fit": "^0.10.0", + "@xterm/xterm": "^5.5.0", "cronstrue": "^2.32.0", "js-yaml": "^4.1.0", "kubernetes-models": "^4.3.1", "lodash": "^4.17.21", "luxon": "^3.0.0", - "react-use": "^17.4.0", - "xterm": "^5.3.0", - "xterm-addon-attach": "^0.9.0", - "xterm-addon-fit": "^0.8.0" + "react-use": "^17.4.0" }, "devDependencies": { "@backstage/cli": "workspace:^", diff --git a/plugins/kubernetes-react/src/components/PodExecTerminal/PodExecTerminal.tsx b/plugins/kubernetes-react/src/components/PodExecTerminal/PodExecTerminal.tsx index eeaf535a05..a3ef823356 100644 --- a/plugins/kubernetes-react/src/components/PodExecTerminal/PodExecTerminal.tsx +++ b/plugins/kubernetes-react/src/components/PodExecTerminal/PodExecTerminal.tsx @@ -13,14 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import 'xterm/css/xterm.css'; +import '@xterm/xterm/css/xterm.css'; import { discoveryApiRef, useApi } from '@backstage/core-plugin-api'; import { ClusterAttributes } from '@backstage/plugin-kubernetes-common'; import { createStyles, makeStyles, Theme } from '@material-ui/core/styles'; import { useRef, useEffect, useMemo, useState } from 'react'; -import { Terminal } from 'xterm'; -import { FitAddon } from 'xterm-addon-fit'; +import { Terminal } from '@xterm/xterm'; +import { FitAddon } from '@xterm/addon-fit'; import { PodExecTerminalAttachAddon } from './PodExecTerminalAttachAddon'; diff --git a/plugins/kubernetes-react/src/components/PodExecTerminal/PodExecTerminalAttachAddon.ts b/plugins/kubernetes-react/src/components/PodExecTerminal/PodExecTerminalAttachAddon.ts index dba58a6746..55171e1cb1 100644 --- a/plugins/kubernetes-react/src/components/PodExecTerminal/PodExecTerminalAttachAddon.ts +++ b/plugins/kubernetes-react/src/components/PodExecTerminal/PodExecTerminalAttachAddon.ts @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { AttachAddon, IAttachOptions } from 'xterm-addon-attach'; +import { AttachAddon, IAttachOptions } from '@xterm/addon-attach'; export class PodExecTerminalAttachAddon extends AttachAddon { #textEncoder = new TextEncoder(); diff --git a/plugins/kubernetes/CHANGELOG.md b/plugins/kubernetes/CHANGELOG.md index 4d6678299d..fe906bc2a1 100644 --- a/plugins/kubernetes/CHANGELOG.md +++ b/plugins/kubernetes/CHANGELOG.md @@ -1,5 +1,37 @@ # @backstage/plugin-kubernetes +## 0.12.8 + +### Patch Changes + +- 18c64e9: Added the `info.packageJson` option to the plugin instance for the new frontend system. +- 3ea5d1b: chore(deps): Update deprecated xterm to new package under @xterm +- Updated dependencies + - @backstage/core-components@0.17.3 + - @backstage/plugin-kubernetes-react@0.5.8 + - @backstage/core-plugin-api@1.10.8 + - @backstage/frontend-plugin-api@0.10.3 + - @backstage/plugin-catalog-react@1.19.0 + - @backstage/catalog-model@1.7.4 + - @backstage/core-compat-api@0.4.3 + - @backstage/plugin-kubernetes-common@0.9.5 + - @backstage/plugin-permission-react@0.4.35 + +## 0.12.8-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/plugin-catalog-react@1.19.0-next.2 + - @backstage/frontend-plugin-api@0.10.3-next.1 + - @backstage/plugin-kubernetes-react@0.5.8-next.0 + - @backstage/catalog-model@1.7.4 + - @backstage/core-compat-api@0.4.3-next.2 + - @backstage/core-plugin-api@1.10.7 + - @backstage/plugin-kubernetes-common@0.9.5 + - @backstage/plugin-permission-react@0.4.34 + ## 0.12.8-next.1 ### Patch Changes diff --git a/plugins/kubernetes/package.json b/plugins/kubernetes/package.json index d0fe8bc9d9..e8e9c1b867 100644 --- a/plugins/kubernetes/package.json +++ b/plugins/kubernetes/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-kubernetes", - "version": "0.12.8-next.1", + "version": "0.12.8", "description": "A Backstage plugin that integrates towards Kubernetes", "backstage": { "role": "frontend-plugin", @@ -71,14 +71,14 @@ "@kubernetes-models/base": "^5.0.0", "@kubernetes/client-node": "1.1.2", "@material-ui/core": "^4.12.2", + "@xterm/addon-attach": "^0.11.0", + "@xterm/addon-fit": "^0.10.0", + "@xterm/xterm": "^5.5.0", "cronstrue": "^2.2.0", "js-yaml": "^4.0.0", "kubernetes-models": "^4.1.0", "lodash": "^4.17.21", - "luxon": "^3.0.0", - "xterm": "^5.2.1", - "xterm-addon-attach": "^0.9.0", - "xterm-addon-fit": "^0.8.0" + "luxon": "^3.0.0" }, "devDependencies": { "@backstage/cli": "workspace:^", diff --git a/plugins/mcp-actions-backend/.eslintrc.js b/plugins/mcp-actions-backend/.eslintrc.js new file mode 100644 index 0000000000..e2a53a6ad2 --- /dev/null +++ b/plugins/mcp-actions-backend/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/plugins/mcp-actions-backend/CHANGELOG.md b/plugins/mcp-actions-backend/CHANGELOG.md new file mode 100644 index 0000000000..a00d07bda8 --- /dev/null +++ b/plugins/mcp-actions-backend/CHANGELOG.md @@ -0,0 +1,17 @@ +# @backstage/plugin-mcp-actions-backend + +## 0.1.0 + +### Minor Changes + +- 4ed0fb6: Initial implementation of an `mcp-actions` backend + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.10.1 + - @backstage/backend-defaults@0.11.0 + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 diff --git a/plugins/mcp-actions-backend/README.md b/plugins/mcp-actions-backend/README.md new file mode 100644 index 0000000000..b14f252bce --- /dev/null +++ b/plugins/mcp-actions-backend/README.md @@ -0,0 +1,134 @@ +# MCP Actions Backend + +This plugin exposes Backstage actions as MCP (Model Context Protocol) tools, allowing AI clients to discover and invoke registered actions in your Backstage backend. + +## Installation + +This plugin is installed via the `@backstage/plugin-mcp-actions-backend` package. To install it to your backend package, run the following command: + +```bash +# From your root directory +yarn --cwd packages/backend add @backstage/plugin-mcp-actions-backend +``` + +Then add the plugin to your backend in `packages/backend/src/index.ts`: + +```ts +const backend = createBackend(); +// ... +backend.add(import('@backstage/plugin-mcp-actions-backend')); +``` + +## Configuration + +### Configuring Actions Registry + +The MCP Actions Backend exposes actions that are registered with the Actions Registry. You can register actions from specific plugins by configuring the `pluginSources` in your app configuration: + +```yaml +backend: + actions: + pluginSources: + - 'catalog' + - 'my-custom-plugin' +``` + +Actions from these plugins will be discovered and exposed as MCP tools. Each action must be registered using the Actions Registry Service in the respective plugin: + +```ts +// In your plugin +import { actionsRegistryServiceRef } from '@backstage/backend-plugin-api/alpha'; + +export const myPlugin = createBackendPlugin({ + pluginId: 'my-custom-plugin', + register(env) { + env.registerInit({ + deps: { + actionsRegistry: actionsRegistryServiceRef, + }, + async init({ actionsRegistry }) { + actionsRegistry.register({ + name: 'greet-user', + title: 'Greet User', + description: 'Generate a personalized greeting', + schema: { + input: z => + z.object({ + name: z.string().describe('The name of the person to greet'), + }), + output: z => + z.object({ + greeting: z.string().describe('The generated greeting'), + }), + }, + action: async ({ input }) => ({ + output: { greeting: `Hello ${input.name}!` }, + }), + }); + }, + }); + }, +}); +``` + +### Authentication Configuration + +By default, the Backstage backend requires authentication for all requests. + +#### External Access with Static Tokens + +> This is meant to be a temporary workaround until work on [device authentication](https://github.com/backstage/backstage/pull/27680) is completed. +> This will make authentication for MCP clients and CLI's in Backstage easier than having to configure static tokens. + +Configure external access with static tokens in your app configuration: + +```yaml +backend: + auth: + externalAccess: + - type: static + options: + token: ${MCP_TOKEN} + accessRestrictions: + - plugin: mcp-actions + - plugin: catalog +``` + +Generate a secure token: + +```bash +node -p 'require("crypto").randomBytes(24).toString("base64")' +``` + +Set the `MCP_TOKEN` environment variable with this token, and configure your MCP client to use it in the [Authorization header](#configuring-mcp-clients) + +## Configuring MCP Clients + +The MCP server supports both Server-Sent Events (SSE) and Streamable HTTP protocols. + +The SSE protocol is deprecated, and should be avoided as it will be removed in a future release. + +- `Streamable HTTP`: `http://localhost:7007/api/mcp-actions/v1` +- `SSE`: `http://localhost:7007/api/mcp-actions/v1/sse` + +There's a few different ways to configure MCP tools, but here's a snippet of the most common. + +```json +{ + "mcpServers": { + "backstage-actions": { + // you can also replace this with the public / internal URL of the deployed backend. + "url": "http://localhost:7007/api/mcp-actions/v1", + "headers": { + "Authorization": "Bearer ${MCP_TOKEN}" + } + } + } +} +``` + +## Development + +This plugin backend can be started in a standalone mode from directly in this package with `yarn start`. It is a limited setup that is most convenient when developing the plugin backend itself. + +If you want to run the entire project, including the frontend, run `yarn start` from the root directory. diff --git a/plugins/mcp-actions-backend/catalog-info.yaml b/plugins/mcp-actions-backend/catalog-info.yaml new file mode 100644 index 0000000000..1a0199210e --- /dev/null +++ b/plugins/mcp-actions-backend/catalog-info.yaml @@ -0,0 +1,9 @@ +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: backstage-plugin-mcp-actions-backend + title: '@backstage/plugin-mcp-actions-backend' +spec: + lifecycle: experimental + type: backstage-backend-plugin + owner: maintainers diff --git a/plugins/mcp-actions-backend/dev/index.ts b/plugins/mcp-actions-backend/dev/index.ts new file mode 100644 index 0000000000..74a6d814f8 --- /dev/null +++ b/plugins/mcp-actions-backend/dev/index.ts @@ -0,0 +1,84 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { createBackend } from '@backstage/backend-defaults'; +import { createBackendPlugin } from '@backstage/backend-plugin-api'; +import { actionsRegistryServiceRef } from '@backstage/backend-plugin-api/alpha'; +import { mockServices } from '@backstage/backend-test-utils'; +import { catalogServiceMock } from '@backstage/plugin-catalog-node/testUtils'; + +const backend = createBackend(); + +backend.add(mockServices.auth.factory()); +backend.add(mockServices.httpAuth.factory()); + +// TEMPLATE NOTE: +// Rather than using a real catalog you can use a mock with a fixed set of entities. +backend.add( + catalogServiceMock.factory({ + entities: [ + { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + name: 'sample', + title: 'Sample Component', + }, + spec: { + type: 'service', + }, + }, + ], + }), +); + +backend.add( + createBackendPlugin({ + pluginId: 'local', + register({ registerInit }) { + registerInit({ + deps: { + actionsRegistry: actionsRegistryServiceRef, + }, + async init({ actionsRegistry }) { + actionsRegistry.register({ + name: 'make-greeting', + title: 'Test Action', + description: 'Test Action', + schema: { + input: z => + z.object({ + name: z.string(), + }), + output: z => + z.object({ + greeting: z.string(), + }), + }, + action: async ({ input }) => ({ + output: { + greeting: `Hello ${input.name}!`, + }, + }), + }); + }, + }); + }, + }), +); + +backend.add(import('../src')); + +backend.start(); diff --git a/plugins/mcp-actions-backend/package.json b/plugins/mcp-actions-backend/package.json new file mode 100644 index 0000000000..72064a3490 --- /dev/null +++ b/plugins/mcp-actions-backend/package.json @@ -0,0 +1,53 @@ +{ + "name": "@backstage/plugin-mcp-actions-backend", + "version": "0.1.0", + "backstage": { + "role": "backend-plugin", + "pluginId": "mcp-actions", + "pluginPackages": [ + "@backstage/plugin-mcp-actions-backend" + ] + }, + "publishConfig": { + "access": "public", + "main": "dist/index.cjs.js", + "types": "dist/index.d.ts" + }, + "repository": { + "type": "git", + "url": "https://github.com/backstage/backstage", + "directory": "plugins/mcp-actions-backend" + }, + "license": "Apache-2.0", + "main": "src/index.ts", + "types": "src/index.ts", + "files": [ + "dist" + ], + "scripts": { + "build": "backstage-cli package build", + "clean": "backstage-cli package clean", + "lint": "backstage-cli package lint", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "start": "backstage-cli package start", + "test": "backstage-cli package test" + }, + "dependencies": { + "@backstage/backend-defaults": "workspace:^", + "@backstage/backend-plugin-api": "workspace:^", + "@backstage/catalog-client": "workspace:^", + "@backstage/errors": "workspace:^", + "@backstage/plugin-catalog-node": "workspace:^", + "@backstage/types": "workspace:^", + "@modelcontextprotocol/sdk": "^1.12.3", + "express": "^4.17.1", + "express-promise-router": "^4.1.0", + "zod": "^3.22.4" + }, + "devDependencies": { + "@backstage/backend-test-utils": "workspace:^", + "@backstage/cli": "workspace:^", + "@types/express": "^4.17.6" + } +} diff --git a/plugins/mcp-actions-backend/report.api.md b/plugins/mcp-actions-backend/report.api.md new file mode 100644 index 0000000000..2f1b9fcbf0 --- /dev/null +++ b/plugins/mcp-actions-backend/report.api.md @@ -0,0 +1,13 @@ +## API Report File for "@backstage/plugin-mcp-actions-backend" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { BackendFeature } from '@backstage/backend-plugin-api'; + +// @public +const mcpPlugin: BackendFeature; +export default mcpPlugin; + +// (No @packageDocumentation comment for this package) +``` diff --git a/plugins/mcp-actions-backend/src/index.ts b/plugins/mcp-actions-backend/src/index.ts new file mode 100644 index 0000000000..75fa097c85 --- /dev/null +++ b/plugins/mcp-actions-backend/src/index.ts @@ -0,0 +1,16 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export { mcpPlugin as default } from './plugin'; diff --git a/plugins/mcp-actions-backend/src/plugin.test.ts b/plugins/mcp-actions-backend/src/plugin.test.ts new file mode 100644 index 0000000000..ace988cfc1 --- /dev/null +++ b/plugins/mcp-actions-backend/src/plugin.test.ts @@ -0,0 +1,165 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { mockServices, startTestBackend } from '@backstage/backend-test-utils'; +import { mcpPlugin } from './plugin'; +import { actionsRegistryServiceRef } from '@backstage/backend-plugin-api/alpha'; +import { createBackendPlugin } from '@backstage/backend-plugin-api'; +import { Client } from '@modelcontextprotocol/sdk/client/index.js'; +import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js'; +import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js'; +import { ListToolsResultSchema } from '@modelcontextprotocol/sdk/types'; + +describe('Mcp Backend', () => { + const mockPluginWithActions = createBackendPlugin({ + pluginId: 'local', + register({ registerInit }) { + registerInit({ + deps: { actionsRegistry: actionsRegistryServiceRef }, + async init({ actionsRegistry }) { + actionsRegistry.register({ + name: 'make-greeting', + title: 'Make Greeting', + description: 'Make a greeting', + schema: { + input: z => z.object({ name: z.string() }), + output: z => z.object({ greeting: z.string() }), + }, + action: async ({ input }) => ({ + output: { greeting: `Hello ${input.name}!` }, + }), + }); + }, + }); + }, + }); + + const getContext = async () => { + const { server } = await startTestBackend({ + features: [ + mcpPlugin, + mockPluginWithActions, + mockServices.rootConfig.factory({ + data: { + backend: { + actions: { + pluginSources: ['local'], + }, + }, + }, + }), + ], + }); + + const client = new Client({ + name: 'test client', + version: '1.0', + }); + + const address = server.address(); + if (typeof address !== 'object' || !('port' in address!)) { + throw new Error('server broke'); + } + + return { + client, + serverAddress: `http://localhost:${address.port}`, + }; + }; + + it('should support streamable spec', async () => { + const { client, serverAddress } = await getContext(); + const transport = new StreamableHTTPClientTransport( + new URL(`${serverAddress}/api/mcp-actions/v1`), + ); + + await client.connect(transport); + + const result = await client.request( + { + method: 'tools/list', + }, + ListToolsResultSchema, + ); + + expect(result.tools).toEqual([ + { + annotations: { + destructiveHint: true, + idempotentHint: false, + openWorldHint: false, + readOnlyHint: false, + title: 'Make Greeting', + }, + description: 'Make a greeting', + inputSchema: { + $schema: 'http://json-schema.org/draft-07/schema#', + additionalProperties: false, + properties: { + name: { + type: 'string', + }, + }, + required: ['name'], + type: 'object', + }, + name: 'make-greeting', + }, + ]); + }); + + it('should support sse spec', async () => { + const { client, serverAddress } = await getContext(); + const transport = new SSEClientTransport( + new URL(`${serverAddress}/api/mcp-actions/v1/sse`), + ); + + await client.connect(transport); + + const result = await client.request( + { + method: 'tools/list', + }, + ListToolsResultSchema, + ); + + await client.close(); + + expect(result.tools).toEqual([ + { + annotations: { + destructiveHint: true, + idempotentHint: false, + openWorldHint: false, + readOnlyHint: false, + title: 'Make Greeting', + }, + description: 'Make a greeting', + inputSchema: { + $schema: 'http://json-schema.org/draft-07/schema#', + additionalProperties: false, + properties: { + name: { + type: 'string', + }, + }, + required: ['name'], + type: 'object', + }, + name: 'make-greeting', + }, + ]); + }); +}); diff --git a/plugins/mcp-actions-backend/src/plugin.ts b/plugins/mcp-actions-backend/src/plugin.ts new file mode 100644 index 0000000000..f1e89417e9 --- /dev/null +++ b/plugins/mcp-actions-backend/src/plugin.ts @@ -0,0 +1,72 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { + coreServices, + createBackendPlugin, +} from '@backstage/backend-plugin-api'; +import { json, Router } from 'express'; +import { McpService } from './services/McpService'; +import { createStreamableRouter } from './routers/createStreamableRouter'; +import { createSseRouter } from './routers/createSseRouter'; +import { + actionsRegistryServiceRef, + actionsServiceRef, +} from '@backstage/backend-plugin-api/alpha'; + +/** + * mcpPlugin backend plugin + * + * @public + */ +export const mcpPlugin = createBackendPlugin({ + pluginId: 'mcp-actions', + register(env) { + env.registerInit({ + deps: { + logger: coreServices.logger, + auth: coreServices.auth, + httpAuth: coreServices.httpAuth, + httpRouter: coreServices.httpRouter, + actions: actionsServiceRef, + registry: actionsRegistryServiceRef, + }, + async init({ actions, logger, httpRouter, httpAuth }) { + const mcpService = await McpService.create({ + actions, + }); + + const sseRouter = createSseRouter({ + mcpService, + httpAuth, + }); + + const streamableRouter = createStreamableRouter({ + mcpService, + httpAuth, + logger, + }); + + const router = Router(); + router.use(json()); + + router.use('/v1/sse', sseRouter); + router.use('/v1', streamableRouter); + + httpRouter.use(router); + }, + }); + }, +}); diff --git a/plugins/mcp-actions-backend/src/routers/createSseRouter.ts b/plugins/mcp-actions-backend/src/routers/createSseRouter.ts new file mode 100644 index 0000000000..19bcf288e9 --- /dev/null +++ b/plugins/mcp-actions-backend/src/routers/createSseRouter.ts @@ -0,0 +1,73 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import PromiseRouter from 'express-promise-router'; +import { Router } from 'express'; +import { McpService } from '../services/McpService'; +import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js'; +import { HttpAuthService } from '@backstage/backend-plugin-api'; + +/** + * Legacy SSE endpoint for older clients, hopefully will not be needed for much longer. + */ +export const createSseRouter = ({ + mcpService, + httpAuth, +}: { + mcpService: McpService; + httpAuth: HttpAuthService; +}): Router => { + const router = PromiseRouter(); + const transportsToSessionId = new Map(); + + router.get('/', async (req, res) => { + const server = mcpService.getServer({ + credentials: await httpAuth.credentials(req), + }); + + const transport = new SSEServerTransport( + `${req.originalUrl}/messages`, + res, + ); + + transportsToSessionId.set(transport.sessionId, transport); + + res.on('close', () => { + transportsToSessionId.delete(transport.sessionId); + }); + + await server.connect(transport); + }); + + router.post('/messages', async (req, res) => { + const sessionId = req.query.sessionId as string; + + if (!sessionId) { + res.status(400).contentType('text/plain').write('sessionId is required'); + return; + } + + const transport = transportsToSessionId.get(sessionId); + if (transport) { + await transport.handlePostMessage(req, res, req.body); + } else { + res + .status(400) + .contentType('text/plain') + .write(`No transport found for sessionId "${sessionId}"`); + } + }); + return router; +}; diff --git a/plugins/mcp-actions-backend/src/routers/createStreamableRouter.ts b/plugins/mcp-actions-backend/src/routers/createStreamableRouter.ts new file mode 100644 index 0000000000..9d6fd1840b --- /dev/null +++ b/plugins/mcp-actions-backend/src/routers/createStreamableRouter.ts @@ -0,0 +1,100 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import PromiseRouter from 'express-promise-router'; +import { Router } from 'express'; +import { McpService } from '../services/McpService'; +import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js'; +import { HttpAuthService, LoggerService } from '@backstage/backend-plugin-api'; +import { isError } from '@backstage/errors'; + +export const createStreamableRouter = ({ + mcpService, + httpAuth, + logger, +}: { + mcpService: McpService; + logger: LoggerService; + httpAuth: HttpAuthService; +}): Router => { + const router = PromiseRouter(); + + router.post('/', async (req, res) => { + try { + const server = mcpService.getServer({ + credentials: await httpAuth.credentials(req), + }); + + const transport = new StreamableHTTPServerTransport({ + // stateless implementation for now, so that we can support multiple + // instances of the server backend, and avoid sticky sessions. + sessionIdGenerator: undefined, + }); + + await server.connect(transport); + await transport.handleRequest(req, res, req.body); + + res.on('close', () => { + transport.close(); + server.close(); + }); + } catch (error) { + if (isError(error)) { + logger.error(error.message); + } + + if (!res.headersSent) { + res.status(500).json({ + jsonrpc: '2.0', + error: { + code: -32603, + message: 'Internal server error', + }, + id: null, + }); + } + } + }); + + router.get('/', async (_, res) => { + // We only support POST requests, so we return a 405 error for all other methods. + res.writeHead(405).end( + JSON.stringify({ + jsonrpc: '2.0', + error: { + code: -32000, + message: 'Method not allowed.', + }, + id: null, + }), + ); + }); + + router.delete('/', async (_, res) => { + // We only support POST requests, so we return a 405 error for all other methods. + res.writeHead(405).end( + JSON.stringify({ + jsonrpc: '2.0', + error: { + code: -32000, + message: 'Method not allowed.', + }, + id: null, + }), + ); + }); + + return router; +}; diff --git a/plugins/mcp-actions-backend/src/services/McpService.test.ts b/plugins/mcp-actions-backend/src/services/McpService.test.ts new file mode 100644 index 0000000000..e3339be1d5 --- /dev/null +++ b/plugins/mcp-actions-backend/src/services/McpService.test.ts @@ -0,0 +1,191 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { mockCredentials } from '@backstage/backend-test-utils'; +import { McpService } from './McpService'; +import { actionsRegistryServiceMock } from '@backstage/backend-test-utils/alpha'; +import { InMemoryTransport } from '@modelcontextprotocol/sdk/inMemory.js'; +import { Client } from '@modelcontextprotocol/sdk/client/index.js'; +import { + CallToolResultSchema, + ListToolsResultSchema, +} from '@modelcontextprotocol/sdk/types.js'; + +describe('McpService', () => { + it('should list the available actions as tools in the mcp backend', async () => { + const mockActionsRegistry = actionsRegistryServiceMock(); + mockActionsRegistry.register({ + name: 'mock-action', + title: 'Test', + description: 'Test', + schema: { + input: z => z.object({ input: z.string() }), + output: z => z.object({ output: z.string() }), + }, + action: async () => ({ output: { output: 'test' } }), + }); + + const mcpService = await McpService.create({ + actions: mockActionsRegistry, + }); + + const server = mcpService.getServer({ + credentials: mockCredentials.user(), + }); + + const client = new Client({ + name: 'test client', + version: '1.0', + }); + + const [clientTransport, serverTransport] = + InMemoryTransport.createLinkedPair(); + + await Promise.all([ + client.connect(clientTransport), + server.connect(serverTransport), + ]); + + const result = await client.request( + { + method: 'tools/list', + }, + ListToolsResultSchema, + ); + + expect(result.tools).toEqual([ + { + annotations: { + destructiveHint: true, + idempotentHint: false, + openWorldHint: false, + readOnlyHint: false, + title: 'Test', + }, + description: 'Test', + inputSchema: { + $schema: 'http://json-schema.org/draft-07/schema#', + additionalProperties: false, + properties: { + input: { + type: 'string', + }, + }, + required: ['input'], + type: 'object', + }, + name: 'mock-action', + }, + ]); + }); + + it('should call the action when the tool is invoked', async () => { + const mockActionsRegistry = actionsRegistryServiceMock(); + const mockAction = jest.fn(async () => ({ output: { output: 'test' } })); + + mockActionsRegistry.register({ + name: 'mock-action', + title: 'Test', + description: 'Test', + schema: { + input: z => z.object({ input: z.string() }), + output: z => z.object({ output: z.string() }), + }, + action: mockAction, + }); + + const mcpService = await McpService.create({ + actions: mockActionsRegistry, + }); + + const server = mcpService.getServer({ + credentials: mockCredentials.user(), + }); + + const client = new Client({ + name: 'test client', + version: '1.0', + }); + + const [clientTransport, serverTransport] = + InMemoryTransport.createLinkedPair(); + + await Promise.all([ + client.connect(clientTransport), + server.connect(serverTransport), + ]); + + const result = await client.request( + { + method: 'tools/call', + params: { name: 'mock-action', arguments: { input: 'test' } }, + }, + CallToolResultSchema, + ); + + expect(mockAction).toHaveBeenCalledWith( + expect.objectContaining({ + credentials: mockCredentials.user(), + input: { input: 'test' }, + logger: expect.anything(), + }), + ); + + expect(result.content).toEqual([ + { + type: 'text', + text: [ + '```json', + JSON.stringify({ output: 'test' }, null, 2), + '```', + ].join('\n'), + }, + ]); + }); + + it('should return an error when the action is not found', async () => { + const mcpService = await McpService.create({ + actions: actionsRegistryServiceMock(), + }); + + const server = mcpService.getServer({ + credentials: mockCredentials.user(), + }); + + const client = new Client({ + name: 'test client', + version: '1.0', + }); + + const [clientTransport, serverTransport] = + InMemoryTransport.createLinkedPair(); + + await Promise.all([ + client.connect(clientTransport), + server.connect(serverTransport), + ]); + + await expect( + client.request( + { + method: 'tools/call', + params: { name: 'mock-action', arguments: { input: 'test' } }, + }, + CallToolResultSchema, + ), + ).rejects.toThrow('Action "mock-action" not found'); + }); +}); diff --git a/plugins/mcp-actions-backend/src/services/McpService.ts b/plugins/mcp-actions-backend/src/services/McpService.ts new file mode 100644 index 0000000000..9c44e6d4c1 --- /dev/null +++ b/plugins/mcp-actions-backend/src/services/McpService.ts @@ -0,0 +1,98 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { BackstageCredentials } from '@backstage/backend-plugin-api'; +import { Server as McpServer } from '@modelcontextprotocol/sdk/server/index.js'; +import { + ListToolsRequestSchema, + CallToolRequestSchema, +} from '@modelcontextprotocol/sdk/types.js'; +import { JsonObject } from '@backstage/types'; +import { ActionsService } from '@backstage/backend-plugin-api/alpha'; +import { version } from '@backstage/plugin-mcp-actions-backend/package.json'; +import { NotFoundError } from '@backstage/errors'; + +export class McpService { + constructor(private readonly actions: ActionsService) {} + + static async create({ actions }: { actions: ActionsService }) { + return new McpService(actions); + } + + getServer({ credentials }: { credentials: BackstageCredentials }) { + const server = new McpServer( + { + name: 'backstage', + // TODO: this version will most likely change in the future. + version, + }, + { capabilities: { tools: {} } }, + ); + + server.setRequestHandler(ListToolsRequestSchema, async () => { + // TODO: switch this to be configuration based later + const { actions } = await this.actions.list({ credentials }); + + return { + tools: actions.map(action => ({ + inputSchema: action.schema.input, + // todo(blam): this is unfortunately not supported by most clients yet. + // When this is provided you need to provide structuredContent instead. + // outputSchema: action.schema.output, + name: action.name, + description: action.description, + annotations: { + title: action.title, + destructiveHint: action.attributes.destructive, + idempotentHint: action.attributes.idempotent, + readOnlyHint: action.attributes.readOnly, + openWorldHint: false, + }, + })), + }; + }); + + server.setRequestHandler(CallToolRequestSchema, async ({ params }) => { + const { actions } = await this.actions.list({ credentials }); + const action = actions.find(a => a.name === params.name); + + if (!action) { + throw new NotFoundError(`Action "${params.name}" not found`); + } + + const { output } = await this.actions.invoke({ + id: action.id, + input: params.arguments as JsonObject, + credentials, + }); + + return { + // todo(blam): unfortunately structuredContent is not supported by most clients yet. + // so the validation for the output happens in the default actions registry + // and we return it as json text instead for now. + content: [ + { + type: 'text', + text: ['```json', JSON.stringify(output, null, 2), '```'].join( + '\n', + ), + }, + ], + }; + }); + + return server; + } +} diff --git a/plugins/notifications-backend-module-email/CHANGELOG.md b/plugins/notifications-backend-module-email/CHANGELOG.md index 32bb0891e4..98d6646b1d 100644 --- a/plugins/notifications-backend-module-email/CHANGELOG.md +++ b/plugins/notifications-backend-module-email/CHANGELOG.md @@ -1,5 +1,37 @@ # @backstage/plugin-notifications-backend-module-email +## 0.3.10 + +### Patch Changes + +- 8a150bf: Internal changes to switch to the non-alpha `catalogServiceRef` +- Updated dependencies + - @backstage/catalog-client@1.10.1 + - @backstage/plugin-notifications-common@0.0.9 + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/plugin-notifications-node@0.2.16 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/integration-aws-node@0.1.16 + - @backstage/types@1.2.1 + +## 0.3.10-next.2 + +### Patch Changes + +- 8a150bf: Internal changes to switch to the non-alpha `catalogServiceRef` +- Updated dependencies + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/catalog-client@1.10.1-next.0 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/integration-aws-node@0.1.16 + - @backstage/types@1.2.1 + - @backstage/plugin-catalog-node@1.17.1-next.1 + - @backstage/plugin-notifications-common@0.0.9-next.0 + - @backstage/plugin-notifications-node@0.2.16-next.1 + ## 0.3.10-next.1 ### Patch Changes diff --git a/plugins/notifications-backend-module-email/package.json b/plugins/notifications-backend-module-email/package.json index b841dafc2e..33efc60e35 100644 --- a/plugins/notifications-backend-module-email/package.json +++ b/plugins/notifications-backend-module-email/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-notifications-backend-module-email", - "version": "0.3.10-next.1", + "version": "0.3.10", "description": "The email backend module for the notifications plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/notifications-backend-module-slack/CHANGELOG.md b/plugins/notifications-backend-module-slack/CHANGELOG.md index 2effe53d63..a72c7dc3bc 100644 --- a/plugins/notifications-backend-module-slack/CHANGELOG.md +++ b/plugins/notifications-backend-module-slack/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-notifications-backend-module-slack +## 0.1.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-notifications-common@0.0.9 + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/plugin-notifications-node@0.2.16 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + ## 0.1.2-next.1 ### Patch Changes diff --git a/plugins/notifications-backend-module-slack/package.json b/plugins/notifications-backend-module-slack/package.json index bb5ed460df..9bb85918ff 100644 --- a/plugins/notifications-backend-module-slack/package.json +++ b/plugins/notifications-backend-module-slack/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-notifications-backend-module-slack", - "version": "0.1.2-next.1", + "version": "0.1.2", "description": "The slack backend module for the notifications plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/notifications-backend/CHANGELOG.md b/plugins/notifications-backend/CHANGELOG.md index 065282a44c..98aa805d31 100644 --- a/plugins/notifications-backend/CHANGELOG.md +++ b/plugins/notifications-backend/CHANGELOG.md @@ -1,5 +1,55 @@ # @backstage/plugin-notifications-backend +## 0.5.7 + +### Patch Changes + +- 41d4d6e: Notifications are now automatically deleted after 1 year by default. + + There is a new scheduled task that runs every 24 hours to delete notifications older than 1 year. + This can be configured by setting the `notifications.retention` in the `app-config.yaml` file. + + ```yaml + notifications: + retention: 1y + ``` + + If the retention is set to false, notifications will not be automatically deleted. + +- 8a150bf: Internal changes to switch to the non-alpha `catalogServiceRef` +- 1fb5f06: Adds ability for user to turn on/off notifications for specific topics within an origin. +- ef9ab82: Notifications API will now return user as null always for broadcast notifications +- Updated dependencies + - @backstage/plugin-notifications-common@0.0.9 + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/plugin-notifications-node@0.2.16 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/plugin-events-node@0.4.12 + - @backstage/plugin-signals-node@0.1.21 + +## 0.5.7-next.2 + +### Patch Changes + +- 8a150bf: Internal changes to switch to the non-alpha `catalogServiceRef` +- Updated dependencies + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/plugin-auth-node@0.6.4-next.1 + - @backstage/plugin-catalog-node@1.17.1-next.1 + - @backstage/plugin-events-node@0.4.12-next.1 + - @backstage/plugin-notifications-common@0.0.9-next.0 + - @backstage/plugin-notifications-node@0.2.16-next.1 + - @backstage/plugin-signals-node@0.1.21-next.1 + ## 0.5.7-next.1 ### Patch Changes diff --git a/plugins/notifications-backend/config.d.ts b/plugins/notifications-backend/config.d.ts index 5dd795f8d3..61ae411df8 100644 --- a/plugins/notifications-backend/config.d.ts +++ b/plugins/notifications-backend/config.d.ts @@ -28,5 +28,10 @@ export interface Config { * Throttle duration between notification sending, defaults to 50ms */ throttleInterval?: HumanDuration | string; + /** + * Time to keep the notifications in the database, defaults to 365 days. + * Can be disabled by setting to false. + */ + retention?: HumanDuration | string | false; }; } diff --git a/plugins/notifications-backend/package.json b/plugins/notifications-backend/package.json index f94548d377..9a1efaae84 100644 --- a/plugins/notifications-backend/package.json +++ b/plugins/notifications-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-notifications-backend", - "version": "0.5.7-next.1", + "version": "0.5.7", "backstage": { "role": "backend-plugin", "pluginId": "notifications", diff --git a/plugins/notifications-backend/src/database/DatabaseNotificationsStore.test.ts b/plugins/notifications-backend/src/database/DatabaseNotificationsStore.test.ts index c7819552cb..d8ae3faf57 100644 --- a/plugins/notifications-backend/src/database/DatabaseNotificationsStore.test.ts +++ b/plugins/notifications-backend/src/database/DatabaseNotificationsStore.test.ts @@ -228,6 +228,13 @@ describe.each(databases.eachSupportedId())( ]); }); + it('should return null value for user for broadcast notifications', async () => { + await storage.saveBroadcast({ ...testNotification1, read: new Date() }); + const notifications = await storage.getNotifications({ user }); + expect(notifications).toHaveLength(1); + expect(notifications[0].user).toBeNull(); + }); + it('should return read notifications for user', async () => { await storage.saveNotification(testNotification1); await storage.saveBroadcast(testNotification2); @@ -298,7 +305,7 @@ describe.each(databases.eachSupportedId())( user: otherUser, }); expect(otherUserNotifications.map(idOnly)).toEqual([id0, id2]); - expect(otherUserNotifications[1].user).toBe(otherUser); + expect(otherUserNotifications[1].user).toBeNull(); }); it('should allow searching for notifications', async () => { @@ -635,7 +642,7 @@ describe.each(databases.eachSupportedId())( expect(notification?.user).toBeNull(); await storage.markRead({ ids: [id1], user }); notification = await storage.getNotification({ id: id1, user }); - expect(notification?.user).toBe(user); + expect(notification?.user).toBeNull(); const otherNotification = await storage.getNotification({ id: id1, @@ -798,5 +805,24 @@ describe.each(databases.eachSupportedId())( }); }); }); + + describe('clearNotifications', () => { + it('should clear notifications older than specified days', async () => { + const oldDate = new Date(); + oldDate.setDate(oldDate.getDate() - 10); // 10 days ago + await storage.saveNotification({ + ...testNotification1, + created: oldDate, + }); + await storage.saveNotification(testNotification2); + + const result = await storage.clearNotifications({ + maxAge: { days: 5 }, + }); // Clear notifications older than 5 days + expect(result.deletedCount).toBe(1); // Only the first notification should be cleared + const remainingNotifications = await storage.getNotifications({ user }); + expect(remainingNotifications.map(idOnly)).toEqual([id2]); + }); + }); }, ); diff --git a/plugins/notifications-backend/src/database/DatabaseNotificationsStore.ts b/plugins/notifications-backend/src/database/DatabaseNotificationsStore.ts index 35ecf1d778..94131ca257 100644 --- a/plugins/notifications-backend/src/database/DatabaseNotificationsStore.ts +++ b/plugins/notifications-backend/src/database/DatabaseNotificationsStore.ts @@ -31,6 +31,7 @@ import { } from '@backstage/plugin-notifications-common'; import { Knex } from 'knex'; import crypto from 'crypto'; +import { durationToMilliseconds, HumanDuration } from '@backstage/types'; const migrationsDir = resolvePackagePath( '@backstage/plugin-notifications-backend', @@ -149,7 +150,7 @@ export class DatabaseNotificationsStore implements NotificationsStore { private mapToNotifications = (rows: any[]): Notification[] => { return rows.map(row => ({ id: row.id, - user: row.user, + user: row.type === 'broadcast' ? null : row.user, created: new Date(row.created), saved: row.saved, read: row.read, @@ -252,7 +253,7 @@ export class DatabaseNotificationsStore implements NotificationsStore { join.andOnVal('user', '=', user); } }) - .select(NOTIFICATION_COLUMNS); + .select([...NOTIFICATION_COLUMNS, this.db.raw("'broadcast' as type")]); }; private getNotificationsBaseQuery = ( @@ -261,7 +262,7 @@ export class DatabaseNotificationsStore implements NotificationsStore { const { user, orderField } = options; const subQuery = this.db('notification') - .select(NOTIFICATION_COLUMNS) + .select([...NOTIFICATION_COLUMNS, this.db.raw("'entity' as type")]) .unionAll([this.getBroadcastUnion(user)]) .as('notifications'); @@ -331,7 +332,10 @@ export class DatabaseNotificationsStore implements NotificationsStore { async getNotifications(options: NotificationGetOptions) { const notificationQuery = this.getNotificationsBaseQuery(options); - const notifications = await notificationQuery.select(NOTIFICATION_COLUMNS); + const notifications = await notificationQuery.select([ + ...NOTIFICATION_COLUMNS, + 'type', + ]); return this.mapToNotifications(notifications); } @@ -462,7 +466,7 @@ export class DatabaseNotificationsStore implements NotificationsStore { .select('*') .from( this.db('notification') - .select(NOTIFICATION_COLUMNS) + .select([...NOTIFICATION_COLUMNS, this.db.raw("'entity' as type")]) .unionAll([this.getBroadcastUnion(options.user)]) .as('notifications'), ) @@ -653,4 +657,24 @@ export class DatabaseNotificationsStore implements NotificationsStore { .distinct(['topic']); return { topics: topics.map(row => row.topic) }; } + + async clearNotifications(options: { + maxAge: HumanDuration; + }): Promise<{ deletedCount: number }> { + const ms = durationToMilliseconds(options.maxAge); + const now = new Date(new Date().getTime() - ms); + const notificationsCount = await this.db('notification') + .where(builder => { + builder.where('created', '<=', now).whereNull('updated'); + }) + .orWhere('updated', '<=', now) + .delete(); + const broadcastsCount = await this.db('broadcast') + .where(builder => { + builder.where('created', '<=', now).whereNull('updated'); + }) + .orWhere('updated', '<=', now) + .delete(); + return { deletedCount: notificationsCount + broadcastsCount }; + } } diff --git a/plugins/notifications-backend/src/database/NotificationsStore.ts b/plugins/notifications-backend/src/database/NotificationsStore.ts index a1f4eb6999..1f25b28bbe 100644 --- a/plugins/notifications-backend/src/database/NotificationsStore.ts +++ b/plugins/notifications-backend/src/database/NotificationsStore.ts @@ -20,6 +20,7 @@ import { NotificationSeverity, NotificationStatus, } from '@backstage/plugin-notifications-common'; +import { HumanDuration } from '@backstage/types'; /** @internal */ export type EntityOrder = { @@ -99,6 +100,10 @@ export interface NotificationsStore { user: string; }): Promise<{ origins: string[] }>; + getUserNotificationTopics(options: { + user: string; + }): Promise<{ topics: { origin: string; topic: string }[] }>; + getNotificationSettings(options: { user: string; }): Promise; @@ -109,4 +114,8 @@ export interface NotificationsStore { }): Promise; getTopics(options: TopicGetOptions): Promise<{ topics: string[] }>; + + clearNotifications(options: { + maxAge: HumanDuration; + }): Promise<{ deletedCount: number }>; } diff --git a/plugins/notifications-backend/src/plugin.ts b/plugins/notifications-backend/src/plugin.ts index a5a31d92ed..5f430318b5 100644 --- a/plugins/notifications-backend/src/plugin.ts +++ b/plugins/notifications-backend/src/plugin.ts @@ -26,6 +26,8 @@ import { NotificationsProcessingExtensionPoint, } from '@backstage/plugin-notifications-node'; import { catalogServiceRef } from '@backstage/plugin-catalog-node'; +import { DatabaseNotificationsStore } from './database'; +import { NotificationCleaner } from './service/NotificationCleaner.ts'; class NotificationsProcessingExtensionPointImpl implements NotificationsProcessingExtensionPoint @@ -69,6 +71,7 @@ export const notificationsPlugin = createBackendPlugin({ signals: signalsServiceRef, config: coreServices.rootConfig, catalog: catalogServiceRef, + scheduler: coreServices.scheduler, }, async init({ auth, @@ -80,7 +83,10 @@ export const notificationsPlugin = createBackendPlugin({ signals, config, catalog, + scheduler, }) { + const store = await DatabaseNotificationsStore.create({ database }); + httpRouter.use( await createRouter({ auth, @@ -88,7 +94,7 @@ export const notificationsPlugin = createBackendPlugin({ userInfo, logger, config, - database, + store, catalog, signals, processors: processingExtensions.processors, @@ -98,6 +104,14 @@ export const notificationsPlugin = createBackendPlugin({ path: '/health', allow: 'unauthenticated', }); + + const cleaner = new NotificationCleaner( + config, + scheduler, + logger, + store, + ); + await cleaner.initTaskRunner(); }, }); }, diff --git a/plugins/notifications-backend/src/service/NotificationCleaner.test.ts b/plugins/notifications-backend/src/service/NotificationCleaner.test.ts new file mode 100644 index 0000000000..bfd3cc62b9 --- /dev/null +++ b/plugins/notifications-backend/src/service/NotificationCleaner.test.ts @@ -0,0 +1,118 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { LoggerService, SchedulerService } from '@backstage/backend-plugin-api'; +import { Config } from '@backstage/config'; +import { mockServices } from '@backstage/backend-test-utils'; +import { NotificationsStore } from '../database'; +import { NotificationCleaner } from './NotificationCleaner.ts'; + +describe('NotificationCleaner', () => { + let mockConfig: Config; + let mockScheduler: SchedulerService; + let mockLogger: LoggerService; + let mockDatabase: NotificationsStore; + + beforeEach(() => { + mockConfig = mockServices.rootConfig(); + mockScheduler = mockServices.scheduler.mock(); + mockLogger = mockServices.logger.mock(); + mockDatabase = { + clearNotifications: jest.fn(), + } as unknown as NotificationsStore; + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + describe('initNotificationCleaner', () => { + it('should initialize the notification cleaner with the correct schedule', async () => { + const mockTaskRunner = { + run: jest.fn(), + }; + mockScheduler.createScheduledTaskRunner = jest + .fn() + .mockReturnValue(mockTaskRunner); + + const cleaner = new NotificationCleaner( + mockConfig, + mockScheduler, + mockLogger, + mockDatabase, + ); + expect(cleaner).toBeInstanceOf(NotificationCleaner); + await cleaner.initTaskRunner(); + + expect(mockScheduler.createScheduledTaskRunner).toHaveBeenCalled(); + expect(mockTaskRunner.run).toHaveBeenCalledWith( + expect.objectContaining({ + id: 'notification-cleaner', + fn: expect.any(Function), + }), + ); + }); + + it('should not create a task runner if retention is disabled', async () => { + mockConfig = mockServices.rootConfig({ + data: { notifications: { retention: false } }, + }); + const cleaner = new NotificationCleaner( + mockConfig, + mockScheduler, + mockLogger, + mockDatabase, + ); + await cleaner.initTaskRunner(); + + expect(mockScheduler.createScheduledTaskRunner).not.toHaveBeenCalled(); + expect(mockLogger.info).toHaveBeenCalledWith( + 'Notification retention is disabled, skipping notification cleaner task', + ); + }); + }); + + describe('clearNotifications', () => { + it('should clear notifications', async () => { + mockDatabase.clearNotifications = jest + .fn() + .mockResolvedValue({ deletedCount: 1 }); + const mockTaskRunner = { + run: jest.fn().mockImplementation(({ fn }) => fn()), + }; + mockScheduler.createScheduledTaskRunner = jest + .fn() + .mockReturnValue(mockTaskRunner); + + const cleaner = new NotificationCleaner( + mockConfig, + mockScheduler, + mockLogger, + mockDatabase, + ); + await cleaner.initTaskRunner(); + + expect(mockLogger.info).toHaveBeenCalledWith( + 'Starting notification cleaner task', + ); + expect(mockLogger.info).toHaveBeenCalledWith( + 'Notification cleaner task completed successfully, deleted 1 notifications', + ); + expect(mockDatabase.clearNotifications).toHaveBeenCalledWith({ + maxAge: { years: 1 }, + }); + }); + }); +}); diff --git a/plugins/notifications-backend/src/service/NotificationCleaner.ts b/plugins/notifications-backend/src/service/NotificationCleaner.ts new file mode 100644 index 0000000000..6733a843b5 --- /dev/null +++ b/plugins/notifications-backend/src/service/NotificationCleaner.ts @@ -0,0 +1,91 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { + LoggerService, + SchedulerService, + SchedulerServiceTaskScheduleDefinition, +} from '@backstage/backend-plugin-api'; +import { Config, readDurationFromConfig } from '@backstage/config'; +import { NotificationsStore } from '../database'; +import { HumanDuration } from '@backstage/types'; +import { ForwardedError } from '@backstage/errors'; + +export class NotificationCleaner { + private readonly retention: HumanDuration = { years: 1 }; + private readonly enabled: boolean = true; + + constructor( + config: Config, + private readonly scheduler: SchedulerService, + private readonly logger: LoggerService, + private readonly database: NotificationsStore, + ) { + if (config.has('notifications.retention')) { + const retentionConfig = config.get('notifications.retention'); + if (typeof retentionConfig === 'boolean' && !retentionConfig) { + logger.info( + 'Notification retention is disabled, skipping notification cleaner task', + ); + this.enabled = false; + return; + } + this.retention = readDurationFromConfig(config, { + key: 'notifications.retention', + }); + } + } + + async initTaskRunner() { + if (!this.enabled) { + return; + } + + const schedule: SchedulerServiceTaskScheduleDefinition = { + frequency: { cron: '0 0 * * *' }, + timeout: { hours: 1 }, + initialDelay: { hours: 1 }, + scope: 'global', + }; + + const taskRunner = this.scheduler.createScheduledTaskRunner(schedule); + await taskRunner.run({ + id: 'notification-cleaner', + fn: async () => { + await this.clearNotifications( + this.logger, + this.database, + this.retention, + ); + }, + }); + } + + private async clearNotifications( + logger: LoggerService, + database: NotificationsStore, + retention: HumanDuration, + ) { + logger.info('Starting notification cleaner task'); + try { + const result = await database.clearNotifications({ maxAge: retention }); + logger.info( + `Notification cleaner task completed successfully, deleted ${result.deletedCount} notifications`, + ); + } catch (error) { + throw new ForwardedError('Notification cleaner task failed', error); + } + } +} diff --git a/plugins/notifications-backend/src/service/router.test.ts b/plugins/notifications-backend/src/service/router.test.ts index 0538e90697..1b3f2e8fd6 100644 --- a/plugins/notifications-backend/src/service/router.test.ts +++ b/plugins/notifications-backend/src/service/router.test.ts @@ -29,8 +29,10 @@ import { NotificationSendOptions } from '@backstage/plugin-notifications-node'; import { catalogServiceMock } from '@backstage/plugin-catalog-node/testUtils'; import { DatabaseService } from '@backstage/backend-plugin-api'; import { v4 as uuid } from 'uuid'; +import { DatabaseNotificationsStore } from '../database'; const databases = TestDatabases.create(); +let store: DatabaseNotificationsStore; async function createDatabase( databaseId: TestDatabaseId, @@ -83,6 +85,9 @@ describe.each(databases.eachSupportedId())('createRouter (%s)', databaseId => { beforeAll(async () => { database = await createDatabase(databaseId); + store = await DatabaseNotificationsStore.create({ + database, + }); }); describe('POST /notifications', () => { @@ -93,7 +98,7 @@ describe.each(databases.eachSupportedId())('createRouter (%s)', databaseId => { beforeAll(async () => { const router = await createRouter({ logger: mockServices.logger.mock(), - database, + store, signals: signalService, userInfo, config, @@ -460,7 +465,7 @@ describe.each(databases.eachSupportedId())('createRouter (%s)', databaseId => { beforeAll(async () => { const router = await createRouter({ logger: mockServices.logger.mock(), - database, + store, signals: signalService, userInfo, config, @@ -550,7 +555,7 @@ describe.each(databases.eachSupportedId())('createRouter (%s)', databaseId => { beforeAll(async () => { const router = await createRouter({ logger: mockServices.logger.mock(), - database, + store, signals: signalService, userInfo, config, @@ -600,7 +605,7 @@ describe.each(databases.eachSupportedId())('createRouter (%s)', databaseId => { beforeAll(async () => { const router = await createRouter({ logger: mockServices.logger.mock(), - database, + store, signals: signalService, userInfo, config, diff --git a/plugins/notifications-backend/src/service/router.ts b/plugins/notifications-backend/src/service/router.ts index f502d49cc4..9563d7965b 100644 --- a/plugins/notifications-backend/src/service/router.ts +++ b/plugins/notifications-backend/src/service/router.ts @@ -17,9 +17,9 @@ import express, { Request, Response } from 'express'; import Router from 'express-promise-router'; import { - DatabaseNotificationsStore, normalizeSeverity, NotificationGetOptions, + NotificationsStore, TopicGetOptions, } from '../database'; import { v4 as uuid } from 'uuid'; @@ -31,7 +31,6 @@ import { import { InputError, NotFoundError } from '@backstage/errors'; import { AuthService, - DatabaseService, HttpAuthService, LoggerService, UserInfoService, @@ -58,7 +57,7 @@ import pThrottle from 'p-throttle'; export interface RouterOptions { logger: LoggerService; config: Config; - database: DatabaseService; + store: NotificationsStore; auth: AuthService; httpAuth: HttpAuthService; userInfo: UserInfoService; @@ -74,7 +73,7 @@ export async function createRouter( const { config, logger, - database, + store, auth, httpAuth, userInfo, @@ -84,7 +83,6 @@ export async function createRouter( } = options; const WEB_NOTIFICATION_CHANNEL = 'Web'; - const store = await DatabaseNotificationsStore.create({ database }); const frontendBaseUrl = config.getString('app.baseUrl'); const concurrencyLimit = config.getOptionalNumber('notifications.concurrencyLimit') ?? 10; diff --git a/plugins/notifications-common/CHANGELOG.md b/plugins/notifications-common/CHANGELOG.md index 0bcbc7e926..9e73b026f9 100644 --- a/plugins/notifications-common/CHANGELOG.md +++ b/plugins/notifications-common/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-notifications-common +## 0.0.9 + +### Patch Changes + +- 1fb5f06: Adds ability for user to turn on/off notifications for specific topics within an origin. +- Updated dependencies + - @backstage/config@1.3.2 + ## 0.0.9-next.0 ### Patch Changes diff --git a/plugins/notifications-common/package.json b/plugins/notifications-common/package.json index cdca935d38..c47af28ddd 100644 --- a/plugins/notifications-common/package.json +++ b/plugins/notifications-common/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-notifications-common", - "version": "0.0.9-next.0", + "version": "0.0.9", "description": "Common functionalities for the notifications plugin", "backstage": { "role": "common-library", diff --git a/plugins/notifications-node/CHANGELOG.md b/plugins/notifications-node/CHANGELOG.md index abfa9e282b..2ad8c1eefc 100644 --- a/plugins/notifications-node/CHANGELOG.md +++ b/plugins/notifications-node/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-notifications-node +## 0.2.16 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.10.1 + - @backstage/plugin-notifications-common@0.0.9 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/catalog-model@1.7.4 + - @backstage/plugin-signals-node@0.1.21 + ## 0.2.16-next.1 ### Patch Changes diff --git a/plugins/notifications-node/package.json b/plugins/notifications-node/package.json index ce823ffe0d..47e6947ace 100644 --- a/plugins/notifications-node/package.json +++ b/plugins/notifications-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-notifications-node", - "version": "0.2.16-next.1", + "version": "0.2.16", "description": "Node.js library for the notifications plugin", "backstage": { "role": "node-library", diff --git a/plugins/notifications/CHANGELOG.md b/plugins/notifications/CHANGELOG.md index a9df09639b..48cab7385c 100644 --- a/plugins/notifications/CHANGELOG.md +++ b/plugins/notifications/CHANGELOG.md @@ -1,5 +1,39 @@ # @backstage/plugin-notifications +## 0.5.6 + +### Patch Changes + +- 18c64e9: Added the `info.packageJson` option to the plugin instance for the new frontend system. +- b00c160: Remove React import form notification and scaffolder plugin +- 1fb5f06: Adds ability for user to turn on/off notifications for specific topics within an origin. +- Updated dependencies + - @backstage/core-components@0.17.3 + - @backstage/core-plugin-api@1.10.8 + - @backstage/plugin-notifications-common@0.0.9 + - @backstage/frontend-plugin-api@0.10.3 + - @backstage/core-compat-api@0.4.3 + - @backstage/errors@1.2.7 + - @backstage/theme@0.6.6 + - @backstage/types@1.2.1 + - @backstage/plugin-signals-react@0.0.14 + +## 0.5.6-next.2 + +### Patch Changes + +- b00c160: Remove React import form notification and scaffolder plugin +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/frontend-plugin-api@0.10.3-next.1 + - @backstage/core-compat-api@0.4.3-next.2 + - @backstage/core-plugin-api@1.10.7 + - @backstage/errors@1.2.7 + - @backstage/theme@0.6.6 + - @backstage/types@1.2.1 + - @backstage/plugin-notifications-common@0.0.9-next.0 + - @backstage/plugin-signals-react@0.0.13 + ## 0.5.6-next.1 ### Patch Changes diff --git a/plugins/notifications/package.json b/plugins/notifications/package.json index 4a9f2fc583..80bf36820b 100644 --- a/plugins/notifications/package.json +++ b/plugins/notifications/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-notifications", - "version": "0.5.6-next.1", + "version": "0.5.6", "backstage": { "role": "frontend-plugin", "pluginId": "notifications", diff --git a/plugins/org-react/CHANGELOG.md b/plugins/org-react/CHANGELOG.md index 93db912391..f570e99ecb 100644 --- a/plugins/org-react/CHANGELOG.md +++ b/plugins/org-react/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-org-react +## 0.1.39 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3 + - @backstage/catalog-client@1.10.1 + - @backstage/core-plugin-api@1.10.8 + - @backstage/plugin-catalog-react@1.19.0 + - @backstage/catalog-model@1.7.4 + +## 0.1.39-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/plugin-catalog-react@1.19.0-next.2 + - @backstage/catalog-client@1.10.1-next.0 + - @backstage/catalog-model@1.7.4 + - @backstage/core-plugin-api@1.10.7 + ## 0.1.39-next.1 ### Patch Changes diff --git a/plugins/org-react/package.json b/plugins/org-react/package.json index 78e690e390..c4531704a3 100644 --- a/plugins/org-react/package.json +++ b/plugins/org-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-org-react", - "version": "0.1.39-next.1", + "version": "0.1.39", "backstage": { "role": "web-library", "pluginId": "org", diff --git a/plugins/org/CHANGELOG.md b/plugins/org/CHANGELOG.md index ff423ab5f6..79481c4512 100644 --- a/plugins/org/CHANGELOG.md +++ b/plugins/org/CHANGELOG.md @@ -1,5 +1,33 @@ # @backstage/plugin-org +## 0.6.40 + +### Patch Changes + +- 18c64e9: Added the `info.packageJson` option to the plugin instance for the new frontend system. +- 4fe364f: Org plugin support i18n +- Updated dependencies + - @backstage/core-components@0.17.3 + - @backstage/core-plugin-api@1.10.8 + - @backstage/frontend-plugin-api@0.10.3 + - @backstage/plugin-catalog-react@1.19.0 + - @backstage/catalog-model@1.7.4 + - @backstage/core-compat-api@0.4.3 + - @backstage/plugin-catalog-common@1.1.4 + +## 0.6.40-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/plugin-catalog-react@1.19.0-next.2 + - @backstage/frontend-plugin-api@0.10.3-next.1 + - @backstage/catalog-model@1.7.4 + - @backstage/core-compat-api@0.4.3-next.2 + - @backstage/core-plugin-api@1.10.7 + - @backstage/plugin-catalog-common@1.1.4 + ## 0.6.40-next.1 ### Patch Changes diff --git a/plugins/org/package.json b/plugins/org/package.json index ea9d705feb..1d430267be 100644 --- a/plugins/org/package.json +++ b/plugins/org/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-org", - "version": "0.6.40-next.1", + "version": "0.6.40", "description": "A Backstage plugin that helps you create entity pages for your organization", "backstage": { "role": "frontend-plugin", diff --git a/plugins/permission-backend-module-policy-allow-all/CHANGELOG.md b/plugins/permission-backend-module-policy-allow-all/CHANGELOG.md index 0d5f459c4c..ed05fc0897 100644 --- a/plugins/permission-backend-module-policy-allow-all/CHANGELOG.md +++ b/plugins/permission-backend-module-policy-allow-all/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-permission-backend-module-allow-all-policy +## 0.2.9 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/plugin-permission-common@0.9.0 + - @backstage/plugin-permission-node@0.10.1 + ## 0.2.9-next.1 ### Patch Changes diff --git a/plugins/permission-backend-module-policy-allow-all/package.json b/plugins/permission-backend-module-policy-allow-all/package.json index 3ef2bcd7e6..8a9a103618 100644 --- a/plugins/permission-backend-module-policy-allow-all/package.json +++ b/plugins/permission-backend-module-policy-allow-all/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-permission-backend-module-allow-all-policy", - "version": "0.2.9-next.1", + "version": "0.2.9", "description": "Allow all policy backend module for the permission plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/permission-backend/CHANGELOG.md b/plugins/permission-backend/CHANGELOG.md index 8d0849da56..41094f6485 100644 --- a/plugins/permission-backend/CHANGELOG.md +++ b/plugins/permission-backend/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-permission-backend +## 0.7.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/plugin-permission-common@0.9.0 + - @backstage/plugin-permission-node@0.10.1 + ## 0.7.1-next.1 ### Patch Changes diff --git a/plugins/permission-backend/package.json b/plugins/permission-backend/package.json index ef970b4c5c..db494304b9 100644 --- a/plugins/permission-backend/package.json +++ b/plugins/permission-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-permission-backend", - "version": "0.7.1-next.1", + "version": "0.7.1", "backstage": { "role": "backend-plugin", "pluginId": "permission", diff --git a/plugins/permission-node/CHANGELOG.md b/plugins/permission-node/CHANGELOG.md index c86d51f9c2..76ac7984e0 100644 --- a/plugins/permission-node/CHANGELOG.md +++ b/plugins/permission-node/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-permission-node +## 0.10.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/plugin-permission-common@0.9.0 + ## 0.10.1-next.1 ### Patch Changes diff --git a/plugins/permission-node/package.json b/plugins/permission-node/package.json index 805b1c919b..65c81820ec 100644 --- a/plugins/permission-node/package.json +++ b/plugins/permission-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-permission-node", - "version": "0.10.1-next.1", + "version": "0.10.1", "description": "Common permission and authorization utilities for backend plugins", "backstage": { "role": "node-library", diff --git a/plugins/permission-react/CHANGELOG.md b/plugins/permission-react/CHANGELOG.md index 8c29c0cc6d..8d591c0bdb 100644 --- a/plugins/permission-react/CHANGELOG.md +++ b/plugins/permission-react/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-permission-react +## 0.4.35 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.10.8 + - @backstage/config@1.3.2 + - @backstage/plugin-permission-common@0.9.0 + ## 0.4.34 ### Patch Changes diff --git a/plugins/permission-react/package.json b/plugins/permission-react/package.json index b9cb46ac47..062bd8bc47 100644 --- a/plugins/permission-react/package.json +++ b/plugins/permission-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-permission-react", - "version": "0.4.34", + "version": "0.4.35", "backstage": { "role": "web-library", "pluginId": "permission", diff --git a/plugins/proxy-backend/CHANGELOG.md b/plugins/proxy-backend/CHANGELOG.md index 924fc7c193..d619d13779 100644 --- a/plugins/proxy-backend/CHANGELOG.md +++ b/plugins/proxy-backend/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-proxy-backend +## 0.6.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.0 + - @backstage/types@1.2.1 + - @backstage/plugin-proxy-node@0.1.5 + ## 0.6.3-next.1 ### Patch Changes diff --git a/plugins/proxy-backend/package.json b/plugins/proxy-backend/package.json index fc3c2d3147..e925722ca3 100644 --- a/plugins/proxy-backend/package.json +++ b/plugins/proxy-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-proxy-backend", - "version": "0.6.3-next.1", + "version": "0.6.3", "description": "A Backstage backend plugin that helps you set up proxy endpoints in the backend", "backstage": { "role": "backend-plugin", diff --git a/plugins/proxy-node/CHANGELOG.md b/plugins/proxy-node/CHANGELOG.md index c1cfc3a736..b06ed5f44e 100644 --- a/plugins/proxy-node/CHANGELOG.md +++ b/plugins/proxy-node/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/plugin-proxy-node +## 0.1.5 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.0 + ## 0.1.5-next.1 ### Patch Changes diff --git a/plugins/proxy-node/package.json b/plugins/proxy-node/package.json index a99b2b6913..0d2d372fdd 100644 --- a/plugins/proxy-node/package.json +++ b/plugins/proxy-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-proxy-node", - "version": "0.1.5-next.1", + "version": "0.1.5", "description": "The plugin-proxy-node module for @backstage/plugin-proxy-backend", "backstage": { "role": "node-library", diff --git a/plugins/scaffolder-backend-module-azure/CHANGELOG.md b/plugins/scaffolder-backend-module-azure/CHANGELOG.md index a5e9c298e9..8df6679a1d 100644 --- a/plugins/scaffolder-backend-module-azure/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-azure/CHANGELOG.md @@ -1,5 +1,28 @@ # @backstage/plugin-scaffolder-backend-module-azure +## 0.2.10 + +### Patch Changes + +- e89d7b6: Migrating `azure` actions to using the new `zod` schema format +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.9.0 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + +## 0.2.10-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.9.0-next.2 + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + ## 0.2.10-next.1 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-azure/package.json b/plugins/scaffolder-backend-module-azure/package.json index 975a446efc..865262795b 100644 --- a/plugins/scaffolder-backend-module-azure/package.json +++ b/plugins/scaffolder-backend-module-azure/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-azure", - "version": "0.2.10-next.1", + "version": "0.2.10", "description": "The azure module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-bitbucket-cloud/CHANGELOG.md b/plugins/scaffolder-backend-module-bitbucket-cloud/CHANGELOG.md index 852df7a904..d301f3c62c 100644 --- a/plugins/scaffolder-backend-module-bitbucket-cloud/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-bitbucket-cloud/CHANGELOG.md @@ -1,5 +1,32 @@ # @backstage/plugin-scaffolder-backend-module-bitbucket-cloud +## 0.2.10 + +### Patch Changes + +- ca9fdc0: Migrate `bitbucket-cloud` to new actions format +- 9c8ff0c: Update pull request creation filter to include .gitignore files in the created pull request +- 280611d: Fix `bitbucketCloudBranchRestrictions` API calls to accept null to prevent 400 errors for some branch restriction kinds defined. +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.9.0 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + - @backstage/plugin-bitbucket-cloud-common@0.3.0 + +## 0.2.10-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.9.0-next.2 + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + - @backstage/plugin-bitbucket-cloud-common@0.3.0 + ## 0.2.10-next.1 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-bitbucket-cloud/package.json b/plugins/scaffolder-backend-module-bitbucket-cloud/package.json index 2c4c83f5b6..d3244cb55b 100644 --- a/plugins/scaffolder-backend-module-bitbucket-cloud/package.json +++ b/plugins/scaffolder-backend-module-bitbucket-cloud/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-bitbucket-cloud", - "version": "0.2.10-next.1", + "version": "0.2.10", "description": "The Bitbucket Cloud module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-bitbucket-server/CHANGELOG.md b/plugins/scaffolder-backend-module-bitbucket-server/CHANGELOG.md index 7d56244457..e65f866b2a 100644 --- a/plugins/scaffolder-backend-module-bitbucket-server/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-bitbucket-server/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-scaffolder-backend-module-bitbucket-server +## 0.2.10 + +### Patch Changes + +- d8169fc: Migrate the actions to the new format +- 9c8ff0c: Update pull request creation filter to include .gitignore files in the created pull request +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.9.0 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + +## 0.2.10-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.9.0-next.2 + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + ## 0.2.10-next.1 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-bitbucket-server/package.json b/plugins/scaffolder-backend-module-bitbucket-server/package.json index 5a6cf1f317..10cd7ddd3d 100644 --- a/plugins/scaffolder-backend-module-bitbucket-server/package.json +++ b/plugins/scaffolder-backend-module-bitbucket-server/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-bitbucket-server", - "version": "0.2.10-next.1", + "version": "0.2.10", "description": "The Bitbucket Server module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-bitbucket/CHANGELOG.md b/plugins/scaffolder-backend-module-bitbucket/CHANGELOG.md index 0f55793ec6..24566d2810 100644 --- a/plugins/scaffolder-backend-module-bitbucket/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-bitbucket/CHANGELOG.md @@ -1,5 +1,32 @@ # @backstage/plugin-scaffolder-backend-module-bitbucket +## 0.3.11 + +### Patch Changes + +- 7f710d2: Migrating `bitbucket` actions to use the new `zod` format +- Updated dependencies + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.2.10 + - @backstage/plugin-scaffolder-node@0.9.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.2.10 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + +## 0.3.11-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.9.0-next.2 + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.2.10-next.2 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.2.10-next.2 + ## 0.3.11-next.1 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-bitbucket/package.json b/plugins/scaffolder-backend-module-bitbucket/package.json index ef8ecb4e7c..09b4b4a14f 100644 --- a/plugins/scaffolder-backend-module-bitbucket/package.json +++ b/plugins/scaffolder-backend-module-bitbucket/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-bitbucket", - "version": "0.3.11-next.1", + "version": "0.3.11", "description": "The bitbucket module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-confluence-to-markdown/CHANGELOG.md b/plugins/scaffolder-backend-module-confluence-to-markdown/CHANGELOG.md index 50ba4a5f6c..41fdbd8e44 100644 --- a/plugins/scaffolder-backend-module-confluence-to-markdown/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-confluence-to-markdown/CHANGELOG.md @@ -1,5 +1,28 @@ # @backstage/plugin-scaffolder-backend-module-confluence-to-markdown +## 0.3.10 + +### Patch Changes + +- 4a86bca: Migrate actions to new format +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.9.0 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + +## 0.3.10-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.9.0-next.2 + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + ## 0.3.10-next.1 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-confluence-to-markdown/package.json b/plugins/scaffolder-backend-module-confluence-to-markdown/package.json index e95d610f48..f3d1cead73 100644 --- a/plugins/scaffolder-backend-module-confluence-to-markdown/package.json +++ b/plugins/scaffolder-backend-module-confluence-to-markdown/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-confluence-to-markdown", - "version": "0.3.10-next.1", + "version": "0.3.10", "description": "The confluence-to-markdown module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md b/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md index 721b05c601..a3bea154d8 100644 --- a/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md @@ -1,5 +1,32 @@ # @backstage/plugin-scaffolder-backend-module-cookiecutter +## 0.3.11 + +### Patch Changes + +- 0b2bbf1: Migrate using new actions format +- Updated dependencies + - @backstage/backend-defaults@0.11.0 + - @backstage/plugin-scaffolder-node@0.9.0 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + - @backstage/types@1.2.1 + +## 0.3.11-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.11.0-next.2 + - @backstage/plugin-scaffolder-node@0.9.0-next.2 + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + - @backstage/types@1.2.1 + ## 0.3.11-next.1 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-cookiecutter/package.json b/plugins/scaffolder-backend-module-cookiecutter/package.json index 21b95c0641..aa07d95a8f 100644 --- a/plugins/scaffolder-backend-module-cookiecutter/package.json +++ b/plugins/scaffolder-backend-module-cookiecutter/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-cookiecutter", - "version": "0.3.11-next.1", + "version": "0.3.11", "description": "A module for the scaffolder backend that lets you template projects using cookiecutter", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-gcp/CHANGELOG.md b/plugins/scaffolder-backend-module-gcp/CHANGELOG.md index bf9576fd11..8f6d77f907 100644 --- a/plugins/scaffolder-backend-module-gcp/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-gcp/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-scaffolder-backend-module-gcp +## 0.2.10 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.9.0 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + +## 0.2.10-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.9.0-next.2 + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + ## 0.2.10-next.1 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-gcp/package.json b/plugins/scaffolder-backend-module-gcp/package.json index 4d1b921556..5c3ee5dc13 100644 --- a/plugins/scaffolder-backend-module-gcp/package.json +++ b/plugins/scaffolder-backend-module-gcp/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-gcp", - "version": "0.2.10-next.1", + "version": "0.2.10", "description": "The GCP Bucket module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-gerrit/CHANGELOG.md b/plugins/scaffolder-backend-module-gerrit/CHANGELOG.md index bcf48115c0..d795bf2275 100644 --- a/plugins/scaffolder-backend-module-gerrit/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-gerrit/CHANGELOG.md @@ -1,5 +1,28 @@ # @backstage/plugin-scaffolder-backend-module-gerrit +## 0.2.10 + +### Patch Changes + +- e24b29b: Migrating to use new format for actions +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.9.0 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + +## 0.2.10-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.9.0-next.2 + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + ## 0.2.10-next.1 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-gerrit/package.json b/plugins/scaffolder-backend-module-gerrit/package.json index 091345a30a..be5b4103fe 100644 --- a/plugins/scaffolder-backend-module-gerrit/package.json +++ b/plugins/scaffolder-backend-module-gerrit/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-gerrit", - "version": "0.2.10-next.1", + "version": "0.2.10", "description": "The gerrit module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-gitea/CHANGELOG.md b/plugins/scaffolder-backend-module-gitea/CHANGELOG.md index 94172f1fdb..e4cf277e46 100644 --- a/plugins/scaffolder-backend-module-gitea/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-gitea/CHANGELOG.md @@ -1,5 +1,28 @@ # @backstage/plugin-scaffolder-backend-module-gitea +## 0.2.10 + +### Patch Changes + +- ed41017: Migrate to new actions format +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.9.0 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + +## 0.2.10-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.9.0-next.2 + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + ## 0.2.10-next.1 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-gitea/package.json b/plugins/scaffolder-backend-module-gitea/package.json index 545a778646..3218a3f649 100644 --- a/plugins/scaffolder-backend-module-gitea/package.json +++ b/plugins/scaffolder-backend-module-gitea/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-gitea", - "version": "0.2.10-next.1", + "version": "0.2.10", "description": "The gitea module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-github/CHANGELOG.md b/plugins/scaffolder-backend-module-github/CHANGELOG.md index 3944c6d88a..88220d2042 100644 --- a/plugins/scaffolder-backend-module-github/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-github/CHANGELOG.md @@ -1,5 +1,105 @@ # @backstage/plugin-scaffolder-backend-module-github +## 0.8.0 + +### Minor Changes + +- 5863b04: **BREAKING CHANGES** + + The `createGithubEnvironmentAction` action no longer requires an `AuthService`, and now accepts a `CatalogService` instead of `CatalogClient`. + + Unless you're providing your own override action to the default, this should be a non-breaking change. + + You can migrate using the following if you're getting typescript errors: + + ```ts + import { catalogServiceRef } from '@backstage/plugin-catalog-node'; + import { scaffolderActionsExtensionPoint } from '@backstage/plugin-scaffolder-node/alpha'; + + export const myModule = createBackendModule({ + pluginId: 'scaffolder', + moduleId: 'test', + register({ registerInit }) { + registerInit({ + deps: { + scaffolder: scaffolderActionsExtensionPoint, + catalog: catalogServiceRef, + }, + async init({ scaffolder, catalog }) { + scaffolder.addActions( + createGithubEnvironmentAction({ + catalog, + }), + ); + }, + }); + }, + }); + ``` + +### Patch Changes + +- 575c76b: Migrate to using new actions +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.9.0 + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + - @backstage/types@1.2.1 + +## 0.8.0-next.2 + +### Minor Changes + +- 5863b04: **BREAKING CHANGES** + + The `createGithubEnvironmentAction` action no longer requires an `AuthService`, and now accepts a `CatalogService` instead of `CatalogClient`. + + Unless you're providing your own override action to the default, this should be a non-breaking change. + + You can migrate using the following if you're getting typescript errors: + + ```ts + import { catalogServiceRef } from '@backstage/plugin-catalog-node'; + import { scaffolderActionsExtensionPoint } from '@backstage/plugin-scaffolder-node/alpha'; + + export const myModule = createBackendModule({ + pluginId: 'scaffolder', + moduleId: 'test', + register({ registerInit }) { + registerInit({ + deps: { + scaffolder: scaffolderActionsExtensionPoint, + catalog: catalogServiceRef, + }, + async init({ scaffolder, catalog }) { + scaffolder.addActions( + createGithubEnvironmentAction({ + catalog, + }), + ); + }, + }); + }, + }); + ``` + +### Patch Changes + +- 575c76b: Migrate to using new actions +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.9.0-next.2 + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + - @backstage/types@1.2.1 + - @backstage/plugin-catalog-node@1.17.1-next.1 + ## 0.7.2-next.1 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-github/package.json b/plugins/scaffolder-backend-module-github/package.json index 1df39a57be..3e074432d2 100644 --- a/plugins/scaffolder-backend-module-github/package.json +++ b/plugins/scaffolder-backend-module-github/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-github", - "version": "0.7.2-next.1", + "version": "0.8.0", "description": "The github module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-gitlab/CHANGELOG.md b/plugins/scaffolder-backend-module-gitlab/CHANGELOG.md index a2fb152ee4..16a5cf8c44 100644 --- a/plugins/scaffolder-backend-module-gitlab/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-gitlab/CHANGELOG.md @@ -1,5 +1,31 @@ # @backstage/plugin-scaffolder-backend-module-gitlab +## 0.9.2 + +### Patch Changes + +- 063b2d3: Fixed dependency to frontend package from tests +- a296637: Migrate to new action format +- 3d6493a: Support merge request labels in publish:gitlab:merge-request +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.9.0 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + +## 0.9.2-next.2 + +### Patch Changes + +- a296637: Migrate to new action format +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.9.0-next.2 + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + ## 0.9.2-next.1 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-gitlab/package.json b/plugins/scaffolder-backend-module-gitlab/package.json index 03965d92cd..9c0f754a03 100644 --- a/plugins/scaffolder-backend-module-gitlab/package.json +++ b/plugins/scaffolder-backend-module-gitlab/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-gitlab", - "version": "0.9.2-next.1", + "version": "0.9.2", "backstage": { "role": "backend-plugin-module", "pluginId": "scaffolder", @@ -59,7 +59,6 @@ "devDependencies": { "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", - "@backstage/core-app-api": "workspace:^", "@backstage/plugin-scaffolder-node-test-utils": "workspace:^" } } diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabGroupEnsureExists.examples.test.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabGroupEnsureExists.examples.test.ts index 4d8e0fd0c0..449c5980a4 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabGroupEnsureExists.examples.test.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabGroupEnsureExists.examples.test.ts @@ -14,12 +14,12 @@ * limitations under the License. */ -import { ConfigReader } from '@backstage/core-app-api'; import { ScmIntegrations } from '@backstage/integration'; import { createMockActionContext } from '@backstage/plugin-scaffolder-node-test-utils'; import yaml from 'yaml'; import { createGitlabGroupEnsureExistsAction } from './gitlabGroupEnsureExists'; import { examples } from './gitlabGroupEnsureExists.examples'; +import { mockServices } from '@backstage/backend-test-utils'; const mockGitlabClient = { Groups: { @@ -50,15 +50,17 @@ describe('gitlab:group:ensureExists', () => { full_path: 'group1', }); - const config = new ConfigReader({ - integrations: { - gitlab: [ - { - host: 'gitlab.com', - token: 'tokenlols', - apiBaseUrl: 'https://gitlab.com/api/v4', - }, - ], + const config = mockServices.rootConfig({ + data: { + integrations: { + gitlab: [ + { + host: 'gitlab.com', + token: 'tokenlols', + apiBaseUrl: 'https://gitlab.com/api/v4', + }, + ], + }, }, }); const integrations = ScmIntegrations.fromConfig(config); @@ -91,15 +93,17 @@ describe('gitlab:group:ensureExists', () => { full_path: 'group1/group2', }); - const config = new ConfigReader({ - integrations: { - gitlab: [ - { - host: 'gitlab.com', - token: 'tokenlols', - apiBaseUrl: 'https://api.gitlab.com', - }, - ], + const config = mockServices.rootConfig({ + data: { + integrations: { + gitlab: [ + { + host: 'gitlab.com', + token: 'tokenlols', + apiBaseUrl: 'https://api.gitlab.com', + }, + ], + }, }, }); const integrations = ScmIntegrations.fromConfig(config); @@ -138,15 +142,17 @@ describe('gitlab:group:ensureExists', () => { full_path: 'group1/group2/group3', }); - const config = new ConfigReader({ - integrations: { - gitlab: [ - { - host: 'gitlab.com', - token: 'tokenlols', - apiBaseUrl: 'https://api.gitlab.com', - }, - ], + const config = mockServices.rootConfig({ + data: { + integrations: { + gitlab: [ + { + host: 'gitlab.com', + token: 'tokenlols', + apiBaseUrl: 'https://api.gitlab.com', + }, + ], + }, }, }); const integrations = ScmIntegrations.fromConfig(config); @@ -170,15 +176,17 @@ describe('gitlab:group:ensureExists', () => { }); it(`Should ${examples[3].description}`, async () => { - const config = new ConfigReader({ - integrations: { - gitlab: [ - { - host: 'gitlab.com', - token: 'tokenlols', - apiBaseUrl: 'https://api.gitlab.com', - }, - ], + const config = mockServices.rootConfig({ + data: { + integrations: { + gitlab: [ + { + host: 'gitlab.com', + token: 'tokenlols', + apiBaseUrl: 'https://api.gitlab.com', + }, + ], + }, }, }); const integrations = ScmIntegrations.fromConfig(config); @@ -213,15 +221,17 @@ describe('gitlab:group:ensureExists', () => { full_path: 'group1/group2/group3', }); - const config = new ConfigReader({ - integrations: { - gitlab: [ - { - host: 'gitlab.com', - token: 'tokenlols', - apiBaseUrl: 'https://api.gitlab.com', - }, - ], + const config = mockServices.rootConfig({ + data: { + integrations: { + gitlab: [ + { + host: 'gitlab.com', + token: 'tokenlols', + apiBaseUrl: 'https://api.gitlab.com', + }, + ], + }, }, }); const integrations = ScmIntegrations.fromConfig(config); @@ -264,15 +274,17 @@ describe('gitlab:group:ensureExists', () => { full_path: 'group1/group2/group3/group4', }); - const config = new ConfigReader({ - integrations: { - gitlab: [ - { - host: 'gitlab.com', - token: 'tokenlols', - apiBaseUrl: 'https://api.gitlab.com', - }, - ], + const config = mockServices.rootConfig({ + data: { + integrations: { + gitlab: [ + { + host: 'gitlab.com', + token: 'tokenlols', + apiBaseUrl: 'https://api.gitlab.com', + }, + ], + }, }, }); const integrations = ScmIntegrations.fromConfig(config); diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabGroupEnsureExists.test.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabGroupEnsureExists.test.ts index 3d703eb91f..8e52ee999e 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabGroupEnsureExists.test.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabGroupEnsureExists.test.ts @@ -14,11 +14,11 @@ * limitations under the License. */ -import { ConfigReader } from '@backstage/core-app-api'; import { ScmIntegrations } from '@backstage/integration'; import { createMockActionContext } from '@backstage/plugin-scaffolder-node-test-utils'; import { createGitlabGroupEnsureExistsAction } from './gitlabGroupEnsureExists'; import { getClient } from '../util'; +import { mockServices } from '@backstage/backend-test-utils'; const mockGitlabClient = { Groups: { @@ -45,15 +45,17 @@ describe('gitlab:group:ensureExists', () => { jest.clearAllMocks(); }); - const config = new ConfigReader({ - integrations: { - gitlab: [ - { - host: 'gitlab.com', - token: 'tokenlols', - apiBaseUrl: 'https://gitlab.com/api/v4', - }, - ], + const config = mockServices.rootConfig({ + data: { + integrations: { + gitlab: [ + { + host: 'gitlab.com', + token: 'tokenlols', + apiBaseUrl: 'https://gitlab.com/api/v4', + }, + ], + }, }, }); const integrations = ScmIntegrations.fromConfig(config); diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabIssueCreate.examples.test.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabIssueCreate.examples.test.ts index 917ba61d91..858adb4b99 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabIssueCreate.examples.test.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabIssueCreate.examples.test.ts @@ -14,12 +14,12 @@ * limitations under the License. */ -import { ConfigReader } from '@backstage/core-app-api'; import { ScmIntegrations } from '@backstage/integration'; import { createMockActionContext } from '@backstage/plugin-scaffolder-node-test-utils'; import { createGitlabIssueAction } from './gitlabIssueCreate'; import { examples } from './gitlabIssueCreate.examples'; import yaml from 'yaml'; +import { mockServices } from '@backstage/backend-test-utils'; const mockGitlabClient = { Issues: { @@ -46,15 +46,17 @@ describe('gitlab:issues:create', () => { jest.useRealTimers(); }); - const config = new ConfigReader({ - integrations: { - gitlab: [ - { - host: 'gitlab.com', - token: 'sample-token', - apiBaseUrl: 'https://gitlab.com/api/v1', - }, - ], + const config = mockServices.rootConfig({ + data: { + integrations: { + gitlab: [ + { + host: 'gitlab.com', + token: 'sample-token', + apiBaseUrl: 'https://gitlab.com/api/v1', + }, + ], + }, }, }); const integrations = ScmIntegrations.fromConfig(config); diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabIssueCreate.test.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabIssueCreate.test.ts index d5aa2d1e17..e09bfaf249 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabIssueCreate.test.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabIssueCreate.test.ts @@ -14,11 +14,11 @@ * limitations under the License. */ -import { ConfigReader } from '@backstage/core-app-api'; import { ScmIntegrations } from '@backstage/integration'; import { createMockActionContext } from '@backstage/plugin-scaffolder-node-test-utils'; import { IssueType } from '../commonGitlabConfig'; import { createGitlabIssueAction } from './gitlabIssueCreate'; +import { mockServices } from '@backstage/backend-test-utils'; const mockGitlabClient = { Issues: { @@ -45,15 +45,17 @@ describe('gitlab:issues:create', () => { jest.useRealTimers(); }); - const config = new ConfigReader({ - integrations: { - gitlab: [ - { - host: 'gitlab.com', - token: 'myIntegrationsToken', - apiBaseUrl: 'https://gitlab.com/api/v4', - }, - ], + const config = mockServices.rootConfig({ + data: { + integrations: { + gitlab: [ + { + host: 'gitlab.com', + token: 'myIntegrationsToken', + apiBaseUrl: 'https://gitlab.com/api/v4', + }, + ], + }, }, }); const integrations = ScmIntegrations.fromConfig(config); diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabIssueEdit.examples.test.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabIssueEdit.examples.test.ts index 7e50eac66c..fa53609c19 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabIssueEdit.examples.test.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabIssueEdit.examples.test.ts @@ -15,11 +15,11 @@ */ import { createMockActionContext } from '@backstage/plugin-scaffolder-node-test-utils'; -import { ConfigReader } from '@backstage/core-app-api'; import { ScmIntegrations } from '@backstage/integration'; import { editGitlabIssueAction } from './gitlabIssueEdit'; import { examples } from './gitlabIssueEdit.examples'; import yaml from 'yaml'; +import { mockServices } from '@backstage/backend-test-utils'; const mockGitlabClient = { Issues: { @@ -46,15 +46,17 @@ describe('gitlab:issue:edit', () => { jest.useRealTimers(); }); - const config = new ConfigReader({ - integrations: { - gitlab: [ - { - host: 'gitlab.com', - token: 'myIntegrationsToken', - apiBaseUrl: 'https://gitlab.com/api/v4', - }, - ], + const config = mockServices.rootConfig({ + data: { + integrations: { + gitlab: [ + { + host: 'gitlab.com', + token: 'myIntegrationsToken', + apiBaseUrl: 'https://gitlab.com/api/v4', + }, + ], + }, }, }); const integrations = ScmIntegrations.fromConfig(config); diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabIssueEdit.test.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabIssueEdit.test.ts index 9604fe8fe2..a16236a509 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabIssueEdit.test.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabIssueEdit.test.ts @@ -15,10 +15,10 @@ */ import { createMockActionContext } from '@backstage/plugin-scaffolder-node-test-utils'; -import { ConfigReader } from '@backstage/core-app-api'; import { ScmIntegrations } from '@backstage/integration'; import { IssueType } from '../commonGitlabConfig'; import { editGitlabIssueAction } from './gitlabIssueEdit'; +import { mockServices } from '@backstage/backend-test-utils'; const mockGitlabClient = { Issues: { @@ -45,15 +45,17 @@ describe('gitlab:issue:edit', () => { jest.useRealTimers(); }); - const config = new ConfigReader({ - integrations: { - gitlab: [ - { - host: 'gitlab.com', - token: 'myIntegrationsToken', - apiBaseUrl: 'https://gitlab.com/api/v4', - }, - ], + const config = mockServices.rootConfig({ + data: { + integrations: { + gitlab: [ + { + host: 'gitlab.com', + token: 'myIntegrationsToken', + apiBaseUrl: 'https://gitlab.com/api/v4', + }, + ], + }, }, }); const integrations = ScmIntegrations.fromConfig(config); diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabPipelineTrigger.examples.test.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabPipelineTrigger.examples.test.ts index 53cbfb0b87..41535479fe 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabPipelineTrigger.examples.test.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabPipelineTrigger.examples.test.ts @@ -14,12 +14,12 @@ * limitations under the License. */ -import { ConfigReader } from '@backstage/core-app-api'; import { ScmIntegrations } from '@backstage/integration'; import { createMockActionContext } from '@backstage/plugin-scaffolder-node-test-utils'; import { createTriggerGitlabPipelineAction } from './gitlabPipelineTrigger'; import { examples } from './gitlabPipelineTrigger.examples'; import yaml from 'yaml'; +import { mockServices } from '@backstage/backend-test-utils'; const mockGitlabClient = { PipelineTriggerTokens: { @@ -49,15 +49,17 @@ describe('gitlab:pipeline:trigger', () => { jest.useRealTimers(); }); - const config = new ConfigReader({ - integrations: { - gitlab: [ - { - host: 'gitlab.com', - token: 'glpat-abcdef', - apiBaseUrl: 'https://gitlab.com/api/v4', - }, - ], + const config = mockServices.rootConfig({ + data: { + integrations: { + gitlab: [ + { + host: 'gitlab.com', + token: 'glpat-abcdef', + apiBaseUrl: 'https://gitlab.com/api/v4', + }, + ], + }, }, }); const integrations = ScmIntegrations.fromConfig(config); diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabPipelineTrigger.test.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabPipelineTrigger.test.ts index 3803198ec8..89498c52f2 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabPipelineTrigger.test.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabPipelineTrigger.test.ts @@ -14,10 +14,10 @@ * limitations under the License. */ -import { ConfigReader } from '@backstage/core-app-api'; import { ScmIntegrations } from '@backstage/integration'; import { createMockActionContext } from '@backstage/plugin-scaffolder-node-test-utils'; import { createTriggerGitlabPipelineAction } from './gitlabPipelineTrigger'; +import { mockServices } from '@backstage/backend-test-utils'; const mockGitlabClient = { PipelineTriggerTokens: { @@ -47,15 +47,17 @@ describe('gitlab:pipeline:trigger', () => { jest.useRealTimers(); }); - const config = new ConfigReader({ - integrations: { - gitlab: [ - { - host: 'gitlab.com', - token: 'glpat-abcdef', - apiBaseUrl: 'https://gitlab.com/api/v4', - }, - ], + const config = mockServices.rootConfig({ + data: { + integrations: { + gitlab: [ + { + host: 'gitlab.com', + token: 'glpat-abcdef', + apiBaseUrl: 'https://gitlab.com/api/v4', + }, + ], + }, }, }); const integrations = ScmIntegrations.fromConfig(config); diff --git a/plugins/scaffolder-backend-module-notifications/CHANGELOG.md b/plugins/scaffolder-backend-module-notifications/CHANGELOG.md index cc8b465587..0cc9672729 100644 --- a/plugins/scaffolder-backend-module-notifications/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-notifications/CHANGELOG.md @@ -1,5 +1,28 @@ # @backstage/plugin-scaffolder-backend-module-notifications +## 0.1.11 + +### Patch Changes + +- 1fb5f06: Adds ability for user to turn on/off notifications for specific topics within an origin. +- 3f56115: Removed `octokit` dependency as it was not being used +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.9.0 + - @backstage/plugin-notifications-common@0.0.9 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/plugin-notifications-node@0.2.16 + +## 0.1.11-next.2 + +### Patch Changes + +- 3f56115: Removed `octokit` dependency as it was not being used +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.9.0-next.2 + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/plugin-notifications-common@0.0.9-next.0 + - @backstage/plugin-notifications-node@0.2.16-next.1 + ## 0.1.11-next.1 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-notifications/package.json b/plugins/scaffolder-backend-module-notifications/package.json index a89f504f96..2f355e338e 100644 --- a/plugins/scaffolder-backend-module-notifications/package.json +++ b/plugins/scaffolder-backend-module-notifications/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-notifications", - "version": "0.1.11-next.1", + "version": "0.1.11", "description": "The notifications backend module for the scaffolder plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-rails/CHANGELOG.md b/plugins/scaffolder-backend-module-rails/CHANGELOG.md index 7aeb534e06..6f8631be4a 100644 --- a/plugins/scaffolder-backend-module-rails/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-rails/CHANGELOG.md @@ -1,5 +1,31 @@ # @backstage/plugin-scaffolder-backend-module-rails +## 0.5.10 + +### Patch Changes + +- a579693: Migrate to new actions format +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.9.0 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + - @backstage/types@1.2.1 + +## 0.5.10-next.2 + +### Patch Changes + +- a579693: Migrate to new actions format +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.9.0-next.2 + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + - @backstage/types@1.2.1 + ## 0.5.10-next.1 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-rails/package.json b/plugins/scaffolder-backend-module-rails/package.json index f2293a966a..2afa72c360 100644 --- a/plugins/scaffolder-backend-module-rails/package.json +++ b/plugins/scaffolder-backend-module-rails/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-rails", - "version": "0.5.10-next.1", + "version": "0.5.10", "description": "A module for the scaffolder backend that lets you template projects using Rails", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-sentry/CHANGELOG.md b/plugins/scaffolder-backend-module-sentry/CHANGELOG.md index 433f6060d8..59a7223fb7 100644 --- a/plugins/scaffolder-backend-module-sentry/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-sentry/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-scaffolder-backend-module-sentry +## 0.2.10 + +### Patch Changes + +- 6c6fb4a: Migrate to new actions format +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.9.0 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + +## 0.2.10-next.2 + +### Patch Changes + +- 6c6fb4a: Migrate to new actions format +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.9.0-next.2 + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + ## 0.2.10-next.1 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-sentry/package.json b/plugins/scaffolder-backend-module-sentry/package.json index b5b56d213f..260b9f4fd3 100644 --- a/plugins/scaffolder-backend-module-sentry/package.json +++ b/plugins/scaffolder-backend-module-sentry/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-sentry", - "version": "0.2.10-next.1", + "version": "0.2.10", "backstage": { "role": "backend-plugin-module", "pluginId": "scaffolder", diff --git a/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md b/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md index 5faceb7501..599c5f73d9 100644 --- a/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-scaffolder-backend-module-yeoman +## 0.4.11 + +### Patch Changes + +- b392a34: Migrate to new actions format +- Updated dependencies + - @backstage/plugin-scaffolder-node-test-utils@0.3.0 + - @backstage/plugin-scaffolder-node@0.9.0 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/types@1.2.1 + +## 0.4.11-next.2 + +### Patch Changes + +- b392a34: Migrate to new actions format +- Updated dependencies + - @backstage/plugin-scaffolder-node-test-utils@0.3.0-next.2 + - @backstage/plugin-scaffolder-node@0.9.0-next.2 + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/types@1.2.1 + ## 0.4.11-next.1 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-yeoman/package.json b/plugins/scaffolder-backend-module-yeoman/package.json index a121d7ef0c..c8199d0c3a 100644 --- a/plugins/scaffolder-backend-module-yeoman/package.json +++ b/plugins/scaffolder-backend-module-yeoman/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-yeoman", - "version": "0.4.11-next.1", + "version": "0.4.11", "backstage": { "role": "backend-plugin-module", "pluginId": "scaffolder", diff --git a/plugins/scaffolder-backend/CHANGELOG.md b/plugins/scaffolder-backend/CHANGELOG.md index 629f1a23bd..2169f7d96c 100644 --- a/plugins/scaffolder-backend/CHANGELOG.md +++ b/plugins/scaffolder-backend/CHANGELOG.md @@ -1,5 +1,226 @@ # @backstage/plugin-scaffolder-backend +## 2.0.0 + +### Major Changes + +- 33394db: **BREAKING CHANGES** + + Removal of deprecated re-exports from module packages. + + The following functions have been re-exported from the `scaffolder-backend` plugin for quite some time, and now it's time to clean them up. They've been moved as follows: + + - `createPublishAzureAction` should be imported from `@backstage/plugin-scaffolder-backend-module-azure` instead. + + - `createPublishBitbucketCloudAction` should be imported from `@backstage/plugin-scaffolder-backend-module-bitbucket-cloud` instead. + + - `createPublishBitbucketServerAction` and `createPublishBitbucketServerPullRequestAction` can be imported from `@backstage/plugin-scaffolder-backend-module-bitbucket-server` instead. + + - `createPublishBitbucketAction` should be imported from `@backstage/plugin-scaffolder-backend-module-bitbucket` instead. + + - `createPublishGerritAction` and `createPublishGerritReviewAction` can be imported from `@backstage/plugin-scaffolder-backend-module-gerrit` instead. + + - `createGithubActionsDispatchAction`, `createGithubDeployKeyAction`, `createGithubEnvironmentAction`, `createGithubIssuesLabelAction`, `CreateGithubPullRequestActionOptions`, `createGithubRepoCreateAction`, `createGithubRepoPushAction`, `createGithubWebhookAction`, and `createPublishGithubAction` can be imported from `@backstage/plugin-scaffolder-backend-module-github` instead. + + - `createPublishGitlabAction` should be imported from `@backstage/plugin-scaffolder-backend-module-gitlab` instead. + + - `ActionContext`. `createTemplateAction`, `executeShellCommand`, `ExecuteShellCommandOptions`, `fetchContents`, `TaskSecrets`, and `TemplateAction` should be imported from `@backstage/plugin-scaffolder-node` instead. + + - `ScaffolderEntitiesProcessor` should be imported from `@backstage/plugin-catalog-backend-module-scaffolder-entity-model` instead. + +- a8fcf04: **BREAKING ALPHA**: The `/alpha` export no longer exports the plugin. Please use `import('@backstage/plugin-scaffolder-backend')` instead as this has been removed. + + **BREAKING CHANGES**: The old `createRouter` function which was used in the old backend system has been removed along with the `RouterOptions` type. + +- 73b94d7: **BREAKING CHANGES** + + The following functions have been re-exported from the `scaffolder-backend` plugin for quite some time, and now it's time to clean them up. They've been moved as follows: + + - `SerializedTask`, `SerializedTaskEvent`, `TaskBroker`, `TaskBrokerDispatchOptions`, `TaskBrokerDispatchResult`, `TaskCompletionState`, `TaskContext`, `TaskEventType`, `TaskStatus`, `TemplateFilter`, and `TemplateGlobal` should be imported from `@backstage/plugin-scaffolder-node` instead. + + - The deprecated `copyWithoutRender` option has been removed from `fetch:template` action. You should rename the option to `copyWithoutTemplating` instead. + +- 5863b04: **BREAKING CHANGES** + + - The `createBuiltinActions` method has been removed, as this should no longer be needed with the new backend system route, and was only useful when passing the default list of actions again in the old backend system. You should be able to rely on the default behaviour of the new backend system which is to merge the actions. + + - The `createCatalogRegisterAction` and `createFetchCatalogEntityAction` actions no longer require an `AuthService`, and now accepts a `CatalogService` instead of `CatalogClient`. + + Unless you're providing your own override action to the default, this should be a non-breaking change. + + You can migrate using the following if you're getting typescript errors: + + ```ts + import { catalogServiceRef } from '@backstage/plugin-catalog-node'; + import { scaffolderActionsExtensionPoint } from '@backstage/plugin-scaffolder-node/alpha'; + + export const myModule = createBackendModule({ + pluginId: 'scaffolder', + moduleId: 'test', + register({ registerInit }) { + registerInit({ + deps: { + scaffolder: scaffolderActionsExtensionPoint, + catalog: catalogServiceRef, + }, + async init({ scaffolder, catalog }) { + scaffolder.addActions( + createCatalogRegisterAction({ + catalog, + }), + createFetchCatalogEntityAction({ + catalog, + integrations, + }), + ); + }, + }); + }, + }); + ``` + +### Minor Changes + +- 73b94d7: **DEPRECATIONS** + + The following types and implementations have been deprecated, either because they're no longer relevant, or because upcoming changes to the `scaffolder-backend` after `2.0.0` will influence the changes to these API surfaces. + + - `CreateWorkerOptions` + - `DatabaseTaskStore` + - `DatabaseTaskStoreOptions` + - `TaskManager` + - `TaskStoreCreateTaskOptions` + - `TaskStoreCreateTaskResult` + - `TaskStoreEmitOptions` + - `TaskStoreListEventsOptions` + - `TaskStoreRecoverTaskOptions` + - `TaskStoreShutDownTaskOptions` + + There is no current path off deprecation, these types are going to be removed and rethought with a better way to define workers in the new backend system. + +### Patch Changes + +- 89a941d: Migrating to latest action format +- 023629e: Enable usage of secrets within 'each' step of software templates. For example, you can now structure your `each` step like this: + + ``` + each: + [ + { name: "Service1", token: "${{ secrets.token1 }}" }, + { name: "Service2", token: "${{ secrets.token2 }}" }, + ] + ``` + +- e92e481: Add tests for Scaffolder +- Updated dependencies + - @backstage/plugin-scaffolder-backend-module-gitlab@0.9.2 + - @backstage/plugin-scaffolder-backend-module-azure@0.2.10 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.2.10 + - @backstage/plugin-scaffolder-backend-module-github@0.8.0 + - @backstage/backend-defaults@0.11.0 + - @backstage/plugin-scaffolder-node@0.9.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.2.10 + - @backstage/plugin-scaffolder-backend-module-gerrit@0.2.10 + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/plugin-auth-node@0.6.4 + - @backstage/plugin-scaffolder-backend-module-gitea@0.2.10 + - @backstage/plugin-scaffolder-backend-module-bitbucket@0.3.11 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + - @backstage/types@1.2.1 + - @backstage/plugin-bitbucket-cloud-common@0.3.0 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.2.9 + - @backstage/plugin-events-node@0.4.12 + - @backstage/plugin-permission-common@0.9.0 + - @backstage/plugin-permission-node@0.10.1 + - @backstage/plugin-scaffolder-common@1.5.11 + +## 2.0.0-next.2 + +### Major Changes + +- 5863b04: **BREAKING CHANGES** + + - The `createBuiltinActions` method has been removed, as this should no longer be needed with the new backend system route, and was only useful when passing the default list of actions again in the old backend system. You should be able to rely on the default behaviour of the new backend system which is to merge the actions. + + - The `createCatalogRegisterAction` and `createFetchCatalogEntityAction` actions no longer require an `AuthService`, and now accepts a `CatalogService` instead of `CatalogClient`. + + Unless you're providing your own override action to the default, this should be a non-breaking change. + + You can migrate using the following if you're getting typescript errors: + + ```ts + import { catalogServiceRef } from '@backstage/plugin-catalog-node'; + import { scaffolderActionsExtensionPoint } from '@backstage/plugin-scaffolder-node/alpha'; + + export const myModule = createBackendModule({ + pluginId: 'scaffolder', + moduleId: 'test', + register({ registerInit }) { + registerInit({ + deps: { + scaffolder: scaffolderActionsExtensionPoint, + catalog: catalogServiceRef, + }, + async init({ scaffolder, catalog }) { + scaffolder.addActions( + createCatalogRegisterAction({ + catalog, + }), + createFetchCatalogEntityAction({ + catalog, + integrations, + }), + ); + }, + }); + }, + }); + ``` + +### Patch Changes + +- 89a941d: Migrating to latest action format +- 023629e: Enable usage of secrets within 'each' step of software templates. For example, you can now structure your `each` step like this: + + ``` + each: + [ + { name: "Service1", token: "${{ secrets.token1 }}" }, + { name: "Service2", token: "${{ secrets.token2 }}" }, + ] + ``` + +- e92e481: Add tests for Scaffolder +- Updated dependencies + - @backstage/plugin-scaffolder-backend-module-gitlab@0.9.2-next.2 + - @backstage/plugin-scaffolder-backend-module-github@0.8.0-next.2 + - @backstage/backend-defaults@0.11.0-next.2 + - @backstage/plugin-scaffolder-node@0.9.0-next.2 + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + - @backstage/types@1.2.1 + - @backstage/plugin-auth-node@0.6.4-next.1 + - @backstage/plugin-bitbucket-cloud-common@0.3.0 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.2.9-next.1 + - @backstage/plugin-catalog-node@1.17.1-next.1 + - @backstage/plugin-events-node@0.4.12-next.1 + - @backstage/plugin-permission-common@0.9.0 + - @backstage/plugin-permission-node@0.10.1-next.1 + - @backstage/plugin-scaffolder-backend-module-azure@0.2.10-next.2 + - @backstage/plugin-scaffolder-backend-module-bitbucket@0.3.11-next.2 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.2.10-next.2 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.2.10-next.2 + - @backstage/plugin-scaffolder-backend-module-gerrit@0.2.10-next.2 + - @backstage/plugin-scaffolder-backend-module-gitea@0.2.10-next.2 + - @backstage/plugin-scaffolder-common@1.5.11 + ## 2.0.0-next.1 ### Major Changes diff --git a/plugins/scaffolder-backend/package.json b/plugins/scaffolder-backend/package.json index d3db857d91..d3fb0fa81b 100644 --- a/plugins/scaffolder-backend/package.json +++ b/plugins/scaffolder-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend", - "version": "2.0.0-next.1", + "version": "2.0.0", "description": "The Backstage backend plugin that helps you create new things", "backstage": { "role": "backend-plugin", diff --git a/plugins/scaffolder-backend/src/ScaffolderPlugin.test.ts b/plugins/scaffolder-backend/src/ScaffolderPlugin.test.ts new file mode 100644 index 0000000000..b9cb397ae6 --- /dev/null +++ b/plugins/scaffolder-backend/src/ScaffolderPlugin.test.ts @@ -0,0 +1,1266 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { IncomingMessage } from 'http'; +import request from 'supertest'; +import waitForExpect from 'wait-for-expect'; + +import { createBackendModule } from '@backstage/backend-plugin-api'; +import { + mockCredentials, + mockServices, + startTestBackend, +} from '@backstage/backend-test-utils'; +import { stringifyEntityRef } from '@backstage/catalog-model'; +import { catalogServiceMock } from '@backstage/plugin-catalog-node/testUtils'; +import { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common'; +import { scaffolderAutocompleteExtensionPoint } from '@backstage/plugin-scaffolder-node/alpha'; + +import { scaffolderPlugin } from './ScaffolderPlugin'; + +describe('scaffolderPlugin', () => { + const mockTemplateEntity = { + apiVersion: 'scaffolder.backstage.io/v1beta3', + kind: 'Template', + metadata: { + description: 'Create a new CRA website project', + name: 'create-react-app-template', + tags: ['experimental', 'react', 'cra'], + title: 'Create React App Template', + annotations: { + 'backstage.io/managed-by-location': 'url:https://dev.azure.com', + }, + }, + spec: { + owner: 'web@example.com', + type: 'website', + steps: [ + { + id: 'step-one', + name: 'First log', + action: 'debug:log', + input: { + message: 'hello', + }, + }, + { + id: 'step-two', + name: 'Second log', + action: 'debug:log', + input: { + message: 'world', + }, + 'backstage:permissions': { + tags: ['steps-tag'], + }, + }, + ], + parameters: [ + { + type: 'object', + required: ['requiredParameter1'], + properties: { + requiredParameter1: { + type: 'string', + description: 'Required parameter 1', + }, + }, + }, + { + type: 'object', + required: ['requiredParameter2'], + 'backstage:permissions': { + tags: ['parameters-tag'], + }, + properties: { + requiredParameter2: { + type: 'string', + description: 'Required parameter 2', + }, + }, + }, + ], + }, + } satisfies TemplateEntityV1beta3; + + it('supports fetching template parameters schema', async () => { + const { server } = await startTestBackend({ + features: [ + scaffolderPlugin, + catalogServiceMock.factory({ + entities: [mockTemplateEntity], + }), + ], + }); + + const { body, status } = await request(server).get( + '/api/scaffolder/v2/templates/default/template/create-react-app-template/parameter-schema', + ); + + expect(status).toBe(200); + + expect(body).toMatchObject({ + description: 'Create a new CRA website project', + steps: [ + { + schema: { + properties: { + requiredParameter1: { + description: 'Required parameter 1', + type: 'string', + }, + }, + required: ['requiredParameter1'], + type: 'object', + }, + title: 'Please enter the following information', + }, + { + schema: { + 'backstage:permissions': { tags: ['parameters-tag'] }, + properties: { + requiredParameter2: { + description: 'Required parameter 2', + type: 'string', + }, + }, + required: ['requiredParameter2'], + type: 'object', + }, + title: 'Please enter the following information', + }, + ], + title: 'Create React App Template', + }); + }); + + it('supports listing actions', async () => { + const { server } = await startTestBackend({ + features: [scaffolderPlugin], + }); + + const { body, status } = await request(server).get( + '/api/scaffolder/v2/actions', + ); + + expect(status).toBe(200); + expect(body).toBeInstanceOf(Array); + + const actionSchema = { + id: expect.any(String), + description: expect.any(String), + examples: expect.any(Array), + schema: expect.any(Object), + }; + + // General cursory check + body.forEach((action: any) => expect(action).toMatchObject(actionSchema)); + + expect(body).toContainEqual({ + id: 'fetch:plain', + description: + 'Downloads content and places it in the workspace, or optionally in a subdirectory specified by the `targetPath` input option.', + examples: [ + { + description: 'Downloads content and places it in the workspace.', + example: + 'steps:\n - action: fetch:plain\n id: fetch-plain\n name: Fetch plain\n input:\n url: https://github.com/backstage/community/tree/main/backstage-community-sessions/assets\n', + }, + { + description: + 'Optionally, if you would prefer the data to be downloaded to a subdirectory in the workspace you may specify the ‘targetPath’ input option.', + example: + 'steps:\n - action: fetch:plain\n id: fetch-plain\n name: Fetch plain\n input:\n url: https://github.com/backstage/community/tree/main/backstage-community-sessions/assets\n targetPath: fetched-data\n', + }, + ], + schema: { + input: { + type: 'object', + properties: { + url: { + type: 'string', + description: + 'Relative path or absolute URL pointing to the directory tree to fetch', + }, + targetPath: { + type: 'string', + description: + 'Target path within the working directory to download the contents to.', + }, + token: { + type: 'string', + description: + 'An optional token to use for authentication when reading the resources.', + }, + }, + required: ['url'], + additionalProperties: false, + $schema: 'http://json-schema.org/draft-07/schema#', + }, + }, + }); + }); + + it('supports listing tasks', async () => { + const { server } = await startTestBackend({ + features: [scaffolderPlugin], + }); + + const { body, status } = await request(server).get( + '/api/scaffolder/v2/tasks', + ); + + expect(status).toBe(200); + expect(body).toMatchObject({ tasks: [], totalTasks: 0 }); + }); + + it('rejects creating tasks if template schema definition mismatches', async () => { + const { server } = await startTestBackend({ + features: [ + scaffolderPlugin, + catalogServiceMock.factory({ + entities: [mockTemplateEntity], + }), + ], + }); + + // Confirm no tasks are present + let response = await request(server).get('/api/scaffolder/v2/tasks'); + + expect(response.status).toBe(200); + expect(response.body).toMatchObject({ tasks: [], totalTasks: 0 }); + + // Create a task + response = await request(server) + .post('/api/scaffolder/v2/tasks') + .send({ + templateRef: stringifyEntityRef({ + kind: 'template', + name: 'create-react-app-template', + }), + values: { + storePath: 'https://github.com/backstage/backstage', + }, + }); + + expect(response.status).toBe(400); + }); + + it('supports creating tasks', async () => { + const { server } = await startTestBackend({ + features: [ + scaffolderPlugin, + catalogServiceMock.factory({ + entities: [mockTemplateEntity], + }), + ], + }); + + // Confirm no tasks are present + let response = await request(server).get('/api/scaffolder/v2/tasks'); + + expect(response.status).toBe(200); + expect(response.body).toMatchObject({ tasks: [], totalTasks: 0 }); + + // Create a task + response = await request(server) + .post('/api/scaffolder/v2/tasks') + .send({ + templateRef: stringifyEntityRef({ + kind: 'template', + name: 'create-react-app-template', + }), + values: { + requiredParameter1: 'required-value-1', + requiredParameter2: 'required-value-2', + }, + }); + + expect(response.status).toBe(201); + expect(response.body).toMatchObject({ id: expect.any(String) }); + + const { id: taskId } = response.body; + + // Wait for task to complete + await waitForExpect(async () => { + response = await request(server).get( + `/api/scaffolder/v2/tasks/${taskId}`, + ); + + expect(response.body).toMatchObject({ + status: 'completed', + }); + }); + + response = await request(server).get('/api/scaffolder/v2/tasks'); + + expect(response.status).toBe(200); + expect(response.body).toMatchObject({ + tasks: expect.any(Array), + totalTasks: 1, + }); + + const { tasks } = response.body; + expect(tasks.length).toBe(1); + expect(tasks).toContainEqual({ + createdAt: expect.any(String), + createdBy: 'user:default/mock', + id: taskId, + lastHeartbeatAt: expect.any(String), + spec: { + apiVersion: 'scaffolder.backstage.io/v1beta3', + output: {}, + parameters: { + requiredParameter1: 'required-value-1', + requiredParameter2: 'required-value-2', + }, + steps: [ + { + action: 'debug:log', + id: 'step-one', + input: { message: 'hello' }, + name: 'First log', + }, + { + action: 'debug:log', + 'backstage:permissions': { tags: ['steps-tag'] }, + id: 'step-two', + input: { message: 'world' }, + name: 'Second log', + }, + ], + templateInfo: { + baseUrl: 'https://dev.azure.com', + entity: { + metadata: { + annotations: { + 'backstage.io/managed-by-location': 'url:https://dev.azure.com', + }, + description: 'Create a new CRA website project', + name: 'create-react-app-template', + tags: ['experimental', 'react', 'cra'], + title: 'Create React App Template', + }, + }, + entityRef: 'template:default/create-react-app-template', + }, + user: { ref: 'user:default/mock' }, + }, + status: 'completed', + }); + }); + + it('emits auditlog containing user identifier when backstage auth is passed', async () => { + const mockLogger = mockServices.logger.mock(); + mockLogger.child.mockReturnValue(mockLogger); + const loggerSpy = jest.spyOn(mockLogger, 'info'); + + const { server } = await startTestBackend({ + features: [ + scaffolderPlugin, + catalogServiceMock.factory({ + entities: [mockTemplateEntity], + }), + mockLogger.factory, + ], + }); + + // Confirm no tasks are present + let response = await request(server).get('/api/scaffolder/v2/tasks'); + + expect(response.status).toBe(200); + expect(response.body).toMatchObject({ tasks: [], totalTasks: 0 }); + + // Create a task + response = await request(server) + .post('/api/scaffolder/v2/tasks') + .send({ + templateRef: stringifyEntityRef({ + kind: 'template', + name: 'create-react-app-template', + }), + values: { + requiredParameter1: 'required-value-1', + requiredParameter2: 'required-value-2', + }, + }); + + expect(response.status).toBe(201); + expect(response.body).toMatchObject({ id: expect.any(String) }); + + const { id: taskId } = response.body; + + // Wait for task to complete + await waitForExpect(async () => { + response = await request(server).get( + `/api/scaffolder/v2/tasks/${taskId}`, + ); + + expect(response.body).toMatchObject({ + status: 'completed', + }); + }); + + expect(loggerSpy).toHaveBeenCalledTimes(10); + expect(loggerSpy).toHaveBeenNthCalledWith( + 3, + 'Scaffolding task for template:default/create-react-app-template created by user:default/mock', + ); + }); + + it('supports fetching a task by ID', async () => { + const { server } = await startTestBackend({ + features: [ + scaffolderPlugin, + catalogServiceMock.factory({ + entities: [mockTemplateEntity], + }), + ], + }); + + // Confirm no tasks are present + let response = await request(server).get('/api/scaffolder/v2/tasks'); + + expect(response.status).toBe(200); + expect(response.body).toMatchObject({ tasks: [], totalTasks: 0 }); + + // Create a task to lookup + response = await request(server) + .post('/api/scaffolder/v2/tasks') + .send({ + templateRef: stringifyEntityRef({ + kind: 'template', + name: 'create-react-app-template', + }), + values: { + requiredParameter1: 'required-value-1', + requiredParameter2: 'required-value-2', + }, + }); + + expect(response.status).toBe(201); + expect(response.body).toMatchObject({ id: expect.any(String) }); + + const { id: taskId } = response.body; + + // Wait for task to complete + await waitForExpect(async () => { + response = await request(server).get( + `/api/scaffolder/v2/tasks/${taskId}`, + ); + + expect(response.body).toMatchObject({ + status: 'completed', + }); + }); + + // Get the task by ID + response = await request(server).get(`/api/scaffolder/v2/tasks/${taskId}`); + expect(response.status).toBe(200); + expect(response.body).toMatchObject({ + createdAt: expect.any(String), + createdBy: 'user:default/mock', + id: taskId, + lastHeartbeatAt: expect.any(String), + spec: { + apiVersion: 'scaffolder.backstage.io/v1beta3', + output: {}, + parameters: { + requiredParameter1: 'required-value-1', + requiredParameter2: 'required-value-2', + }, + steps: [ + { + action: 'debug:log', + id: 'step-one', + input: { message: 'hello' }, + name: 'First log', + }, + { + action: 'debug:log', + 'backstage:permissions': { tags: ['steps-tag'] }, + id: 'step-two', + input: { message: 'world' }, + name: 'Second log', + }, + ], + templateInfo: { + baseUrl: 'https://dev.azure.com', + entity: { + metadata: { + annotations: { + 'backstage.io/managed-by-location': 'url:https://dev.azure.com', + }, + description: 'Create a new CRA website project', + name: 'create-react-app-template', + tags: ['experimental', 'react', 'cra'], + title: 'Create React App Template', + }, + }, + entityRef: 'template:default/create-react-app-template', + }, + user: { + ref: 'user:default/mock', + }, + }, + status: 'completed', + }); + expect(response.body.secrets).toBeUndefined(); + }); + + it('supports listing tasks using a filter', async () => { + const { server } = await startTestBackend({ + features: [ + scaffolderPlugin, + catalogServiceMock.factory({ + entities: [mockTemplateEntity], + }), + ], + }); + + // Confirm no tasks are present + let response = await request(server).get('/api/scaffolder/v2/tasks'); + + expect(response.status).toBe(200); + expect(response.body).toMatchObject({ tasks: [], totalTasks: 0 }); + + // Create a task to lookup + response = await request(server) + .post('/api/scaffolder/v2/tasks') + .send({ + templateRef: stringifyEntityRef({ + kind: 'template', + name: 'create-react-app-template', + }), + values: { + requiredParameter1: 'required-value-1', + requiredParameter2: 'required-value-2', + }, + }); + + expect(response.status).toBe(201); + expect(response.body).toMatchObject({ id: expect.any(String) }); + + const { id: taskId } = response.body; + + // Wait for task to complete + await waitForExpect(async () => { + response = await request(server).get( + `/api/scaffolder/v2/tasks/${taskId}`, + ); + + expect(response.body).toMatchObject({ + status: 'completed', + }); + }); + + // Confirm non-matching `createdBy` filter does not return any results + let { body, status } = await request(server).get( + '/api/scaffolder/v2/tasks?createdBy=user:default/foo&status=completed&limit=1&offset=0&order=desc:created_at', + ); + + expect(status).toBe(200); + expect(body).toMatchObject({ tasks: [], totalTasks: 0 }); + + // Confirm matching `createdBy` filter returns the expected result + ({ body, status } = await request(server).get( + '/api/scaffolder/v2/tasks?createdBy=user:default/mock&status=completed&limit=1&offset=0&order=desc:created_at', + )); + + expect(status).toBe(200); + expect(body).toMatchObject({ + tasks: [ + { + createdAt: expect.any(String), + createdBy: 'user:default/mock', + id: taskId, + lastHeartbeatAt: expect.any(String), + spec: { + apiVersion: 'scaffolder.backstage.io/v1beta3', + output: {}, + parameters: { + requiredParameter1: 'required-value-1', + requiredParameter2: 'required-value-2', + }, + steps: [ + { + action: 'debug:log', + id: 'step-one', + input: { message: 'hello' }, + name: 'First log', + }, + { + action: 'debug:log', + 'backstage:permissions': { tags: ['steps-tag'] }, + id: 'step-two', + input: { message: 'world' }, + name: 'Second log', + }, + ], + templateInfo: { + baseUrl: 'https://dev.azure.com', + entity: { + metadata: { + annotations: { + 'backstage.io/managed-by-location': + 'url:https://dev.azure.com', + }, + description: 'Create a new CRA website project', + name: 'create-react-app-template', + tags: ['experimental', 'react', 'cra'], + title: 'Create React App Template', + }, + }, + entityRef: 'template:default/create-react-app-template', + }, + user: { ref: 'user:default/mock' }, + }, + status: 'completed', + }, + ], + totalTasks: 1, + }); + }); + + it('supports canceling a task by ID', async () => { + const { server } = await startTestBackend({ + features: [ + scaffolderPlugin, + catalogServiceMock.factory({ + entities: [mockTemplateEntity], + }), + ], + }); + + // Confirm no tasks are present + let response = await request(server).get('/api/scaffolder/v2/tasks'); + + expect(response.status).toBe(200); + expect(response.body).toMatchObject({ tasks: [], totalTasks: 0 }); + + // Create a task to cancel + response = await request(server) + .post('/api/scaffolder/v2/tasks') + .send({ + templateRef: stringifyEntityRef({ + kind: 'template', + name: 'create-react-app-template', + }), + values: { + requiredParameter1: 'required-value-1', + requiredParameter2: 'required-value-2', + }, + }); + + expect(response.status).toBe(201); + expect(response.body).toMatchObject({ id: expect.any(String) }); + + const { id: taskId } = response.body; + + // Wait for task to complete + await waitForExpect(async () => { + response = await request(server).get( + `/api/scaffolder/v2/tasks/${taskId}`, + ); + + expect(response.body).toMatchObject({ + status: 'completed', + }); + }); + + // Cancel the task by ID + response = await request(server).post( + `/api/scaffolder/v2/tasks/${taskId}/cancel`, + ); + expect(response.status).toBe(200); + expect(response.body).toMatchObject({ + status: 'cancelled', + }); + }); + + it('supports retrying a task by ID', async () => { + const { server } = await startTestBackend({ + features: [ + scaffolderPlugin, + catalogServiceMock.factory({ + entities: [mockTemplateEntity], + }), + ], + }); + + // Confirm no tasks are present + let response = await request(server).get('/api/scaffolder/v2/tasks'); + + expect(response.status).toBe(200); + expect(response.body).toMatchObject({ tasks: [], totalTasks: 0 }); + + // Create a task to retry + response = await request(server) + .post('/api/scaffolder/v2/tasks') + .send({ + templateRef: stringifyEntityRef({ + kind: 'template', + name: 'create-react-app-template', + }), + values: { + requiredParameter1: 'required-value-1', + requiredParameter2: 'required-value-2', + }, + }); + + expect(response.status).toBe(201); + expect(response.body).toMatchObject({ id: expect.any(String) }); + + const { id: taskId } = response.body; + + // Wait for task to complete + await waitForExpect(async () => { + response = await request(server).get( + `/api/scaffolder/v2/tasks/${taskId}`, + ); + + expect(response.body).toMatchObject({ + status: 'completed', + }); + }); + + // Retry the task by ID + response = await request(server).post( + `/api/scaffolder/v2/tasks/${taskId}/retry`, + ); + expect(response.status).toBe(201); + expect(response.body).toMatchObject({ id: taskId }); + + // Wait for task to complete + await waitForExpect(async () => { + response = await request(server).get( + `/api/scaffolder/v2/tasks/${taskId}`, + ); + + expect(response.body).toMatchObject({ + status: 'completed', + }); + }); + }); + + it('supports fetching event stream for a task', async () => { + const { server } = await startTestBackend({ + features: [ + scaffolderPlugin, + catalogServiceMock.factory({ + entities: [mockTemplateEntity], + }), + ], + }); + + // Confirm no tasks are present + let response = await request(server).get('/api/scaffolder/v2/tasks'); + + expect(response.status).toBe(200); + expect(response.body).toMatchObject({ tasks: [], totalTasks: 0 }); + + // Create a task to fetch event stream for + response = await request(server) + .post('/api/scaffolder/v2/tasks') + .send({ + templateRef: stringifyEntityRef({ + kind: 'template', + name: 'create-react-app-template', + }), + values: { + requiredParameter1: 'required-value-1', + requiredParameter2: 'required-value-2', + }, + }); + + expect(response.status).toBe(201); + expect(response.body).toMatchObject({ id: expect.any(String) }); + + const { id: taskId } = response.body; + + let statusCode: IncomingMessage['statusCode'] = undefined; + let headers: IncomingMessage['headers'] = {}; + const responseDataFn = jest.fn(); + + // Get event stream for the task + const req = request(server) + .get(`/api/scaffolder/v2/tasks/${taskId}/eventstream`) + .set('accept', 'text/event-stream') + .parse((res, _) => { + ({ statusCode, headers } = res as unknown as IncomingMessage); + + res.on('data', chunk => { + responseDataFn(chunk.toString()); + + // the server expects the client to abort the request + if (chunk.includes('completion')) { + req.abort(); + } + }); + }); + + // wait for the request to finish + await req.catch(() => { + // ignore 'aborted' error + }); + + expect(statusCode).toBe(200); + expect(headers['content-type']).toBe('text/event-stream'); + expect(responseDataFn).toHaveBeenCalledTimes(10); + expect(responseDataFn).toHaveBeenLastCalledWith( + expect.stringContaining(taskId), + ); + expect(responseDataFn).toHaveBeenLastCalledWith( + expect.stringContaining('event: completion'), + ); + }); + + it('supports fetching event stream for a task with after query', async () => { + const { server } = await startTestBackend({ + features: [ + scaffolderPlugin, + catalogServiceMock.factory({ + entities: [mockTemplateEntity], + }), + ], + }); + + // Confirm no tasks are present + let response = await request(server).get('/api/scaffolder/v2/tasks'); + + expect(response.status).toBe(200); + expect(response.body).toMatchObject({ tasks: [], totalTasks: 0 }); + + // Create a task to fetch event stream for + response = await request(server) + .post('/api/scaffolder/v2/tasks') + .send({ + templateRef: stringifyEntityRef({ + kind: 'template', + name: 'create-react-app-template', + }), + values: { + requiredParameter1: 'required-value-1', + requiredParameter2: 'required-value-2', + }, + }); + + expect(response.status).toBe(201); + expect(response.body).toMatchObject({ id: expect.any(String) }); + + const { id: taskId } = response.body; + + let statusCode: IncomingMessage['statusCode'] = undefined; + let headers: IncomingMessage['headers'] = {}; + const responseDataFn = jest.fn(); + + // Get event stream for the task + const req = request(server) + .get(`/api/scaffolder/v2/tasks/${taskId}/eventstream`) + .query({ after: 8 }) // out of 10 events + .set('accept', 'text/event-stream') + .parse((res, _) => { + ({ statusCode, headers } = res as unknown as IncomingMessage); + + res.on('data', chunk => { + responseDataFn(chunk.toString()); + + // the server expects the client to abort the request + if (chunk.includes('completion')) { + req.abort(); + } + }); + }); + + // wait for the request to finish + await req.catch(() => { + // ignore 'aborted' error + }); + + expect(statusCode).toBe(200); + expect(headers['content-type']).toBe('text/event-stream'); + expect(responseDataFn).toHaveBeenCalledTimes(2); + expect(responseDataFn).toHaveBeenNthCalledWith( + 1, + expect.stringContaining(taskId), + ); + expect(responseDataFn).toHaveBeenNthCalledWith( + 1, + expect.stringContaining('event: log'), + ); + expect(responseDataFn).toHaveBeenLastCalledWith( + expect.stringContaining(taskId), + ); + expect(responseDataFn).toHaveBeenLastCalledWith( + expect.stringContaining('event: completion'), + ); + }); + + it('supports fetching events for a task', async () => { + const { server } = await startTestBackend({ + features: [ + scaffolderPlugin, + catalogServiceMock.factory({ + entities: [mockTemplateEntity], + }), + ], + }); + + // Confirm no tasks are present + let response = await request(server).get('/api/scaffolder/v2/tasks'); + + expect(response.status).toBe(200); + expect(response.body).toMatchObject({ tasks: [], totalTasks: 0 }); + + // Create a task to fetch events for + response = await request(server) + .post('/api/scaffolder/v2/tasks') + .send({ + templateRef: stringifyEntityRef({ + kind: 'template', + name: 'create-react-app-template', + }), + values: { + requiredParameter1: 'required-value-1', + requiredParameter2: 'required-value-2', + }, + }); + + expect(response.status).toBe(201); + expect(response.body).toMatchObject({ id: expect.any(String) }); + + const { id: taskId } = response.body; + + // Wait for task to complete + await waitForExpect(async () => { + response = await request(server).get( + `/api/scaffolder/v2/tasks/${taskId}`, + ); + + expect(response.body).toMatchObject({ + status: 'completed', + }); + }); + + // Get events for the task + response = await request(server).get( + `/api/scaffolder/v2/tasks/${taskId}/events`, + ); + + expect(response.status).toEqual(200); + expect(response.body).toHaveLength(10); + expect(response.body).toContainEqual({ + body: { message: 'Starting up task with 2 steps' }, + id: 1, + isTaskRecoverable: false, + taskId: taskId, + type: 'log', + createdAt: expect.any(String), + }); + expect(response.body).toContainEqual({ + body: { message: 'Run completed with status: completed', output: {} }, + id: 10, + isTaskRecoverable: false, + taskId: taskId, + type: 'completion', + createdAt: expect.any(String), + }); + }); + + it('supports fetching events for a task with after query', async () => { + const { server } = await startTestBackend({ + features: [ + scaffolderPlugin, + catalogServiceMock.factory({ + entities: [mockTemplateEntity], + }), + ], + }); + + // Confirm no tasks are present + let response = await request(server).get('/api/scaffolder/v2/tasks'); + + expect(response.status).toBe(200); + expect(response.body).toMatchObject({ tasks: [], totalTasks: 0 }); + + // Create a task to fetch events for + response = await request(server) + .post('/api/scaffolder/v2/tasks') + .send({ + templateRef: stringifyEntityRef({ + kind: 'template', + name: 'create-react-app-template', + }), + values: { + requiredParameter1: 'required-value-1', + requiredParameter2: 'required-value-2', + }, + }); + + expect(response.status).toBe(201); + expect(response.body).toMatchObject({ id: expect.any(String) }); + + const { id: taskId } = response.body; + + // Wait for task to complete + await waitForExpect(async () => { + response = await request(server).get( + `/api/scaffolder/v2/tasks/${taskId}`, + ); + + expect(response.body).toMatchObject({ + status: 'completed', + }); + }); + + // Get events for the task + response = await request(server) + .get(`/api/scaffolder/v2/tasks/${taskId}/events`) + .query({ after: 8 }); // out of 10 events + + expect(response.status).toEqual(200); + expect(response.body).toHaveLength(2); + expect(response.body).toContainEqual({ + body: { + message: 'Finished step Second log', + status: 'completed', + stepId: 'step-two', + }, + createdAt: expect.any(String), + id: 9, + isTaskRecoverable: false, + taskId: taskId, + type: 'log', + }); + expect(response.body).toContainEqual({ + body: { message: 'Run completed with status: completed', output: {} }, + createdAt: expect.any(String), + id: 10, + isTaskRecoverable: false, + taskId: taskId, + type: 'completion', + }); + }); + + it('supports performing a dry-run of a template', async () => { + const { server } = await startTestBackend({ + features: [ + scaffolderPlugin, + catalogServiceMock.factory({ + entities: [mockTemplateEntity], + }), + ], + }); + + const { body, status } = await request(server) + .post('/api/scaffolder/v2/dry-run') + .auth(mockCredentials.user.token(), { type: 'bearer' }) + .send({ + template: mockTemplateEntity, + values: { + requiredParameter1: 'required-value-1', + requiredParameter2: 'required-value-2', + }, + directoryContents: [], + }); + + expect(status).toBe(200); + expect(body).toMatchObject({ + log: [ + { body: { message: 'Starting up task with 3 steps' } }, + { + body: { + stepId: 'step-one', + status: 'processing', + message: 'Beginning step First log', + }, + }, + { + body: { + stepId: 'step-one', + message: + '\u001b[32minfo\u001b[39m: Running debug:log in dry-run mode with inputs (secrets redacted): {\n "message": "hello"\n}', + }, + }, + { + body: { + stepId: 'step-one', + message: '\u001b[32minfo\u001b[39m: {\n "message": "hello"\n}', + }, + }, + { + body: { + stepId: 'step-one', + message: '\u001b[32minfo\u001b[39m: hello', + }, + }, + { + body: { + stepId: 'step-one', + status: 'completed', + message: 'Finished step First log', + }, + }, + { + body: { + stepId: 'step-two', + status: 'processing', + message: 'Beginning step Second log', + }, + }, + { + body: { + stepId: 'step-two', + message: + '\u001b[32minfo\u001b[39m: Running debug:log in dry-run mode with inputs (secrets redacted): {\n "message": "world"\n}', + }, + }, + { + body: { + stepId: 'step-two', + message: '\u001b[32minfo\u001b[39m: {\n "message": "world"\n}', + }, + }, + { + body: { + stepId: 'step-two', + message: '\u001b[32minfo\u001b[39m: world', + }, + }, + { + body: { + stepId: 'step-two', + status: 'completed', + message: 'Finished step Second log', + }, + }, + ], + directoryContents: [], + output: {}, + steps: [ + { + id: 'step-one', + name: 'First log', + action: 'debug:log', + input: { message: 'hello' }, + }, + { + id: 'step-two', + name: 'Second log', + action: 'debug:log', + input: { message: 'world' }, + 'backstage:permissions': { tags: ['steps-tag'] }, + }, + ], + }); + }); + + it('supports performing an autocomplete for a given provider and resource', async () => { + const handleAutocompleteRequest = jest.fn().mockResolvedValue({ + results: [{ title: 'blob' }], + }); + + const mockContext = { mock: 'context' }; + const mockToken = 'mocktoken'; + + const { server } = await startTestBackend({ + features: [ + scaffolderPlugin, + createBackendModule({ + pluginId: 'scaffolder', + moduleId: 'custom-extensions', + register(env) { + env.registerInit({ + deps: { + scaffolder: scaffolderAutocompleteExtensionPoint, + }, + async init({ scaffolder }) { + scaffolder.addAutocompleteProvider({ + id: 'test-provider', + handler: handleAutocompleteRequest, + }); + }, + }); + }, + }), + ], + }); + + const { body, status } = await request(server) + .post('/api/scaffolder/v2/autocomplete/test-provider/my-resource') + .send({ + token: mockToken, + context: mockContext, + }); + + expect(status).toBe(200); + expect(body).toMatchObject({ results: [{ title: 'blob' }] }); + + expect(handleAutocompleteRequest).toHaveBeenCalledWith({ + context: mockContext, + resource: 'my-resource', + token: mockToken, + }); + }); + + it('supports listing templating extensions', async () => { + const { server } = await startTestBackend({ + features: [scaffolderPlugin], + }); + + const { body, status } = await request(server).get( + '/api/scaffolder/v2/templating-extensions', + ); + + expect(status).toBe(200); + expect(body).toMatchObject({ + filters: expect.objectContaining({ + parseRepoUrl: expect.objectContaining({ + description: expect.any(String), + examples: expect.any(Array), + schema: expect.objectContaining({ + input: expect.any(Object), + output: expect.any(Object), + }), + }), + parseEntityRef: expect.objectContaining({ + description: expect.any(String), + examples: expect.any(Array), + schema: expect.objectContaining({ + input: expect.any(Object), + output: expect.any(Object), + }), + }), + pick: expect.objectContaining({ + description: expect.any(String), + examples: expect.any(Array), + schema: expect.objectContaining({ + input: expect.any(Object), + output: expect.any(Object), + }), + }), + projectSlug: expect.objectContaining({ + description: expect.any(String), + examples: expect.any(Array), + schema: expect.objectContaining({ + input: expect.any(Object), + output: expect.any(Object), + }), + }), + }), + globals: { functions: {}, values: {} }, + }); + }); +}); diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/filesystem/read.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/filesystem/read.ts index 3ab6526b4b..c41e6f1aac 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/filesystem/read.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/filesystem/read.ts @@ -18,6 +18,7 @@ import { resolveSafeChildPath } from '@backstage/backend-plugin-api'; import fs from 'fs/promises'; import path from 'path'; import { z as zod } from 'zod'; +import { examples } from './rename.examples'; const contentSchema = (z: typeof zod) => z.object({ @@ -39,6 +40,7 @@ export const createFilesystemReadDirAction = () => { id: 'fs:readdir', description: 'Reads files and directories from the workspace', supportsDryRun: true, + examples, schema: { input: { paths: z => z.array(z.string().min(1)), diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.test.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.test.ts index a4876f2edb..79a847c46d 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.test.ts @@ -832,6 +832,42 @@ describe('NunjucksWorkflowRunner', () => { }); }); + it('should run a step repeatedly - flat values with secrets', async () => { + const secrets = { + s1: 'secret-value1', + s2: 'secret-value2', + s3: 'secret-value3', + }; + const task = createMockTaskWithSpec( + { + steps: [ + { + id: 'test', + name: 'name', + each: [ + '${{ secrets.s1 }}', + '${{ secrets.s2 }}', + '${{ secrets.s3 }}', + ], + action: 'jest-mock-action', + input: { secret: '${{each.value}}' }, + }, + ], + }, + secrets, + ); + await runner.execute(task); + + Object.values(secrets).forEach((secret, idx) => { + expectTaskLog( + `info: Running step each: {"key":"${idx}","value":"***"}`, + ); + expect(fakeActionHandler).toHaveBeenCalledWith( + expect.objectContaining({ input: { secret } }), + ); + }); + }); + it('should run a step repeatedly - object list', async () => { const task = createMockTaskWithSpec({ steps: [ @@ -862,6 +898,46 @@ describe('NunjucksWorkflowRunner', () => { ); }); + it('should run a step repeatedly - object list with secrets', async () => { + const secrets = { + s1: 'secret-value1', + s2: 'secret-value2', + }; + const names = ['Service1', 'Service2']; + const task = createMockTaskWithSpec( + { + steps: [ + { + id: 'test', + name: 'name', + each: [ + { name: names[0], token: '${{ secrets.s1 }}' }, + { name: names[1], token: '${{ secrets.s2 }}' }, + ], + action: 'jest-mock-action', + input: { + name: '${{each.value.name}}', + token: '${{each.value.token}}', + }, + }, + ], + }, + secrets, + ); + await runner.execute(task); + + Object.values(secrets).forEach((secret, idx) => { + expectTaskLog( + `info: Running step each: {"key":"${idx}","value":"[object Object]"}`, + ); + expect(fakeActionHandler).toHaveBeenCalledWith( + expect.objectContaining({ + input: { name: names[idx], token: secret }, + }), + ); + }); + }); + it('should run a step repeatedly - object', async () => { const settings = { color: 'blue', diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts index a66ae0e789..7802a7ab8d 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts @@ -299,7 +299,12 @@ export class NunjucksWorkflowRunner implements WorkflowRunner { } const resolvedEach = - step.each && this.render(step.each, context, renderTemplate); + step.each && + this.render( + step.each, + { ...context, secrets: task.secrets ?? {} }, + renderTemplate, + ); if (step.each && !resolvedEach) { throw new InputError( diff --git a/plugins/scaffolder-backend/src/service/router.test.ts b/plugins/scaffolder-backend/src/service/router.test.ts index 04f619fd02..679ac44640 100644 --- a/plugins/scaffolder-backend/src/service/router.test.ts +++ b/plugins/scaffolder-backend/src/service/router.test.ts @@ -16,8 +16,6 @@ import { DatabaseManager } from '@backstage/backend-common'; import { ConfigReader } from '@backstage/config'; -import { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common'; -import express from 'express'; import request from 'supertest'; import ObservableImpl from 'zen-observable'; @@ -26,10 +24,6 @@ import ObservableImpl from 'zen-observable'; * Due to a circular dependency between this plugin and the * plugin-scaffolder-backend-module-cookiecutter plugin, it results in an error: * TypeError: _pluginscaffolderbackend.createTemplateAction is not a function - * - * TODO: These tests need refactoring. Seems like the identityApi tests don't do anything different anymore. - * And there's very little value re-reunning all the tests again with just additional template filters and values. - * Let's break them out into better tests. Didn't want to do it in the same PR i'm working on right now. */ import { parseEntityRef, @@ -41,12 +35,12 @@ import { TaskBroker, TemplateFilter, TemplateGlobal, + SerializedTaskEvent, } from '@backstage/plugin-scaffolder-node'; +import { TaskSpec } from '@backstage/plugin-scaffolder-common'; +import { JsonValue } from '@backstage/types'; import { StorageTaskBroker } from '../scaffolder/tasks/StorageTaskBroker'; -import { - AuthorizeResult, - PermissionEvaluator, -} from '@backstage/plugin-permission-common'; +import { AuthorizeResult } from '@backstage/plugin-permission-common'; import { mockCredentials, mockErrorHandler, @@ -54,14 +48,15 @@ import { } from '@backstage/backend-test-utils'; import { AutocompleteHandler, + CreatedTemplateFilter, + CreatedTemplateGlobal, createTemplateFilter, createTemplateGlobalFunction, createTemplateGlobalValue, } from '@backstage/plugin-scaffolder-node/alpha'; import { catalogServiceMock } from '@backstage/plugin-catalog-node/testUtils'; -import { EventsService } from '@backstage/plugin-events-node'; import { DatabaseService } from '@backstage/backend-plugin-api'; -import { loggerToWinstonLogger } from '../util/loggerToWinstonLogger'; + import { ScmIntegrations } from '@backstage/integration'; import { extractFilterMetadata, @@ -72,21 +67,6 @@ import { createDefaultFilters } from '../lib/templating/filters/createDefaultFil import { createRouter } from './router'; import { DatabaseTaskStore } from '../scaffolder/tasks/DatabaseTaskStore'; -const mockAccess = jest.fn(); - -jest.mock('fs-extra', () => ({ - access: (...args: any[]) => mockAccess(...args), - promises: { - access: (...args: any[]) => mockAccess(...args), - }, - constants: { - F_OK: 0, - W_OK: 1, - }, - mkdir: jest.fn(), - remove: jest.fn(), -})); - function createDatabase(): DatabaseService { return DatabaseManager.fromConfig( new ConfigReader({ @@ -102,1619 +82,1217 @@ function createDatabase(): DatabaseService { const config = new ConfigReader({}); -describe.each([ - { - desc: 'no template filters/globals', +// todo: this needs to return a new object every time as there seems to +// be some mutation in the tests. +const generateMockTemplate = () => ({ + apiVersion: 'scaffolder.backstage.io/v1beta3', + kind: 'Template', + metadata: { + description: 'Create a new CRA website project', + name: 'create-react-app-template', + tags: ['experimental', 'react', 'cra'], + title: 'Create React App Template', + annotations: { + 'backstage.io/managed-by-location': 'url:https://dev.azure.com', + }, }, - { - desc: 'legacy template filters', - additionalTemplateFilters: { - foo: (s: any) => s, - bar: (bar: any) => !!bar, - baz: (what: string, ever: string) => what + ever, - } as Record, - }, - { - desc: 'created template filters', - additionalTemplateFilters: [ - createTemplateFilter({ - id: 'foo', - schema: z => - z - .function() - .args(z.any().describe('a value')) - .returns(z.any().describe('same value')), - filter: s => s, - }), - createTemplateFilter({ - id: 'bar', - filter: bar => !!bar, - }), - createTemplateFilter({ - id: 'baz', - description: 'append the argument to the incoming value', - schema: z => - z - .function() - .args(z.string(), z.string().describe('value to append to input')) - .returns(z.string().describe('input+suffix')), - filter: (what, ever) => what + ever, - }), - createTemplateFilter({ - id: 'blah', - schema: z => - z - .function() - .args( - z.number(), - z.number().describe('factor by which to multiply input'), - z.number().describe('addend by which to increase input * factor'), - ), - filter: (base, factor, addend) => base * factor + addend, - }), - ], - }, - { - desc: 'legacy template globals', - additionalTemplateGlobals: { - nul: null, - nop: x => x, - } as Record, - }, - { - desc: 'created template globals', - additionalTemplateGlobals: [ - createTemplateGlobalValue({ - id: 'nul', - description: 'null value', - value: null, - }), - createTemplateGlobalFunction({ - id: 'nop', - description: 'nop function', - schema: z => - z - .function() - .args(z.any().describe('input')) - .returns(z.any().describe('output')), - fn: x => x, - }), - ], - }, -])( - 'createRouter, $desc', - ({ additionalTemplateFilters, additionalTemplateGlobals }) => { - let app: express.Express; - let loggerSpy: jest.SpyInstance; - let taskBroker: TaskBroker; - const catalogMock = catalogServiceMock.mock(); - const permissionApi = { - authorize: jest.fn(), - authorizeConditional: jest.fn(), - } as unknown as PermissionEvaluator; - const auth = mockServices.auth(); - const httpAuth = mockServices.httpAuth(); - const events = { - publish: jest.fn(), - } as unknown as EventsService; - - const credentials = mockCredentials.user(); - - const getMockTemplate = (): TemplateEntityV1beta3 => ({ - apiVersion: 'scaffolder.backstage.io/v1beta3', - kind: 'Template', - metadata: { - description: 'Create a new CRA website project', - name: 'create-react-app-template', - tags: ['experimental', 'react', 'cra'], - title: 'Create React App Template', - annotations: { - 'backstage.io/managed-by-location': 'url:https://dev.azure.com', + spec: { + owner: 'web@example.com', + type: 'website', + steps: [ + { + id: 'step-one', + name: 'First log', + action: 'debug:log', + input: { + message: 'hello', }, }, - spec: { - owner: 'web@example.com', - type: 'website', + { + id: 'step-two', + name: 'Second log', + action: 'debug:log', + input: { + message: 'world', + }, + 'backstage:permissions': { + tags: ['steps-tag'], + }, + }, + ], + parameters: [ + { + type: 'object', + required: ['requiredParameter1'], + properties: { + requiredParameter1: { + type: 'string', + description: 'Required parameter 1', + }, + }, + }, + { + type: 'object', + required: ['requiredParameter2'], + 'backstage:permissions': { + tags: ['parameters-tag'], + }, + properties: { + requiredParameter2: { + type: 'string', + description: 'Required parameter 2', + }, + }, + }, + ], + }, +}); + +const mockUser: UserEntity = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'User', + metadata: { + name: 'guest', + annotations: { + 'google.com/email': 'bobby@tables.com', + }, + }, + spec: { + profile: { + displayName: 'Robert Tables of the North', + }, + }, +}; + +const createTestRouter = async ( + overrides: { + additionalTemplateFilters?: + | Record + | CreatedTemplateFilter[]; + additionalTemplateGlobals?: + | Record + | CreatedTemplateGlobal[]; + autocompleteHandlers?: Record; + } = {}, +) => { + const logger = mockServices.logger.mock({ + child: () => logger, + }); + + const databaseTaskStore = await DatabaseTaskStore.create({ + database: createDatabase(), + }); + + const taskBroker = new StorageTaskBroker(databaseTaskStore, logger, config); + + jest.spyOn(taskBroker, 'dispatch'); + jest.spyOn(taskBroker, 'claim'); + jest.spyOn(taskBroker, 'cancel'); + jest.spyOn(taskBroker, 'retry'); + jest.spyOn(taskBroker, 'list'); + jest.spyOn(taskBroker, 'get'); + jest.spyOn(taskBroker, 'vacuumTasks'); + jest.spyOn(taskBroker, 'event$'); + + const catalog = catalogServiceMock.mock(); + const permissions = mockServices.permissions(); + const auth = mockServices.auth(); + const httpAuth = mockServices.httpAuth(); + const events = mockServices.events(); + + catalog.getEntityByRef.mockImplementation(async ref => { + const { kind } = parseEntityRef(ref); + + if (kind.toLocaleLowerCase() === 'template') { + return generateMockTemplate(); + } + + if (kind.toLocaleLowerCase() === 'user') { + return mockUser; + } + + throw new Error(`no mock found for kind: ${kind}`); + }); + + const router = await createRouter({ + logger, + config: new ConfigReader({}), + database: createDatabase(), + catalog, + taskBroker, + permissions, + auth, + httpAuth, + events, + additionalTemplateFilters: overrides.additionalTemplateFilters, + additionalTemplateGlobals: overrides.additionalTemplateGlobals, + autocompleteHandlers: overrides.autocompleteHandlers, + actions: [ + createTemplateAction({ + id: 'test', + description: 'test', + schema: { + input: z => + z.object({ + test: z.string(), + }), + }, + handler: async () => {}, + }), + ], + }); + + router.use(mockErrorHandler()); + return { router, logger, taskBroker, permissions, catalog }; +}; + +describe('scaffolder router', () => { + const credentials = mockCredentials.user(); + + afterEach(() => { + jest.clearAllMocks(); + }); + + describe('GET /v2/actions', () => { + it('lists available actions', async () => { + const { router } = await createTestRouter(); + const response = await request(router).get('/v2/actions').send(); + expect(response.status).toEqual(200); + expect(response.body[0].id).toBeDefined(); + expect(response.body.length).toBe(1); + }); + }); + + describe('GET /v2/templating-extensions', () => { + it('lists template filters and globals', async () => { + const { router } = await createTestRouter(); + const response = await request(router) + .get('/v2/templating-extensions') + .send(); + expect(response.status).toEqual(200); + const integrations = ScmIntegrations.fromConfig(config); + + expect(response.body).toMatchObject({ + filters: { + ...extractFilterMetadata(createDefaultFilters({ integrations })), + }, + globals: { + functions: {}, + values: {}, + }, + }); + }); + + it('should include legacy template filters in templating extensions', async () => { + const { router } = await createTestRouter({ + additionalTemplateFilters: { + foo: (s: JsonValue) => s, + bar: (bar: JsonValue) => !!bar, + baz: (what: JsonValue, ever: JsonValue) => + String(what) + String(ever), + } as Record, + }); + + const response = await request(router) + .get('/v2/templating-extensions') + .send(); + expect(response.status).toEqual(200); + + const integrations = ScmIntegrations.fromConfig(config); + + expect(response.body).toMatchObject({ + filters: { + ...extractFilterMetadata(createDefaultFilters({ integrations })), + ...extractFilterMetadata({ + foo: (s: JsonValue) => s, + bar: (bar: JsonValue) => !!bar, + baz: (what: JsonValue, ever: JsonValue) => + String(what) + String(ever), + }), + }, + globals: { + functions: {}, + values: {}, + }, + }); + }); + + it('should include created template filters in templating extensions', async () => { + const { router } = await createTestRouter({ + additionalTemplateFilters: [ + createTemplateFilter({ + id: 'foo', + schema: z => + z + .function() + .args(z.any().describe('a value')) + .returns(z.any().describe('same value')), + filter: s => s, + }), + createTemplateFilter({ + id: 'bar', + filter: bar => !!bar, + }), + createTemplateFilter({ + id: 'baz', + description: 'append the argument to the incoming value', + schema: z => + z + .function() + .args( + z.string(), + z.string().describe('value to append to input'), + ) + .returns(z.string().describe('input+suffix')), + filter: (what, ever) => what + ever, + }), + createTemplateFilter({ + id: 'blah', + schema: z => + z + .function() + .args( + z.number(), + z.number().describe('factor by which to multiply input'), + z + .number() + .describe('addend by which to increase input * factor'), + ), + filter: (base, factor, addend) => base * factor + addend, + }), + ], + }); + + const response = await request(router) + .get('/v2/templating-extensions') + .send(); + + expect(response.status).toEqual(200); + + const integrations = ScmIntegrations.fromConfig(config); + + expect(response.body.filters).toMatchObject({ + ...extractFilterMetadata(createDefaultFilters({ integrations })), + foo: expect.any(Object), + bar: expect.any(Object), + baz: expect.any(Object), + blah: expect.any(Object), + }); + }); + + it('should include legacy template globals in templating extensions', async () => { + const { router } = await createTestRouter({ + additionalTemplateGlobals: { + nul: null, + nop: (x: JsonValue) => x, + } as Record, + }); + + const response = await request(router) + .get('/v2/templating-extensions') + .send(); + + expect(response.status).toEqual(200); + + expect(response.body.globals).toMatchObject({ + functions: extractGlobalFunctionMetadata({ + nul: null, + nop: (x: JsonValue) => x, + }), + values: extractGlobalValueMetadata({ + nul: null, + nop: (x: JsonValue) => x, + }), + }); + }); + + it('should include created template globals in templating extensions', async () => { + const { router } = await createTestRouter({ + additionalTemplateGlobals: [ + createTemplateGlobalValue({ + id: 'nul', + description: 'null value', + value: null, + }), + createTemplateGlobalFunction({ + id: 'nop', + description: 'nop function', + schema: z => + z + .function() + .args(z.any().describe('input')) + .returns(z.any().describe('output')), + fn: (x: JsonValue) => x, + }), + ], + }); + const response = await request(router) + .get('/v2/templating-extensions') + .send(); + expect(response.status).toEqual(200); + + expect(response.body.globals).toMatchObject({ + functions: expect.objectContaining({ + nop: expect.any(Object), + }), + values: expect.objectContaining({ + nul: expect.any(Object), + }), + }); + }); + }); + + describe('GET /v2/templates/:namespace/:kind/:name/parameter-schema', () => { + it('returns the parameter schema', async () => { + const { router, permissions } = await createTestRouter(); + jest + .spyOn(permissions, 'authorizeConditional') + .mockImplementationOnce(async () => [ + { + result: AuthorizeResult.ALLOW, + }, + { + result: AuthorizeResult.ALLOW, + }, + ]); + const response = await request(router) + .get( + '/v2/templates/default/Template/create-react-app-template/parameter-schema', + ) + .send(); + + expect(response.status).toEqual(200); + + expect(response.body).toEqual({ + title: 'Create React App Template', + description: 'Create a new CRA website project', steps: [ { - id: 'step-one', - name: 'First log', - action: 'debug:log', - input: { - message: 'hello', - }, - }, - { - id: 'step-two', - name: 'Second log', - action: 'debug:log', - input: { - message: 'world', - }, - 'backstage:permissions': { - tags: ['steps-tag'], - }, - }, - ], - parameters: [ - { - type: 'object', - required: ['requiredParameter1'], - properties: { - requiredParameter1: { - type: 'string', - description: 'Required parameter 1', + title: 'Please enter the following information', + schema: { + required: ['requiredParameter1'], + type: 'object', + properties: { + requiredParameter1: { + description: 'Required parameter 1', + type: 'string', + }, }, }, }, { - type: 'object', - required: ['requiredParameter2'], - 'backstage:permissions': { - tags: ['parameters-tag'], - }, - properties: { - requiredParameter2: { - type: 'string', - description: 'Required parameter 2', + title: 'Please enter the following information', + schema: { + type: 'object', + required: ['requiredParameter2'], + 'backstage:permissions': { + tags: ['parameters-tag'], + }, + properties: { + requiredParameter2: { + type: 'string', + description: 'Required parameter 2', + }, }, }, }, ], - }, + }); }); - const mockUser: UserEntity = { - apiVersion: 'backstage.io/v1alpha1', - kind: 'User', - metadata: { - name: 'guest', - annotations: { - 'google.com/email': 'bobby@tables.com', - }, - }, - spec: { - profile: { - displayName: 'Robert Tables of the North', - }, - }, - }; - - describe('not providing an identity api', () => { - beforeEach(async () => { - const logger = loggerToWinstonLogger(mockServices.logger.mock()); - const databaseTaskStore = await DatabaseTaskStore.create({ - database: createDatabase(), - }); - taskBroker = new StorageTaskBroker(databaseTaskStore, logger, config); - - jest.spyOn(taskBroker, 'dispatch'); - jest.spyOn(taskBroker, 'get'); - jest.spyOn(taskBroker, 'list'); - jest.spyOn(taskBroker, 'event$'); - loggerSpy = jest.spyOn(logger, 'info'); - - const router = await createRouter({ - logger: logger, - config: new ConfigReader({}), - database: createDatabase(), - catalog: catalogMock, - taskBroker, - permissions: permissionApi, - auth, - httpAuth, - events, - additionalTemplateFilters, - additionalTemplateGlobals, - actions: [ - createTemplateAction({ - id: 'test', - description: 'test', - schema: { - input: z => - z.object({ - test: z.string(), - }), - }, - handler: async () => {}, - }), - ], - }); - app = express().use(router); - - catalogMock.getEntityByRef.mockImplementation(async ref => { - const { kind } = parseEntityRef(ref); - - if (kind.toLocaleLowerCase() === 'template') { - return getMockTemplate(); - } - - if (kind.toLocaleLowerCase() === 'user') { - return mockUser; - } - - throw new Error(`no mock found for kind: ${kind}`); - }); - - jest - .spyOn(permissionApi, 'authorizeConditional') - .mockImplementation(async () => [ - { - result: AuthorizeResult.ALLOW, - }, - { - result: AuthorizeResult.ALLOW, - }, - ]); - jest.spyOn(permissionApi, 'authorize').mockImplementation(async () => [ + it('filters parameters that the user is not authorized to see', async () => { + const { router, permissions } = await createTestRouter(); + jest + .spyOn(permissions, 'authorizeConditional') + .mockImplementationOnce(async () => [ + { + result: AuthorizeResult.DENY, + }, { result: AuthorizeResult.ALLOW, }, ]); - }); - afterEach(() => { - jest.clearAllMocks(); - }); - - describe('GET /v2/actions', () => { - it('lists available actions', async () => { - const response = await request(app).get('/v2/actions').send(); - expect(response.status).toEqual(200); - expect(response.body[0].id).toBeDefined(); - expect(response.body.length).toBe(1); - }); - }); - - describe('GET /v2/templating-extensions', () => { - it('lists template filters and globals', async () => { - const response = await request(app) - .get('/v2/templating-extensions') - .send(); - expect(response.status).toEqual(200); - const integrations = ScmIntegrations.fromConfig(config); - - expect(response.body).toMatchObject({ - filters: { - ...extractFilterMetadata(createDefaultFilters({ integrations })), - ...extractFilterMetadata(additionalTemplateFilters), - }, - globals: { - functions: extractGlobalFunctionMetadata( - additionalTemplateGlobals, - ), - values: extractGlobalValueMetadata(additionalTemplateGlobals), - }, - }); - }); - }); - - describe('POST /v2/tasks', () => { - it('rejects template values which do not match the template schema definition', async () => { - const response = await request(app) - .post('/v2/tasks') - .send({ - templateRef: stringifyEntityRef({ - kind: 'template', - name: 'create-react-app-template', - }), - values: { - storePath: 'https://github.com/backstage/backstage', - }, - }); - - expect(response.status).toEqual(400); - }); - - it('return the template id', async () => { - const broker = - taskBroker.dispatch as jest.Mocked['dispatch']; - broker.mockResolvedValue({ - taskId: 'a-random-id', - }); - - const response = await request(app) - .post('/v2/tasks') - .send({ - templateRef: stringifyEntityRef({ - kind: 'template', - name: 'create-react-app-template', - }), - values: { - requiredParameter1: 'required-value-1', - requiredParameter2: 'required-value-2', - }, - }); - - expect(response.status).toEqual(201); - expect(response.body.id).toBe('a-random-id'); - }); - - it('should call the broker with a correct spec', async () => { - const broker = - taskBroker.dispatch as jest.Mocked['dispatch']; - const mockToken = mockCredentials.user.token(); - const mockTemplate = getMockTemplate(); - - await request(app) - .post('/v2/tasks') - .set('Authorization', `Bearer ${mockToken}`) - .send({ - templateRef: stringifyEntityRef({ - kind: 'template', - name: 'create-react-app-template', - }), - values: { - requiredParameter1: 'required-value-1', - requiredParameter2: 'required-value-2', - }, - }); - - expect(broker).toHaveBeenCalledWith( - expect.objectContaining({ - createdBy: 'user:default/mock', - secrets: { - __initiatorCredentials: JSON.stringify(credentials), - }, - - spec: { - apiVersion: mockTemplate.apiVersion, - steps: mockTemplate.spec.steps.map((step, index) => ({ - ...step, - id: step.id ?? `step-${index + 1}`, - name: step.name ?? step.action, - })), - output: mockTemplate.spec.output ?? {}, - parameters: { - requiredParameter1: 'required-value-1', - requiredParameter2: 'required-value-2', - }, - user: { - entity: mockUser, - ref: 'user:default/mock', - }, - templateInfo: { - entityRef: stringifyEntityRef({ - kind: 'Template', - namespace: 'Default', - name: mockTemplate.metadata?.name, - }), - baseUrl: 'https://dev.azure.com', - entity: { - metadata: mockTemplate.metadata, - }, - }, - }, - }), - ); - }); - - it('should emit auditlog containing user identifier when backstage auth is passed', async () => { - const mockToken = mockCredentials.user.token(); - - await request(app) - .post('/v2/tasks') - .set('Authorization', `Bearer ${mockToken}`) - .send({ - templateRef: stringifyEntityRef({ - kind: 'template', - name: 'create-react-app-template', - }), - values: { - requiredParameter1: 'required-value-1', - requiredParameter2: 'required-value-2', - }, - }); - - expect(loggerSpy).toHaveBeenCalledTimes(1); - expect(loggerSpy).toHaveBeenCalledWith( - 'Scaffolding task for template:default/create-react-app-template created by user:default/mock', - ); - }); - }); - - describe('GET /v2/tasks', () => { - it('return all tasks', async () => { - ( - taskBroker.list as jest.Mocked>['list'] - ).mockResolvedValue({ - tasks: [ - { - id: 'a-random-id', - spec: {} as any, - status: 'completed', - createdAt: '', - createdBy: '', - }, - ], - totalTasks: 1, - }); - - const response = await request(app).get(`/v2/tasks`); - expect(taskBroker.list).toHaveBeenCalledWith({ - filters: {}, - pagination: {}, - }); - expect(response.status).toEqual(200); - expect(response.body).toStrictEqual({ - tasks: [ - { - id: 'a-random-id', - spec: {} as any, - status: 'completed', - createdAt: '', - createdBy: '', - }, - ], - totalTasks: 1, - }); - }); - - it('return filtered tasks', async () => { - ( - taskBroker.list as jest.Mocked>['list'] - ).mockResolvedValue({ - tasks: [ - { - id: 'a-random-id', - spec: {} as any, - status: 'completed', - createdAt: '', - createdBy: 'user:default/foo', - }, - ], - totalTasks: 1, - }); - - const response = await request(app).get( - `/v2/tasks?createdBy=user:default/foo&createdBy=user:default/bar&status=completed&status=open&limit=1&offset=0&order=desc:created_at`, - ); - - expect(response.status).toEqual(200); - expect(response.body).toStrictEqual({ - tasks: [ - { - id: 'a-random-id', - spec: {} as any, - status: 'completed', - createdAt: '', - createdBy: 'user:default/foo', - }, - ], - totalTasks: 1, - }); - expect(taskBroker.list).toHaveBeenCalledWith({ - filters: { - createdBy: ['user:default/foo', 'user:default/bar'], - status: ['completed', 'open'], - }, - pagination: { - limit: 1, - offset: 0, - }, - order: [{ order: 'desc', field: 'created_at' }], - }); - }); - }); - - describe('GET /v2/tasks/:taskId', () => { - it('does not divulge secrets', async () => { - (taskBroker.get as jest.Mocked['get']).mockResolvedValue({ - id: 'a-random-id', - spec: {} as any, - status: 'completed', - createdAt: '', - secrets: { - __initiatorCredentials: JSON.stringify(credentials), - }, - createdBy: '', - }); - - const response = await request(app).get(`/v2/tasks/a-random-id`); - expect(response.status).toEqual(200); - expect(response.body.status).toBe('completed'); - expect(response.body.secrets).toBeUndefined(); - }); - }); - - describe('GET /v2/tasks/:taskId/eventstream', () => { - it('should return log messages', async () => { - let subscriber: ZenObservable.SubscriptionObserver; - ( - taskBroker.event$ as jest.Mocked['event$'] - ).mockImplementation(({ taskId }) => { - return new ObservableImpl(observer => { - subscriber = observer; - setImmediate(() => { - observer.next({ - events: [ - { - id: 0, - taskId, - type: 'log', - createdAt: '', - body: { message: 'My log message' }, - }, - ], - }); - observer.next({ - events: [ - { - id: 1, - taskId, - type: 'completion', - createdAt: '', - body: { message: 'Finished!' }, - }, - ], - }); - }); - }); - // emit after this function returned - }); - - let statusCode: any = undefined; - let headers: any = {}; - const responseDataFn = jest.fn(); - - const req = request(app) - .get('/v2/tasks/a-random-id/eventstream') - .set('accept', 'text/event-stream') - .parse((res, _) => { - ({ statusCode, headers } = res as any); - - res.on('data', chunk => { - responseDataFn(chunk.toString()); - - // the server expects the client to abort the request - if (chunk.includes('completion')) { - req.abort(); - } - }); - }); - - // wait for the request to finish - await req.catch(() => { - // ignore 'aborted' error - }); - - expect(statusCode).toBe(200); - expect(headers['content-type']).toBe('text/event-stream'); - expect(responseDataFn).toHaveBeenCalledTimes(2); - expect(responseDataFn).toHaveBeenCalledWith(`event: log -data: {"id":0,"taskId":"a-random-id","type":"log","createdAt":"","body":{"message":"My log message"}} - -`); - expect(responseDataFn).toHaveBeenCalledWith(`event: completion -data: {"id":1,"taskId":"a-random-id","type":"completion","createdAt":"","body":{"message":"Finished!"}} - -`); - - expect(taskBroker.event$).toHaveBeenCalledTimes(1); - expect(taskBroker.event$).toHaveBeenCalledWith({ - taskId: 'a-random-id', - }); - expect(subscriber!.closed).toBe(true); - }); - - it('should return log messages with after query', async () => { - let subscriber: ZenObservable.SubscriptionObserver; - ( - taskBroker.event$ as jest.Mocked['event$'] - ).mockImplementation(({ taskId }) => { - return new ObservableImpl(observer => { - subscriber = observer; - setImmediate(() => { - observer.next({ - events: [ - { - id: 1, - taskId, - type: 'completion', - createdAt: '', - body: { message: 'Finished!' }, - }, - ], - }); - }); - }); - }); - - let statusCode: any = undefined; - let headers: any = {}; - - const req = request(app) - .get('/v2/tasks/a-random-id/eventstream') - .query({ after: 10 }) - .set('accept', 'text/event-stream') - .parse((res, _) => { - ({ statusCode, headers } = res as any); - - res.on('data', () => { - // close immediately - req.abort(); - }); - }); - - // wait for the request to finish - await req.catch(() => { - // ignore 'aborted' error - }); - - expect(statusCode).toBe(200); - expect(headers['content-type']).toBe('text/event-stream'); - - expect(taskBroker.event$).toHaveBeenCalledTimes(1); - expect(taskBroker.event$).toHaveBeenCalledWith({ - taskId: 'a-random-id', - after: 10, - }); - - expect(subscriber!.closed).toBe(true); - }); - }); - - describe('GET /v2/tasks/:taskId/events', () => { - it('should return log messages', async () => { - let subscriber: ZenObservable.SubscriptionObserver; - ( - taskBroker.event$ as jest.Mocked['event$'] - ).mockImplementation(({ taskId }) => { - return new ObservableImpl(observer => { - subscriber = observer; - observer.next({ - events: [ - { - id: 0, - taskId, - type: 'log', - createdAt: '', - body: { message: 'My log message' }, - }, - { - id: 1, - taskId, - type: 'completion', - createdAt: '', - body: { message: 'Finished!' }, - }, - ], - }); - }); - }); - - const response = await request(app).get( - '/v2/tasks/a-random-id/events', - ); - - expect(response.status).toEqual(200); - expect(response.body).toEqual([ - { - id: 0, - taskId: 'a-random-id', - type: 'log', - createdAt: '', - body: { message: 'My log message' }, - }, - { - id: 1, - taskId: 'a-random-id', - type: 'completion', - createdAt: '', - body: { message: 'Finished!' }, - }, - ]); - - expect(taskBroker.event$).toHaveBeenCalledTimes(1); - expect(taskBroker.event$).toHaveBeenCalledWith({ - taskId: 'a-random-id', - }); - expect(subscriber!.closed).toBe(true); - }); - - it('should return log messages with after query', async () => { - let subscriber: ZenObservable.SubscriptionObserver; - ( - taskBroker.event$ as jest.Mocked['event$'] - ).mockImplementation(() => { - return new ObservableImpl(observer => { - subscriber = observer; - observer.next({ events: [] }); - }); - }); - - const response = await request(app) - .get('/v2/tasks/a-random-id/events') - .query({ after: 10 }); - - expect(response.status).toEqual(200); - expect(response.body).toEqual([]); - - expect(taskBroker.event$).toHaveBeenCalledTimes(1); - expect(taskBroker.event$).toHaveBeenCalledWith({ - taskId: 'a-random-id', - after: 10, - }); - expect(subscriber!.closed).toBe(true); - }); - }); - - describe('POST /v2/dry-run', () => { - it('should get user entity', async () => { - const mockToken = mockCredentials.user.token(); - const mockTemplate = getMockTemplate(); - - await request(app) - .post('/v2/dry-run') - .set('Authorization', `Bearer ${mockToken}`) - .send({ - template: mockTemplate, - values: { - requiredParameter1: 'required-value-1', - requiredParameter2: 'required-value-2', - }, - directoryContents: [], - }); - - expect(catalogMock.getEntityByRef).toHaveBeenCalledTimes(1); - - expect(catalogMock.getEntityByRef).toHaveBeenCalledWith( - 'user:default/mock', - expect.anything(), - ); - }); + const response = await request(router) + .get( + '/v2/templates/default/Template/create-react-app-template/parameter-schema', + ) + .send(); + expect(response.status).toEqual(200); + expect(response.body).toEqual({ + title: 'Create React App Template', + description: 'Create a new CRA website project', + steps: [], }); }); - describe('providing an identity api', () => { - beforeEach(async () => { - const logger = loggerToWinstonLogger(mockServices.logger.mock()); - const databaseTaskStore = await DatabaseTaskStore.create({ - database: createDatabase(), - }); - taskBroker = new StorageTaskBroker(databaseTaskStore, logger, config); - - jest.spyOn(taskBroker, 'dispatch'); - jest.spyOn(taskBroker, 'get'); - jest.spyOn(taskBroker, 'list'); - jest.spyOn(taskBroker, 'event$'); - loggerSpy = jest.spyOn(logger, 'info'); - - const router = await createRouter({ - logger: logger, - config: new ConfigReader({}), - database: createDatabase(), - catalog: catalogMock, - taskBroker, - permissions: permissionApi, - auth, - httpAuth, - actions: [ - createTemplateAction({ - id: 'test', - description: 'test', - schema: { - input: z => - z.object({ - test: z.string(), - }), - }, - handler: async () => {}, - }), - ], - }); - app = express().use(router); - - catalogMock.getEntityByRef.mockImplementation(async ref => { - const { kind } = parseEntityRef(ref); - - if (kind.toLocaleLowerCase() === 'template') { - return getMockTemplate(); - } - - if (kind.toLocaleLowerCase() === 'user') { - return mockUser; - } - throw new Error(`no mock found for kind: ${kind}`); - }); - - jest - .spyOn(permissionApi, 'authorizeConditional') - .mockImplementation(async () => [ - { - result: AuthorizeResult.ALLOW, + it('filters parameters that the user is not authorized to see in case of conditional decision', async () => { + const { permissions, router } = await createTestRouter(); + jest + .spyOn(permissions, 'authorizeConditional') + .mockImplementation(async () => [ + { + conditions: { + resourceType: 'scaffolder-template', + rule: 'HAS_TAG', + params: { tag: 'parameters-tag' }, }, - { - result: AuthorizeResult.ALLOW, - }, - ]); - jest.spyOn(permissionApi, 'authorize').mockImplementation(async () => [ + pluginId: 'scaffolder', + resourceType: 'scaffolder-template', + result: AuthorizeResult.CONDITIONAL, + }, { result: AuthorizeResult.ALLOW, }, ]); - }); - afterEach(() => { - jest.resetAllMocks(); - }); + const response = await request(router) + .get( + '/v2/templates/default/Template/create-react-app-template/parameter-schema', + ) + .send(); - describe('GET /v2/actions', () => { - it('lists available actions', async () => { - const response = await request(app).get('/v2/actions').send(); - expect(response.status).toEqual(200); - expect(response.body[0].id).toBeDefined(); - expect(response.body.length).toBe(1); - }); - }); - - describe('GET /v2/templates/:namespace/:kind/:name/parameter-schema', () => { - it('returns the parameter schema', async () => { - const response = await request(app) - .get( - '/v2/templates/default/Template/create-react-app-template/parameter-schema', - ) - .send(); - - expect(response.status).toEqual(200); - expect(response.body).toEqual({ - title: 'Create React App Template', - description: 'Create a new CRA website project', - steps: [ - { - title: 'Please enter the following information', - schema: { - required: ['requiredParameter1'], - type: 'object', - properties: { - requiredParameter1: { - description: 'Required parameter 1', - type: 'string', - }, - }, + expect(response.status).toEqual(200); + expect(response.body).toEqual({ + title: 'Create React App Template', + description: 'Create a new CRA website project', + steps: [ + { + title: 'Please enter the following information', + schema: { + type: 'object', + required: ['requiredParameter2'], + 'backstage:permissions': { + tags: ['parameters-tag'], + }, + properties: { + requiredParameter2: { + type: 'string', + description: 'Required parameter 2', }, }, - { - title: 'Please enter the following information', - schema: { - type: 'object', - required: ['requiredParameter2'], - 'backstage:permissions': { - tags: ['parameters-tag'], - }, - properties: { - requiredParameter2: { - type: 'string', - description: 'Required parameter 2', - }, - }, - }, - }, - ], - }); - }); - - it('filters parameters that the user is not authorized to see', async () => { - jest - .spyOn(permissionApi, 'authorizeConditional') - .mockImplementationOnce(async () => [ - { - result: AuthorizeResult.DENY, - }, - { - result: AuthorizeResult.ALLOW, - }, - ]); - const response = await request(app) - .get( - '/v2/templates/default/Template/create-react-app-template/parameter-schema', - ) - .send(); - expect(response.status).toEqual(200); - expect(response.body).toEqual({ - title: 'Create React App Template', - description: 'Create a new CRA website project', - steps: [], - }); - }); - - it('filters parameters that the user is not authorized to see in case of conditional decision', async () => { - jest - .spyOn(permissionApi, 'authorizeConditional') - .mockImplementationOnce(async () => [ - { - conditions: { - resourceType: 'scaffolder-template', - rule: 'HAS_TAG', - params: { tag: 'parameters-tag' }, - }, - pluginId: 'scaffolder', - resourceType: 'scaffolder-template', - result: AuthorizeResult.CONDITIONAL, - }, - { - result: AuthorizeResult.ALLOW, - }, - ]); - const response = await request(app) - .get( - '/v2/templates/default/Template/create-react-app-template/parameter-schema', - ) - .send(); - expect(response.status).toEqual(200); - expect(response.body).toEqual({ - title: 'Create React App Template', - description: 'Create a new CRA website project', - steps: [ - { - title: 'Please enter the following information', - schema: { - type: 'object', - required: ['requiredParameter2'], - 'backstage:permissions': { - tags: ['parameters-tag'], - }, - properties: { - requiredParameter2: { - type: 'string', - description: 'Required parameter 2', - }, - }, - }, - }, - ], - }); - }); - }); - - describe('POST /v2/tasks', () => { - it('rejects template values which do not match the template schema definition', async () => { - const response = await request(app) - .post('/v2/tasks') - .send({ - templateRef: stringifyEntityRef({ - kind: 'template', - name: 'create-react-app-template', - }), - values: { - storePath: 'https://github.com/backstage/backstage', - }, - }); - - expect(response.status).toEqual(400); - }); - - it('filters steps that the user is not authorized to see', async () => { - jest - .spyOn(permissionApi, 'authorizeConditional') - .mockImplementation(async () => [ - { - result: AuthorizeResult.ALLOW, - }, - { - result: AuthorizeResult.DENY, - }, - ]); - - const broker = - taskBroker.dispatch as jest.Mocked['dispatch']; - const mockTemplate = getMockTemplate(); - - await request(app) - .post('/v2/tasks') - .send({ - templateRef: stringifyEntityRef({ - kind: 'template', - name: 'create-react-app-template', - }), - values: { - requiredParameter1: 'required-value-1', - requiredParameter2: 'required-value-2', - }, - }); - expect(broker).toHaveBeenCalledWith( - expect.objectContaining({ - createdBy: 'user:default/mock', - secrets: { - __initiatorCredentials: JSON.stringify(credentials), - }, - - spec: { - apiVersion: mockTemplate.apiVersion, - steps: [], - output: mockTemplate.spec.output ?? {}, - parameters: { - requiredParameter1: 'required-value-1', - requiredParameter2: 'required-value-2', - }, - user: { - entity: mockUser, - ref: 'user:default/mock', - }, - templateInfo: { - entityRef: stringifyEntityRef({ - kind: 'Template', - namespace: 'Default', - name: mockTemplate.metadata?.name, - }), - baseUrl: 'https://dev.azure.com', - entity: { - metadata: mockTemplate.metadata, - }, - }, - }, - }), - ); - }); - - it('filters steps that the user is not authorized to see in case of conditional decision', async () => { - jest - .spyOn(permissionApi, 'authorizeConditional') - .mockImplementation(async () => [ - { - result: AuthorizeResult.ALLOW, - }, - { - conditions: { - resourceType: 'scaffolder-template', - rule: 'HAS_TAG', - params: { tag: 'steps-tag' }, - }, - pluginId: 'scaffolder', - resourceType: 'scaffolder-template', - result: AuthorizeResult.CONDITIONAL, - }, - ]); - - const broker = - taskBroker.dispatch as jest.Mocked['dispatch']; - const mockTemplate = getMockTemplate(); - await request(app) - .post('/v2/tasks') - .send({ - templateRef: stringifyEntityRef({ - kind: 'template', - name: 'create-react-app-template', - }), - values: { - requiredParameter1: 'required-value-1', - requiredParameter2: 'required-value-2', - }, - }); - expect(broker).toHaveBeenCalledWith( - expect.objectContaining({ - createdBy: 'user:default/mock', - secrets: { - __initiatorCredentials: JSON.stringify(credentials), - }, - - spec: { - apiVersion: mockTemplate.apiVersion, - steps: [ - { - id: 'step-two', - name: 'Second log', - action: 'debug:log', - input: { - message: 'world', - }, - 'backstage:permissions': { - tags: ['steps-tag'], - }, - }, - ], - output: mockTemplate.spec.output ?? {}, - parameters: { - requiredParameter1: 'required-value-1', - requiredParameter2: 'required-value-2', - }, - user: { - entity: mockUser, - ref: 'user:default/mock', - }, - templateInfo: { - entityRef: stringifyEntityRef({ - kind: 'Template', - namespace: 'Default', - name: mockTemplate.metadata?.name, - }), - baseUrl: 'https://dev.azure.com', - entity: { - metadata: mockTemplate.metadata, - }, - }, - }, - }), - ); - }); - - it('return the template id', async () => { - const broker = - taskBroker.dispatch as jest.Mocked['dispatch']; - broker.mockResolvedValue({ - taskId: 'a-random-id', - }); - - const response = await request(app) - .post('/v2/tasks') - .send({ - templateRef: stringifyEntityRef({ - kind: 'template', - name: 'create-react-app-template', - }), - values: { - requiredParameter1: 'required-value-1', - requiredParameter2: 'required-value-2', - }, - }); - - expect(response.body.id).toBe('a-random-id'); - expect(response.status).toEqual(201); - }); - - it('should call the broker with a correct spec', async () => { - const broker = - taskBroker.dispatch as jest.Mocked['dispatch']; - const mockTemplate = getMockTemplate(); - - await request(app) - .post('/v2/tasks') - .send({ - templateRef: stringifyEntityRef({ - kind: 'template', - name: 'create-react-app-template', - }), - values: { - requiredParameter1: 'required-value-1', - requiredParameter2: 'required-value-2', - }, - }); - expect(broker).toHaveBeenCalledWith( - expect.objectContaining({ - createdBy: 'user:default/mock', - secrets: { - __initiatorCredentials: JSON.stringify(credentials), - }, - - spec: { - apiVersion: mockTemplate.apiVersion, - steps: mockTemplate.spec.steps.map((step, index) => ({ - ...step, - id: step.id ?? `step-${index + 1}`, - name: step.name ?? step.action, - })), - output: mockTemplate.spec.output ?? {}, - parameters: { - requiredParameter1: 'required-value-1', - requiredParameter2: 'required-value-2', - }, - user: { - entity: mockUser, - ref: 'user:default/mock', - }, - templateInfo: { - entityRef: stringifyEntityRef({ - kind: 'Template', - namespace: 'Default', - name: mockTemplate.metadata?.name, - }), - baseUrl: 'https://dev.azure.com', - entity: { - metadata: mockTemplate.metadata, - }, - }, - }, - }), - ); - }); - - it('should emit auditlog containing user identifier when backstage auth is passed', async () => { - await request(app) - .post('/v2/tasks') - .send({ - templateRef: stringifyEntityRef({ - kind: 'template', - name: 'create-react-app-template', - }), - values: { - requiredParameter1: 'required-value-1', - requiredParameter2: 'required-value-2', - }, - }); - - expect(loggerSpy).toHaveBeenCalledTimes(1); - expect(loggerSpy).toHaveBeenCalledWith( - 'Scaffolding task for template:default/create-react-app-template created by user:default/mock', - ); - }); - }); - - describe('GET /v2/tasks', () => { - it('return all tasks', async () => { - ( - taskBroker.list as jest.Mocked>['list'] - ).mockResolvedValue({ - tasks: [ - { - id: 'a-random-id', - spec: {} as any, - status: 'completed', - createdAt: '', - createdBy: '', - }, - ], - totalTasks: 1, - }); - - const response = await request(app).get(`/v2/tasks`); - expect(taskBroker.list).toHaveBeenCalledWith({ - pagination: {}, - filters: {}, - }); - expect(response.status).toEqual(200); - expect(response.body).toStrictEqual({ - tasks: [ - { - id: 'a-random-id', - spec: {} as any, - status: 'completed', - createdAt: '', - createdBy: '', - }, - ], - totalTasks: 1, - }); - }); - - it('return filtered tasks', async () => { - ( - taskBroker.list as jest.Mocked>['list'] - ).mockResolvedValue({ - tasks: [ - { - id: 'a-random-id', - spec: {} as any, - status: 'completed', - createdAt: '', - createdBy: 'user:default/foo', - }, - ], - totalTasks: 1, - }); - - const response = await request(app).get( - `/v2/tasks?createdBy=user:default/foo`, - ); - expect(taskBroker.list).toHaveBeenCalledWith({ - filters: { - createdBy: ['user:default/foo'], }, - pagination: {}, - }); + }, + ], + }); + }); + }); - expect(response.status).toEqual(200); - expect(response.body).toStrictEqual({ - tasks: [ - { - id: 'a-random-id', - spec: {} as any, - status: 'completed', - createdAt: '', - createdBy: 'user:default/foo', - }, - ], - totalTasks: 1, - }); + describe('POST /v2/tasks', () => { + it('rejects template values which do not match the template schema definition', async () => { + const { router } = await createTestRouter(); + const response = await request(router) + .post('/v2/tasks') + .send({ + templateRef: stringifyEntityRef({ + kind: 'template', + name: 'create-react-app-template', + }), + values: { + storePath: 'https://github.com/backstage/backstage', + }, }); + + expect(response.status).toEqual(400); + }); + + it('return the template id', async () => { + const { router, taskBroker } = await createTestRouter(); + const broker = taskBroker.dispatch as jest.Mocked['dispatch']; + + broker.mockResolvedValue({ + taskId: 'a-random-id', }); - describe('GET /v2/tasks/:taskId', () => { - it('does not divulge secrets', async () => { - (taskBroker.get as jest.Mocked['get']).mockResolvedValue({ - id: 'a-random-id', - spec: {} as any, - status: 'completed', - createdAt: '', - secrets: { - __initiatorCredentials: JSON.stringify(credentials), - }, - createdBy: '', - }); - - const response = await request(app).get(`/v2/tasks/a-random-id`); - expect(response.status).toEqual(200); - expect(response.body.status).toBe('completed'); - expect(response.body.secrets).toBeUndefined(); - }); - }); - - describe('GET /v2/tasks/:taskId/eventstream', () => { - it('should return log messages', async () => { - let subscriber: ZenObservable.SubscriptionObserver; - ( - taskBroker.event$ as jest.Mocked['event$'] - ).mockImplementation(({ taskId }) => { - return new ObservableImpl(observer => { - subscriber = observer; - setImmediate(() => { - observer.next({ - events: [ - { - id: 0, - taskId, - type: 'log', - createdAt: '', - body: { message: 'My log message' }, - }, - ], - }); - observer.next({ - events: [ - { - id: 1, - taskId, - type: 'completion', - createdAt: '', - body: { message: 'Finished!' }, - }, - ], - }); - }); - }); - // emit after this function returned - }); - - let statusCode: any = undefined; - let headers: any = {}; - const responseDataFn = jest.fn(); - - const req = request(app) - .get('/v2/tasks/a-random-id/eventstream') - .set('accept', 'text/event-stream') - .parse((res, _) => { - ({ statusCode, headers } = res as any); - - res.on('data', chunk => { - responseDataFn(chunk.toString()); - - // the server expects the client to abort the request - if (chunk.includes('completion')) { - req.abort(); - } - }); - }); - - // wait for the request to finish - await req.catch(() => { - // ignore 'aborted' error - }); - - expect(statusCode).toBe(200); - expect(headers['content-type']).toBe('text/event-stream'); - expect(responseDataFn).toHaveBeenCalledTimes(2); - expect(responseDataFn).toHaveBeenCalledWith(`event: log -data: {"id":0,"taskId":"a-random-id","type":"log","createdAt":"","body":{"message":"My log message"}} - -`); - expect(responseDataFn).toHaveBeenCalledWith(`event: completion -data: {"id":1,"taskId":"a-random-id","type":"completion","createdAt":"","body":{"message":"Finished!"}} - -`); - - expect(taskBroker.event$).toHaveBeenCalledTimes(1); - expect(taskBroker.event$).toHaveBeenCalledWith({ - taskId: 'a-random-id', - }); - expect(subscriber!.closed).toBe(true); + const response = await request(router) + .post('/v2/tasks') + .send({ + templateRef: stringifyEntityRef({ + kind: 'template', + name: 'create-react-app-template', + }), + values: { + requiredParameter1: 'required-value-1', + requiredParameter2: 'required-value-2', + }, }); - it('should return log messages with after query', async () => { - let subscriber: ZenObservable.SubscriptionObserver; - ( - taskBroker.event$ as jest.Mocked['event$'] - ).mockImplementation(({ taskId }) => { - return new ObservableImpl(observer => { - subscriber = observer; - setImmediate(() => { - observer.next({ - events: [ - { - id: 1, - taskId, - type: 'completion', - createdAt: '', - body: { message: 'Finished!' }, - }, - ], - }); - }); - }); - }); + expect(response.status).toEqual(201); + expect(response.body.id).toBe('a-random-id'); + }); - let statusCode: any = undefined; - let headers: any = {}; + it('should call the broker with a correct spec', async () => { + const { router, taskBroker } = await createTestRouter(); + const broker = taskBroker.dispatch as jest.Mocked['dispatch']; + const mockToken = mockCredentials.user.token(); + const mockTemplate = generateMockTemplate(); - const req = request(app) - .get('/v2/tasks/a-random-id/eventstream') - .query({ after: 10 }) - .set('accept', 'text/event-stream') - .parse((res, _) => { - ({ statusCode, headers } = res as any); - - res.on('data', () => { - // close immediately - req.abort(); - }); - }); - - // wait for the request to finish - await req.catch(() => { - // ignore 'aborted' error - }); - - expect(statusCode).toBe(200); - expect(headers['content-type']).toBe('text/event-stream'); - - expect(taskBroker.event$).toHaveBeenCalledTimes(1); - expect(taskBroker.event$).toHaveBeenCalledWith({ - taskId: 'a-random-id', - after: 10, - }); - - expect(subscriber!.closed).toBe(true); - }); - }); - - describe('GET /v2/tasks/:taskId/events', () => { - it('should return log messages', async () => { - let subscriber: ZenObservable.SubscriptionObserver; - ( - taskBroker.event$ as jest.Mocked['event$'] - ).mockImplementation(({ taskId }) => { - return new ObservableImpl(observer => { - subscriber = observer; - observer.next({ - events: [ - { - id: 0, - taskId, - type: 'log', - createdAt: '', - body: { message: 'My log message' }, - }, - { - id: 1, - taskId, - type: 'completion', - createdAt: '', - body: { message: 'Finished!' }, - }, - ], - }); - }); - }); - - const response = await request(app).get( - '/v2/tasks/a-random-id/events', - ); - - expect(response.status).toEqual(200); - expect(response.body).toEqual([ - { - id: 0, - taskId: 'a-random-id', - type: 'log', - createdAt: '', - body: { message: 'My log message' }, - }, - { - id: 1, - taskId: 'a-random-id', - type: 'completion', - createdAt: '', - body: { message: 'Finished!' }, - }, - ]); - - expect(taskBroker.event$).toHaveBeenCalledTimes(1); - expect(taskBroker.event$).toHaveBeenCalledWith({ - taskId: 'a-random-id', - }); - expect(subscriber!.closed).toBe(true); + await request(router) + .post('/v2/tasks') + .set('Authorization', `Bearer ${mockToken}`) + .send({ + templateRef: stringifyEntityRef({ + kind: 'template', + name: 'create-react-app-template', + }), + values: { + requiredParameter1: 'required-value-1', + requiredParameter2: 'required-value-2', + }, }); - it('should return log messages with after query', async () => { - let subscriber: ZenObservable.SubscriptionObserver; - ( - taskBroker.event$ as jest.Mocked['event$'] - ).mockImplementation(() => { - return new ObservableImpl(observer => { - subscriber = observer; - observer.next({ events: [] }); - }); - }); - - const response = await request(app) - .get('/v2/tasks/a-random-id/events') - .query({ after: 10 }); - - expect(response.status).toEqual(200); - expect(response.body).toEqual([]); - - expect(taskBroker.event$).toHaveBeenCalledTimes(1); - expect(taskBroker.event$).toHaveBeenCalledWith({ - taskId: 'a-random-id', - after: 10, - }); - expect(subscriber!.closed).toBe(true); - }); - }); - - describe('GET /v2/autocomplete/:provider/:resource', () => { - let handleAutocompleteRequest: AutocompleteHandler; - - beforeEach(async () => { - handleAutocompleteRequest = jest.fn().mockResolvedValue({ - results: [{ title: 'blob' }], - }); - - const router = await createRouter({ - logger: loggerToWinstonLogger(mockServices.logger.mock()), - config: new ConfigReader({}), - database: createDatabase(), - catalog: catalogMock, - taskBroker, - permissions: permissionApi, - auth, - httpAuth, - autocompleteHandlers: { - 'test-provider': handleAutocompleteRequest, - }, - }); - - app = express().use(router).use(mockErrorHandler()); - }); - - it('should throw an error when the provider is not registered', async () => { - const response = await request(app) - .post('/v2/autocomplete/unknown-provider/resource') - .send({ - token: 'token', - context: {}, - }); - - expect(response.status).toEqual(400); - expect(response.body).toEqual( - expect.objectContaining({ - error: { - message: 'Unsupported provider: unknown-provider', - name: 'InputError', - }, - }), - ); - }); - - it('should call the autocomplete handler', async () => { - const context = { mock: 'context' }; - const mockToken = 'mocktoken'; - - const response = await request(app) - .post('/v2/autocomplete/test-provider/resource') - .send({ + expect(broker).toHaveBeenCalledWith( + expect.objectContaining({ + createdBy: 'user:default/mock', + secrets: { + __initiatorCredentials: JSON.stringify({ + ...credentials, token: mockToken, - context, + }), + backstageToken: mockToken, + }, + spec: { + apiVersion: mockTemplate.apiVersion, + steps: mockTemplate.spec.steps.map((step, index) => ({ + ...step, + id: step.id ?? `step-${index + 1}`, + name: step.name ?? step.action, + })), + output: {}, + parameters: { + requiredParameter1: 'required-value-1', + requiredParameter2: 'required-value-2', + }, + user: { + entity: mockUser, + ref: 'user:default/mock', + }, + templateInfo: { + entityRef: stringifyEntityRef({ + kind: 'Template', + namespace: 'Default', + name: mockTemplate.metadata?.name, + }), + baseUrl: 'https://dev.azure.com', + entity: { + metadata: mockTemplate.metadata, + }, + }, + }, + }), + ); + }); + + it('should emit auditlog containing user identifier when backstage auth is passed', async () => { + const { logger, router } = await createTestRouter(); + const mockToken = mockCredentials.user.token(); + + const { status, body } = await request(router) + .post('/v2/tasks') + .set('Authorization', `Bearer ${mockToken}`) + .send({ + templateRef: stringifyEntityRef({ + kind: 'template', + name: 'create-react-app-template', + }), + values: { + requiredParameter1: 'required-value-1', + requiredParameter2: 'required-value-2', + }, + }); + + console.log(status, body); + expect(logger.info).toHaveBeenCalledTimes(1); + expect(logger.info).toHaveBeenCalledWith( + 'Scaffolding task for template:default/create-react-app-template created by user:default/mock', + ); + }); + + it('filters steps that the user is not authorized to see', async () => { + const { router, permissions, taskBroker } = await createTestRouter(); + jest + .spyOn(permissions, 'authorizeConditional') + .mockImplementation(async () => [ + { + result: AuthorizeResult.ALLOW, + }, + { + result: AuthorizeResult.DENY, + }, + ]); + + const broker = taskBroker.dispatch as jest.Mocked['dispatch']; + const mockTemplate = generateMockTemplate(); + + await request(router) + .post('/v2/tasks') + .send({ + templateRef: stringifyEntityRef({ + kind: 'template', + name: 'create-react-app-template', + }), + values: { + requiredParameter1: 'required-value-1', + requiredParameter2: 'required-value-2', + }, + }); + expect(broker).toHaveBeenCalledWith( + expect.objectContaining({ + createdBy: 'user:default/mock', + secrets: { + __initiatorCredentials: JSON.stringify({ + ...credentials, + token: mockCredentials.user.token(), + }), + backstageToken: mockCredentials.user.token(), + }, + + spec: { + apiVersion: mockTemplate.apiVersion, + steps: [], + output: {}, + parameters: { + requiredParameter1: 'required-value-1', + requiredParameter2: 'required-value-2', + }, + user: { + entity: mockUser, + ref: 'user:default/mock', + }, + templateInfo: { + entityRef: stringifyEntityRef({ + kind: 'Template', + namespace: 'Default', + name: mockTemplate.metadata?.name, + }), + baseUrl: 'https://dev.azure.com', + entity: { + metadata: mockTemplate.metadata, + }, + }, + }, + }), + ); + }); + + it('filters steps that the user is not authorized to see in case of conditional decision', async () => { + const { permissions, router, taskBroker } = await createTestRouter(); + jest + .spyOn(permissions, 'authorizeConditional') + .mockImplementation(async () => [ + { + result: AuthorizeResult.ALLOW, + }, + { + conditions: { + resourceType: 'scaffolder-template', + rule: 'HAS_TAG', + params: { tag: 'steps-tag' }, + }, + pluginId: 'scaffolder', + resourceType: 'scaffolder-template', + result: AuthorizeResult.CONDITIONAL, + }, + ]); + + const broker = taskBroker.dispatch as jest.Mocked['dispatch']; + const mockTemplate = generateMockTemplate(); + await request(router) + .post('/v2/tasks') + .send({ + templateRef: stringifyEntityRef({ + kind: 'template', + name: 'create-react-app-template', + }), + values: { + requiredParameter1: 'required-value-1', + requiredParameter2: 'required-value-2', + }, + }); + expect(broker).toHaveBeenCalledWith( + expect.objectContaining({ + createdBy: 'user:default/mock', + secrets: { + __initiatorCredentials: JSON.stringify({ + ...credentials, + token: mockCredentials.user.token(), + }), + backstageToken: mockCredentials.user.token(), + }, + + spec: { + apiVersion: mockTemplate.apiVersion, + steps: [ + { + id: 'step-two', + name: 'Second log', + action: 'debug:log', + input: { + message: 'world', + }, + 'backstage:permissions': { + tags: ['steps-tag'], + }, + }, + ], + output: {}, + parameters: { + requiredParameter1: 'required-value-1', + requiredParameter2: 'required-value-2', + }, + user: { + entity: mockUser, + ref: 'user:default/mock', + }, + templateInfo: { + entityRef: stringifyEntityRef({ + kind: 'Template', + namespace: 'Default', + name: mockTemplate.metadata?.name, + }), + baseUrl: 'https://dev.azure.com', + entity: { + metadata: mockTemplate.metadata, + }, + }, + }, + }), + ); + }); + }); + + describe('GET /v2/tasks', () => { + it('return all tasks', async () => { + const { router, taskBroker } = await createTestRouter(); + ( + taskBroker.list as jest.Mocked>['list'] + ).mockResolvedValue({ + tasks: [ + { + id: 'a-random-id', + spec: {} as TaskSpec, + status: 'completed', + createdAt: '', + createdBy: '', + }, + ], + totalTasks: 1, + }); + + const response = await request(router).get(`/v2/tasks`); + expect(taskBroker.list).toHaveBeenCalledWith({ + filters: {}, + pagination: {}, + }); + expect(response.status).toEqual(200); + expect(response.body).toStrictEqual({ + tasks: [ + { + id: 'a-random-id', + spec: {} as TaskSpec, + status: 'completed', + createdAt: '', + createdBy: '', + }, + ], + totalTasks: 1, + }); + }); + + it('return filtered tasks', async () => { + const { router, taskBroker } = await createTestRouter(); + ( + taskBroker.list as jest.Mocked>['list'] + ).mockResolvedValue({ + tasks: [ + { + id: 'a-random-id', + spec: {} as TaskSpec, + status: 'completed', + createdAt: '', + createdBy: 'user:default/foo', + }, + ], + totalTasks: 1, + }); + + const response = await request(router).get( + `/v2/tasks?createdBy=user:default/foo&createdBy=user:default/bar&status=completed&status=open&limit=1&offset=0&order=desc:created_at`, + ); + + expect(response.status).toEqual(200); + expect(response.body).toStrictEqual({ + tasks: [ + { + id: 'a-random-id', + spec: {} as TaskSpec, + status: 'completed', + createdAt: '', + createdBy: 'user:default/foo', + }, + ], + totalTasks: 1, + }); + expect(taskBroker.list).toHaveBeenCalledWith({ + filters: { + createdBy: ['user:default/foo', 'user:default/bar'], + status: ['completed', 'open'], + }, + pagination: { + limit: 1, + offset: 0, + }, + order: [{ order: 'desc', field: 'created_at' }], + }); + }); + }); + + describe('GET /v2/tasks/:taskId', () => { + it('does not divulge secrets', async () => { + const { router, taskBroker } = await createTestRouter(); + (taskBroker.get as jest.Mocked['get']).mockResolvedValue({ + id: 'a-random-id', + spec: {} as TaskSpec, + status: 'completed', + createdAt: '', + secrets: { + __initiatorCredentials: JSON.stringify(credentials), + }, + createdBy: '', + }); + + const response = await request(router).get(`/v2/tasks/a-random-id`); + expect(response.status).toEqual(200); + expect(response.body.status).toBe('completed'); + expect(response.body.secrets).toBeUndefined(); + }); + }); + + describe('GET /v2/tasks/:taskId/eventstream', () => { + it('should return log messages', async () => { + const { router, taskBroker } = await createTestRouter(); + let subscriber: ZenObservable.SubscriptionObserver<{ + events: SerializedTaskEvent[]; + }>; + ( + taskBroker.event$ as jest.Mocked['event$'] + ).mockImplementation(({ taskId }) => { + return new ObservableImpl(observer => { + subscriber = observer; + setImmediate(() => { + observer.next({ + events: [ + { + id: 0, + taskId, + type: 'log', + createdAt: '', + body: { message: 'My log message' }, + }, + ], }); + observer.next({ + events: [ + { + id: 1, + taskId, + type: 'completion', + createdAt: '', + body: { message: 'Finished!' }, + }, + ], + }); + }); + }); + // emit after this function returned + }); - expect(response.status).toEqual(200); + let statusCode: number | undefined = undefined; + let headers: Record = {}; + const responseDataFn = jest.fn(); - expect(response.body).toEqual({ results: [{ title: 'blob' }] }); - expect(handleAutocompleteRequest).toHaveBeenCalledWith({ - token: mockToken, - context, - resource: 'resource', + const req = request(router) + .get('/v2/tasks/a-random-id/eventstream') + .set('accept', 'text/event-stream') + .parse((res, _) => { + ({ statusCode, headers } = res as unknown as { + statusCode: number; + headers: Record; + }); + + res.on('data', chunk => { + responseDataFn(chunk.toString()); + + // the server expects the client to abort the request + if (chunk.includes('completion')) { + req.abort(); + } + }); + }); + + // wait for the request to finish + await req.catch(() => { + // ignore 'aborted' error + }); + + expect(statusCode).toBe(200); + expect(headers['content-type']).toBe('text/event-stream'); + expect(responseDataFn).toHaveBeenCalledTimes(2); + expect(responseDataFn).toHaveBeenCalledWith(`event: log +data: {"id":0,"taskId":"a-random-id","type":"log","createdAt":"","body":{"message":"My log message"}} + +`); + expect(responseDataFn).toHaveBeenCalledWith(`event: completion +data: {"id":1,"taskId":"a-random-id","type":"completion","createdAt":"","body":{"message":"Finished!"}} + +`); + + expect(taskBroker.event$).toHaveBeenCalledTimes(1); + expect(taskBroker.event$).toHaveBeenCalledWith({ + taskId: 'a-random-id', + }); + expect(subscriber!.closed).toBe(true); + }); + + it('should return log messages with after query', async () => { + const { router, taskBroker } = await createTestRouter(); + let subscriber: ZenObservable.SubscriptionObserver<{ + events: SerializedTaskEvent[]; + }>; + ( + taskBroker.event$ as jest.Mocked['event$'] + ).mockImplementation(({ taskId }) => { + return new ObservableImpl(observer => { + subscriber = observer; + setImmediate(() => { + observer.next({ + events: [ + { + id: 1, + taskId, + type: 'completion', + createdAt: '', + body: { message: 'Finished!' }, + }, + ], + }); }); }); }); + + let statusCode: number | undefined = undefined; + let headers: Record = {}; + + const req = request(router) + .get('/v2/tasks/a-random-id/eventstream') + .query({ after: 10 }) + .set('accept', 'text/event-stream') + .parse((res, _) => { + ({ statusCode, headers } = res as unknown as { + statusCode: number; + headers: Record; + }); + + res.on('data', () => { + // close immediately + req.abort(); + }); + }); + + // wait for the request to finish + await req.catch(() => { + // ignore 'aborted' error + }); + + expect(statusCode).toBe(200); + expect(headers['content-type']).toBe('text/event-stream'); + + expect(taskBroker.event$).toHaveBeenCalledTimes(1); + expect(taskBroker.event$).toHaveBeenCalledWith({ + taskId: 'a-random-id', + after: 10, + }); + + expect(subscriber!.closed).toBe(true); }); - }, -); + }); + + describe('GET /v2/tasks/:taskId/events', () => { + it('should return log messages', async () => { + const { router, taskBroker } = await createTestRouter(); + let subscriber: ZenObservable.SubscriptionObserver<{ + events: SerializedTaskEvent[]; + }>; + ( + taskBroker.event$ as jest.Mocked['event$'] + ).mockImplementation(({ taskId }) => { + return new ObservableImpl(observer => { + subscriber = observer; + observer.next({ + events: [ + { + id: 0, + taskId, + type: 'log', + createdAt: '', + body: { message: 'My log message' }, + }, + { + id: 1, + taskId, + type: 'completion', + createdAt: '', + body: { message: 'Finished!' }, + }, + ], + }); + }); + }); + + const response = await request(router).get( + '/v2/tasks/a-random-id/events', + ); + + expect(response.status).toEqual(200); + expect(response.body).toEqual([ + { + id: 0, + taskId: 'a-random-id', + type: 'log', + createdAt: '', + body: { message: 'My log message' }, + }, + { + id: 1, + taskId: 'a-random-id', + type: 'completion', + createdAt: '', + body: { message: 'Finished!' }, + }, + ]); + + expect(taskBroker.event$).toHaveBeenCalledTimes(1); + expect(taskBroker.event$).toHaveBeenCalledWith({ + taskId: 'a-random-id', + }); + expect(subscriber!.closed).toBe(true); + }); + + it('should return log messages with after query', async () => { + const { router, taskBroker } = await createTestRouter(); + let subscriber: ZenObservable.SubscriptionObserver<{ + events: SerializedTaskEvent[]; + }>; + ( + taskBroker.event$ as jest.Mocked['event$'] + ).mockImplementation(() => { + return new ObservableImpl(observer => { + subscriber = observer; + observer.next({ events: [] }); + }); + }); + + const response = await request(router) + .get('/v2/tasks/a-random-id/events') + .query({ after: 10 }); + + expect(response.status).toEqual(200); + expect(response.body).toEqual([]); + + expect(taskBroker.event$).toHaveBeenCalledTimes(1); + expect(taskBroker.event$).toHaveBeenCalledWith({ + taskId: 'a-random-id', + after: 10, + }); + expect(subscriber!.closed).toBe(true); + }); + }); + + describe('POST /v2/dry-run', () => { + it('should get user entity', async () => { + const { router, catalog } = await createTestRouter(); + const mockToken = mockCredentials.user.token(); + const mockTemplate = generateMockTemplate(); + + await request(router) + .post('/v2/dry-run') + .set('Authorization', `Bearer ${mockToken}`) + .send({ + template: mockTemplate, + values: { + requiredParameter1: 'required-value-1', + requiredParameter2: 'required-value-2', + }, + directoryContents: [], + }); + + expect(catalog.getEntityByRef).toHaveBeenCalledTimes(1); + + expect(catalog.getEntityByRef).toHaveBeenCalledWith( + 'user:default/mock', + expect.anything(), + ); + }); + }); + + describe('GET /v2/autocomplete/:provider/:resource', () => { + it('should throw an error when the provider is not registered', async () => { + const handleAutocompleteRequest = jest.fn().mockResolvedValue({ + results: [{ title: 'blob' }], + }); + const { router } = await createTestRouter({ + autocompleteHandlers: { + 'test-provider': handleAutocompleteRequest, + }, + }); + + const response = await request(router) + .post('/v2/autocomplete/unknown-provider/resource') + .send({ + token: 'token', + context: {}, + }); + + expect(response.status).toEqual(400); + expect(response.body).toEqual( + expect.objectContaining({ + error: { + message: 'Unsupported provider: unknown-provider', + name: 'InputError', + }, + }), + ); + }); + + it('should call the autocomplete handler', async () => { + const handleAutocompleteRequest = jest.fn().mockResolvedValue({ + results: [{ title: 'blob' }], + }); + + const { router } = await createTestRouter({ + autocompleteHandlers: { + 'test-provider': handleAutocompleteRequest, + }, + }); + + const context = { mock: 'context' }; + const mockToken = 'mocktoken'; + + const response = await request(router) + .post('/v2/autocomplete/test-provider/resource') + .send({ + token: mockToken, + context, + }); + + expect(response.status).toEqual(200); + + expect(response.body).toEqual({ results: [{ title: 'blob' }] }); + expect(handleAutocompleteRequest).toHaveBeenCalledWith({ + token: mockToken, + context, + resource: 'resource', + }); + }); + }); +}); diff --git a/plugins/scaffolder-node-test-utils/CHANGELOG.md b/plugins/scaffolder-node-test-utils/CHANGELOG.md index 6eddc2ddb1..bf20a8b4af 100644 --- a/plugins/scaffolder-node-test-utils/CHANGELOG.md +++ b/plugins/scaffolder-node-test-utils/CHANGELOG.md @@ -1,5 +1,41 @@ # @backstage/plugin-scaffolder-node-test-utils +## 0.3.0 + +### Minor Changes + +- 3cea7ee: **BREAKING CHANGES** + + Because of the removal of the `logStream` property to the `ActionsContext` this has been removed from the `createMockActionContext` method. + + You can remove this as it's no longer supported in the scaffolder actions. + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.9.0 + - @backstage/backend-test-utils@1.6.0 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/types@1.2.1 + +## 0.3.0-next.2 + +### Minor Changes + +- 3cea7ee: **BREAKING CHANGES** + + Because of the removal of the `logStream` property to the `ActionsContext` this has been removed from the `createMockActionContext` method. + + You can remove this as it's no longer supported in the scaffolder actions. + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.9.0-next.2 + - @backstage/backend-test-utils@1.6.0-next.2 + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/types@1.2.1 + ## 0.2.3-next.1 ### Patch Changes diff --git a/plugins/scaffolder-node-test-utils/package.json b/plugins/scaffolder-node-test-utils/package.json index 8f334cd23f..6275762142 100644 --- a/plugins/scaffolder-node-test-utils/package.json +++ b/plugins/scaffolder-node-test-utils/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-node-test-utils", - "version": "0.2.3-next.1", + "version": "0.3.0", "backstage": { "role": "node-library", "pluginId": "scaffolder", diff --git a/plugins/scaffolder-node/CHANGELOG.md b/plugins/scaffolder-node/CHANGELOG.md index 068a613888..5ed6355c8c 100644 --- a/plugins/scaffolder-node/CHANGELOG.md +++ b/plugins/scaffolder-node/CHANGELOG.md @@ -1,5 +1,149 @@ # @backstage/plugin-scaffolder-node +## 0.9.0 + +### Minor Changes + +- 5863b04: **BREAKING CHANGES** + + The legacy methods to define `createTemplateActions` have been replaced with the new native `zod` approaches for defining input and output schemas. + + You can migrate actions that look like the following with the below examples: + + ```ts + // really old legacy json schema + createTemplateAction<{ repoUrl: string }, { repoOutput: string }>({ + id: 'test', + schema: { + input: { + type: 'object' + required: ['repoUrl'] + properties: { + repoUrl: { + type: 'string', + description: 'repository url description' + } + } + } + } + }); + + // old zod method + createTemplateAction({ + id: 'test' + schema: { + input: { + repoUrl: z.string({ description: 'repository url description' }) + } + } + }) + + // new method: + createTemplateAction({ + id: 'test', + schema: { + input: { + repoUrl: z => z.string({ description: 'repository url description' }) + } + } + }) + + // or for more complex zod types like unions + createTemplateAction({ + id: 'test', + schema: { + input: z => z.object({ + repoUrl: z.string({ description: 'repository url description' }) + }) + } + }) + ``` + + This breaking change also means that `logStream` has been removed entirely from `ActionsContext`, and that the `logger` is now just a `LoggerService` implementation instead. There is no replacement for the `logStream`, if you wish to still keep using a `logStream` we recommend that you create your own stream that writes to `ctx.logger` instead. + +### Patch Changes + +- e89d7b6: Use `LoggerService` instead of `Logger`. This is a non-breaking change, as the `LoggerService` is a subset of the `Logger` interface. +- 9c8ff0c: Update pull request creation filter to include .gitignore files in the created pull request +- Updated dependencies + - @backstage/backend-plugin-api@1.4.0 + - @backstage/catalog-model@1.7.4 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + - @backstage/types@1.2.1 + - @backstage/plugin-scaffolder-common@1.5.11 + +## 0.9.0-next.2 + +### Minor Changes + +- 5863b04: **BREAKING CHANGES** + + The legacy methods to define `createTemplateActions` have been replaced with the new native `zod` approaches for defining input and output schemas. + + You can migrate actions that look like the following with the below examples: + + ```ts + // really old legacy json schema + createTemplateAction<{ repoUrl: string }, { repoOutput: string }>({ + id: 'test', + schema: { + input: { + type: 'object' + required: ['repoUrl'] + properties: { + repoUrl: { + type: 'string', + description: 'repository url description' + } + } + } + } + }); + + // old zod method + createTemplateAction({ + id: 'test' + schema: { + input: { + repoUrl: z.string({ description: 'repository url description' }) + } + } + }) + + // new method: + createTemplateAction({ + id: 'test', + schema: { + input: { + repoUrl: z => z.string({ description: 'repository url description' }) + } + } + }) + + // or for more complex zod types like unions + createTemplateAction({ + id: 'test', + schema: { + input: z => z.object({ + repoUrl: z.string({ description: 'repository url description' }) + }) + } + }) + ``` + + This breaking change also means that `logStream` has been removed entirely from `ActionsContext`, and that the `logger` is now just a `LoggerService` implementation instead. There is no replacement for the `logStream`, if you wish to still keep using a `logStream` we recommend that you create your own stream that writes to `ctx.logger` instead. + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/catalog-model@1.7.4 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + - @backstage/types@1.2.1 + - @backstage/plugin-scaffolder-common@1.5.11 + ## 0.8.3-next.1 ### Patch Changes diff --git a/plugins/scaffolder-node/package.json b/plugins/scaffolder-node/package.json index 6e44babf81..cd03ead977 100644 --- a/plugins/scaffolder-node/package.json +++ b/plugins/scaffolder-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-node", - "version": "0.8.3-next.1", + "version": "0.9.0", "description": "The plugin-scaffolder-node module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "node-library", diff --git a/plugins/scaffolder-react/CHANGELOG.md b/plugins/scaffolder-react/CHANGELOG.md index b9561731f3..cd44a6cbc0 100644 --- a/plugins/scaffolder-react/CHANGELOG.md +++ b/plugins/scaffolder-react/CHANGELOG.md @@ -1,5 +1,43 @@ # @backstage/plugin-scaffolder-react +## 1.17.0 + +### Minor Changes + +- 6c972fe: Added information about the `entityRef` and `taskId` to the analytics events whenever is possible. + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3 + - @backstage/catalog-client@1.10.1 + - @backstage/core-plugin-api@1.10.8 + - @backstage/frontend-plugin-api@0.10.3 + - @backstage/plugin-catalog-react@1.19.0 + - @backstage/catalog-model@1.7.4 + - @backstage/theme@0.6.6 + - @backstage/types@1.2.1 + - @backstage/version-bridge@1.0.11 + - @backstage/plugin-permission-react@0.4.35 + - @backstage/plugin-scaffolder-common@1.5.11 + +## 1.16.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/plugin-catalog-react@1.19.0-next.2 + - @backstage/frontend-plugin-api@0.10.3-next.1 + - @backstage/catalog-client@1.10.1-next.0 + - @backstage/catalog-model@1.7.4 + - @backstage/core-plugin-api@1.10.7 + - @backstage/theme@0.6.6 + - @backstage/types@1.2.1 + - @backstage/version-bridge@1.0.11 + - @backstage/plugin-permission-react@0.4.34 + - @backstage/plugin-scaffolder-common@1.5.11 + ## 1.16.1-next.1 ### Patch Changes diff --git a/plugins/scaffolder-react/package.json b/plugins/scaffolder-react/package.json index d0e2c6344b..b4adfd9c50 100644 --- a/plugins/scaffolder-react/package.json +++ b/plugins/scaffolder-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-react", - "version": "1.16.1-next.1", + "version": "1.17.0", "description": "A frontend library that helps other Backstage plugins interact with the Scaffolder", "backstage": { "role": "web-library", diff --git a/plugins/scaffolder-react/src/next/components/TemplateGroup/TemplateGroup.tsx b/plugins/scaffolder-react/src/next/components/TemplateGroup/TemplateGroup.tsx index a70b822d13..74ade33344 100644 --- a/plugins/scaffolder-react/src/next/components/TemplateGroup/TemplateGroup.tsx +++ b/plugins/scaffolder-react/src/next/components/TemplateGroup/TemplateGroup.tsx @@ -22,7 +22,7 @@ import { } from '@backstage/core-components'; import { stringifyEntityRef } from '@backstage/catalog-model'; import { TemplateCardProps, TemplateCard } from '../TemplateCard'; -import { IconComponent } from '@backstage/core-plugin-api'; +import { AnalyticsContext, IconComponent } from '@backstage/core-plugin-api'; /** * The props for the {@link TemplateGroup} component. @@ -69,12 +69,18 @@ export const TemplateGroup = (props: TemplateGroupProps) => { {titleComponent} {templates.map(({ template, additionalLinks }) => ( - + > + + ))} diff --git a/plugins/scaffolder-react/src/next/components/TemplateGroups/TemplateGroups.tsx b/plugins/scaffolder-react/src/next/components/TemplateGroups/TemplateGroups.tsx index a0070765fe..58b74dff9d 100644 --- a/plugins/scaffolder-react/src/next/components/TemplateGroups/TemplateGroups.tsx +++ b/plugins/scaffolder-react/src/next/components/TemplateGroups/TemplateGroups.tsx @@ -22,7 +22,7 @@ import { } from '@backstage/plugin-scaffolder-common'; import { TemplateGroupFilter } from '@backstage/plugin-scaffolder-react'; import Typography from '@material-ui/core/Typography'; -import { ComponentType, useCallback } from 'react'; +import { ComponentType, useCallback, useEffect } from 'react'; import { TemplateGroup } from '../TemplateGroup/TemplateGroup'; @@ -58,12 +58,17 @@ export const TemplateGroups = (props: TemplateGroupsProps) => { [onTemplateSelected], ); + useEffect(() => { + if (error) { + errorApi.post(error); + } + }, [error, errorApi]); + if (loading) { return ; } if (error) { - errorApi.post(error); return null; } diff --git a/plugins/scaffolder-react/src/next/components/Workflow/Workflow.tsx b/plugins/scaffolder-react/src/next/components/Workflow/Workflow.tsx index 2aa4ee9b2d..527009037d 100644 --- a/plugins/scaffolder-react/src/next/components/Workflow/Workflow.tsx +++ b/plugins/scaffolder-react/src/next/components/Workflow/Workflow.tsx @@ -97,13 +97,14 @@ export const Workflow = (workflowProps: WorkflowProps): JSX.Element | null => { async (formState: Record) => { await onCreate(formState); - const name = - typeof formState.name === 'string' ? formState.name : undefined; - analytics.captureEvent('create', name ?? templateName ?? 'unknown', { + analytics.captureEvent('create', 'Task has been created', { value: minutesSaved, + attributes: { + templateSteps: sortedManifest?.steps?.length ?? 0, + }, }); }, - [onCreate, analytics, templateName, minutesSaved], + [onCreate, analytics, minutesSaved, sortedManifest], ); useEffect(() => { diff --git a/plugins/scaffolder-react/src/next/hooks/useFilteredSchemaProperties.ts b/plugins/scaffolder-react/src/next/hooks/useFilteredSchemaProperties.ts index be6f581f87..cac696a745 100644 --- a/plugins/scaffolder-react/src/next/hooks/useFilteredSchemaProperties.ts +++ b/plugins/scaffolder-react/src/next/hooks/useFilteredSchemaProperties.ts @@ -16,6 +16,7 @@ import cloneDeep from 'lodash/cloneDeep'; import { useApi, featureFlagsApiRef } from '@backstage/core-plugin-api'; import { TemplateParameterSchema } from '@backstage/plugin-scaffolder-react'; +import { useMemo } from 'react'; /** * Returns manifest of software templates with steps without a featureFlag tag. @@ -28,49 +29,51 @@ export const useFilteredSchemaProperties = ( const featureFlagKey = 'backstage:featureFlag'; const featureFlagApi = useApi(featureFlagsApiRef); - if (!manifest) { - return undefined; - } - - const filteredSteps = manifest?.steps - .filter(step => { - const featureFlag = step.schema[featureFlagKey]; - return ( - typeof featureFlag !== 'string' || featureFlagApi.isActive(featureFlag) - ); - }) - .map(step => { - const filteredStep = cloneDeep(step); - const removedPropertyKeys: Array = []; - if (filteredStep.schema.properties) { - filteredStep.schema.properties = Object.fromEntries( - Object.entries(filteredStep.schema.properties).filter( - ([key, value]) => { - if (value[featureFlagKey]) { - if (featureFlagApi.isActive(value[featureFlagKey])) { - return true; - } - - removedPropertyKeys.push(key); - return false; - } - return true; - }, - ), + return useMemo(() => { + if (!manifest) { + return undefined; + } + const filteredSteps = manifest?.steps + .filter(step => { + const featureFlag = step.schema[featureFlagKey]; + return ( + typeof featureFlag !== 'string' || + featureFlagApi.isActive(featureFlag) ); + }) + .map(step => { + const filteredStep = cloneDeep(step); + const removedPropertyKeys: Array = []; + if (filteredStep.schema.properties) { + filteredStep.schema.properties = Object.fromEntries( + Object.entries(filteredStep.schema.properties).filter( + ([key, value]) => { + if (value[featureFlagKey]) { + if (featureFlagApi.isActive(value[featureFlagKey])) { + return true; + } - // remove the feature flag property key from required if they are not active - filteredStep.schema.required = Array.isArray( - filteredStep.schema.required, - ) - ? filteredStep.schema.required?.filter( - r => !removedPropertyKeys.includes(r as string), - ) - : filteredStep.schema.required; - } + removedPropertyKeys.push(key); + return false; + } + return true; + }, + ), + ); - return filteredStep; - }); + // remove the feature flag property key from required if they are not active + filteredStep.schema.required = Array.isArray( + filteredStep.schema.required, + ) + ? filteredStep.schema.required?.filter( + r => !removedPropertyKeys.includes(r as string), + ) + : filteredStep.schema.required; + } - return { ...manifest, steps: filteredSteps }; + return filteredStep; + }); + + return { ...manifest, steps: filteredSteps }; + }, [manifest, featureFlagApi]); }; diff --git a/plugins/scaffolder/CHANGELOG.md b/plugins/scaffolder/CHANGELOG.md index 82b8029637..a9fcc8001e 100644 --- a/plugins/scaffolder/CHANGELOG.md +++ b/plugins/scaffolder/CHANGELOG.md @@ -1,5 +1,64 @@ # @backstage/plugin-scaffolder +## 1.32.0 + +### Minor Changes + +- 6c972fe: Added information about the `entityRef` and `taskId` to the analytics events whenever is possible. +- 3c59ece: **New Frontend System Only:** + The `Scaffolder` plugin is now responsible for providing an entity icon link extension to launch templates from the catalog entity page. + +### Patch Changes + +- d781b33: render details for composite property schemas +- 18c64e9: Added the `info.packageJson` option to the plugin instance for the new frontend system. +- b00c160: Remove React import form notification and scaffolder plugin +- 95a1d72: Added appropriate message when global templating function metadata is absent. +- Updated dependencies + - @backstage/core-components@0.17.3 + - @backstage/catalog-client@1.10.1 + - @backstage/plugin-scaffolder-react@1.17.0 + - @backstage/core-plugin-api@1.10.8 + - @backstage/frontend-plugin-api@0.10.3 + - @backstage/plugin-catalog-react@1.19.0 + - @backstage/integration-react@1.2.8 + - @backstage/catalog-model@1.7.4 + - @backstage/core-compat-api@0.4.3 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + - @backstage/types@1.2.1 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-permission-react@0.4.35 + - @backstage/plugin-scaffolder-common@1.5.11 + +## 1.32.0-next.2 + +### Minor Changes + +- 3c59ece: **New Frontend System Only:** + The `Scaffolder` plugin is now responsible for providing an entity icon link extension to launch templates from the catalog entity page. + +### Patch Changes + +- b00c160: Remove React import form notification and scaffolder plugin +- 95a1d72: Added appropriate message when global templating function metadata is absent. +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/plugin-catalog-react@1.19.0-next.2 + - @backstage/frontend-plugin-api@0.10.3-next.1 + - @backstage/integration-react@1.2.7 + - @backstage/plugin-scaffolder-react@1.16.1-next.2 + - @backstage/catalog-client@1.10.1-next.0 + - @backstage/catalog-model@1.7.4 + - @backstage/core-compat-api@0.4.3-next.2 + - @backstage/core-plugin-api@1.10.7 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + - @backstage/types@1.2.1 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-permission-react@0.4.34 + - @backstage/plugin-scaffolder-common@1.5.11 + ## 1.31.1-next.1 ### Patch Changes diff --git a/plugins/scaffolder/package.json b/plugins/scaffolder/package.json index afcb93ff68..2cbe62cdbf 100644 --- a/plugins/scaffolder/package.json +++ b/plugins/scaffolder/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder", - "version": "1.31.1-next.1", + "version": "1.32.0", "description": "The Backstage plugin that helps you create new things", "backstage": { "role": "frontend-plugin", diff --git a/plugins/scaffolder/src/alpha/components/TemplateWizardPage/TemplateWizardPage.test.tsx b/plugins/scaffolder/src/alpha/components/TemplateWizardPage/TemplateWizardPage.test.tsx index d3a02931de..6836259dd8 100644 --- a/plugins/scaffolder/src/alpha/components/TemplateWizardPage/TemplateWizardPage.test.tsx +++ b/plugins/scaffolder/src/alpha/components/TemplateWizardPage/TemplateWizardPage.test.tsx @@ -21,7 +21,7 @@ import { renderInTestApp, TestApiRegistry, } from '@backstage/test-utils'; -import { act, fireEvent } from '@testing-library/react'; +import { fireEvent, waitFor } from '@testing-library/react'; import { ScaffolderApi, scaffolderApiRef, @@ -127,14 +127,10 @@ describe('TemplateWizardPage', () => { }); // Go to the final page - await act(async () => { - fireEvent.click(await findByRole('button', { name: 'Review' })); - }); + fireEvent.click(await findByRole('button', { name: 'Review' })); // Create the software - await act(async () => { - fireEvent.click(await findByRole('button', { name: 'Create' })); - }); + fireEvent.click(await findByRole('button', { name: 'Create' })); // The "Next Step" button should have fired an event expect(analyticsApi.captureEvent).toHaveBeenCalledWith( @@ -148,15 +144,20 @@ describe('TemplateWizardPage', () => { ); // And the "Create" button should have fired an event - expect(analyticsApi.captureEvent).toHaveBeenCalledWith( - expect.objectContaining({ - action: 'create', - subject: 'expected-name', - context: expect.objectContaining({ - entityRef: 'template:default/test', + await waitFor(() => + expect(analyticsApi.captureEvent).toHaveBeenCalledWith( + expect.objectContaining({ + action: 'create', + subject: 'Task has been created', + attributes: { + templateSteps: 1, + }, + context: expect.objectContaining({ + entityRef: 'template:default/test', + }), + value: 120, }), - value: 120, - }), + ), ); }); diff --git a/plugins/scaffolder/src/alpha/components/TemplateWizardPage/TemplateWizardPageContextMenu.tsx b/plugins/scaffolder/src/alpha/components/TemplateWizardPage/TemplateWizardPageContextMenu.tsx index 9a912f265f..c15795de2c 100644 --- a/plugins/scaffolder/src/alpha/components/TemplateWizardPage/TemplateWizardPageContextMenu.tsx +++ b/plugins/scaffolder/src/alpha/components/TemplateWizardPage/TemplateWizardPageContextMenu.tsx @@ -26,6 +26,7 @@ import MoreVert from '@material-ui/icons/MoreVert'; import { SyntheticEvent, useState } from 'react'; import { useTranslationRef } from '@backstage/core-plugin-api/alpha'; import { scaffolderTranslationRef } from '../../../translation'; +import { Link } from '@backstage/core-components'; const useStyles = makeStyles(theme => ({ button: { @@ -82,7 +83,7 @@ export function TemplateWizardPageContextMenu( transformOrigin={{ vertical: 'top', horizontal: 'right' }} > - window.open(editUrl, '_blank')}> + diff --git a/plugins/scaffolder/src/components/OngoingTask/ContextMenu.tsx b/plugins/scaffolder/src/components/OngoingTask/ContextMenu.tsx index 704d39a8fd..e1a5f37ddc 100644 --- a/plugins/scaffolder/src/components/OngoingTask/ContextMenu.tsx +++ b/plugins/scaffolder/src/components/OngoingTask/ContextMenu.tsx @@ -21,7 +21,6 @@ import MenuItem from '@material-ui/core/MenuItem'; import MenuList from '@material-ui/core/MenuList'; import Popover from '@material-ui/core/Popover'; import { makeStyles, Theme, useTheme } from '@material-ui/core/styles'; -import { useAsync } from '@react-hookz/web'; import Cancel from '@material-ui/icons/Cancel'; import Repeat from '@material-ui/icons/Repeat'; import Replay from '@material-ui/icons/Replay'; @@ -29,11 +28,8 @@ import Toc from '@material-ui/icons/Toc'; import ControlPointIcon from '@material-ui/icons/ControlPoint'; import MoreVert from '@material-ui/icons/MoreVert'; import { SyntheticEvent, useState } from 'react'; -import { useAnalytics, useApi } from '@backstage/core-plugin-api'; -import { scaffolderApiRef } from '@backstage/plugin-scaffolder-react'; import { usePermission } from '@backstage/plugin-permission-react'; import { - taskCancelPermission, taskReadPermission, taskCreatePermission, } from '@backstage/plugin-scaffolder-common/alpha'; @@ -50,7 +46,8 @@ type ContextMenuProps = { onStartOver?: () => void; onToggleLogs?: (state: boolean) => void; onToggleButtonBar?: (state: boolean) => void; - taskId?: string; + isCancelButtonDisabled: boolean; + onCancel: () => void; }; const useStyles = makeStyles(() => ({ @@ -70,27 +67,13 @@ export const ContextMenu = (props: ContextMenuProps) => { onStartOver, onToggleLogs, onToggleButtonBar, - taskId, } = props; const { getPageTheme } = useTheme(); const pageTheme = getPageTheme({ themeId: 'website' }); const classes = useStyles({ fontColor: pageTheme.fontColor }); - const scaffolderApi = useApi(scaffolderApiRef); - const analytics = useAnalytics(); const [anchorEl, setAnchorEl] = useState(); const { t } = useTranslationRef(scaffolderTranslationRef); - const [{ status: cancelStatus }, { execute: cancel }] = useAsync(async () => { - if (taskId) { - analytics.captureEvent('cancelled', 'Template has been cancelled'); - await scaffolderApi.cancelTask(taskId); - } - }); - - const { allowed: canCancelTask } = usePermission({ - permission: taskCancelPermission, - }); - const { allowed: canReadTask } = usePermission({ permission: taskReadPermission, }); @@ -171,12 +154,8 @@ export const ContextMenu = (props: ContextMenuProps) => { )} diff --git a/plugins/scaffolder/src/components/OngoingTask/OngoingTask.tsx b/plugins/scaffolder/src/components/OngoingTask/OngoingTask.tsx index b718a257b6..c9a119e4a1 100644 --- a/plugins/scaffolder/src/components/OngoingTask/OngoingTask.tsx +++ b/plugins/scaffolder/src/components/OngoingTask/OngoingTask.tsx @@ -32,7 +32,12 @@ import { useTaskEventStream, } from '@backstage/plugin-scaffolder-react'; import { selectedTemplateRouteRef } from '../../routes'; -import { useAnalytics, useApi, useRouteRef } from '@backstage/core-plugin-api'; +import { + AnalyticsContext, + useAnalytics, + useApi, + useRouteRef, +} from '@backstage/core-plugin-api'; import qs from 'qs'; import { ContextMenu } from './ContextMenu'; import { @@ -51,6 +56,7 @@ import { useTranslationRef } from '@backstage/core-plugin-api/alpha'; import { scaffolderTranslationRef } from '../../translation'; import { entityPresentationApiRef } from '@backstage/plugin-catalog-react'; import { default as reactUseAsync } from 'react-use/esm/useAsync'; +import { stringifyEntityRef } from '@backstage/catalog-model'; const useStyles = makeStyles(theme => ({ contentWrapper: { @@ -82,6 +88,36 @@ export const OngoingTask = (props: { }>; }) => { // todo(blam): check that task Id actually exists, and that it's valid. otherwise redirect to something more useful. + const { taskId } = useParams(); + const taskStream = useTaskEventStream(taskId!); + const { namespace, name } = + taskStream.task?.spec.templateInfo?.entity?.metadata ?? {}; + + return ( + + + + + + ); +}; + +function OngoingTaskContent(props: { + TemplateOutputsComponent?: ComponentType<{ + output?: ScaffolderTaskOutput; + }>; +}) { const { taskId } = useParams(); const templateRouteRef = useRouteRef(selectedTemplateRouteRef); const navigate = useNavigate(); @@ -183,7 +219,7 @@ export const OngoingTask = (props: { templateRouteRef, ]); - const [{ status: _ }, { execute: triggerRetry }] = useAsync(async () => { + const [, { execute: triggerRetry }] = useAsync(async () => { if (taskId) { analytics.captureEvent('retried', 'Template has been retried'); await scaffolderApi.retry?.(taskId); @@ -202,9 +238,11 @@ export const OngoingTask = (props: { const Outputs = props.TemplateOutputsComponent ?? DefaultTemplateOutputs; const cancelEnabled = !(taskStream.cancelled || taskStream.completed); + const isCancelButtonDisabled = + !cancelEnabled || cancelStatus !== 'not-executed' || !canCancelTask; return ( - + <>
@@ -316,6 +355,6 @@ export const OngoingTask = (props: { ) : null} -
+ ); -}; +} diff --git a/plugins/search-backend-module-catalog/CHANGELOG.md b/plugins/search-backend-module-catalog/CHANGELOG.md index 71c11e8986..14cb48f3a0 100644 --- a/plugins/search-backend-module-catalog/CHANGELOG.md +++ b/plugins/search-backend-module-catalog/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-search-backend-module-catalog +## 0.3.5 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.10.1 + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-permission-common@0.9.0 + - @backstage/plugin-search-backend-node@1.3.12 + - @backstage/plugin-search-common@1.2.18 + ## 0.3.5-next.1 ### Patch Changes diff --git a/plugins/search-backend-module-catalog/package.json b/plugins/search-backend-module-catalog/package.json index 12f3a1001c..46782aac2f 100644 --- a/plugins/search-backend-module-catalog/package.json +++ b/plugins/search-backend-module-catalog/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search-backend-module-catalog", - "version": "0.3.5-next.1", + "version": "0.3.5", "description": "A module for the search backend that exports catalog modules", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/search-backend-module-elasticsearch/CHANGELOG.md b/plugins/search-backend-module-elasticsearch/CHANGELOG.md index b51ab568bd..26cc4c5390 100644 --- a/plugins/search-backend-module-elasticsearch/CHANGELOG.md +++ b/plugins/search-backend-module-elasticsearch/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-search-backend-module-elasticsearch +## 1.7.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/integration-aws-node@0.1.16 + - @backstage/plugin-search-backend-node@1.3.12 + - @backstage/plugin-search-common@1.2.18 + ## 1.7.3-next.1 ### Patch Changes diff --git a/plugins/search-backend-module-elasticsearch/package.json b/plugins/search-backend-module-elasticsearch/package.json index a989e08cd9..cd1d8588d2 100644 --- a/plugins/search-backend-module-elasticsearch/package.json +++ b/plugins/search-backend-module-elasticsearch/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search-backend-module-elasticsearch", - "version": "1.7.3-next.1", + "version": "1.7.3", "description": "A module for the search backend that implements search using ElasticSearch", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/search-backend-module-explore/CHANGELOG.md b/plugins/search-backend-module-explore/CHANGELOG.md index 2b34facfe7..074df19408 100644 --- a/plugins/search-backend-module-explore/CHANGELOG.md +++ b/plugins/search-backend-module-explore/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-search-backend-module-explore +## 0.3.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/plugin-search-backend-node@1.3.12 + - @backstage/plugin-search-common@1.2.18 + ## 0.3.3-next.1 ### Patch Changes diff --git a/plugins/search-backend-module-explore/package.json b/plugins/search-backend-module-explore/package.json index b6c1f5aae3..e2d1bd81f7 100644 --- a/plugins/search-backend-module-explore/package.json +++ b/plugins/search-backend-module-explore/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search-backend-module-explore", - "version": "0.3.3-next.1", + "version": "0.3.3", "description": "A module for the search backend that exports explore modules", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/search-backend-module-pg/CHANGELOG.md b/plugins/search-backend-module-pg/CHANGELOG.md index 8334585cf9..d485ba36f7 100644 --- a/plugins/search-backend-module-pg/CHANGELOG.md +++ b/plugins/search-backend-module-pg/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-search-backend-module-pg +## 0.5.45 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/plugin-search-backend-node@1.3.12 + - @backstage/plugin-search-common@1.2.18 + ## 0.5.45-next.1 ### Patch Changes diff --git a/plugins/search-backend-module-pg/package.json b/plugins/search-backend-module-pg/package.json index 25533d1ad2..256f4d360b 100644 --- a/plugins/search-backend-module-pg/package.json +++ b/plugins/search-backend-module-pg/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search-backend-module-pg", - "version": "0.5.45-next.1", + "version": "0.5.45", "description": "A module for the search backend that implements search using PostgreSQL", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/search-backend-module-stack-overflow-collator/CHANGELOG.md b/plugins/search-backend-module-stack-overflow-collator/CHANGELOG.md index f0a9051be9..9e29c90271 100644 --- a/plugins/search-backend-module-stack-overflow-collator/CHANGELOG.md +++ b/plugins/search-backend-module-stack-overflow-collator/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-search-backend-module-stack-overflow-collator +## 0.3.10 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/plugin-search-backend-node@1.3.12 + - @backstage/plugin-search-common@1.2.18 + ## 0.3.10-next.1 ### Patch Changes diff --git a/plugins/search-backend-module-stack-overflow-collator/package.json b/plugins/search-backend-module-stack-overflow-collator/package.json index 01f1389f35..7fff2d51f8 100644 --- a/plugins/search-backend-module-stack-overflow-collator/package.json +++ b/plugins/search-backend-module-stack-overflow-collator/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search-backend-module-stack-overflow-collator", - "version": "0.3.10-next.1", + "version": "0.3.10", "description": "A module for the search backend that exports stack overflow modules", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/search-backend-module-techdocs/CHANGELOG.md b/plugins/search-backend-module-techdocs/CHANGELOG.md index 1f72c806e9..bafe7a3598 100644 --- a/plugins/search-backend-module-techdocs/CHANGELOG.md +++ b/plugins/search-backend-module-techdocs/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-search-backend-module-techdocs +## 0.4.3 + +### Patch Changes + +- b47ec38: Exports the default document collator for use in document transformation during search indexing. +- Updated dependencies + - @backstage/catalog-client@1.10.1 + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-permission-common@0.9.0 + - @backstage/plugin-search-backend-node@1.3.12 + - @backstage/plugin-search-common@1.2.18 + - @backstage/plugin-techdocs-node@1.13.4 + ## 0.4.3-next.1 ### Patch Changes diff --git a/plugins/search-backend-module-techdocs/package.json b/plugins/search-backend-module-techdocs/package.json index 3cec11b059..2d79594425 100644 --- a/plugins/search-backend-module-techdocs/package.json +++ b/plugins/search-backend-module-techdocs/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search-backend-module-techdocs", - "version": "0.4.3-next.1", + "version": "0.4.3", "description": "A module for the search backend that exports techdocs modules", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/search-backend-node/CHANGELOG.md b/plugins/search-backend-node/CHANGELOG.md index fe9bcce037..4011f37d73 100644 --- a/plugins/search-backend-node/CHANGELOG.md +++ b/plugins/search-backend-node/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-search-backend-node +## 1.3.12 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/plugin-permission-common@0.9.0 + - @backstage/plugin-search-common@1.2.18 + ## 1.3.12-next.1 ### Patch Changes diff --git a/plugins/search-backend-node/package.json b/plugins/search-backend-node/package.json index b54fc5b403..8a9bb61c1e 100644 --- a/plugins/search-backend-node/package.json +++ b/plugins/search-backend-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search-backend-node", - "version": "1.3.12-next.1", + "version": "1.3.12", "description": "A library for Backstage backend plugins that want to interact with the search backend plugin", "backstage": { "role": "node-library", diff --git a/plugins/search-backend/CHANGELOG.md b/plugins/search-backend/CHANGELOG.md index 5117375cb3..e82e398599 100644 --- a/plugins/search-backend/CHANGELOG.md +++ b/plugins/search-backend/CHANGELOG.md @@ -1,5 +1,38 @@ # @backstage/plugin-search-backend +## 2.0.3 + +### Patch Changes + +- c83cd8b: Fixed some circular or otherwise unclear imports +- Updated dependencies + - @backstage/backend-defaults@0.11.0 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/backend-openapi-utils@0.5.4 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/plugin-permission-common@0.9.0 + - @backstage/plugin-permission-node@0.10.1 + - @backstage/plugin-search-backend-node@1.3.12 + - @backstage/plugin-search-common@1.2.18 + +## 2.0.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.11.0-next.2 + - @backstage/backend-openapi-utils@0.5.4-next.1 + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/plugin-permission-common@0.9.0 + - @backstage/plugin-permission-node@0.10.1-next.1 + - @backstage/plugin-search-backend-node@1.3.12-next.1 + - @backstage/plugin-search-common@1.2.18 + ## 2.0.3-next.1 ### Patch Changes diff --git a/plugins/search-backend/package.json b/plugins/search-backend/package.json index 5226e3529f..02acb8dd77 100644 --- a/plugins/search-backend/package.json +++ b/plugins/search-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search-backend", - "version": "2.0.3-next.1", + "version": "2.0.3", "description": "The Backstage backend plugin that provides your backstage app with search", "backstage": { "role": "backend-plugin", diff --git a/plugins/search-backend/src/schema/openapi/generated/router.ts b/plugins/search-backend/src/schema/openapi/generated/router.ts index cf972d9f6c..a2510346ca 100644 --- a/plugins/search-backend/src/schema/openapi/generated/router.ts +++ b/plugins/search-backend/src/schema/openapi/generated/router.ts @@ -18,7 +18,7 @@ // * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * // ****************************************************************** import { createValidatedOpenApiRouterFromGeneratedEndpointMap } from '@backstage/backend-openapi-utils'; -import { EndpointMap } from './'; +import { EndpointMap } from './apis'; export const spec = { openapi: '3.0.3', diff --git a/plugins/search-react/CHANGELOG.md b/plugins/search-react/CHANGELOG.md index da0a5e1c0f..157a5664a9 100644 --- a/plugins/search-react/CHANGELOG.md +++ b/plugins/search-react/CHANGELOG.md @@ -1,5 +1,33 @@ # @backstage/plugin-search-react +## 1.9.1 + +### Patch Changes + +- 869fa46: SearchBar clear button support i18n +- Updated dependencies + - @backstage/core-components@0.17.3 + - @backstage/core-plugin-api@1.10.8 + - @backstage/frontend-plugin-api@0.10.3 + - @backstage/theme@0.6.6 + - @backstage/types@1.2.1 + - @backstage/version-bridge@1.0.11 + - @backstage/plugin-search-common@1.2.18 + +## 1.9.1-next.1 + +### Patch Changes + +- 869fa46: SearchBar clear button support i18n +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/frontend-plugin-api@0.10.3-next.1 + - @backstage/core-plugin-api@1.10.7 + - @backstage/theme@0.6.6 + - @backstage/types@1.2.1 + - @backstage/version-bridge@1.0.11 + - @backstage/plugin-search-common@1.2.18 + ## 1.9.1-next.0 ### Patch Changes diff --git a/plugins/search-react/package.json b/plugins/search-react/package.json index f157471d76..2d0617a6b3 100644 --- a/plugins/search-react/package.json +++ b/plugins/search-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search-react", - "version": "1.9.1-next.0", + "version": "1.9.1", "backstage": { "role": "web-library", "pluginId": "search", diff --git a/plugins/search/CHANGELOG.md b/plugins/search/CHANGELOG.md index 9b9f4a532d..7d6e4248de 100644 --- a/plugins/search/CHANGELOG.md +++ b/plugins/search/CHANGELOG.md @@ -1,5 +1,38 @@ # @backstage/plugin-search +## 1.4.27 + +### Patch Changes + +- 18c64e9: Added the `info.packageJson` option to the plugin instance for the new frontend system. +- Updated dependencies + - @backstage/core-components@0.17.3 + - @backstage/core-plugin-api@1.10.8 + - @backstage/frontend-plugin-api@0.10.3 + - @backstage/plugin-catalog-react@1.19.0 + - @backstage/plugin-search-react@1.9.1 + - @backstage/core-compat-api@0.4.3 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/version-bridge@1.0.11 + - @backstage/plugin-search-common@1.2.18 + +## 1.4.27-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/plugin-catalog-react@1.19.0-next.2 + - @backstage/plugin-search-react@1.9.1-next.1 + - @backstage/frontend-plugin-api@0.10.3-next.1 + - @backstage/core-compat-api@0.4.3-next.2 + - @backstage/core-plugin-api@1.10.7 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/version-bridge@1.0.11 + - @backstage/plugin-search-common@1.2.18 + ## 1.4.27-next.1 ### Patch Changes diff --git a/plugins/search/package.json b/plugins/search/package.json index ca31eb1244..56382bc5ee 100644 --- a/plugins/search/package.json +++ b/plugins/search/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search", - "version": "1.4.27-next.1", + "version": "1.4.27", "description": "The Backstage plugin that provides your backstage app with search", "backstage": { "role": "frontend-plugin", diff --git a/plugins/signals-backend/CHANGELOG.md b/plugins/signals-backend/CHANGELOG.md index 3f09417863..daa8f03014 100644 --- a/plugins/signals-backend/CHANGELOG.md +++ b/plugins/signals-backend/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-signals-backend +## 0.3.5 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/types@1.2.1 + - @backstage/plugin-events-node@0.4.12 + - @backstage/plugin-signals-node@0.1.21 + ## 0.3.5-next.1 ### Patch Changes diff --git a/plugins/signals-backend/package.json b/plugins/signals-backend/package.json index cb9146c9c4..04dcdc60d2 100644 --- a/plugins/signals-backend/package.json +++ b/plugins/signals-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-signals-backend", - "version": "0.3.5-next.1", + "version": "0.3.5", "backstage": { "role": "backend-plugin", "pluginId": "signals", diff --git a/plugins/signals-node/CHANGELOG.md b/plugins/signals-node/CHANGELOG.md index 8e753081d8..d24f1cc0b1 100644 --- a/plugins/signals-node/CHANGELOG.md +++ b/plugins/signals-node/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-signals-node +## 0.1.21 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/config@1.3.2 + - @backstage/types@1.2.1 + - @backstage/plugin-events-node@0.4.12 + ## 0.1.21-next.1 ### Patch Changes diff --git a/plugins/signals-node/package.json b/plugins/signals-node/package.json index 4cb5c08f79..15472a930d 100644 --- a/plugins/signals-node/package.json +++ b/plugins/signals-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-signals-node", - "version": "0.1.21-next.1", + "version": "0.1.21", "description": "Node.js library for the signals plugin", "backstage": { "role": "node-library", diff --git a/plugins/signals-react/CHANGELOG.md b/plugins/signals-react/CHANGELOG.md index 43aee22b12..223dfed79c 100644 --- a/plugins/signals-react/CHANGELOG.md +++ b/plugins/signals-react/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-signals-react +## 0.0.14 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.10.8 + - @backstage/types@1.2.1 + ## 0.0.13 ### Patch Changes diff --git a/plugins/signals-react/package.json b/plugins/signals-react/package.json index d1fa5f9392..d8bf9d4e0f 100644 --- a/plugins/signals-react/package.json +++ b/plugins/signals-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-signals-react", - "version": "0.0.13", + "version": "0.0.14", "description": "Web library for the signals plugin", "backstage": { "role": "web-library", diff --git a/plugins/signals/CHANGELOG.md b/plugins/signals/CHANGELOG.md index db16d0ade5..ce4971a5d9 100644 --- a/plugins/signals/CHANGELOG.md +++ b/plugins/signals/CHANGELOG.md @@ -1,5 +1,30 @@ # @backstage/plugin-signals +## 0.0.20 + +### Patch Changes + +- 18c64e9: Added the `info.packageJson` option to the plugin instance for the new frontend system. +- Updated dependencies + - @backstage/core-components@0.17.3 + - @backstage/core-plugin-api@1.10.8 + - @backstage/frontend-plugin-api@0.10.3 + - @backstage/theme@0.6.6 + - @backstage/types@1.2.1 + - @backstage/plugin-signals-react@0.0.14 + +## 0.0.20-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/frontend-plugin-api@0.10.3-next.1 + - @backstage/core-plugin-api@1.10.7 + - @backstage/theme@0.6.6 + - @backstage/types@1.2.1 + - @backstage/plugin-signals-react@0.0.13 + ## 0.0.20-next.0 ### Patch Changes diff --git a/plugins/signals/package.json b/plugins/signals/package.json index 5a5c17a82f..dd025dfbb2 100644 --- a/plugins/signals/package.json +++ b/plugins/signals/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-signals", - "version": "0.0.20-next.0", + "version": "0.0.20", "backstage": { "role": "frontend-plugin", "pluginId": "signals", diff --git a/plugins/techdocs-addons-test-utils/CHANGELOG.md b/plugins/techdocs-addons-test-utils/CHANGELOG.md index be8b0d5920..1df73776db 100644 --- a/plugins/techdocs-addons-test-utils/CHANGELOG.md +++ b/plugins/techdocs-addons-test-utils/CHANGELOG.md @@ -1,5 +1,35 @@ # @backstage/plugin-techdocs-addons-test-utils +## 1.0.49 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs@1.13.0 + - @backstage/plugin-catalog@1.31.0 + - @backstage/core-plugin-api@1.10.8 + - @backstage/plugin-catalog-react@1.19.0 + - @backstage/plugin-techdocs-react@1.3.0 + - @backstage/plugin-search-react@1.9.1 + - @backstage/integration-react@1.2.8 + - @backstage/core-app-api@1.17.1 + - @backstage/test-utils@1.7.9 + +## 1.0.49-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog@1.31.0-next.2 + - @backstage/plugin-techdocs@1.13.0-next.2 + - @backstage/plugin-catalog-react@1.19.0-next.2 + - @backstage/plugin-search-react@1.9.1-next.1 + - @backstage/integration-react@1.2.7 + - @backstage/plugin-techdocs-react@1.3.0-next.1 + - @backstage/core-app-api@1.17.0 + - @backstage/core-plugin-api@1.10.7 + - @backstage/test-utils@1.7.8 + ## 1.0.49-next.1 ### Patch Changes diff --git a/plugins/techdocs-addons-test-utils/package.json b/plugins/techdocs-addons-test-utils/package.json index 668f2bea88..c10539afeb 100644 --- a/plugins/techdocs-addons-test-utils/package.json +++ b/plugins/techdocs-addons-test-utils/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-techdocs-addons-test-utils", - "version": "1.0.49-next.1", + "version": "1.0.49", "backstage": { "role": "web-library", "pluginId": "techdocs-addons", diff --git a/plugins/techdocs-backend/CHANGELOG.md b/plugins/techdocs-backend/CHANGELOG.md index a24b2477ca..f4d3b62cca 100644 --- a/plugins/techdocs-backend/CHANGELOG.md +++ b/plugins/techdocs-backend/CHANGELOG.md @@ -1,5 +1,43 @@ # @backstage/plugin-techdocs-backend +## 2.0.3 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.10.1 + - @backstage/backend-defaults@0.11.0 + - @backstage/plugin-catalog-node@1.17.1 + - @backstage/plugin-search-backend-module-techdocs@0.4.3 + - @backstage/plugin-techdocs-common@0.1.1 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-permission-common@0.9.0 + - @backstage/plugin-techdocs-node@1.13.4 + +## 2.0.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.11.0-next.2 + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/catalog-client@1.10.1-next.0 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + - @backstage/plugin-catalog-common@1.1.4 + - @backstage/plugin-catalog-node@1.17.1-next.1 + - @backstage/plugin-permission-common@0.9.0 + - @backstage/plugin-search-backend-module-techdocs@0.4.3-next.1 + - @backstage/plugin-techdocs-common@0.1.1-next.0 + - @backstage/plugin-techdocs-node@1.13.4-next.1 + ## 2.0.3-next.1 ### Patch Changes diff --git a/plugins/techdocs-backend/package.json b/plugins/techdocs-backend/package.json index afb3694630..00135b3535 100644 --- a/plugins/techdocs-backend/package.json +++ b/plugins/techdocs-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-techdocs-backend", - "version": "2.0.3-next.1", + "version": "2.0.3", "description": "The Backstage backend plugin that renders technical documentation for your components", "backstage": { "role": "backend-plugin", diff --git a/plugins/techdocs-common/CHANGELOG.md b/plugins/techdocs-common/CHANGELOG.md index bf2a3300ea..7e2568ab78 100644 --- a/plugins/techdocs-common/CHANGELOG.md +++ b/plugins/techdocs-common/CHANGELOG.md @@ -1,5 +1,11 @@ # @backstage/plugin-techdocs-common +## 0.1.1 + +### Patch Changes + +- ec7b35d: Introduced `backstage.io/techdocs-entity-path` annotation which allows deep linking into another entities TechDocs in conjunction with `backstage.io/techdocs-entity`. + ## 0.1.1-next.0 ### Patch Changes diff --git a/plugins/techdocs-common/package.json b/plugins/techdocs-common/package.json index ef0a6c613e..1f43a48f13 100644 --- a/plugins/techdocs-common/package.json +++ b/plugins/techdocs-common/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-techdocs-common", - "version": "0.1.1-next.0", + "version": "0.1.1", "description": "Common functionality for TechDocs", "backstage": { "role": "common-library", diff --git a/plugins/techdocs-module-addons-contrib/CHANGELOG.md b/plugins/techdocs-module-addons-contrib/CHANGELOG.md index 978d09e195..6cb56e3184 100644 --- a/plugins/techdocs-module-addons-contrib/CHANGELOG.md +++ b/plugins/techdocs-module-addons-contrib/CHANGELOG.md @@ -1,5 +1,30 @@ # @backstage/plugin-techdocs-module-addons-contrib +## 1.1.25 + +### Patch Changes + +- 9dde3ba: Improved Keyboard accessibility in techdocs. +- Updated dependencies + - @backstage/core-components@0.17.3 + - @backstage/core-plugin-api@1.10.8 + - @backstage/frontend-plugin-api@0.10.3 + - @backstage/plugin-techdocs-react@1.3.0 + - @backstage/integration-react@1.2.8 + - @backstage/integration@1.17.0 + +## 1.1.25-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/frontend-plugin-api@0.10.3-next.1 + - @backstage/integration-react@1.2.7 + - @backstage/plugin-techdocs-react@1.3.0-next.1 + - @backstage/core-plugin-api@1.10.7 + - @backstage/integration@1.17.0 + ## 1.1.25-next.1 ### Patch Changes diff --git a/plugins/techdocs-module-addons-contrib/package.json b/plugins/techdocs-module-addons-contrib/package.json index b0bbd9c36f..bede6d623c 100644 --- a/plugins/techdocs-module-addons-contrib/package.json +++ b/plugins/techdocs-module-addons-contrib/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-techdocs-module-addons-contrib", - "version": "1.1.25-next.1", + "version": "1.1.25", "description": "Plugin module for contributed TechDocs Addons", "backstage": { "role": "frontend-plugin-module", diff --git a/plugins/techdocs-node/CHANGELOG.md b/plugins/techdocs-node/CHANGELOG.md index 85a11b495c..c44b7fca9e 100644 --- a/plugins/techdocs-node/CHANGELOG.md +++ b/plugins/techdocs-node/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-techdocs-node +## 1.13.4 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs-common@0.1.1 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + - @backstage/integration-aws-node@0.1.16 + - @backstage/plugin-search-common@1.2.18 + ## 1.13.4-next.1 ### Patch Changes diff --git a/plugins/techdocs-node/package.json b/plugins/techdocs-node/package.json index 25aaa92014..9616553217 100644 --- a/plugins/techdocs-node/package.json +++ b/plugins/techdocs-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-techdocs-node", - "version": "1.13.4-next.1", + "version": "1.13.4", "description": "Common node.js functionalities for TechDocs, to be shared between techdocs-backend plugin and techdocs-cli", "backstage": { "role": "node-library", diff --git a/plugins/techdocs-react/CHANGELOG.md b/plugins/techdocs-react/CHANGELOG.md index 5357f4c90d..bc8c2a7bff 100644 --- a/plugins/techdocs-react/CHANGELOG.md +++ b/plugins/techdocs-react/CHANGELOG.md @@ -1,5 +1,35 @@ # @backstage/plugin-techdocs-react +## 1.3.0 + +### Minor Changes + +- ec7b35d: Introduced `backstage.io/techdocs-entity-path` annotation which allows deep linking into another entities TechDocs in conjunction with `backstage.io/techdocs-entity`. + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3 + - @backstage/core-plugin-api@1.10.8 + - @backstage/frontend-plugin-api@0.10.3 + - @backstage/plugin-techdocs-common@0.1.1 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/version-bridge@1.0.11 + +## 1.3.0-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/frontend-plugin-api@0.10.3-next.1 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/core-plugin-api@1.10.7 + - @backstage/version-bridge@1.0.11 + - @backstage/plugin-techdocs-common@0.1.1-next.0 + ## 1.3.0-next.0 ### Minor Changes diff --git a/plugins/techdocs-react/package.json b/plugins/techdocs-react/package.json index 618af87698..94494a7266 100644 --- a/plugins/techdocs-react/package.json +++ b/plugins/techdocs-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-techdocs-react", - "version": "1.3.0-next.0", + "version": "1.3.0", "description": "Shared frontend utilities for TechDocs and Addons", "backstage": { "role": "web-library", diff --git a/plugins/techdocs/CHANGELOG.md b/plugins/techdocs/CHANGELOG.md index 9b70f65408..8ff3635285 100644 --- a/plugins/techdocs/CHANGELOG.md +++ b/plugins/techdocs/CHANGELOG.md @@ -1,5 +1,64 @@ # @backstage/plugin-techdocs +## 1.13.0 + +### Minor Changes + +- 3c59ece: **New Frontend System Only:** + The `TechDocs` plugin is now responsible for providing an entity icon link extension to read documentation from the catalog entity page. +- ec7b35d: Introduced `backstage.io/techdocs-entity-path` annotation which allows deep linking into another entities TechDocs in conjunction with `backstage.io/techdocs-entity`. + +### Patch Changes + +- 18c64e9: Added the `info.packageJson` option to the plugin instance for the new frontend system. +- 9dde3ba: Improved Keyboard accessibility in techdocs. +- Updated dependencies + - @backstage/core-components@0.17.3 + - @backstage/catalog-client@1.10.1 + - @backstage/core-plugin-api@1.10.8 + - @backstage/frontend-plugin-api@0.10.3 + - @backstage/plugin-catalog-react@1.19.0 + - @backstage/plugin-techdocs-react@1.3.0 + - @backstage/plugin-techdocs-common@0.1.1 + - @backstage/plugin-search-react@1.9.1 + - @backstage/integration-react@1.2.8 + - @backstage/plugin-auth-react@0.1.16 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/core-compat-api@0.4.3 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + - @backstage/theme@0.6.6 + - @backstage/plugin-search-common@1.2.18 + +## 1.13.0-next.2 + +### Minor Changes + +- 3c59ece: **New Frontend System Only:** + The `TechDocs` plugin is now responsible for providing an entity icon link extension to read documentation from the catalog entity page. + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/plugin-catalog-react@1.19.0-next.2 + - @backstage/plugin-search-react@1.9.1-next.1 + - @backstage/frontend-plugin-api@0.10.3-next.1 + - @backstage/integration-react@1.2.7 + - @backstage/plugin-auth-react@0.1.16-next.0 + - @backstage/plugin-techdocs-react@1.3.0-next.1 + - @backstage/catalog-client@1.10.1-next.0 + - @backstage/catalog-model@1.7.4 + - @backstage/config@1.3.2 + - @backstage/core-compat-api@0.4.3-next.2 + - @backstage/core-plugin-api@1.10.7 + - @backstage/errors@1.2.7 + - @backstage/integration@1.17.0 + - @backstage/theme@0.6.6 + - @backstage/plugin-search-common@1.2.18 + - @backstage/plugin-techdocs-common@0.1.1-next.0 + ## 1.13.0-next.1 ### Patch Changes diff --git a/plugins/techdocs/package.json b/plugins/techdocs/package.json index c79dadca05..40ed4856bf 100644 --- a/plugins/techdocs/package.json +++ b/plugins/techdocs/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-techdocs", - "version": "1.13.0-next.1", + "version": "1.13.0", "description": "The Backstage plugin that renders technical documentation for your components", "backstage": { "role": "frontend-plugin", diff --git a/plugins/user-settings-backend/CHANGELOG.md b/plugins/user-settings-backend/CHANGELOG.md index 679a2ef2b8..2139fc3f72 100644 --- a/plugins/user-settings-backend/CHANGELOG.md +++ b/plugins/user-settings-backend/CHANGELOG.md @@ -1,5 +1,31 @@ # @backstage/plugin-user-settings-backend +## 0.3.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.11.0 + - @backstage/plugin-auth-node@0.6.4 + - @backstage/backend-plugin-api@1.4.0 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/plugin-signals-node@0.1.21 + - @backstage/plugin-user-settings-common@0.0.1 + +## 0.3.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.11.0-next.2 + - @backstage/backend-plugin-api@1.4.0-next.1 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.1 + - @backstage/plugin-auth-node@0.6.4-next.1 + - @backstage/plugin-signals-node@0.1.21-next.1 + - @backstage/plugin-user-settings-common@0.0.1 + ## 0.3.3-next.1 ### Patch Changes diff --git a/plugins/user-settings-backend/package.json b/plugins/user-settings-backend/package.json index b5e513ede8..992f3ce5ed 100644 --- a/plugins/user-settings-backend/package.json +++ b/plugins/user-settings-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-user-settings-backend", - "version": "0.3.3-next.1", + "version": "0.3.3", "description": "The Backstage backend plugin to manage user settings", "backstage": { "role": "backend-plugin", diff --git a/plugins/user-settings/CHANGELOG.md b/plugins/user-settings/CHANGELOG.md index bc936a1007..036af600c6 100644 --- a/plugins/user-settings/CHANGELOG.md +++ b/plugins/user-settings/CHANGELOG.md @@ -1,5 +1,44 @@ # @backstage/plugin-user-settings +## 0.8.23 + +### Patch Changes + +- 18c64e9: Added the `info.packageJson` option to the plugin instance for the new frontend system. +- ab6d3dd: Add some translation to user-setting plugin +- c83cd8b: Fixed some circular or otherwise unclear imports +- Updated dependencies + - @backstage/core-components@0.17.3 + - @backstage/core-plugin-api@1.10.8 + - @backstage/frontend-plugin-api@0.10.3 + - @backstage/plugin-catalog-react@1.19.0 + - @backstage/catalog-model@1.7.4 + - @backstage/core-app-api@1.17.1 + - @backstage/core-compat-api@0.4.3 + - @backstage/errors@1.2.7 + - @backstage/theme@0.6.6 + - @backstage/types@1.2.1 + - @backstage/plugin-signals-react@0.0.14 + - @backstage/plugin-user-settings-common@0.0.1 + +## 0.8.23-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.17.3-next.0 + - @backstage/plugin-catalog-react@1.19.0-next.2 + - @backstage/frontend-plugin-api@0.10.3-next.1 + - @backstage/catalog-model@1.7.4 + - @backstage/core-app-api@1.17.0 + - @backstage/core-compat-api@0.4.3-next.2 + - @backstage/core-plugin-api@1.10.7 + - @backstage/errors@1.2.7 + - @backstage/theme@0.6.6 + - @backstage/types@1.2.1 + - @backstage/plugin-signals-react@0.0.13 + - @backstage/plugin-user-settings-common@0.0.1 + ## 0.8.23-next.1 ### Patch Changes diff --git a/plugins/user-settings/package.json b/plugins/user-settings/package.json index 2acac5406c..2ae1c9991d 100644 --- a/plugins/user-settings/package.json +++ b/plugins/user-settings/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-user-settings", - "version": "0.8.23-next.1", + "version": "0.8.23", "description": "A Backstage plugin that provides a settings page", "backstage": { "role": "frontend-plugin", diff --git a/plugins/user-settings/src/index.ts b/plugins/user-settings/src/index.ts index bc878ecbb3..e64d3c926c 100644 --- a/plugins/user-settings/src/index.ts +++ b/plugins/user-settings/src/index.ts @@ -26,4 +26,4 @@ export { userSettingsPlugin as plugin, UserSettingsPage, } from './plugin'; -export * from './components/'; +export * from './components'; diff --git a/storybook/yarn.lock b/storybook/yarn.lock index 96cf1e99bb..d7e83584d1 100644 --- a/storybook/yarn.lock +++ b/storybook/yarn.lock @@ -1552,12 +1552,12 @@ __metadata: linkType: hard "@types/react@npm:^18.0.0": - version: 18.3.21 - resolution: "@types/react@npm:18.3.21" + version: 18.3.23 + resolution: "@types/react@npm:18.3.23" dependencies: "@types/prop-types": "npm:*" csstype: "npm:^3.0.2" - checksum: 10/89adc2fe391fd63b620db0aaa10b2be89fad338039415fd748e60c962e47bf2b0f1897cb5226f181eda963f37a1c8ac1bf0b3b29a0e35313bacd0355e5d6c736 + checksum: 10/4b965dffe34a1f8aac8e2d7e976f113373f38134f9e37239f7e75d7ac6b3c2e1333a8df21febf1fe7749640f8de5708f7668cdfc70bffebda1cc4d3346724fd5 languageName: node linkType: hard diff --git a/yarn.lock b/yarn.lock index d8736591ea..c3e37b0ac0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3602,6 +3602,7 @@ __metadata: cron: "npm:^3.0.0" express: "npm:^4.17.1" express-promise-router: "npm:^4.1.0" + express-rate-limit: "npm:^7.5.0" fs-extra: "npm:^11.2.0" git-url-parse: "npm:^15.0.0" helmet: "npm:^6.0.0" @@ -3624,6 +3625,7 @@ __metadata: pg: "npm:^8.11.3" pg-connection-string: "npm:^2.3.0" pg-format: "npm:^1.0.4" + rate-limit-redis: "npm:^4.2.0" raw-body: "npm:^2.4.1" selfsigned: "npm:^2.0.0" supertest: "npm:^7.0.0" @@ -3722,26 +3724,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/backend-plugin-api@npm:^1.0.0, @backstage/backend-plugin-api@npm:^1.1.1, @backstage/backend-plugin-api@npm:^1.3.1": - version: 1.3.1 - resolution: "@backstage/backend-plugin-api@npm:1.3.1" - dependencies: - "@backstage/cli-common": "npm:^0.1.15" - "@backstage/config": "npm:^1.3.2" - "@backstage/errors": "npm:^1.2.7" - "@backstage/plugin-auth-node": "npm:^0.6.3" - "@backstage/plugin-permission-common": "npm:^0.9.0" - "@backstage/plugin-permission-node": "npm:^0.10.0" - "@backstage/types": "npm:^1.2.1" - "@types/express": "npm:^4.17.6" - "@types/luxon": "npm:^3.0.0" - knex: "npm:^3.0.0" - luxon: "npm:^3.0.0" - checksum: 10/c78a0cd73c9e2ab3f611e62b1570b83fd496f501616caf00877c5191a7c431671f66f77d6e7fd2a35982915f8cb1b69a85cf7d26e3f236a28f709a6ae7af8eaf - languageName: node - linkType: hard - -"@backstage/backend-plugin-api@workspace:^, @backstage/backend-plugin-api@workspace:packages/backend-plugin-api": +"@backstage/backend-plugin-api@npm:^1.0.0, @backstage/backend-plugin-api@npm:^1.1.1, @backstage/backend-plugin-api@workspace:^, @backstage/backend-plugin-api@workspace:packages/backend-plugin-api": version: 0.0.0-use.local resolution: "@backstage/backend-plugin-api@workspace:packages/backend-plugin-api" dependencies: @@ -3776,6 +3759,7 @@ __metadata: "@backstage/errors": "workspace:^" "@backstage/plugin-auth-node": "workspace:^" "@backstage/plugin-events-node": "workspace:^" + "@backstage/plugin-permission-common": "workspace:^" "@backstage/types": "workspace:^" "@keyv/memcache": "npm:^2.0.1" "@keyv/redis": "npm:^4.0.1" @@ -3800,6 +3784,8 @@ __metadata: textextensions: "npm:^5.16.0" uuid: "npm:^11.0.0" yn: "npm:^4.0.0" + zod: "npm:^3.22.4" + zod-to-json-schema: "npm:^3.20.4" languageName: unknown linkType: soft @@ -3830,6 +3816,7 @@ __metadata: lightningcss: "npm:^1.29.1" mini-css-extract-plugin: "npm:^2.9.2" react: "npm:^18.0.2" + react-aria-components: "npm:^1.10.1" react-dom: "npm:^18.0.2" react-router-dom: "npm:^6.3.0" storybook: "npm:^8.6.12" @@ -3844,19 +3831,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/catalog-client@npm:^1.10.0, @backstage/catalog-client@npm:^1.9.1": - version: 1.10.0 - resolution: "@backstage/catalog-client@npm:1.10.0" - dependencies: - "@backstage/catalog-model": "npm:^1.7.4" - "@backstage/errors": "npm:^1.2.7" - cross-fetch: "npm:^4.0.0" - uri-template: "npm:^2.0.0" - checksum: 10/565512931ef340c272ebbffcac7c5f54348ed67a73be80cdecb8768c547a1da41c72b02c0830f3036a06edbc8c77b9720ee5f1f498b2308f799fd409bb4bbbe1 - languageName: node - linkType: hard - -"@backstage/catalog-client@workspace:^, @backstage/catalog-client@workspace:packages/catalog-client": +"@backstage/catalog-client@npm:^1.9.1, @backstage/catalog-client@workspace:^, @backstage/catalog-client@workspace:packages/catalog-client": version: 0.0.0-use.local resolution: "@backstage/catalog-client@workspace:packages/catalog-client" dependencies: @@ -3869,7 +3844,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/catalog-model@npm:^1.4.3, @backstage/catalog-model@npm:^1.7.3, @backstage/catalog-model@npm:^1.7.4, @backstage/catalog-model@workspace:^, @backstage/catalog-model@workspace:packages/catalog-model": +"@backstage/catalog-model@npm:^1.4.3, @backstage/catalog-model@npm:^1.7.3, @backstage/catalog-model@workspace:^, @backstage/catalog-model@workspace:packages/catalog-model": version: 0.0.0-use.local resolution: "@backstage/catalog-model@workspace:packages/catalog-model" dependencies: @@ -3884,7 +3859,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/cli-common@npm:^0.1.14, @backstage/cli-common@npm:^0.1.15, @backstage/cli-common@workspace:^, @backstage/cli-common@workspace:packages/cli-common": +"@backstage/cli-common@npm:^0.1.14, @backstage/cli-common@workspace:^, @backstage/cli-common@workspace:packages/cli-common": version: 0.0.0-use.local resolution: "@backstage/cli-common@workspace:packages/cli-common" dependencies: @@ -4078,7 +4053,6 @@ __metadata: optional: true bin: backstage-cli: bin/backstage-cli - backstage-cli-alpha: bin/backstage-cli-alpha languageName: unknown linkType: soft @@ -4139,7 +4113,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/core-app-api@npm:^1.17.0, @backstage/core-app-api@workspace:^, @backstage/core-app-api@workspace:packages/core-app-api": +"@backstage/core-app-api@workspace:^, @backstage/core-app-api@workspace:packages/core-app-api": version: 0.0.0-use.local resolution: "@backstage/core-app-api@workspace:packages/core-app-api" dependencies: @@ -4183,27 +4157,6 @@ __metadata: languageName: unknown linkType: soft -"@backstage/core-compat-api@npm:^0.4.2": - version: 0.4.2 - resolution: "@backstage/core-compat-api@npm:0.4.2" - dependencies: - "@backstage/core-plugin-api": "npm:^1.10.7" - "@backstage/frontend-plugin-api": "npm:^0.10.2" - "@backstage/plugin-catalog-react": "npm:^1.18.0" - "@backstage/version-bridge": "npm:^1.0.11" - lodash: "npm:^4.17.21" - peerDependencies: - "@types/react": ^17.0.0 || ^18.0.0 - react: ^17.0.0 || ^18.0.0 - react-dom: ^17.0.0 || ^18.0.0 - react-router-dom: ^6.3.0 - peerDependenciesMeta: - "@types/react": - optional: true - checksum: 10/7e93c3ff7a9979ee8cb0ab582e66bd0febb5995c91cc0545473e9e86fc75c1ebbb0a24a901e120d7e4ecf122bbb31de1b4f8fc78c7da5f6d84daa9d6b9194035 - languageName: node - linkType: hard - "@backstage/core-compat-api@workspace:^, @backstage/core-compat-api@workspace:packages/core-compat-api": version: 0.0.0-use.local resolution: "@backstage/core-compat-api@workspace:packages/core-compat-api" @@ -4344,7 +4297,7 @@ __metadata: languageName: node linkType: hard -"@backstage/core-components@npm:^0.17.1, @backstage/core-components@npm:^0.17.2, @backstage/core-components@workspace:^, @backstage/core-components@workspace:packages/core-components": +"@backstage/core-components@npm:^0.17.1, @backstage/core-components@workspace:^, @backstage/core-components@workspace:packages/core-components": version: 0.0.0-use.local resolution: "@backstage/core-components@workspace:packages/core-components" dependencies: @@ -4422,7 +4375,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/core-plugin-api@npm:^1.10.0, @backstage/core-plugin-api@npm:^1.10.6, @backstage/core-plugin-api@npm:^1.10.7, @backstage/core-plugin-api@npm:^1.8.2, @backstage/core-plugin-api@workspace:^, @backstage/core-plugin-api@workspace:packages/core-plugin-api": +"@backstage/core-plugin-api@npm:^1.10.0, @backstage/core-plugin-api@npm:^1.10.6, @backstage/core-plugin-api@npm:^1.8.2, @backstage/core-plugin-api@workspace:^, @backstage/core-plugin-api@workspace:packages/core-plugin-api": version: 0.0.0-use.local resolution: "@backstage/core-plugin-api@workspace:packages/core-plugin-api" dependencies: @@ -4543,7 +4496,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/eslint-plugin@workspace:^, @backstage/eslint-plugin@workspace:packages/eslint-plugin": +"@backstage/eslint-plugin@workspace:*, @backstage/eslint-plugin@workspace:^, @backstage/eslint-plugin@workspace:packages/eslint-plugin": version: 0.0.0-use.local resolution: "@backstage/eslint-plugin@workspace:packages/eslint-plugin" dependencies: @@ -4555,32 +4508,6 @@ __metadata: languageName: unknown linkType: soft -"@backstage/frontend-app-api@npm:^0.11.2": - version: 0.11.2 - resolution: "@backstage/frontend-app-api@npm:0.11.2" - dependencies: - "@backstage/config": "npm:^1.3.2" - "@backstage/core-app-api": "npm:^1.17.0" - "@backstage/core-plugin-api": "npm:^1.10.7" - "@backstage/errors": "npm:^1.2.7" - "@backstage/frontend-defaults": "npm:^0.2.2" - "@backstage/frontend-plugin-api": "npm:^0.10.2" - "@backstage/types": "npm:^1.2.1" - "@backstage/version-bridge": "npm:^1.0.11" - lodash: "npm:^4.17.21" - zod: "npm:^3.22.4" - peerDependencies: - "@types/react": ^17.0.0 || ^18.0.0 - react: ^17.0.0 || ^18.0.0 - react-dom: ^17.0.0 || ^18.0.0 - react-router-dom: ^6.3.0 - peerDependenciesMeta: - "@types/react": - optional: true - checksum: 10/06cf128df60b0322c07c14853146da5096625d58a344555571a65ead221f03dc1f4e2fe7da364b2afec010be13a4d4a4574060a3f65c023bdcdc93d20d09c33d - languageName: node - linkType: hard - "@backstage/frontend-app-api@workspace:^, @backstage/frontend-app-api@workspace:packages/frontend-app-api": version: 0.0.0-use.local resolution: "@backstage/frontend-app-api@workspace:packages/frontend-app-api" @@ -4615,28 +4542,6 @@ __metadata: languageName: unknown linkType: soft -"@backstage/frontend-defaults@npm:^0.2.2": - version: 0.2.2 - resolution: "@backstage/frontend-defaults@npm:0.2.2" - dependencies: - "@backstage/config": "npm:^1.3.2" - "@backstage/errors": "npm:^1.2.7" - "@backstage/frontend-app-api": "npm:^0.11.2" - "@backstage/frontend-plugin-api": "npm:^0.10.2" - "@backstage/plugin-app": "npm:^0.1.9" - "@react-hookz/web": "npm:^24.0.0" - peerDependencies: - "@types/react": ^17.0.0 || ^18.0.0 - react: ^17.0.0 || ^18.0.0 - react-dom: ^17.0.0 || ^18.0.0 - react-router-dom: ^6.3.0 - peerDependenciesMeta: - "@types/react": - optional: true - checksum: 10/23e6156314cb80d9cc1128ee3ad2d3afee3e2a6e88c049853b19133fc95e75f4361e735f26903e44fa62b29d39df5381c53200799a8cc3b3fd0943682a5e51f5 - languageName: node - linkType: hard - "@backstage/frontend-defaults@workspace:^, @backstage/frontend-defaults@workspace:packages/frontend-defaults": version: 0.0.0-use.local resolution: "@backstage/frontend-defaults@workspace:packages/frontend-defaults" @@ -4698,30 +4603,6 @@ __metadata: languageName: unknown linkType: soft -"@backstage/frontend-plugin-api@npm:^0.10.2": - version: 0.10.2 - resolution: "@backstage/frontend-plugin-api@npm:0.10.2" - dependencies: - "@backstage/core-components": "npm:^0.17.2" - "@backstage/core-plugin-api": "npm:^1.10.7" - "@backstage/types": "npm:^1.2.1" - "@backstage/version-bridge": "npm:^1.0.11" - "@material-ui/core": "npm:^4.12.4" - lodash: "npm:^4.17.21" - zod: "npm:^3.22.4" - zod-to-json-schema: "npm:^3.21.4" - peerDependencies: - "@types/react": ^17.0.0 || ^18.0.0 - react: ^17.0.0 || ^18.0.0 - react-dom: ^17.0.0 || ^18.0.0 - react-router-dom: ^6.3.0 - peerDependenciesMeta: - "@types/react": - optional: true - checksum: 10/4f01cf2ae8352dd8b5f7ff66a97739c6f9f8b19b182ae7cb05db542d02fa0cdee805712c0d355068de3c7cd851404fe6e424c5b7a0ffbcec686c42bc78030510 - languageName: node - linkType: hard - "@backstage/frontend-plugin-api@workspace:^, @backstage/frontend-plugin-api@workspace:packages/frontend-plugin-api": version: 0.0.0-use.local resolution: "@backstage/frontend-plugin-api@workspace:packages/frontend-plugin-api" @@ -4756,31 +4637,6 @@ __metadata: languageName: unknown linkType: soft -"@backstage/frontend-test-utils@npm:^0.3.2": - version: 0.3.2 - resolution: "@backstage/frontend-test-utils@npm:0.3.2" - dependencies: - "@backstage/config": "npm:^1.3.2" - "@backstage/frontend-app-api": "npm:^0.11.2" - "@backstage/frontend-plugin-api": "npm:^0.10.2" - "@backstage/plugin-app": "npm:^0.1.9" - "@backstage/test-utils": "npm:^1.7.8" - "@backstage/types": "npm:^1.2.1" - "@backstage/version-bridge": "npm:^1.0.11" - zod: "npm:^3.22.4" - peerDependencies: - "@testing-library/react": ^16.0.0 - "@types/react": ^17.0.0 || ^18.0.0 - react: ^17.0.0 || ^18.0.0 - react-dom: ^17.0.0 || ^18.0.0 - react-router-dom: ^6.3.0 - peerDependenciesMeta: - "@types/react": - optional: true - checksum: 10/3b33d0165e2bda8460e433649fec04d7594c7d987b7cdc59b46a955208266481d15df0f6d529a0bfbece7050d6510c0e320bf77fc81296579747e9a469d8e7d0 - languageName: node - linkType: hard - "@backstage/frontend-test-utils@workspace:^, @backstage/frontend-test-utils@workspace:packages/frontend-test-utils": version: 0.0.0-use.local resolution: "@backstage/frontend-test-utils@workspace:packages/frontend-test-utils" @@ -4830,7 +4686,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/integration-react@npm:^1.1.24, @backstage/integration-react@npm:^1.2.7, @backstage/integration-react@workspace:^, @backstage/integration-react@workspace:packages/integration-react": +"@backstage/integration-react@npm:^1.1.24, @backstage/integration-react@workspace:^, @backstage/integration-react@workspace:packages/integration-react": version: 0.0.0-use.local resolution: "@backstage/integration-react@workspace:packages/integration-react" dependencies: @@ -5022,33 +4878,6 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-app@npm:^0.1.9": - version: 0.1.9 - resolution: "@backstage/plugin-app@npm:0.1.9" - dependencies: - "@backstage/core-components": "npm:^0.17.2" - "@backstage/core-plugin-api": "npm:^1.10.7" - "@backstage/frontend-plugin-api": "npm:^0.10.2" - "@backstage/integration-react": "npm:^1.2.7" - "@backstage/plugin-permission-react": "npm:^0.4.34" - "@backstage/theme": "npm:^0.6.6" - "@backstage/types": "npm:^1.2.1" - "@material-ui/core": "npm:^4.9.13" - "@material-ui/icons": "npm:^4.9.1" - "@material-ui/lab": "npm:^4.0.0-alpha.61" - react-use: "npm:^17.2.4" - peerDependencies: - "@types/react": ^17.0.0 || ^18.0.0 - react: ^17.0.0 || ^18.0.0 - react-dom: ^17.0.0 || ^18.0.0 - react-router-dom: ^6.3.0 - peerDependenciesMeta: - "@types/react": - optional: true - checksum: 10/9c357605a8427f8bf5099968c612f90015d34d757a9494ea22d487bec20593cd80a7a50326e46344fc877ed163a14f2675d33530c1d756411316b0d373096aab - languageName: node - linkType: hard - "@backstage/plugin-app@workspace:^, @backstage/plugin-app@workspace:plugins/app": version: 0.0.0-use.local resolution: "@backstage/plugin-app@workspace:plugins/app" @@ -5401,7 +5230,7 @@ __metadata: "@backstage/plugin-auth-backend": "workspace:^" "@backstage/plugin-auth-node": "workspace:^" "@backstage/types": "workspace:^" - "@davidzemon/passport-okta-oauth": "npm:^0.0.5" + "@davidzemon/passport-okta-oauth": "npm:^0.0.6" express: "npm:^4.18.2" passport: "npm:^0.7.0" supertest: "npm:^7.0.0" @@ -5536,29 +5365,6 @@ __metadata: languageName: node linkType: hard -"@backstage/plugin-auth-node@npm:^0.6.3": - version: 0.6.3 - resolution: "@backstage/plugin-auth-node@npm:0.6.3" - dependencies: - "@backstage/backend-plugin-api": "npm:^1.3.1" - "@backstage/catalog-client": "npm:^1.10.0" - "@backstage/catalog-model": "npm:^1.7.4" - "@backstage/config": "npm:^1.3.2" - "@backstage/errors": "npm:^1.2.7" - "@backstage/types": "npm:^1.2.1" - "@types/express": "npm:^4.17.6" - "@types/passport": "npm:^1.0.3" - express: "npm:^4.17.1" - jose: "npm:^5.0.0" - lodash: "npm:^4.17.21" - passport: "npm:^0.7.0" - zod: "npm:^3.22.4" - zod-to-json-schema: "npm:^3.21.4" - zod-validation-error: "npm:^3.4.0" - checksum: 10/7f7fd4c1072512c8db6902e7a3e75319f73e2e487da0d202f3fde446eb340a34e7b1c0ce92d16f4dc2a5525aecd1df78979cdcfc650a48a41b2441f221fc0579 - languageName: node - linkType: hard - "@backstage/plugin-auth-node@workspace:^, @backstage/plugin-auth-node@workspace:plugins/auth-node": version: 0.0.0-use.local resolution: "@backstage/plugin-auth-node@workspace:plugins/auth-node" @@ -6092,7 +5898,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-catalog-common@npm:^1.0.20, @backstage/plugin-catalog-common@npm:^1.1.4, @backstage/plugin-catalog-common@workspace:^, @backstage/plugin-catalog-common@workspace:plugins/catalog-common": +"@backstage/plugin-catalog-common@npm:^1.0.20, @backstage/plugin-catalog-common@workspace:^, @backstage/plugin-catalog-common@workspace:plugins/catalog-common": version: 0.0.0-use.local resolution: "@backstage/plugin-catalog-common@workspace:plugins/catalog-common" dependencies: @@ -6218,48 +6024,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-catalog-react@npm:^1.17.0, @backstage/plugin-catalog-react@npm:^1.18.0, @backstage/plugin-catalog-react@npm:^1.9.3": - version: 1.18.0 - resolution: "@backstage/plugin-catalog-react@npm:1.18.0" - dependencies: - "@backstage/catalog-client": "npm:^1.10.0" - "@backstage/catalog-model": "npm:^1.7.4" - "@backstage/core-compat-api": "npm:^0.4.2" - "@backstage/core-components": "npm:^0.17.2" - "@backstage/core-plugin-api": "npm:^1.10.7" - "@backstage/errors": "npm:^1.2.7" - "@backstage/frontend-plugin-api": "npm:^0.10.2" - "@backstage/frontend-test-utils": "npm:^0.3.2" - "@backstage/integration-react": "npm:^1.2.7" - "@backstage/plugin-catalog-common": "npm:^1.1.4" - "@backstage/plugin-permission-common": "npm:^0.9.0" - "@backstage/plugin-permission-react": "npm:^0.4.34" - "@backstage/types": "npm:^1.2.1" - "@backstage/version-bridge": "npm:^1.0.11" - "@material-ui/core": "npm:^4.12.2" - "@material-ui/icons": "npm:^4.9.1" - "@material-ui/lab": "npm:4.0.0-alpha.61" - "@react-hookz/web": "npm:^24.0.0" - classnames: "npm:^2.2.6" - lodash: "npm:^4.17.21" - material-ui-popup-state: "npm:^1.9.3" - qs: "npm:^6.9.4" - react-use: "npm:^17.2.4" - yaml: "npm:^2.0.0" - zen-observable: "npm:^0.10.0" - peerDependencies: - "@types/react": ^17.0.0 || ^18.0.0 - react: ^17.0.0 || ^18.0.0 - react-dom: ^17.0.0 || ^18.0.0 - react-router-dom: ^6.3.0 - peerDependenciesMeta: - "@types/react": - optional: true - checksum: 10/1dec452c7bb1bd3538839a3a99943f5a5b50e5f414e31c679461e4810e5ea0e623cd41de6f08922fe577f3855459903f999c0ee0635982e1dd6bffbb46eceb08 - languageName: node - linkType: hard - -"@backstage/plugin-catalog-react@workspace:^, @backstage/plugin-catalog-react@workspace:plugins/catalog-react": +"@backstage/plugin-catalog-react@npm:^1.17.0, @backstage/plugin-catalog-react@npm:^1.9.3, @backstage/plugin-catalog-react@workspace:^, @backstage/plugin-catalog-react@workspace:plugins/catalog-react": version: 0.0.0-use.local resolution: "@backstage/plugin-catalog-react@workspace:plugins/catalog-react" dependencies: @@ -6647,6 +6412,22 @@ __metadata: languageName: unknown linkType: soft +"@backstage/plugin-events-backend-module-kafka@workspace:plugins/events-backend-module-kafka": + version: 0.0.0-use.local + resolution: "@backstage/plugin-events-backend-module-kafka@workspace:plugins/events-backend-module-kafka" + dependencies: + "@backstage/backend-plugin-api": "workspace:^" + "@backstage/backend-test-utils": "workspace:^" + "@backstage/cli": "workspace:^" + "@backstage/config": "workspace:^" + "@backstage/plugin-events-backend-test-utils": "workspace:^" + "@backstage/plugin-events-node": "workspace:^" + "@backstage/types": "workspace:^" + kafkajs: "npm:^2.2.4" + luxon: "npm:^3.0.0" + languageName: unknown + linkType: soft + "@backstage/plugin-events-backend-test-utils@workspace:^, @backstage/plugin-events-backend-test-utils@workspace:plugins/events-backend-test-utils": version: 0.0.0-use.local resolution: "@backstage/plugin-events-backend-test-utils@workspace:plugins/events-backend-test-utils" @@ -6727,6 +6508,7 @@ __metadata: "@backstage/cli": "workspace:^" "@backstage/core-components": "workspace:^" "@backstage/core-plugin-api": "workspace:^" + "@backstage/frontend-plugin-api": "workspace:^" "@material-ui/core": "npm:^4.12.2" "@material-ui/icons": "npm:^4.9.1" "@rjsf/utils": "npm:5.23.2" @@ -6952,6 +6734,9 @@ __metadata: "@testing-library/jest-dom": "npm:^6.0.0" "@testing-library/react": "npm:^16.0.0" "@types/react": "npm:^18.0.0" + "@xterm/addon-attach": "npm:^0.11.0" + "@xterm/addon-fit": "npm:^0.10.0" + "@xterm/xterm": "npm:^5.5.0" cronstrue: "npm:^2.32.0" jest-websocket-mock: "npm:^2.5.0" js-yaml: "npm:^4.1.0" @@ -6963,9 +6748,6 @@ __metadata: react-dom: "npm:^18.0.2" react-router-dom: "npm:^6.3.0" react-use: "npm:^17.4.0" - xterm: "npm:^5.3.0" - xterm-addon-attach: "npm:^0.9.0" - xterm-addon-fit: "npm:^0.8.0" peerDependencies: "@types/react": ^17.0.0 || ^18.0.0 react: ^17.0.0 || ^18.0.0 @@ -7001,6 +6783,9 @@ __metadata: "@testing-library/jest-dom": "npm:^6.0.0" "@testing-library/react": "npm:^16.0.0" "@types/react": "npm:^18.0.0" + "@xterm/addon-attach": "npm:^0.11.0" + "@xterm/addon-fit": "npm:^0.10.0" + "@xterm/xterm": "npm:^5.5.0" cronstrue: "npm:^2.2.0" js-yaml: "npm:^4.0.0" kubernetes-models: "npm:^4.1.0" @@ -7009,9 +6794,6 @@ __metadata: react: "npm:^18.0.2" react-dom: "npm:^18.0.2" react-router-dom: "npm:^6.3.0" - xterm: "npm:^5.2.1" - xterm-addon-attach: "npm:^0.9.0" - xterm-addon-fit: "npm:^0.8.0" peerDependencies: "@types/react": ^17.0.0 || ^18.0.0 react: ^17.0.0 || ^18.0.0 @@ -7023,6 +6805,26 @@ __metadata: languageName: unknown linkType: soft +"@backstage/plugin-mcp-actions-backend@workspace:^, @backstage/plugin-mcp-actions-backend@workspace:plugins/mcp-actions-backend": + version: 0.0.0-use.local + resolution: "@backstage/plugin-mcp-actions-backend@workspace:plugins/mcp-actions-backend" + dependencies: + "@backstage/backend-defaults": "workspace:^" + "@backstage/backend-plugin-api": "workspace:^" + "@backstage/backend-test-utils": "workspace:^" + "@backstage/catalog-client": "workspace:^" + "@backstage/cli": "workspace:^" + "@backstage/errors": "workspace:^" + "@backstage/plugin-catalog-node": "workspace:^" + "@backstage/types": "workspace:^" + "@modelcontextprotocol/sdk": "npm:^1.12.3" + "@types/express": "npm:^4.17.6" + express: "npm:^4.17.1" + express-promise-router: "npm:^4.1.0" + zod: "npm:^3.22.4" + languageName: unknown + linkType: soft + "@backstage/plugin-notifications-backend-module-email@workspace:plugins/notifications-backend-module-email": version: 0.0.0-use.local resolution: "@backstage/plugin-notifications-backend-module-email@workspace:plugins/notifications-backend-module-email" @@ -7306,7 +7108,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-permission-common@npm:^0.9.0, @backstage/plugin-permission-common@workspace:^, @backstage/plugin-permission-common@workspace:plugins/permission-common": +"@backstage/plugin-permission-common@workspace:^, @backstage/plugin-permission-common@workspace:plugins/permission-common": version: 0.0.0-use.local resolution: "@backstage/plugin-permission-common@workspace:plugins/permission-common" dependencies: @@ -7322,24 +7124,6 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-permission-node@npm:^0.10.0": - version: 0.10.0 - resolution: "@backstage/plugin-permission-node@npm:0.10.0" - dependencies: - "@backstage/backend-plugin-api": "npm:^1.3.1" - "@backstage/config": "npm:^1.3.2" - "@backstage/errors": "npm:^1.2.7" - "@backstage/plugin-auth-node": "npm:^0.6.3" - "@backstage/plugin-permission-common": "npm:^0.9.0" - "@types/express": "npm:^4.17.6" - express: "npm:^4.17.1" - express-promise-router: "npm:^4.1.0" - zod: "npm:^3.22.4" - zod-to-json-schema: "npm:^3.20.4" - checksum: 10/ffd6efc8625c36c5afbde08cf31aeac56a64c3b05547c8b2ba77b6301044652d2c5c4145f8445694ec8b1155173100472f21df1a4ec80b95d454485feb35231b - languageName: node - linkType: hard - "@backstage/plugin-permission-node@workspace:^, @backstage/plugin-permission-node@workspace:plugins/permission-node": version: 0.0.0-use.local resolution: "@backstage/plugin-permission-node@workspace:plugins/permission-node" @@ -7363,7 +7147,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-permission-react@npm:^0.4.34, @backstage/plugin-permission-react@workspace:^, @backstage/plugin-permission-react@workspace:plugins/permission-react": +"@backstage/plugin-permission-react@workspace:^, @backstage/plugin-permission-react@workspace:plugins/permission-react": version: 0.0.0-use.local resolution: "@backstage/plugin-permission-react@workspace:plugins/permission-react" dependencies: @@ -7630,7 +7414,6 @@ __metadata: "@backstage/backend-test-utils": "workspace:^" "@backstage/cli": "workspace:^" "@backstage/config": "workspace:^" - "@backstage/core-app-api": "workspace:^" "@backstage/errors": "workspace:^" "@backstage/integration": "workspace:^" "@backstage/plugin-scaffolder-node": "workspace:^" @@ -8715,7 +8498,7 @@ __metadata: "@backstage/config-loader": "workspace:^" "@backstage/errors": "workspace:^" "@backstage/types": "workspace:^" - "@electric-sql/pglite": "npm:^0.2.15" + "@electric-sql/pglite": "npm:^0.3.0" "@manypkg/get-packages": "npm:^1.1.3" "@microsoft/api-documenter": "npm:^7.25.7" "@microsoft/api-extractor": "npm:^7.47.2" @@ -8772,7 +8555,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/test-utils@npm:^1.7.8, @backstage/test-utils@workspace:^, @backstage/test-utils@workspace:packages/test-utils": +"@backstage/test-utils@workspace:^, @backstage/test-utils@workspace:packages/test-utils": version: 0.0.0-use.local resolution: "@backstage/test-utils@workspace:packages/test-utils" dependencies: @@ -8824,7 +8607,7 @@ __metadata: languageName: node linkType: hard -"@backstage/theme@npm:^0.6.0, @backstage/theme@npm:^0.6.6, @backstage/theme@workspace:^, @backstage/theme@workspace:packages/theme": +"@backstage/theme@npm:^0.6.0, @backstage/theme@workspace:^, @backstage/theme@workspace:packages/theme": version: 0.0.0-use.local resolution: "@backstage/theme@workspace:packages/theme" dependencies: @@ -8862,7 +8645,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/version-bridge@npm:^1.0.10, @backstage/version-bridge@npm:^1.0.11, @backstage/version-bridge@npm:^1.0.7, @backstage/version-bridge@workspace:^, @backstage/version-bridge@workspace:packages/version-bridge": +"@backstage/version-bridge@npm:^1.0.10, @backstage/version-bridge@npm:^1.0.7, @backstage/version-bridge@workspace:^, @backstage/version-bridge@workspace:packages/version-bridge": version: 0.0.0-use.local resolution: "@backstage/version-bridge@workspace:packages/version-bridge" dependencies: @@ -9218,8 +9001,8 @@ __metadata: linkType: hard "@codemirror/language@npm:^6.0.0": - version: 6.11.0 - resolution: "@codemirror/language@npm:6.11.0" + version: 6.11.1 + resolution: "@codemirror/language@npm:6.11.1" dependencies: "@codemirror/state": "npm:^6.0.0" "@codemirror/view": "npm:^6.23.0" @@ -9227,7 +9010,7 @@ __metadata: "@lezer/highlight": "npm:^1.0.0" "@lezer/lr": "npm:^1.0.0" style-mod: "npm:^4.0.0" - checksum: 10/571d8d18c51173c25dc3a1c1327fa2265e3d666acd2f2e3dbab828f49bc7f350159bbe8d46ee4baf88cb3eb0fbcfb3351028df6e2981455a55fd2951254c950f + checksum: 10/024969113d61ccb5d497b75a8a9875d43e1bfc8466de2819bb5db23f01b200937366800a812e8d33eb5e34e3a5d2aa22d0ff8205f34a5e8aeb4cd1d221bcaa78 languageName: node linkType: hard @@ -9284,13 +9067,14 @@ __metadata: linkType: hard "@codemirror/view@npm:^6.0.0, @codemirror/view@npm:^6.23.0": - version: 6.36.8 - resolution: "@codemirror/view@npm:6.36.8" + version: 6.37.2 + resolution: "@codemirror/view@npm:6.37.2" dependencies: "@codemirror/state": "npm:^6.5.0" + crelt: "npm:^1.0.6" style-mod: "npm:^4.1.0" w3c-keyname: "npm:^2.2.4" - checksum: 10/cb2cbfb8a41ee1d6cfb17c2ea91b9763e692f85d523b55276cc46ab7fda3f6ba0bcc03e2194ad6cf6b413ec34d309ab408300c19b62d5d6d6f9e2071fb99d489 + checksum: 10/410ef68c5bd3395c556f5a1298afd6a37eecd88b825435dc19ce7143b0eb5c4114486b444e56fd156371fcc329ad9425635c0703322384ff582a75a4d61727a7 languageName: node linkType: hard @@ -9355,15 +9139,15 @@ __metadata: languageName: node linkType: hard -"@davidzemon/passport-okta-oauth@npm:^0.0.5": - version: 0.0.5 - resolution: "@davidzemon/passport-okta-oauth@npm:0.0.5" +"@davidzemon/passport-okta-oauth@npm:^0.0.6": + version: 0.0.6 + resolution: "@davidzemon/passport-okta-oauth@npm:0.0.6" dependencies: "@types/passport-oauth2": "npm:^1.4.11" passport-oauth2: "npm:^1.6.1" pkginfo: "npm:^0.4.1" uid2: "npm:^1.0.0" - checksum: 10/6932aca4213f1e47c41454cbb9ef1309643ffa14fa3da401f18e397e76f3fa1669be76d96db65dd6435854d7f05b30d3a27f645d10e3c6ed955ad30930d47b3e + checksum: 10/d29a26459ff387d7507c031a6814e3581eb47e2dc9dda6848667362973455cd125e2a251b30ad6c093dfd6cd8ee7adf48301f395808b212008a6ee702a507354 languageName: node linkType: hard @@ -9390,13 +9174,20 @@ __metadata: languageName: node linkType: hard -"@electric-sql/pglite@npm:^0.2.14, @electric-sql/pglite@npm:^0.2.15": +"@electric-sql/pglite@npm:^0.2.14": version: 0.2.17 resolution: "@electric-sql/pglite@npm:0.2.17" checksum: 10/cb04d18614c9a3d985fa63f5ca889104eab55b15a9aa569df264e335ea559f2279ee64c1284aa68d5b92ff516dd37ae553299cf55c226a3e541d6c46416c7160 languageName: node linkType: hard +"@electric-sql/pglite@npm:^0.3.0": + version: 0.3.3 + resolution: "@electric-sql/pglite@npm:0.3.3" + checksum: 10/fa2b8698c4edb4716b34efd2e8ef1847e5b0c8059afffb21ad5b7cc21dcdca9d86075ac4f1798f1e83a5b2cc1ee8902e1d322fe63d761e065089c7da494ea089 + languageName: node + linkType: hard + "@emotion/babel-plugin@npm:^11.13.5": version: 11.13.5 resolution: "@emotion/babel-plugin@npm:11.13.5" @@ -9587,9 +9378,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/aix-ppc64@npm:0.25.4": - version: 0.25.4 - resolution: "@esbuild/aix-ppc64@npm:0.25.4" +"@esbuild/aix-ppc64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/aix-ppc64@npm:0.25.5" conditions: os=aix & cpu=ppc64 languageName: node linkType: hard @@ -9601,9 +9392,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/android-arm64@npm:0.25.4": - version: 0.25.4 - resolution: "@esbuild/android-arm64@npm:0.25.4" +"@esbuild/android-arm64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/android-arm64@npm:0.25.5" conditions: os=android & cpu=arm64 languageName: node linkType: hard @@ -9615,9 +9406,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/android-arm@npm:0.25.4": - version: 0.25.4 - resolution: "@esbuild/android-arm@npm:0.25.4" +"@esbuild/android-arm@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/android-arm@npm:0.25.5" conditions: os=android & cpu=arm languageName: node linkType: hard @@ -9629,9 +9420,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/android-x64@npm:0.25.4": - version: 0.25.4 - resolution: "@esbuild/android-x64@npm:0.25.4" +"@esbuild/android-x64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/android-x64@npm:0.25.5" conditions: os=android & cpu=x64 languageName: node linkType: hard @@ -9643,9 +9434,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/darwin-arm64@npm:0.25.4": - version: 0.25.4 - resolution: "@esbuild/darwin-arm64@npm:0.25.4" +"@esbuild/darwin-arm64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/darwin-arm64@npm:0.25.5" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard @@ -9657,9 +9448,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/darwin-x64@npm:0.25.4": - version: 0.25.4 - resolution: "@esbuild/darwin-x64@npm:0.25.4" +"@esbuild/darwin-x64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/darwin-x64@npm:0.25.5" conditions: os=darwin & cpu=x64 languageName: node linkType: hard @@ -9671,9 +9462,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/freebsd-arm64@npm:0.25.4": - version: 0.25.4 - resolution: "@esbuild/freebsd-arm64@npm:0.25.4" +"@esbuild/freebsd-arm64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/freebsd-arm64@npm:0.25.5" conditions: os=freebsd & cpu=arm64 languageName: node linkType: hard @@ -9685,9 +9476,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/freebsd-x64@npm:0.25.4": - version: 0.25.4 - resolution: "@esbuild/freebsd-x64@npm:0.25.4" +"@esbuild/freebsd-x64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/freebsd-x64@npm:0.25.5" conditions: os=freebsd & cpu=x64 languageName: node linkType: hard @@ -9699,9 +9490,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-arm64@npm:0.25.4": - version: 0.25.4 - resolution: "@esbuild/linux-arm64@npm:0.25.4" +"@esbuild/linux-arm64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/linux-arm64@npm:0.25.5" conditions: os=linux & cpu=arm64 languageName: node linkType: hard @@ -9713,9 +9504,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-arm@npm:0.25.4": - version: 0.25.4 - resolution: "@esbuild/linux-arm@npm:0.25.4" +"@esbuild/linux-arm@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/linux-arm@npm:0.25.5" conditions: os=linux & cpu=arm languageName: node linkType: hard @@ -9727,9 +9518,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-ia32@npm:0.25.4": - version: 0.25.4 - resolution: "@esbuild/linux-ia32@npm:0.25.4" +"@esbuild/linux-ia32@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/linux-ia32@npm:0.25.5" conditions: os=linux & cpu=ia32 languageName: node linkType: hard @@ -9741,9 +9532,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-loong64@npm:0.25.4": - version: 0.25.4 - resolution: "@esbuild/linux-loong64@npm:0.25.4" +"@esbuild/linux-loong64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/linux-loong64@npm:0.25.5" conditions: os=linux & cpu=loong64 languageName: node linkType: hard @@ -9755,9 +9546,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-mips64el@npm:0.25.4": - version: 0.25.4 - resolution: "@esbuild/linux-mips64el@npm:0.25.4" +"@esbuild/linux-mips64el@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/linux-mips64el@npm:0.25.5" conditions: os=linux & cpu=mips64el languageName: node linkType: hard @@ -9769,9 +9560,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-ppc64@npm:0.25.4": - version: 0.25.4 - resolution: "@esbuild/linux-ppc64@npm:0.25.4" +"@esbuild/linux-ppc64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/linux-ppc64@npm:0.25.5" conditions: os=linux & cpu=ppc64 languageName: node linkType: hard @@ -9783,9 +9574,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-riscv64@npm:0.25.4": - version: 0.25.4 - resolution: "@esbuild/linux-riscv64@npm:0.25.4" +"@esbuild/linux-riscv64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/linux-riscv64@npm:0.25.5" conditions: os=linux & cpu=riscv64 languageName: node linkType: hard @@ -9797,9 +9588,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-s390x@npm:0.25.4": - version: 0.25.4 - resolution: "@esbuild/linux-s390x@npm:0.25.4" +"@esbuild/linux-s390x@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/linux-s390x@npm:0.25.5" conditions: os=linux & cpu=s390x languageName: node linkType: hard @@ -9811,16 +9602,16 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-x64@npm:0.25.4": - version: 0.25.4 - resolution: "@esbuild/linux-x64@npm:0.25.4" +"@esbuild/linux-x64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/linux-x64@npm:0.25.5" conditions: os=linux & cpu=x64 languageName: node linkType: hard -"@esbuild/netbsd-arm64@npm:0.25.4": - version: 0.25.4 - resolution: "@esbuild/netbsd-arm64@npm:0.25.4" +"@esbuild/netbsd-arm64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/netbsd-arm64@npm:0.25.5" conditions: os=netbsd & cpu=arm64 languageName: node linkType: hard @@ -9832,16 +9623,16 @@ __metadata: languageName: node linkType: hard -"@esbuild/netbsd-x64@npm:0.25.4": - version: 0.25.4 - resolution: "@esbuild/netbsd-x64@npm:0.25.4" +"@esbuild/netbsd-x64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/netbsd-x64@npm:0.25.5" conditions: os=netbsd & cpu=x64 languageName: node linkType: hard -"@esbuild/openbsd-arm64@npm:0.25.4": - version: 0.25.4 - resolution: "@esbuild/openbsd-arm64@npm:0.25.4" +"@esbuild/openbsd-arm64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/openbsd-arm64@npm:0.25.5" conditions: os=openbsd & cpu=arm64 languageName: node linkType: hard @@ -9853,9 +9644,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/openbsd-x64@npm:0.25.4": - version: 0.25.4 - resolution: "@esbuild/openbsd-x64@npm:0.25.4" +"@esbuild/openbsd-x64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/openbsd-x64@npm:0.25.5" conditions: os=openbsd & cpu=x64 languageName: node linkType: hard @@ -9867,9 +9658,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/sunos-x64@npm:0.25.4": - version: 0.25.4 - resolution: "@esbuild/sunos-x64@npm:0.25.4" +"@esbuild/sunos-x64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/sunos-x64@npm:0.25.5" conditions: os=sunos & cpu=x64 languageName: node linkType: hard @@ -9881,9 +9672,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/win32-arm64@npm:0.25.4": - version: 0.25.4 - resolution: "@esbuild/win32-arm64@npm:0.25.4" +"@esbuild/win32-arm64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/win32-arm64@npm:0.25.5" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard @@ -9895,9 +9686,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/win32-ia32@npm:0.25.4": - version: 0.25.4 - resolution: "@esbuild/win32-ia32@npm:0.25.4" +"@esbuild/win32-ia32@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/win32-ia32@npm:0.25.5" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard @@ -9909,9 +9700,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/win32-x64@npm:0.25.4": - version: 0.25.4 - resolution: "@esbuild/win32-x64@npm:0.25.4" +"@esbuild/win32-x64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/win32-x64@npm:0.25.5" conditions: os=win32 & cpu=x64 languageName: node linkType: hard @@ -10169,14 +9960,14 @@ __metadata: linkType: hard "@google-cloud/cloud-sql-connector@npm:^1.4.0": - version: 1.8.0 - resolution: "@google-cloud/cloud-sql-connector@npm:1.8.0" + version: 1.8.1 + resolution: "@google-cloud/cloud-sql-connector@npm:1.8.1" dependencies: - "@googleapis/sqladmin": "npm:^28.0.0" + "@googleapis/sqladmin": "npm:^29.0.0" gaxios: "npm:^6.1.1" google-auth-library: "npm:^9.2.0" p-throttle: "npm:^7.0.0" - checksum: 10/a2cd85beb822a37e1eaabd556e2f540f89c41a1614e520b8c120b8107d7edb3c335dcbf62fc34dd8973ae091a2a06882780ae6510c45f2b702a59df4953ba427 + checksum: 10/e13e2e47993d74c770c73318a73047b017266f6f8102e26ebcf90c484fd78ba6141b0fc60f4eced55d438150655b8514423c19e3f30da73a1aaf1c77baadd0ab languageName: node linkType: hard @@ -10278,12 +10069,12 @@ __metadata: languageName: node linkType: hard -"@googleapis/sqladmin@npm:^28.0.0": - version: 28.0.0 - resolution: "@googleapis/sqladmin@npm:28.0.0" +"@googleapis/sqladmin@npm:^29.0.0": + version: 29.0.0 + resolution: "@googleapis/sqladmin@npm:29.0.0" dependencies: googleapis-common: "npm:^7.0.0" - checksum: 10/ee4074b63d45276e0513a75b461bbf3d39abcb894e5eb660f0f28a9d0665c6638079958f04cb171767c69bcbb324ecdd2033199e6ecff61bf10d6a09adecdd16 + checksum: 10/3bf9eea2e6333d394da88404172aeed5ee5fca5fe2ebbba84d427990aab0083281a4cb948c023817ae6dbb618a1e43a296176c7703badd66a60bde695d7c5b3f languageName: node linkType: hard @@ -10902,40 +10693,40 @@ __metadata: languageName: unknown linkType: soft -"@internationalized/date@npm:^3.7.0": - version: 3.7.0 - resolution: "@internationalized/date@npm:3.7.0" +"@internationalized/date@npm:^3.8.2": + version: 3.8.2 + resolution: "@internationalized/date@npm:3.8.2" dependencies: "@swc/helpers": "npm:^0.5.0" - checksum: 10/59adffb57f1391e17bfe9b2e9b1a71c0957a1835b0176a86ad5a99fd2f2919f094d3f553fb39be157d84c315a88917e0eda779c9101026e3bfac217ace18a559 + checksum: 10/ca281d8785acff520ba4782d4eb0c542bb6c2783dbd3eb5457aeddbb68b9674f860fc00c6dd467f39c12eff9a04381742b07f0b9e210a115c094507e046d7b5a languageName: node linkType: hard -"@internationalized/message@npm:^3.1.6": - version: 3.1.6 - resolution: "@internationalized/message@npm:3.1.6" +"@internationalized/message@npm:^3.1.8": + version: 3.1.8 + resolution: "@internationalized/message@npm:3.1.8" dependencies: "@swc/helpers": "npm:^0.5.0" intl-messageformat: "npm:^10.1.0" - checksum: 10/31611a81bba7c0b18fad02ccb363632cbef3a0cc6e6e564578dfc7ae42cfde48b0ec18b89bff24390bb748df63d40cd2028483068e7d1492aee0533648a71e04 + checksum: 10/8f27a31f5d1eef7084447ed141e896e12cc19d786a1346ba60137de5b8bcc58a9da978d79954e2a74302aa673f942fb772130ebd6195565e33db30bd7eb4ef47 languageName: node linkType: hard -"@internationalized/number@npm:^3.6.0": - version: 3.6.0 - resolution: "@internationalized/number@npm:3.6.0" +"@internationalized/number@npm:^3.6.3": + version: 3.6.3 + resolution: "@internationalized/number@npm:3.6.3" dependencies: "@swc/helpers": "npm:^0.5.0" - checksum: 10/76428f75fd289008580108beef02816f94aaca37d48c9e26c2274fdbb81e8f32c4247ff624b8f854384b18ce2556cc8d817ccf1bc39b0fd87b0da1f3d911209b + checksum: 10/b6f1793d12f89aca4c5bd88b60643739c4b02cade50a42c61192a2a5e0a913088ee35e4013b7ef3f675bdc919ebaf9a1631f1c40b1ceffd998f3fc14201a01c3 languageName: node linkType: hard -"@internationalized/string@npm:^3.2.5": - version: 3.2.5 - resolution: "@internationalized/string@npm:3.2.5" +"@internationalized/string@npm:^3.2.7": + version: 3.2.7 + resolution: "@internationalized/string@npm:3.2.7" dependencies: "@swc/helpers": "npm:^0.5.0" - checksum: 10/7a20359796545cd5724aa546018554b81ea168c58738e98884c54ef0de2fba7b802504c79678d690709b0a435478912aa771c426feed72aae1d93ee782b7ac5d + checksum: 10/38b54817cf125ba88d1136a6bca4fb57c46672d26d21490f838efe928049546800df6d9c8048411696455fc8caacb8ac23c2de2a1b61f2258b1302c1c97cc128 languageName: node linkType: hard @@ -10953,6 +10744,22 @@ __metadata: languageName: node linkType: hard +"@isaacs/balanced-match@npm:^4.0.1": + version: 4.0.1 + resolution: "@isaacs/balanced-match@npm:4.0.1" + checksum: 10/102fbc6d2c0d5edf8f6dbf2b3feb21695a21bc850f11bc47c4f06aa83bd8884fde3fe9d6d797d619901d96865fdcb4569ac2a54c937992c48885c5e3d9967fe8 + languageName: node + linkType: hard + +"@isaacs/brace-expansion@npm:^5.0.0": + version: 5.0.0 + resolution: "@isaacs/brace-expansion@npm:5.0.0" + dependencies: + "@isaacs/balanced-match": "npm:^4.0.1" + checksum: 10/cf3b7f206aff12128214a1df764ac8cdbc517c110db85249b945282407e3dfc5c6e66286383a7c9391a059fc8e6e6a8ca82262fc9d2590bd615376141fbebd2d + languageName: node + linkType: hard + "@isaacs/cliui@npm:^8.0.2": version: 8.0.2 resolution: "@isaacs/cliui@npm:8.0.2" @@ -11414,23 +11221,25 @@ __metadata: linkType: hard "@keyv/memcache@npm:^1.3.5": - version: 1.3.7 - resolution: "@keyv/memcache@npm:1.3.7" + version: 1.4.1 + resolution: "@keyv/memcache@npm:1.4.1" dependencies: json-buffer: "npm:^3.0.1" - memjs: "npm:^1.3.1" - checksum: 10/61c836c1b0c264c35281a38dbc380a102b2899eab46226a0e31614d3d7c4708ecdb06d8858f711893212ae5b357a79213c7a7b7a81b6196e56dd889dd1ca498b + memjs: "npm:^1.3.2" + checksum: 10/a3db21549ec445925c28419b19210984875aa03d1ce513792064336c7785c0e6d3ac015e71ca328a2e83f4ed409475f057a37d86c7fb2a11832740b024bcc3ff languageName: node linkType: hard "@keyv/memcache@npm:^2.0.1": - version: 2.0.1 - resolution: "@keyv/memcache@npm:2.0.1" + version: 2.0.2 + resolution: "@keyv/memcache@npm:2.0.2" dependencies: - "@keyv/serialize": "npm:*" + "@keyv/serialize": "npm:^1.0.3" buffer: "npm:^6.0.3" memjs: "npm:^1.3.2" - checksum: 10/618fd2441cb7e0b71c6af37b87bddc39d3439c9863def47cff8c75c9c05ca45e035bfc1bfa140a661befce5a06a491f25388aab6d330c0eaefe7b87534274c48 + peerDependencies: + keyv: ^5.3.4 + checksum: 10/8328bfa4a348d26c1aa1a563561a50114f75288af5fe18e8dc2ce6ff2f7f6aa63c27f8293c5e8b35bc0dcc9740159e56d8ff1b4015fc6a56e18d62850a8a9b83 languageName: node linkType: hard @@ -11444,31 +11253,32 @@ __metadata: linkType: hard "@keyv/redis@npm:^4.0.1": - version: 4.1.0 - resolution: "@keyv/redis@npm:4.1.0" + version: 4.4.0 + resolution: "@keyv/redis@npm:4.4.0" dependencies: + "@redis/client": "npm:^1.6.0" cluster-key-slot: "npm:^1.1.2" - keyv: "npm:^5.2.1" - redis: "npm:^4.7.0" - checksum: 10/5f1d6c6596829bbae5c6369dff6e70de4d7f91c7c8312585b2bef336638582c9969c792a4b328ee07b80b50136e67769fffd844e237d4db32a44ea7de20fb3f5 + peerDependencies: + keyv: ^5.3.3 + checksum: 10/61ad0a026f1ee8bbd0f09bb1b3c731619b37dc4bba0d5f2111cb5249e643e6a776816786090c53d5ac1fa62a43e1b43d406dae06cfb119abcb47b6ac837eebb0 languageName: node linkType: hard -"@keyv/serialize@npm:*, @keyv/serialize@npm:^1.0.2": - version: 1.0.2 - resolution: "@keyv/serialize@npm:1.0.2" +"@keyv/serialize@npm:^1.0.3": + version: 1.0.3 + resolution: "@keyv/serialize@npm:1.0.3" dependencies: buffer: "npm:^6.0.3" - checksum: 10/6a42a5778a6b4542f6903ba7e6a17c5bd116441798d75c95fba9908c76c7606db527fad710b5c54abc6175e49b1bbaaafe3b836ad4b91e1af701394134f1d504 + checksum: 10/d6a9194dd781bc26cc4d55f392d843810c1fdc0da81e69203e633cb289fc0a8edc8bc6466f66c4cbb55da0a5b405e89f14a68b48d6e73919ae82f8249fb5e444 languageName: node linkType: hard "@keyv/valkey@npm:^1.0.1": - version: 1.0.3 - resolution: "@keyv/valkey@npm:1.0.3" + version: 1.0.4 + resolution: "@keyv/valkey@npm:1.0.4" dependencies: iovalkey: "npm:^0.3.1" - checksum: 10/ff6ba62e4d19c426e45a1437fe215ed2baddc58e811d97507dd75ead0058c3105d679c8c7c4241ddf732abe56320357c2e568c014620e50d7c0eaef1f2528b88 + checksum: 10/93362c51c14bb8e515a9af8df4a22e028fcec5a09931eb68f854698676cb16cecad691330c75c1dca8b6a986a4763cac9f1b2fd4e5b8216f06648d9379f55cc6 languageName: node linkType: hard @@ -11960,6 +11770,25 @@ __metadata: languageName: node linkType: hard +"@modelcontextprotocol/sdk@npm:^1.12.3": + version: 1.12.3 + resolution: "@modelcontextprotocol/sdk@npm:1.12.3" + dependencies: + ajv: "npm:^6.12.6" + content-type: "npm:^1.0.5" + cors: "npm:^2.8.5" + cross-spawn: "npm:^7.0.5" + eventsource: "npm:^3.0.2" + express: "npm:^5.0.1" + express-rate-limit: "npm:^7.5.0" + pkce-challenge: "npm:^5.0.0" + raw-body: "npm:^3.0.0" + zod: "npm:^3.23.8" + zod-to-json-schema: "npm:^3.24.1" + checksum: 10/abab9b3fcce45370aadc260e9f02587308455ea907cf58b5e7f2e27c0ef4d19bf591f80284592b69f3d1656e4b362b2a96788eb1492daa3e7e2129c49b3eea98 + languageName: node + linkType: hard + "@module-federation/bridge-react-webpack-plugin@npm:0.9.1": version: 0.9.1 resolution: "@module-federation/bridge-react-webpack-plugin@npm:0.9.1" @@ -12046,10 +11875,10 @@ __metadata: languageName: node linkType: hard -"@module-federation/error-codes@npm:0.13.1": - version: 0.13.1 - resolution: "@module-federation/error-codes@npm:0.13.1" - checksum: 10/fa9bbc0936ad9d037116c05f741bfb0ff741c3e2eaa682fa0132f4825d66ef0c63da0c20ec931ca16c8e7b660c1fdc60101a24ccab8951f19e07fba642aa1c6a +"@module-federation/error-codes@npm:0.14.3": + version: 0.14.3 + resolution: "@module-federation/error-codes@npm:0.14.3" + checksum: 10/3b6c25940d966648c2531b80edabafd36eddccdd8f68ba6702686a1e4fd2dbaa4a34ef6fb22a4d8a615b907e907e233dd0fd312c49a7369a49669bc1ab414a19 languageName: node linkType: hard @@ -12117,13 +11946,13 @@ __metadata: languageName: node linkType: hard -"@module-federation/runtime-core@npm:0.13.1": - version: 0.13.1 - resolution: "@module-federation/runtime-core@npm:0.13.1" +"@module-federation/runtime-core@npm:0.14.3": + version: 0.14.3 + resolution: "@module-federation/runtime-core@npm:0.14.3" dependencies: - "@module-federation/error-codes": "npm:0.13.1" - "@module-federation/sdk": "npm:0.13.1" - checksum: 10/81b52eb7866f623115922af325bcc1dba6c85f95216dfa2cbf2f777b37ec11ba856846892a4a5ab446105a18837c495b0a05cb5d574f7d2e50f340d1e57413f4 + "@module-federation/error-codes": "npm:0.14.3" + "@module-federation/sdk": "npm:0.14.3" + checksum: 10/7e974a8c051334929e28231fe1552489258ab1b545f0f5ad59644b0288765642f3e908b48c3cc59bc74a326f4f92325788b1a898f89d8f795f8036aa812b2bb6 languageName: node linkType: hard @@ -12137,13 +11966,13 @@ __metadata: languageName: node linkType: hard -"@module-federation/runtime-tools@npm:0.13.1": - version: 0.13.1 - resolution: "@module-federation/runtime-tools@npm:0.13.1" +"@module-federation/runtime-tools@npm:0.14.3": + version: 0.14.3 + resolution: "@module-federation/runtime-tools@npm:0.14.3" dependencies: - "@module-federation/runtime": "npm:0.13.1" - "@module-federation/webpack-bundler-runtime": "npm:0.13.1" - checksum: 10/821f32979ef2235cd043b3ef561fd63f7554211bd86d3af7e17a57dd5c709c6ee2ae57935222318694732115d7771c122cf51fb9f71f879269d452bc5ab0a8d2 + "@module-federation/runtime": "npm:0.14.3" + "@module-federation/webpack-bundler-runtime": "npm:0.14.3" + checksum: 10/09bc9d482ead7d38d5f9f6e1d45c85f257833302315447b2a17c26dc44046f8aa0563ffdb2f5addbddbf5f8f972c13dc8e80932a8a34780738232332bbdf5ce9 languageName: node linkType: hard @@ -12157,14 +11986,14 @@ __metadata: languageName: node linkType: hard -"@module-federation/runtime@npm:0.13.1": - version: 0.13.1 - resolution: "@module-federation/runtime@npm:0.13.1" +"@module-federation/runtime@npm:0.14.3": + version: 0.14.3 + resolution: "@module-federation/runtime@npm:0.14.3" dependencies: - "@module-federation/error-codes": "npm:0.13.1" - "@module-federation/runtime-core": "npm:0.13.1" - "@module-federation/sdk": "npm:0.13.1" - checksum: 10/2536ea17d0704bf4d093fe5791720e61fa3f4f4e83b6927b33f1d2ee132bf0cc9232e960cffefe32a6c79f3aedd864738b1be79b3790ad0c9dbd924f15ef2841 + "@module-federation/error-codes": "npm:0.14.3" + "@module-federation/runtime-core": "npm:0.14.3" + "@module-federation/sdk": "npm:0.14.3" + checksum: 10/b7009953998f2624f5ece3da4174d8427d30b2af3b108154f0fa2365aa6c08d167e23b9771508f2c6038a397f21e0e26b93dd09f3d4b7b90eac6b0ee7f1b9ee2 languageName: node linkType: hard @@ -12179,10 +12008,10 @@ __metadata: languageName: node linkType: hard -"@module-federation/sdk@npm:0.13.1": - version: 0.13.1 - resolution: "@module-federation/sdk@npm:0.13.1" - checksum: 10/7cfc98a6ee09aa338a9d76df146d064b5f4c6163b985daf3aa641e3f0e52d7cc40116b449cd1265b1333a66eeec31ce8bb40e1944f3ac62797d87323ce0e91ec +"@module-federation/sdk@npm:0.14.3": + version: 0.14.3 + resolution: "@module-federation/sdk@npm:0.14.3" + checksum: 10/f359fa15ecebe6e1e80e8fbd4d4969ae2d2d92f0d3e338443c45fba4772327368e086b108adcec585763d974e7462227a9e51b0531826292e2249f2612d0f822 languageName: node linkType: hard @@ -12204,13 +12033,13 @@ __metadata: languageName: node linkType: hard -"@module-federation/webpack-bundler-runtime@npm:0.13.1": - version: 0.13.1 - resolution: "@module-federation/webpack-bundler-runtime@npm:0.13.1" +"@module-federation/webpack-bundler-runtime@npm:0.14.3": + version: 0.14.3 + resolution: "@module-federation/webpack-bundler-runtime@npm:0.14.3" dependencies: - "@module-federation/runtime": "npm:0.13.1" - "@module-federation/sdk": "npm:0.13.1" - checksum: 10/bebccaa4411c00355bb399e2dddb946586967642b90da4d4436554093fecb614fdff6c65dc73cef944c7344f169d2c0ecc22ed0b5b899e21d4535507806145e0 + "@module-federation/runtime": "npm:0.14.3" + "@module-federation/sdk": "npm:0.14.3" + checksum: 10/016d1c51e82e230b2d33f67aba7c9ff2cd9f939306a48dfa3aeb0f3939dd82f797e06b478c009459d7516fadbf43024cd0fc13618555a64c470192d9b87ab926 languageName: node linkType: hard @@ -12315,9 +12144,9 @@ __metadata: languageName: node linkType: hard -"@mswjs/interceptors@npm:^0.37.0": - version: 0.37.1 - resolution: "@mswjs/interceptors@npm:0.37.1" +"@mswjs/interceptors@npm:^0.39.1": + version: 0.39.2 + resolution: "@mswjs/interceptors@npm:0.39.2" dependencies: "@open-draft/deferred-promise": "npm:^2.2.0" "@open-draft/logger": "npm:^0.3.0" @@ -12325,7 +12154,7 @@ __metadata: is-node-process: "npm:^1.2.0" outvariant: "npm:^1.4.3" strict-event-emitter: "npm:^0.5.1" - checksum: 10/332d8aa50beb4834ccbda6a800ca00b1204adc0eba23e1c1f7bb9f4e564a92707e563f7a2424d4a8607404ec91424e5d8c34a87c250b191ca7b24dff12eba2c5 + checksum: 10/faaa95d636363a197f125c32066457fa74d5063d8ccae4c9c0e0510179060d92b1faf8640df45a0623e0bf42a30d610c83364a58e0eb0ca412c87b2e835936c1 languageName: node linkType: hard @@ -12516,18 +12345,18 @@ __metadata: languageName: node linkType: hard -"@nestjs/common@npm:11.0.20": - version: 11.0.20 - resolution: "@nestjs/common@npm:11.0.20" +"@nestjs/common@npm:11.1.1": + version: 11.1.1 + resolution: "@nestjs/common@npm:11.1.1" dependencies: - file-type: "npm:20.4.1" + file-type: "npm:20.5.0" iterare: "npm:1.2.1" load-esm: "npm:1.0.2" tslib: "npm:2.8.1" uid: "npm:2.0.2" peerDependencies: - class-transformer: "*" - class-validator: "*" + class-transformer: ">=0.4.1" + class-validator: ">=0.13.2" reflect-metadata: ^0.1.12 || ^0.2.0 rxjs: ^7.1.0 peerDependenciesMeta: @@ -12535,13 +12364,13 @@ __metadata: optional: true class-validator: optional: true - checksum: 10/ab06f3d910a86351e895829773b28236dcb4a80a3eba1ed902c51dbc44db9d40f619d5f8713c5ce42518fc95633bbe9c80b1c7188ffc4fd3d5d934b561e2f495 + checksum: 10/b58b951984df667b794a6c9cf65dda8ee43fe0c4e552183e045b126c82d99b50cddb1e84ea03b8dd7b04fca512acb107222ffad6b19dba359323f9b813032161 languageName: node linkType: hard -"@nestjs/core@npm:11.0.20": - version: 11.0.20 - resolution: "@nestjs/core@npm:11.0.20" +"@nestjs/core@npm:11.1.1": + version: 11.1.1 + resolution: "@nestjs/core@npm:11.1.1" dependencies: "@nuxt/opencollective": "npm:0.4.1" fast-safe-stringify: "npm:2.1.1" @@ -12563,7 +12392,7 @@ __metadata: optional: true "@nestjs/websockets": optional: true - checksum: 10/0e18e6744eaa912442d43d6a8d5543bc4b7e09d350943881d76110aa53a0d26876818898d1ddb71f92d24e6f7154ab3264c6c5604c9670221a5f63552e61d431 + checksum: 10/88f8a3c52a98c059e6d93c5faf9194daee4667b1a855f88233582acf51e3be9aedb3e3f7f992da46e0e45df31ad4e045e0296e6e35ea14e2245d4069176711c0 languageName: node linkType: hard @@ -13282,10 +13111,10 @@ __metadata: languageName: node linkType: hard -"@octokit/openapi-types@npm:^22.2.0": - version: 22.2.0 - resolution: "@octokit/openapi-types@npm:22.2.0" - checksum: 10/0471b0c789fada5aa2390e6f82ba477738228ef7d2d986dda9aab0cb625d1562bd178ba0ba4d2655ce841079cd5efff9e58ece2077c27e569ea22109ea301830 +"@octokit/openapi-types@npm:^24.2.0": + version: 24.2.0 + resolution: "@octokit/openapi-types@npm:24.2.0" + checksum: 10/000897ebc6e247c2591049d6081e95eb5636f73798dadd695ee6048496772b58065df88823e74a760201828545a7ac601dd3c1bcd2e00079a62a9ee9d389409c languageName: node linkType: hard @@ -13298,14 +13127,14 @@ __metadata: languageName: node linkType: hard -"@octokit/plugin-paginate-rest@npm:11.3.1": - version: 11.3.1 - resolution: "@octokit/plugin-paginate-rest@npm:11.3.1" +"@octokit/plugin-paginate-rest@npm:11.4.4-cjs.2": + version: 11.4.4-cjs.2 + resolution: "@octokit/plugin-paginate-rest@npm:11.4.4-cjs.2" dependencies: - "@octokit/types": "npm:^13.5.0" + "@octokit/types": "npm:^13.7.0" peerDependencies: "@octokit/core": 5 - checksum: 10/82f5bcc3a536a44bed0a205c8301176c0d210b7a1c6d035a79b31a102e2e02f46234a38629cc984a21be544194ac69151814e9a909416aa7389cdffd1297bcd9 + checksum: 10/e0f696b3b69febe4e7c736d909065871f38bb8346a07f19a9c83246a02972568ac672667db472f846baef20a9611adf26ce8f0f189a11004c4b6618765078e19 languageName: node linkType: hard @@ -13341,14 +13170,14 @@ __metadata: languageName: node linkType: hard -"@octokit/plugin-rest-endpoint-methods@npm:13.2.2": - version: 13.2.2 - resolution: "@octokit/plugin-rest-endpoint-methods@npm:13.2.2" +"@octokit/plugin-rest-endpoint-methods@npm:13.3.2-cjs.1": + version: 13.3.2-cjs.1 + resolution: "@octokit/plugin-rest-endpoint-methods@npm:13.3.2-cjs.1" dependencies: - "@octokit/types": "npm:^13.5.0" + "@octokit/types": "npm:^13.8.0" peerDependencies: "@octokit/core": ^5 - checksum: 10/9eccc1a22aa0b65f3f9378f26a74c386683db420c33202998918df1eef492e93212e1849e1d85530f425602663cfc2bfbf385a30991b8a04470334c74ba2386b + checksum: 10/479827e62466e55bc1a50129d51597807bddc6c909e56be9e8dd9c1a91efa0f466a2f56b7d80438649e21ab0a3a195f840b3fccf2ae7f11fb0a919db8e62bc62 languageName: node linkType: hard @@ -13490,12 +13319,12 @@ __metadata: languageName: node linkType: hard -"@octokit/types@npm:^13.0.0, @octokit/types@npm:^13.1.0, @octokit/types@npm:^13.5.0": - version: 13.6.2 - resolution: "@octokit/types@npm:13.6.2" +"@octokit/types@npm:^13.0.0, @octokit/types@npm:^13.1.0, @octokit/types@npm:^13.7.0, @octokit/types@npm:^13.8.0": + version: 13.10.0 + resolution: "@octokit/types@npm:13.10.0" dependencies: - "@octokit/openapi-types": "npm:^22.2.0" - checksum: 10/8e614796f3554d28dfb77c570e80ef52d68ef311bdd4614ec263f8ea2266b9c06d4f7963fe2989f32cbfe4ea0c05e13eba9a64a6e0f64afb997cd975af154d52 + "@octokit/openapi-types": "npm:^24.2.0" + checksum: 10/32f8f5010d7faae128b0cdd0c221f0ca8c3781fe44483ecd87162b3da507db667f7369acda81340f6e2c9c374d9a938803409c6085c2c01d98210b6c58efb99a languageName: node linkType: hard @@ -13542,10 +13371,10 @@ __metadata: languageName: node linkType: hard -"@octokit/webhooks-methods@npm:^4.0.0": - version: 4.0.0 - resolution: "@octokit/webhooks-methods@npm:4.0.0" - checksum: 10/f26892ed868488bf08d5be1fdacbc51f5b6ba84cef21067e0b1ff969d087202989e74303049691a77c75bb1940e7835ad6522b0f4f151ceef015e6d083789c80 +"@octokit/webhooks-methods@npm:^4.1.0": + version: 4.1.0 + resolution: "@octokit/webhooks-methods@npm:4.1.0" + checksum: 10/a95ad68600c43798b09ea29d5a356fb69de25b45d38fbddf0ade00aadb0492b1d59985031e072a66d12e91034999a536653e5d2d4d01350d38cccf735d9ca270 languageName: node linkType: hard @@ -13556,10 +13385,10 @@ __metadata: languageName: node linkType: hard -"@octokit/webhooks-types@npm:7.1.0": - version: 7.1.0 - resolution: "@octokit/webhooks-types@npm:7.1.0" - checksum: 10/80b41945586243df9178a24dce9a5c4b2784eb963c5f6a1c76bcf5600a56e9cb51d8dc4a0da2108abfab3323cde577474a6365615fa1dfaac84c14e9295b54f9 +"@octokit/webhooks-types@npm:7.6.1": + version: 7.6.1 + resolution: "@octokit/webhooks-types@npm:7.6.1" + checksum: 10/0b11bd7e8d13b5a9cf14214421298a423d0180a5e1aaaea876ee4db6f97b5cca536f48d89af63105db75419d777a2402733eb0e110002d4dd59581ef36037bdc languageName: node linkType: hard @@ -13575,15 +13404,15 @@ __metadata: languageName: node linkType: hard -"@octokit/webhooks@npm:^12.0.4": - version: 12.0.10 - resolution: "@octokit/webhooks@npm:12.0.10" +"@octokit/webhooks@npm:^12.0.4, @octokit/webhooks@npm:^12.3.1": + version: 12.3.1 + resolution: "@octokit/webhooks@npm:12.3.1" dependencies: "@octokit/request-error": "npm:^5.0.0" - "@octokit/webhooks-methods": "npm:^4.0.0" - "@octokit/webhooks-types": "npm:7.1.0" + "@octokit/webhooks-methods": "npm:^4.1.0" + "@octokit/webhooks-types": "npm:7.6.1" aggregate-error: "npm:^3.1.0" - checksum: 10/ab7d216d1a1fae91bc3f75057c093707c1f6dbd5ff2106656154a7f471b1a1b5b78c947474e21362590e5510516f9537c4ab79ad6780cc91bfaaaa685aa366e0 + checksum: 10/373266807eb8dcf8d8c6f4685594106f1a257798a1b391cbe36e5b5faf60aca38a0467acd1356427ea7375edc111c03be3d443bc04efb16019a84e853c8a1bc3 languageName: node linkType: hard @@ -13628,14 +13457,14 @@ __metadata: linkType: hard "@openapitools/openapi-generator-cli@npm:^2.4.26, @openapitools/openapi-generator-cli@npm:^2.7.0": - version: 2.20.0 - resolution: "@openapitools/openapi-generator-cli@npm:2.20.0" + version: 2.20.2 + resolution: "@openapitools/openapi-generator-cli@npm:2.20.2" dependencies: "@nestjs/axios": "npm:4.0.0" - "@nestjs/common": "npm:11.0.20" - "@nestjs/core": "npm:11.0.20" + "@nestjs/common": "npm:11.1.1" + "@nestjs/core": "npm:11.1.1" "@nuxtjs/opencollective": "npm:0.3.2" - axios: "npm:1.8.4" + axios: "npm:1.9.0" chalk: "npm:4.1.2" commander: "npm:8.3.0" compare-versions: "npm:4.1.4" @@ -13651,7 +13480,7 @@ __metadata: tslib: "npm:2.8.1" bin: openapi-generator-cli: main.js - checksum: 10/b5114d7811505e4fd3e7fa050c1262a76510b1d9e0c1a0e24a417f9570ca986a2edc0c7234eea0e6e30aae2ed698d2e9815ccdd8a5d1663b5794e9e505868edb + checksum: 10/29807b52555e7307207eff6e0c4c1a25b970252915e13d847a6c275d1d638af0732761e51816f5bb5a91830ebabc044b3924a106db8cffa19dda01517a77be17 languageName: node linkType: hard @@ -15037,13 +14866,13 @@ __metadata: linkType: hard "@playwright/test@npm:^1.32.3": - version: 1.52.0 - resolution: "@playwright/test@npm:1.52.0" + version: 1.53.0 + resolution: "@playwright/test@npm:1.53.0" dependencies: - playwright: "npm:1.52.0" + playwright: "npm:1.53.0" bin: playwright: cli.js - checksum: 10/e18a4eb626c7bc6cba212ff2e197cf9ae2e4da1c91bfdf08a744d62e27222751173e4b220fa27da72286a89a3b4dea7c09daf384d23708f284b64f98e9a63a88 + checksum: 10/968df4fba133dd18b8c65504c3cc5a3a6071e49f0706c6524711cdfab321a51debfeb506b9ff0a8f7dd8ce3015921d82fa51429d8f11d392cc68de1938703c33 languageName: node linkType: hard @@ -15738,119 +15567,929 @@ __metadata: languageName: node linkType: hard -"@react-aria/focus@npm:^3.20.1": - version: 3.20.1 - resolution: "@react-aria/focus@npm:3.20.1" +"@react-aria/autocomplete@npm:3.0.0-beta.5": + version: 3.0.0-beta.5 + resolution: "@react-aria/autocomplete@npm:3.0.0-beta.5" dependencies: - "@react-aria/interactions": "npm:^3.24.1" - "@react-aria/utils": "npm:^3.28.1" - "@react-types/shared": "npm:^3.28.0" + "@react-aria/combobox": "npm:^3.12.5" + "@react-aria/focus": "npm:^3.20.5" + "@react-aria/i18n": "npm:^3.12.10" + "@react-aria/interactions": "npm:^3.25.3" + "@react-aria/listbox": "npm:^3.14.6" + "@react-aria/searchfield": "npm:^3.8.6" + "@react-aria/textfield": "npm:^3.17.5" + "@react-aria/utils": "npm:^3.29.1" + "@react-stately/autocomplete": "npm:3.0.0-beta.2" + "@react-stately/combobox": "npm:^3.10.6" + "@react-types/autocomplete": "npm:3.0.0-alpha.32" + "@react-types/button": "npm:^3.12.2" + "@react-types/shared": "npm:^3.30.0" + "@swc/helpers": "npm:^0.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/f8b4427b310a4bd221cb0e38b031a4150c306f7d1177926c5a2bea0dd4370db6e49e220ca2358c283ea4c009f0a65611340486d161193f7943659a60e20a1881 + languageName: node + linkType: hard + +"@react-aria/breadcrumbs@npm:^3.5.26": + version: 3.5.26 + resolution: "@react-aria/breadcrumbs@npm:3.5.26" + dependencies: + "@react-aria/i18n": "npm:^3.12.10" + "@react-aria/link": "npm:^3.8.3" + "@react-aria/utils": "npm:^3.29.1" + "@react-types/breadcrumbs": "npm:^3.7.14" + "@react-types/shared": "npm:^3.30.0" + "@swc/helpers": "npm:^0.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/e0b9fe416cb84281e207ab12644d3bf21d6af82b4ec5d5ac204209ef6aff9abcc242660c23b2f3ef3572aa0f1e72dcc33905066f720afa1ccfc3cf3d4b916c31 + languageName: node + linkType: hard + +"@react-aria/button@npm:^3.13.3": + version: 3.13.3 + resolution: "@react-aria/button@npm:3.13.3" + dependencies: + "@react-aria/interactions": "npm:^3.25.3" + "@react-aria/toolbar": "npm:3.0.0-beta.18" + "@react-aria/utils": "npm:^3.29.1" + "@react-stately/toggle": "npm:^3.8.5" + "@react-types/button": "npm:^3.12.2" + "@react-types/shared": "npm:^3.30.0" + "@swc/helpers": "npm:^0.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/c360899930f648c56f16bf5d0d2d8c01b5d59449b87fff4e758e68127aa8e453396ffbdc6ee0fa2fbcf18fce73472041da36d21929b2d28bd55770bbfd75e384 + languageName: node + linkType: hard + +"@react-aria/calendar@npm:^3.8.3": + version: 3.8.3 + resolution: "@react-aria/calendar@npm:3.8.3" + dependencies: + "@internationalized/date": "npm:^3.8.2" + "@react-aria/i18n": "npm:^3.12.10" + "@react-aria/interactions": "npm:^3.25.3" + "@react-aria/live-announcer": "npm:^3.4.3" + "@react-aria/utils": "npm:^3.29.1" + "@react-stately/calendar": "npm:^3.8.2" + "@react-types/button": "npm:^3.12.2" + "@react-types/calendar": "npm:^3.7.2" + "@react-types/shared": "npm:^3.30.0" + "@swc/helpers": "npm:^0.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/53570c8c95fced3704a908ba218ee316db46f5c58352a5970f3b0a863257d8293dd732b0aaeb983921358f45acd50df623db88afa49df4d6735508d08369212b + languageName: node + linkType: hard + +"@react-aria/checkbox@npm:^3.15.7": + version: 3.15.7 + resolution: "@react-aria/checkbox@npm:3.15.7" + dependencies: + "@react-aria/form": "npm:^3.0.18" + "@react-aria/interactions": "npm:^3.25.3" + "@react-aria/label": "npm:^3.7.19" + "@react-aria/toggle": "npm:^3.11.5" + "@react-aria/utils": "npm:^3.29.1" + "@react-stately/checkbox": "npm:^3.6.15" + "@react-stately/form": "npm:^3.1.5" + "@react-stately/toggle": "npm:^3.8.5" + "@react-types/checkbox": "npm:^3.9.5" + "@react-types/shared": "npm:^3.30.0" + "@swc/helpers": "npm:^0.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/a041baf3977d41f0f46db184b80da9f4d928209ca0bd764cb43202e5fc2f7a1ed44d7b9963d38f11dab934bf0ac5c0ee9311894b8177ed890c4f174b0640b8c8 + languageName: node + linkType: hard + +"@react-aria/collections@npm:3.0.0-rc.3": + version: 3.0.0-rc.3 + resolution: "@react-aria/collections@npm:3.0.0-rc.3" + dependencies: + "@react-aria/interactions": "npm:^3.25.3" + "@react-aria/ssr": "npm:^3.9.9" + "@react-aria/utils": "npm:^3.29.1" + "@react-types/shared": "npm:^3.30.0" + "@swc/helpers": "npm:^0.5.0" + use-sync-external-store: "npm:^1.4.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/a7a6ba15554ba6f3047cf6898a222e800b8317d4f0b05dbe11cf4301bc3aaa249ea2ae855ec4b0afd9f95c33e47f9ad10227299f6c382995155d91a94ce91493 + languageName: node + linkType: hard + +"@react-aria/color@npm:^3.0.9": + version: 3.0.9 + resolution: "@react-aria/color@npm:3.0.9" + dependencies: + "@react-aria/i18n": "npm:^3.12.10" + "@react-aria/interactions": "npm:^3.25.3" + "@react-aria/numberfield": "npm:^3.11.16" + "@react-aria/slider": "npm:^3.7.21" + "@react-aria/spinbutton": "npm:^3.6.16" + "@react-aria/textfield": "npm:^3.17.5" + "@react-aria/utils": "npm:^3.29.1" + "@react-aria/visually-hidden": "npm:^3.8.25" + "@react-stately/color": "npm:^3.8.6" + "@react-stately/form": "npm:^3.1.5" + "@react-types/color": "npm:^3.0.6" + "@react-types/shared": "npm:^3.30.0" + "@swc/helpers": "npm:^0.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/387b1609bafa89297525384925f5c7e290f5a2b592488daae4482873518401b0b5f1eb712000a3ad823f66888937499d3e0522b85ae9adc1e819ea8761abf19a + languageName: node + linkType: hard + +"@react-aria/combobox@npm:^3.12.5": + version: 3.12.5 + resolution: "@react-aria/combobox@npm:3.12.5" + dependencies: + "@react-aria/focus": "npm:^3.20.5" + "@react-aria/i18n": "npm:^3.12.10" + "@react-aria/listbox": "npm:^3.14.6" + "@react-aria/live-announcer": "npm:^3.4.3" + "@react-aria/menu": "npm:^3.18.5" + "@react-aria/overlays": "npm:^3.27.3" + "@react-aria/selection": "npm:^3.24.3" + "@react-aria/textfield": "npm:^3.17.5" + "@react-aria/utils": "npm:^3.29.1" + "@react-stately/collections": "npm:^3.12.5" + "@react-stately/combobox": "npm:^3.10.6" + "@react-stately/form": "npm:^3.1.5" + "@react-types/button": "npm:^3.12.2" + "@react-types/combobox": "npm:^3.13.6" + "@react-types/shared": "npm:^3.30.0" + "@swc/helpers": "npm:^0.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/171d27bb3a2eefc3c5e3ecdca1d760e44116a68d6169bfa214b05caf840aa879033855a3c1ea273f8d288d066800182f4f8a1299c3dbb7f0dff137db78ad9c41 + languageName: node + linkType: hard + +"@react-aria/datepicker@npm:^3.14.5": + version: 3.14.5 + resolution: "@react-aria/datepicker@npm:3.14.5" + dependencies: + "@internationalized/date": "npm:^3.8.2" + "@internationalized/number": "npm:^3.6.3" + "@internationalized/string": "npm:^3.2.7" + "@react-aria/focus": "npm:^3.20.5" + "@react-aria/form": "npm:^3.0.18" + "@react-aria/i18n": "npm:^3.12.10" + "@react-aria/interactions": "npm:^3.25.3" + "@react-aria/label": "npm:^3.7.19" + "@react-aria/spinbutton": "npm:^3.6.16" + "@react-aria/utils": "npm:^3.29.1" + "@react-stately/datepicker": "npm:^3.14.2" + "@react-stately/form": "npm:^3.1.5" + "@react-types/button": "npm:^3.12.2" + "@react-types/calendar": "npm:^3.7.2" + "@react-types/datepicker": "npm:^3.12.2" + "@react-types/dialog": "npm:^3.5.19" + "@react-types/shared": "npm:^3.30.0" + "@swc/helpers": "npm:^0.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/440475577e9aee6c18c5e8f5d2c91f22f5a528ee283b472627eb8cf226c7a2125fa537b30b7e5f20e9d6325631e13c5dfa23f88d6f7e6c1e9fd41eff8ccb7590 + languageName: node + linkType: hard + +"@react-aria/dialog@npm:^3.5.27": + version: 3.5.27 + resolution: "@react-aria/dialog@npm:3.5.27" + dependencies: + "@react-aria/interactions": "npm:^3.25.3" + "@react-aria/overlays": "npm:^3.27.3" + "@react-aria/utils": "npm:^3.29.1" + "@react-types/dialog": "npm:^3.5.19" + "@react-types/shared": "npm:^3.30.0" + "@swc/helpers": "npm:^0.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/21257bb14352ab611e5659ce555cd845d8de51d30eea0cf7882b5119848c2136cd35f796a3031bbbcbc9640bffadeb35eee6f6254b34f2791c5a739c550e60da + languageName: node + linkType: hard + +"@react-aria/disclosure@npm:^3.0.6": + version: 3.0.6 + resolution: "@react-aria/disclosure@npm:3.0.6" + dependencies: + "@react-aria/ssr": "npm:^3.9.9" + "@react-aria/utils": "npm:^3.29.1" + "@react-stately/disclosure": "npm:^3.0.5" + "@react-types/button": "npm:^3.12.2" + "@swc/helpers": "npm:^0.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/c1e602d6bc91b8b4884b2ec4ef4c3f1ea3d3052ead219a73eb4be110348ef0bde8fd3a68af92e7d8af83a59465b208e8a0d363b1ecffde53134516ce13f0361a + languageName: node + linkType: hard + +"@react-aria/dnd@npm:^3.10.1": + version: 3.10.1 + resolution: "@react-aria/dnd@npm:3.10.1" + dependencies: + "@internationalized/string": "npm:^3.2.7" + "@react-aria/i18n": "npm:^3.12.10" + "@react-aria/interactions": "npm:^3.25.3" + "@react-aria/live-announcer": "npm:^3.4.3" + "@react-aria/overlays": "npm:^3.27.3" + "@react-aria/utils": "npm:^3.29.1" + "@react-stately/collections": "npm:^3.12.5" + "@react-stately/dnd": "npm:^3.6.0" + "@react-types/button": "npm:^3.12.2" + "@react-types/shared": "npm:^3.30.0" + "@swc/helpers": "npm:^0.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/bf1058f59d20054571541455d9fa25eff469363b6f65852d237d9479bee4d6323fc3bd8497115d16e93d4396ab2faba0317875416c93d65a1a566881771624c1 + languageName: node + linkType: hard + +"@react-aria/focus@npm:^3.20.5": + version: 3.20.5 + resolution: "@react-aria/focus@npm:3.20.5" + dependencies: + "@react-aria/interactions": "npm:^3.25.3" + "@react-aria/utils": "npm:^3.29.1" + "@react-types/shared": "npm:^3.30.0" "@swc/helpers": "npm:^0.5.0" clsx: "npm:^2.0.0" peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - checksum: 10/7f4652ebbb19a4ede9abce38bf756a44fdebcd6aa6d095ac304cefbed014f1456c45b3cc4e66d0132ffc55ebd5b9c8ba1ed83f61c39b63007a307d06cc12efc3 + checksum: 10/543c2f18c1d4f10940662608ca67947d1bc22630ae272e73136b36c2aefec61243148668201442132825bf4e9c0ab64add86c9870b9a51cb7bde2dfab7453a6e languageName: node linkType: hard -"@react-aria/i18n@npm:^3.12.7": - version: 3.12.7 - resolution: "@react-aria/i18n@npm:3.12.7" +"@react-aria/form@npm:^3.0.18": + version: 3.0.18 + resolution: "@react-aria/form@npm:3.0.18" dependencies: - "@internationalized/date": "npm:^3.7.0" - "@internationalized/message": "npm:^3.1.6" - "@internationalized/number": "npm:^3.6.0" - "@internationalized/string": "npm:^3.2.5" - "@react-aria/ssr": "npm:^3.9.7" - "@react-aria/utils": "npm:^3.28.1" - "@react-types/shared": "npm:^3.28.0" + "@react-aria/interactions": "npm:^3.25.3" + "@react-aria/utils": "npm:^3.29.1" + "@react-stately/form": "npm:^3.1.5" + "@react-types/shared": "npm:^3.30.0" "@swc/helpers": "npm:^0.5.0" peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - checksum: 10/5f086ccc0a7e03637a4c74b2178aa8da9d5992eb15bc55f6ae804692bce01eeca89cc05e967eda6f2705ffb61404c5f9f995f9907063fba212685a7145f54d3d + checksum: 10/8c3edfaf3f2be28a16d7b0dcf00c677926e6e505fe26ebc348201f6f4e9e44aced1f17400a6c19717b18a3378be28438f269b438317a18f2070529fe2ac1e770 languageName: node linkType: hard -"@react-aria/interactions@npm:^3.24.1": - version: 3.24.1 - resolution: "@react-aria/interactions@npm:3.24.1" +"@react-aria/grid@npm:^3.14.2": + version: 3.14.2 + resolution: "@react-aria/grid@npm:3.14.2" dependencies: - "@react-aria/ssr": "npm:^3.9.7" - "@react-aria/utils": "npm:^3.28.1" - "@react-stately/flags": "npm:^3.1.0" - "@react-types/shared": "npm:^3.28.0" + "@react-aria/focus": "npm:^3.20.5" + "@react-aria/i18n": "npm:^3.12.10" + "@react-aria/interactions": "npm:^3.25.3" + "@react-aria/live-announcer": "npm:^3.4.3" + "@react-aria/selection": "npm:^3.24.3" + "@react-aria/utils": "npm:^3.29.1" + "@react-stately/collections": "npm:^3.12.5" + "@react-stately/grid": "npm:^3.11.3" + "@react-stately/selection": "npm:^3.20.3" + "@react-types/checkbox": "npm:^3.9.5" + "@react-types/grid": "npm:^3.3.3" + "@react-types/shared": "npm:^3.30.0" "@swc/helpers": "npm:^0.5.0" peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - checksum: 10/79e40d68b980a84b0a64d8ebf030303558693b489694d439e46e419c79355d632cf3975a52eed30ddce90fff115d9172f6e3e8af5777b69c1a143f4ad81fef1e + checksum: 10/5f19539b1fe01d82b3693166269acae3fe74467b318f257babca79e5689b932ec83e5d7894ea0cbfd5e568fae3ffa61d04ae049a8967af09384f12d8e75792fa languageName: node linkType: hard -"@react-aria/overlays@npm:^3.26.1": - version: 3.26.1 - resolution: "@react-aria/overlays@npm:3.26.1" +"@react-aria/gridlist@npm:^3.13.2": + version: 3.13.2 + resolution: "@react-aria/gridlist@npm:3.13.2" dependencies: - "@react-aria/focus": "npm:^3.20.1" - "@react-aria/i18n": "npm:^3.12.7" - "@react-aria/interactions": "npm:^3.24.1" - "@react-aria/ssr": "npm:^3.9.7" - "@react-aria/utils": "npm:^3.28.1" - "@react-aria/visually-hidden": "npm:^3.8.21" - "@react-stately/overlays": "npm:^3.6.14" - "@react-types/button": "npm:^3.11.0" - "@react-types/overlays": "npm:^3.8.13" - "@react-types/shared": "npm:^3.28.0" + "@react-aria/focus": "npm:^3.20.5" + "@react-aria/grid": "npm:^3.14.2" + "@react-aria/i18n": "npm:^3.12.10" + "@react-aria/interactions": "npm:^3.25.3" + "@react-aria/selection": "npm:^3.24.3" + "@react-aria/utils": "npm:^3.29.1" + "@react-stately/collections": "npm:^3.12.5" + "@react-stately/list": "npm:^3.12.3" + "@react-stately/tree": "npm:^3.9.0" + "@react-types/shared": "npm:^3.30.0" "@swc/helpers": "npm:^0.5.0" peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - checksum: 10/25d582fa5905c9ec42339ddae4aa9fce5d606a504e657d243b0b72fb77316b879c105b4d89e9c394de0aa9ea8514c38c42278d36b6fdd5de57233785fbd17a8c + checksum: 10/ea5e2f986fc74b627afe4918f94aa8cc778f146d7781822ce55788bb59a90e5765446d7c0bb5bcc86c1e4dd17ced3bd52ab6f703a50e8253bef25b70d3be0b56 languageName: node linkType: hard -"@react-aria/ssr@npm:^3.9.7": - version: 3.9.7 - resolution: "@react-aria/ssr@npm:3.9.7" +"@react-aria/i18n@npm:^3.12.10": + version: 3.12.10 + resolution: "@react-aria/i18n@npm:3.12.10" + dependencies: + "@internationalized/date": "npm:^3.8.2" + "@internationalized/message": "npm:^3.1.8" + "@internationalized/number": "npm:^3.6.3" + "@internationalized/string": "npm:^3.2.7" + "@react-aria/ssr": "npm:^3.9.9" + "@react-aria/utils": "npm:^3.29.1" + "@react-types/shared": "npm:^3.30.0" + "@swc/helpers": "npm:^0.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/6f331ceb62a1364d32f2336257ed82715f712e27d3e04a173296efc320f6532626561e883c2c3639ef4efdcd03498005e87d7160d8942ea8255d18d57770d3a0 + languageName: node + linkType: hard + +"@react-aria/interactions@npm:^3.25.3": + version: 3.25.3 + resolution: "@react-aria/interactions@npm:3.25.3" + dependencies: + "@react-aria/ssr": "npm:^3.9.9" + "@react-aria/utils": "npm:^3.29.1" + "@react-stately/flags": "npm:^3.1.2" + "@react-types/shared": "npm:^3.30.0" + "@swc/helpers": "npm:^0.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/21754f3e15c35430262b8e283d00010543c8855bac9b9feeb701c967394940d4063b63380b59637c7da8e9b922f29edb3525d15d6005202a6dc22fd32a0d951f + languageName: node + linkType: hard + +"@react-aria/label@npm:^3.7.19": + version: 3.7.19 + resolution: "@react-aria/label@npm:3.7.19" + dependencies: + "@react-aria/utils": "npm:^3.29.1" + "@react-types/shared": "npm:^3.30.0" + "@swc/helpers": "npm:^0.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/984a97ac0bca6487031bc006d8b697766d990e78e381d5e230414429542e51d84197459b45b834069615d9f17f5b162e671e464e62f78854ac8fbb458d1b3346 + languageName: node + linkType: hard + +"@react-aria/landmark@npm:^3.0.4": + version: 3.0.4 + resolution: "@react-aria/landmark@npm:3.0.4" + dependencies: + "@react-aria/utils": "npm:^3.29.1" + "@react-types/shared": "npm:^3.30.0" + "@swc/helpers": "npm:^0.5.0" + use-sync-external-store: "npm:^1.4.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/ab1d9cc93e83b0f486157dc878474e59b601631220bb688840c55baf6ccfd65d8fe2a04adaaa055f0e2883f3e7428b74d52cc13d32e15f930c0cb1c189309ee8 + languageName: node + linkType: hard + +"@react-aria/link@npm:^3.8.3": + version: 3.8.3 + resolution: "@react-aria/link@npm:3.8.3" + dependencies: + "@react-aria/interactions": "npm:^3.25.3" + "@react-aria/utils": "npm:^3.29.1" + "@react-types/link": "npm:^3.6.2" + "@react-types/shared": "npm:^3.30.0" + "@swc/helpers": "npm:^0.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/978f875a81616f46706da3596dfb52845af93420c3b2ce29d83c8eed5203cd0b5bdd3f988039dff3e3420de668927be46c2971333d628fa7af3f83b7796159f8 + languageName: node + linkType: hard + +"@react-aria/listbox@npm:^3.14.6": + version: 3.14.6 + resolution: "@react-aria/listbox@npm:3.14.6" + dependencies: + "@react-aria/interactions": "npm:^3.25.3" + "@react-aria/label": "npm:^3.7.19" + "@react-aria/selection": "npm:^3.24.3" + "@react-aria/utils": "npm:^3.29.1" + "@react-stately/collections": "npm:^3.12.5" + "@react-stately/list": "npm:^3.12.3" + "@react-types/listbox": "npm:^3.7.1" + "@react-types/shared": "npm:^3.30.0" + "@swc/helpers": "npm:^0.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/068a1e5d56516436dbc8bde6e3a98db7ec277f0a0ce73ce6334e762c196570ae751dc0b0503f1e66624569d89ce412bc9292fa67f5a52db03db3104bb1d2f300 + languageName: node + linkType: hard + +"@react-aria/live-announcer@npm:^3.4.3": + version: 3.4.3 + resolution: "@react-aria/live-announcer@npm:3.4.3" + dependencies: + "@swc/helpers": "npm:^0.5.0" + checksum: 10/73e3fc9bc2796cbccbcd0e01e2b4bd62d0b1a3915b1d0f01d2054141033c6b2a5275a7b7c52bdc0a3b9ef738881b4a84bb5d6df57d1ee066278e5bdf40a8f979 + languageName: node + linkType: hard + +"@react-aria/menu@npm:^3.18.5": + version: 3.18.5 + resolution: "@react-aria/menu@npm:3.18.5" + dependencies: + "@react-aria/focus": "npm:^3.20.5" + "@react-aria/i18n": "npm:^3.12.10" + "@react-aria/interactions": "npm:^3.25.3" + "@react-aria/overlays": "npm:^3.27.3" + "@react-aria/selection": "npm:^3.24.3" + "@react-aria/utils": "npm:^3.29.1" + "@react-stately/collections": "npm:^3.12.5" + "@react-stately/menu": "npm:^3.9.5" + "@react-stately/selection": "npm:^3.20.3" + "@react-stately/tree": "npm:^3.9.0" + "@react-types/button": "npm:^3.12.2" + "@react-types/menu": "npm:^3.10.2" + "@react-types/shared": "npm:^3.30.0" + "@swc/helpers": "npm:^0.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/409f21cfa7d9cca62ca7c21b047bd72314181782b2d6ea0bb16a33075280653eef1b4d9c4b0ad15ebe72ec59e12103f3b1f86e6e7cd8886571956d6d099ae200 + languageName: node + linkType: hard + +"@react-aria/meter@npm:^3.4.24": + version: 3.4.24 + resolution: "@react-aria/meter@npm:3.4.24" + dependencies: + "@react-aria/progress": "npm:^3.4.24" + "@react-types/meter": "npm:^3.4.10" + "@react-types/shared": "npm:^3.30.0" + "@swc/helpers": "npm:^0.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/980e46d3b784c59523ea9eb342c28e2a29e0549937da4def5f61ce011abb2da40f833dbe3f14550ffcd384860e08d4e8ee286e58834100b04c7de93fa5587e50 + languageName: node + linkType: hard + +"@react-aria/numberfield@npm:^3.11.16": + version: 3.11.16 + resolution: "@react-aria/numberfield@npm:3.11.16" + dependencies: + "@react-aria/i18n": "npm:^3.12.10" + "@react-aria/interactions": "npm:^3.25.3" + "@react-aria/spinbutton": "npm:^3.6.16" + "@react-aria/textfield": "npm:^3.17.5" + "@react-aria/utils": "npm:^3.29.1" + "@react-stately/form": "npm:^3.1.5" + "@react-stately/numberfield": "npm:^3.9.13" + "@react-types/button": "npm:^3.12.2" + "@react-types/numberfield": "npm:^3.8.12" + "@react-types/shared": "npm:^3.30.0" + "@swc/helpers": "npm:^0.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/3e83938fe4fe76ef662c543734988b56d60824d8d2d19de5adffe06191106aa98b2b6dd4241ed49fc3e7ad3e1c4c43cbdd81c6fc32d728959e5b377faf8ffdcd + languageName: node + linkType: hard + +"@react-aria/overlays@npm:^3.26.1, @react-aria/overlays@npm:^3.27.3": + version: 3.27.3 + resolution: "@react-aria/overlays@npm:3.27.3" + dependencies: + "@react-aria/focus": "npm:^3.20.5" + "@react-aria/i18n": "npm:^3.12.10" + "@react-aria/interactions": "npm:^3.25.3" + "@react-aria/ssr": "npm:^3.9.9" + "@react-aria/utils": "npm:^3.29.1" + "@react-aria/visually-hidden": "npm:^3.8.25" + "@react-stately/overlays": "npm:^3.6.17" + "@react-types/button": "npm:^3.12.2" + "@react-types/overlays": "npm:^3.8.16" + "@react-types/shared": "npm:^3.30.0" + "@swc/helpers": "npm:^0.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/8cee1a99bc9ff4ecf0577b76f54cccaf684dde2278d0c270e82c683ef6f42bb8100de4596ae411e775643a3765abbd87fdb1c5d46bf05481ed9df9ed9b82276a + languageName: node + linkType: hard + +"@react-aria/progress@npm:^3.4.24": + version: 3.4.24 + resolution: "@react-aria/progress@npm:3.4.24" + dependencies: + "@react-aria/i18n": "npm:^3.12.10" + "@react-aria/label": "npm:^3.7.19" + "@react-aria/utils": "npm:^3.29.1" + "@react-types/progress": "npm:^3.5.13" + "@react-types/shared": "npm:^3.30.0" + "@swc/helpers": "npm:^0.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/e7e4cf6f904f1b35a54704aa6d473c4eb239130ba8fbba71f6298b68a92c067162132fb5adf1e6f8960bdc8a2913004d979e088575761b0ba5252c28cdf62b0b + languageName: node + linkType: hard + +"@react-aria/radio@npm:^3.11.5": + version: 3.11.5 + resolution: "@react-aria/radio@npm:3.11.5" + dependencies: + "@react-aria/focus": "npm:^3.20.5" + "@react-aria/form": "npm:^3.0.18" + "@react-aria/i18n": "npm:^3.12.10" + "@react-aria/interactions": "npm:^3.25.3" + "@react-aria/label": "npm:^3.7.19" + "@react-aria/utils": "npm:^3.29.1" + "@react-stately/radio": "npm:^3.10.14" + "@react-types/radio": "npm:^3.8.10" + "@react-types/shared": "npm:^3.30.0" + "@swc/helpers": "npm:^0.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/63bbca9ad7a065453f60bb759c0377a8febeb0e4582807726d7eef36a05c806d6d0c9d86ad7b73c42cc0a1c47bab5a1d0369e0d670fc4f58924662395418b24d + languageName: node + linkType: hard + +"@react-aria/searchfield@npm:^3.8.6": + version: 3.8.6 + resolution: "@react-aria/searchfield@npm:3.8.6" + dependencies: + "@react-aria/i18n": "npm:^3.12.10" + "@react-aria/textfield": "npm:^3.17.5" + "@react-aria/utils": "npm:^3.29.1" + "@react-stately/searchfield": "npm:^3.5.13" + "@react-types/button": "npm:^3.12.2" + "@react-types/searchfield": "npm:^3.6.3" + "@react-types/shared": "npm:^3.30.0" + "@swc/helpers": "npm:^0.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/7db3dd61084e49c9d2c9fa9aa10821087aff91cfadeade78b559cd1877c67a49dcdd238b48a8b2501cd7070b9123d276e8ef6170cb5438cdce28ef6889eea366 + languageName: node + linkType: hard + +"@react-aria/select@npm:^3.15.7": + version: 3.15.7 + resolution: "@react-aria/select@npm:3.15.7" + dependencies: + "@react-aria/form": "npm:^3.0.18" + "@react-aria/i18n": "npm:^3.12.10" + "@react-aria/interactions": "npm:^3.25.3" + "@react-aria/label": "npm:^3.7.19" + "@react-aria/listbox": "npm:^3.14.6" + "@react-aria/menu": "npm:^3.18.5" + "@react-aria/selection": "npm:^3.24.3" + "@react-aria/utils": "npm:^3.29.1" + "@react-aria/visually-hidden": "npm:^3.8.25" + "@react-stately/select": "npm:^3.6.14" + "@react-types/button": "npm:^3.12.2" + "@react-types/select": "npm:^3.9.13" + "@react-types/shared": "npm:^3.30.0" + "@swc/helpers": "npm:^0.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/8e0974ddc558051c384a7d9da1eeea4623cbe4a61f0f0402aebeb4be23a1cb5875b839608dcc6aaca4ab6c288143c202eb0fa2ee3ed8f62b7e33d142604f2fba + languageName: node + linkType: hard + +"@react-aria/selection@npm:^3.24.3": + version: 3.24.3 + resolution: "@react-aria/selection@npm:3.24.3" + dependencies: + "@react-aria/focus": "npm:^3.20.5" + "@react-aria/i18n": "npm:^3.12.10" + "@react-aria/interactions": "npm:^3.25.3" + "@react-aria/utils": "npm:^3.29.1" + "@react-stately/selection": "npm:^3.20.3" + "@react-types/shared": "npm:^3.30.0" + "@swc/helpers": "npm:^0.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/f2575161b69d87e7c5ee7d0d658c96c97e815a0de74d121f3744efcfb62f181efd3250f3842b0347d54e9d27c85b41292728927efb3bcc2bdcf8873d92647eb1 + languageName: node + linkType: hard + +"@react-aria/separator@npm:^3.4.10": + version: 3.4.10 + resolution: "@react-aria/separator@npm:3.4.10" + dependencies: + "@react-aria/utils": "npm:^3.29.1" + "@react-types/shared": "npm:^3.30.0" + "@swc/helpers": "npm:^0.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/706aed510aa306f70ff98a82061995f3fb1ffa6ca0134b282ac9a776441fe4241ff87f8008fa04761b3edaadf8020c96f55720821a7ff4b5c362cad3eb7ed98a + languageName: node + linkType: hard + +"@react-aria/slider@npm:^3.7.21": + version: 3.7.21 + resolution: "@react-aria/slider@npm:3.7.21" + dependencies: + "@react-aria/i18n": "npm:^3.12.10" + "@react-aria/interactions": "npm:^3.25.3" + "@react-aria/label": "npm:^3.7.19" + "@react-aria/utils": "npm:^3.29.1" + "@react-stately/slider": "npm:^3.6.5" + "@react-types/shared": "npm:^3.30.0" + "@react-types/slider": "npm:^3.7.12" + "@swc/helpers": "npm:^0.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/1a063533b33f224adf782840664e517a8034a28129648908b7391c648c4141c58103dc9733c81f12b1848320669dcca64a059a3279c4114ae81df796a274da59 + languageName: node + linkType: hard + +"@react-aria/spinbutton@npm:^3.6.16": + version: 3.6.16 + resolution: "@react-aria/spinbutton@npm:3.6.16" + dependencies: + "@react-aria/i18n": "npm:^3.12.10" + "@react-aria/live-announcer": "npm:^3.4.3" + "@react-aria/utils": "npm:^3.29.1" + "@react-types/button": "npm:^3.12.2" + "@react-types/shared": "npm:^3.30.0" + "@swc/helpers": "npm:^0.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/2f032d3206738902e91661b0e5ff1cdd75005c40b75a219bbf6aab48b3aad16d1d1090c873ab2e1e0400dee74db56c455948ff2ebe0a6c7f1edb200dfea826e5 + languageName: node + linkType: hard + +"@react-aria/ssr@npm:^3.9.9": + version: 3.9.9 + resolution: "@react-aria/ssr@npm:3.9.9" dependencies: "@swc/helpers": "npm:^0.5.0" peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - checksum: 10/a5c8e9ffee1dfd3c5b9f66051a7faab11d53ba001ac7f476b61fa4b38fd8b4835c1a85ff2157ec25fb5b63beb88fbae9e80610fa065a30cbe30875fcbca3114b + checksum: 10/d0675357b51784e9dbe3add97aa0e6acc810ab0ef01d1c7a317ff8ead5eae64d66c60cc751ea3d10f874bb381e445099bb31cb7f1955801848ce6dce91b588a2 languageName: node linkType: hard -"@react-aria/utils@npm:^3.28.1": - version: 3.28.1 - resolution: "@react-aria/utils@npm:3.28.1" +"@react-aria/switch@npm:^3.7.5": + version: 3.7.5 + resolution: "@react-aria/switch@npm:3.7.5" dependencies: - "@react-aria/ssr": "npm:^3.9.7" - "@react-stately/flags": "npm:^3.1.0" - "@react-stately/utils": "npm:^3.10.5" - "@react-types/shared": "npm:^3.28.0" + "@react-aria/toggle": "npm:^3.11.5" + "@react-stately/toggle": "npm:^3.8.5" + "@react-types/shared": "npm:^3.30.0" + "@react-types/switch": "npm:^3.5.12" + "@swc/helpers": "npm:^0.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/1f716296b444b1db28bd55493ddabbdc403fc48a865cbbd0e383e69e2e42b97e778446383740330cf7e76a4a2dcc0de6f84fed1cddd0f0760b6ffa34118794cb + languageName: node + linkType: hard + +"@react-aria/table@npm:^3.17.5": + version: 3.17.5 + resolution: "@react-aria/table@npm:3.17.5" + dependencies: + "@react-aria/focus": "npm:^3.20.5" + "@react-aria/grid": "npm:^3.14.2" + "@react-aria/i18n": "npm:^3.12.10" + "@react-aria/interactions": "npm:^3.25.3" + "@react-aria/live-announcer": "npm:^3.4.3" + "@react-aria/utils": "npm:^3.29.1" + "@react-aria/visually-hidden": "npm:^3.8.25" + "@react-stately/collections": "npm:^3.12.5" + "@react-stately/flags": "npm:^3.1.2" + "@react-stately/table": "npm:^3.14.3" + "@react-types/checkbox": "npm:^3.9.5" + "@react-types/grid": "npm:^3.3.3" + "@react-types/shared": "npm:^3.30.0" + "@react-types/table": "npm:^3.13.1" + "@swc/helpers": "npm:^0.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/d10e2432b66b0279413fec031673172ed8c49d93185cd1657511467b04ec780bc089a7e45d75c9ba71c94419355107e961e679acd254da8a19d446e1c9343a70 + languageName: node + linkType: hard + +"@react-aria/tabs@npm:^3.10.5": + version: 3.10.5 + resolution: "@react-aria/tabs@npm:3.10.5" + dependencies: + "@react-aria/focus": "npm:^3.20.5" + "@react-aria/i18n": "npm:^3.12.10" + "@react-aria/selection": "npm:^3.24.3" + "@react-aria/utils": "npm:^3.29.1" + "@react-stately/tabs": "npm:^3.8.3" + "@react-types/shared": "npm:^3.30.0" + "@react-types/tabs": "npm:^3.3.16" + "@swc/helpers": "npm:^0.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/39db9d4d5a0e87e7cbdb91bcdc5385e02fd21cb1e1c181ecf226e6b0fba9c948c03623cceb11d831a87056c6bc3a0528a7e7a9f58292b0c4dfaa6b9cce56f3bb + languageName: node + linkType: hard + +"@react-aria/tag@npm:^3.6.2": + version: 3.6.2 + resolution: "@react-aria/tag@npm:3.6.2" + dependencies: + "@react-aria/gridlist": "npm:^3.13.2" + "@react-aria/i18n": "npm:^3.12.10" + "@react-aria/interactions": "npm:^3.25.3" + "@react-aria/label": "npm:^3.7.19" + "@react-aria/selection": "npm:^3.24.3" + "@react-aria/utils": "npm:^3.29.1" + "@react-stately/list": "npm:^3.12.3" + "@react-types/button": "npm:^3.12.2" + "@react-types/shared": "npm:^3.30.0" + "@swc/helpers": "npm:^0.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/fbfb3a9769077bcc23199aacd80c83b42e89f752d0690c6a5751d9a95b6e760365be2915fa134db9ad040355b341b150270f553ece6f791378a27102e90e7fca + languageName: node + linkType: hard + +"@react-aria/textfield@npm:^3.17.5": + version: 3.17.5 + resolution: "@react-aria/textfield@npm:3.17.5" + dependencies: + "@react-aria/form": "npm:^3.0.18" + "@react-aria/interactions": "npm:^3.25.3" + "@react-aria/label": "npm:^3.7.19" + "@react-aria/utils": "npm:^3.29.1" + "@react-stately/form": "npm:^3.1.5" + "@react-stately/utils": "npm:^3.10.7" + "@react-types/shared": "npm:^3.30.0" + "@react-types/textfield": "npm:^3.12.3" + "@swc/helpers": "npm:^0.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/59f2df9650b8acb961a1eaec59bb8a0b18ef6b0b1f3d8bbc2f398ae4fcfc8b3a2a2c22c357319bb53bc166b4e2c624ab58187104621b164de22f465ab342f72d + languageName: node + linkType: hard + +"@react-aria/toast@npm:^3.0.5": + version: 3.0.5 + resolution: "@react-aria/toast@npm:3.0.5" + dependencies: + "@react-aria/i18n": "npm:^3.12.10" + "@react-aria/interactions": "npm:^3.25.3" + "@react-aria/landmark": "npm:^3.0.4" + "@react-aria/utils": "npm:^3.29.1" + "@react-stately/toast": "npm:^3.1.1" + "@react-types/button": "npm:^3.12.2" + "@react-types/shared": "npm:^3.30.0" + "@swc/helpers": "npm:^0.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/d674bde2446e29b44fe393386da154d8a467954edf29c9c2cdb922972ea6f962e4f16220c03a410bb0be555b9f96f96f71146762123b9d9187e081a74696bee2 + languageName: node + linkType: hard + +"@react-aria/toggle@npm:^3.11.5": + version: 3.11.5 + resolution: "@react-aria/toggle@npm:3.11.5" + dependencies: + "@react-aria/interactions": "npm:^3.25.3" + "@react-aria/utils": "npm:^3.29.1" + "@react-stately/toggle": "npm:^3.8.5" + "@react-types/checkbox": "npm:^3.9.5" + "@react-types/shared": "npm:^3.30.0" + "@swc/helpers": "npm:^0.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/6490a53496b317d3f12c93e347b2d9dd0e7e4835d66eb0823612d3918836338566c0ed2ac22bf4d94649c6019bf411d9c9a1b8f49d420d52eab8f737c2c3f8c5 + languageName: node + linkType: hard + +"@react-aria/toolbar@npm:3.0.0-beta.18": + version: 3.0.0-beta.18 + resolution: "@react-aria/toolbar@npm:3.0.0-beta.18" + dependencies: + "@react-aria/focus": "npm:^3.20.5" + "@react-aria/i18n": "npm:^3.12.10" + "@react-aria/utils": "npm:^3.29.1" + "@react-types/shared": "npm:^3.30.0" + "@swc/helpers": "npm:^0.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/0ea1d0d73dad265773678fc66712800840b20558d3e19f0b6aa1f0953ba57e48be9ad293d1f48db3e609b017998ded11227d1aebfb998bcfbe05467498318ced + languageName: node + linkType: hard + +"@react-aria/tooltip@npm:^3.8.5": + version: 3.8.5 + resolution: "@react-aria/tooltip@npm:3.8.5" + dependencies: + "@react-aria/interactions": "npm:^3.25.3" + "@react-aria/utils": "npm:^3.29.1" + "@react-stately/tooltip": "npm:^3.5.5" + "@react-types/shared": "npm:^3.30.0" + "@react-types/tooltip": "npm:^3.4.18" + "@swc/helpers": "npm:^0.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/4398c4ca41ab302b8e50a86c07909b461275bf5025c0163ecb5ae57bbe98e15164927ed58a1137a235996626b19d5397916736ee3257d8bc33d09ec0b1d3f70e + languageName: node + linkType: hard + +"@react-aria/tree@npm:^3.1.1": + version: 3.1.1 + resolution: "@react-aria/tree@npm:3.1.1" + dependencies: + "@react-aria/gridlist": "npm:^3.13.2" + "@react-aria/i18n": "npm:^3.12.10" + "@react-aria/selection": "npm:^3.24.3" + "@react-aria/utils": "npm:^3.29.1" + "@react-stately/tree": "npm:^3.9.0" + "@react-types/button": "npm:^3.12.2" + "@react-types/shared": "npm:^3.30.0" + "@swc/helpers": "npm:^0.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/d387de7a9de81df8f45a16882ddb24ecf8da06638822b8be4d66357b0b3edd67a85aa185f8cf947c4c8f9036c396bea406dd5e277ef0f74828a29d2dd86fd809 + languageName: node + linkType: hard + +"@react-aria/utils@npm:^3.29.1": + version: 3.29.1 + resolution: "@react-aria/utils@npm:3.29.1" + dependencies: + "@react-aria/ssr": "npm:^3.9.9" + "@react-stately/flags": "npm:^3.1.2" + "@react-stately/utils": "npm:^3.10.7" + "@react-types/shared": "npm:^3.30.0" "@swc/helpers": "npm:^0.5.0" clsx: "npm:^2.0.0" peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - checksum: 10/80c1ecf6a570a57aec5ef4eaa2a8715b12bcd4d5b2de26934e7e5af5a2c38cdd229cac116624ecd3e7c97271e534111f600d0baf1976675b778799f8711ce9bf + checksum: 10/90af5ee5b9c7db063ba66a28cfecb8594f356c2b0fc4cce2fcee94543f3b160214e4a9c280e83355af89452b88b1def8856493705c770874da7121ba1d3d0cc0 languageName: node linkType: hard -"@react-aria/visually-hidden@npm:^3.8.21": - version: 3.8.21 - resolution: "@react-aria/visually-hidden@npm:3.8.21" +"@react-aria/virtualizer@npm:^4.1.7": + version: 4.1.7 + resolution: "@react-aria/virtualizer@npm:4.1.7" dependencies: - "@react-aria/interactions": "npm:^3.24.1" - "@react-aria/utils": "npm:^3.28.1" - "@react-types/shared": "npm:^3.28.0" + "@react-aria/i18n": "npm:^3.12.10" + "@react-aria/interactions": "npm:^3.25.3" + "@react-aria/utils": "npm:^3.29.1" + "@react-stately/virtualizer": "npm:^4.4.1" + "@react-types/shared": "npm:^3.30.0" "@swc/helpers": "npm:^0.5.0" peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - checksum: 10/50b4598ae295336cd95f38523abdef8b7fbde2b6b52c99a5fa17527474d58e7444199b97d2409dd8c478321c76bf246dd928ddcb1c303ebc8ab04417a5a59516 + checksum: 10/4bb747314ac96da76c64490041ab95f4a0889bab7e5805b0e18cb71bdb290ae73932ddd866657cfcdfac8382d6b3017c3dfb1a91ae415a6d1ab45b11d88f66ec + languageName: node + linkType: hard + +"@react-aria/visually-hidden@npm:^3.8.25": + version: 3.8.25 + resolution: "@react-aria/visually-hidden@npm:3.8.25" + dependencies: + "@react-aria/interactions": "npm:^3.25.3" + "@react-aria/utils": "npm:^3.29.1" + "@react-types/shared": "npm:^3.30.0" + "@swc/helpers": "npm:^0.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/362a793beac35fde101e598f4cac9cd98394b9a0171309842e2428b25074ee696358c45d2ded8244bc40a9db8471440994be59b0f347d2c643092c6445aaca61 languageName: node linkType: hard @@ -15893,123 +16532,776 @@ __metadata: languageName: node linkType: hard -"@react-stately/flags@npm:^3.1.0": - version: 3.1.0 - resolution: "@react-stately/flags@npm:3.1.0" +"@react-stately/autocomplete@npm:3.0.0-beta.2": + version: 3.0.0-beta.2 + resolution: "@react-stately/autocomplete@npm:3.0.0-beta.2" dependencies: + "@react-stately/utils": "npm:^3.10.7" "@swc/helpers": "npm:^0.5.0" - checksum: 10/022f183415ad8da9484498c506eed97f7562362b427537eb6325a4f37dcbcf26a52f7d135add1574ea049d6a2baa7b0c7c835fb62ac046ca6e8a3cc43bcaf627 + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/836e593688c33ab118547b60fae93ffb1e9e440aed0ffc8c382290f414bfdc313a88964a00a6bd8b7e7b9aca691538b66adfaafee6065b93cedeb80c5aeef675 languageName: node linkType: hard -"@react-stately/overlays@npm:^3.6.14": +"@react-stately/calendar@npm:^3.8.2": + version: 3.8.2 + resolution: "@react-stately/calendar@npm:3.8.2" + dependencies: + "@internationalized/date": "npm:^3.8.2" + "@react-stately/utils": "npm:^3.10.7" + "@react-types/calendar": "npm:^3.7.2" + "@react-types/shared": "npm:^3.30.0" + "@swc/helpers": "npm:^0.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/d2858a42dc2c324248c4c1ddb6f6fe66de11bfe2703c85f0fd739075712f668427212207626ed35af2fcbe15cd0ee6e2ad53eafe98766fd7352e0e2f134435c4 + languageName: node + linkType: hard + +"@react-stately/checkbox@npm:^3.6.15": + version: 3.6.15 + resolution: "@react-stately/checkbox@npm:3.6.15" + dependencies: + "@react-stately/form": "npm:^3.1.5" + "@react-stately/utils": "npm:^3.10.7" + "@react-types/checkbox": "npm:^3.9.5" + "@react-types/shared": "npm:^3.30.0" + "@swc/helpers": "npm:^0.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/4c2b5213395e59432c59609b3cd2ca8316cf77f18716dcee2abe31af5c4a12fac3125408799b0631771e1095fc5924de7850e09c3fa6e53f56c0f79debc0db77 + languageName: node + linkType: hard + +"@react-stately/collections@npm:^3.12.5": + version: 3.12.5 + resolution: "@react-stately/collections@npm:3.12.5" + dependencies: + "@react-types/shared": "npm:^3.30.0" + "@swc/helpers": "npm:^0.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/12024f72ec6602c9447e2bc134da566d99da2e29b41ffba207712be31aaf121b805505397dcfb1ee07dd8d234c40d3018c33364adae271f3231a004775a96fd8 + languageName: node + linkType: hard + +"@react-stately/color@npm:^3.8.6": + version: 3.8.6 + resolution: "@react-stately/color@npm:3.8.6" + dependencies: + "@internationalized/number": "npm:^3.6.3" + "@internationalized/string": "npm:^3.2.7" + "@react-stately/form": "npm:^3.1.5" + "@react-stately/numberfield": "npm:^3.9.13" + "@react-stately/slider": "npm:^3.6.5" + "@react-stately/utils": "npm:^3.10.7" + "@react-types/color": "npm:^3.0.6" + "@react-types/shared": "npm:^3.30.0" + "@swc/helpers": "npm:^0.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/20ec019c71676c5d336c89b703729c0c8098219c942843a3018e5542fee49c6db56c47b746c4c9cddfb9ea48213a3a860861722fc5b41239e3de827c2ef84351 + languageName: node + linkType: hard + +"@react-stately/combobox@npm:^3.10.6": + version: 3.10.6 + resolution: "@react-stately/combobox@npm:3.10.6" + dependencies: + "@react-stately/collections": "npm:^3.12.5" + "@react-stately/form": "npm:^3.1.5" + "@react-stately/list": "npm:^3.12.3" + "@react-stately/overlays": "npm:^3.6.17" + "@react-stately/select": "npm:^3.6.14" + "@react-stately/utils": "npm:^3.10.7" + "@react-types/combobox": "npm:^3.13.6" + "@react-types/shared": "npm:^3.30.0" + "@swc/helpers": "npm:^0.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/8bc67ee18d1c896620cc11233a8efdaf8ec7f5ec31d068fbbc80e75a54e385617518e2b420f3211c17b905e3cac6026f8b056ae96ee114ea4e897f4ce1951502 + languageName: node + linkType: hard + +"@react-stately/data@npm:^3.13.1": + version: 3.13.1 + resolution: "@react-stately/data@npm:3.13.1" + dependencies: + "@react-types/shared": "npm:^3.30.0" + "@swc/helpers": "npm:^0.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/b6eea6a721d4de13ffad7aa12a76012d297e1fbbc919bad35d99f57bf481feb547d56c74467e1dadf8f0cb6be9027e54faa6b10dc4aeb1b46a5c6598218baa2c + languageName: node + linkType: hard + +"@react-stately/datepicker@npm:^3.14.2": + version: 3.14.2 + resolution: "@react-stately/datepicker@npm:3.14.2" + dependencies: + "@internationalized/date": "npm:^3.8.2" + "@internationalized/string": "npm:^3.2.7" + "@react-stately/form": "npm:^3.1.5" + "@react-stately/overlays": "npm:^3.6.17" + "@react-stately/utils": "npm:^3.10.7" + "@react-types/datepicker": "npm:^3.12.2" + "@react-types/shared": "npm:^3.30.0" + "@swc/helpers": "npm:^0.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/dd10f99f32e12eef9d361eb183cd52113a1857613be844da9895b5a8954260ace283e43bd1bae3d73a71f1cb5e6381627999f8a24d4ed320903dba50f864183b + languageName: node + linkType: hard + +"@react-stately/disclosure@npm:^3.0.5": + version: 3.0.5 + resolution: "@react-stately/disclosure@npm:3.0.5" + dependencies: + "@react-stately/utils": "npm:^3.10.7" + "@react-types/shared": "npm:^3.30.0" + "@swc/helpers": "npm:^0.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/b1f3f80e6523a0fb0c325064162a59635f560f41dbadd51fd89db02bbad9bafa843b7b1565420444b3b266f2eb92dcf556916b0dabe06d32bb86a2106849c41c + languageName: node + linkType: hard + +"@react-stately/dnd@npm:^3.6.0": + version: 3.6.0 + resolution: "@react-stately/dnd@npm:3.6.0" + dependencies: + "@react-stately/selection": "npm:^3.20.3" + "@react-types/shared": "npm:^3.30.0" + "@swc/helpers": "npm:^0.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/9fe59a8d5849af27b5fb0609691bdf0ab14ef8cad8a27405e0c83842d44b171e6d1409716b8e80f12797b187bb553f4acf71a87cd5acd86c76137a3525449194 + languageName: node + linkType: hard + +"@react-stately/flags@npm:^3.1.2": + version: 3.1.2 + resolution: "@react-stately/flags@npm:3.1.2" + dependencies: + "@swc/helpers": "npm:^0.5.0" + checksum: 10/a020c3680c36d9624f765c5916ce95d69959f64887928e8f380f11b5362bb0499a901a5842e4e12eb8e5a776af59212b1ee0c4c6a6681ce75f61dace8b2f9c40 + languageName: node + linkType: hard + +"@react-stately/form@npm:^3.1.5": + version: 3.1.5 + resolution: "@react-stately/form@npm:3.1.5" + dependencies: + "@react-types/shared": "npm:^3.30.0" + "@swc/helpers": "npm:^0.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/6c392949ca8ac045163f3716a41f03d6ccbe3fd5704401cbece0ba572d43abbb350f5019534765540d5b511b9aeba70ca2c03dc4ba218074b59a3efbea601564 + languageName: node + linkType: hard + +"@react-stately/grid@npm:^3.11.3": + version: 3.11.3 + resolution: "@react-stately/grid@npm:3.11.3" + dependencies: + "@react-stately/collections": "npm:^3.12.5" + "@react-stately/selection": "npm:^3.20.3" + "@react-types/grid": "npm:^3.3.3" + "@react-types/shared": "npm:^3.30.0" + "@swc/helpers": "npm:^0.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/09655c28cef0c3007024af0c01982d2c079e558169dcf1994966c2526c6346b442068e2e9700a8abbbbcbd13781cc0eb5b346d974dc9a85dd5c263722d96f5c7 + languageName: node + linkType: hard + +"@react-stately/layout@npm:^4.3.1": + version: 4.3.1 + resolution: "@react-stately/layout@npm:4.3.1" + dependencies: + "@react-stately/collections": "npm:^3.12.5" + "@react-stately/table": "npm:^3.14.3" + "@react-stately/virtualizer": "npm:^4.4.1" + "@react-types/grid": "npm:^3.3.3" + "@react-types/shared": "npm:^3.30.0" + "@react-types/table": "npm:^3.13.1" + "@swc/helpers": "npm:^0.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/f7d299038aefba602944b5caa81719388427778edc394582dfe14c70f9f485b74a0da6d0eeb6aab843e3fbdd6af251a3678b1a8c76c77f64adb16d695dbd22cd + languageName: node + linkType: hard + +"@react-stately/list@npm:^3.12.3": + version: 3.12.3 + resolution: "@react-stately/list@npm:3.12.3" + dependencies: + "@react-stately/collections": "npm:^3.12.5" + "@react-stately/selection": "npm:^3.20.3" + "@react-stately/utils": "npm:^3.10.7" + "@react-types/shared": "npm:^3.30.0" + "@swc/helpers": "npm:^0.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/e8edce5e59e061a4b71621ce7617f4e48cbef5e5c5b6377808e0977f4cad4e541726f255bdeb1c18db867b35ab19883981882bbc27ddbc3e5c26722c496b02f8 + languageName: node + linkType: hard + +"@react-stately/menu@npm:^3.9.5": + version: 3.9.5 + resolution: "@react-stately/menu@npm:3.9.5" + dependencies: + "@react-stately/overlays": "npm:^3.6.17" + "@react-types/menu": "npm:^3.10.2" + "@react-types/shared": "npm:^3.30.0" + "@swc/helpers": "npm:^0.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/a8163b76de49ec10da7129c306304a96e8f4e689450ffdbf6ab5f56fd8b0316db5beb16ebc58da52c19b4abe28954a7200955c41e1a9088e40f5e5d00f975067 + languageName: node + linkType: hard + +"@react-stately/numberfield@npm:^3.9.13": + version: 3.9.13 + resolution: "@react-stately/numberfield@npm:3.9.13" + dependencies: + "@internationalized/number": "npm:^3.6.3" + "@react-stately/form": "npm:^3.1.5" + "@react-stately/utils": "npm:^3.10.7" + "@react-types/numberfield": "npm:^3.8.12" + "@swc/helpers": "npm:^0.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/639e2064ed0afd23ec6681b32abca78f9453eb38d11b350247bf4038f6561579f6d444ead6c9c3317c1b1adaaaa22812053cfba8effdd8cb1b199d04b7ce1fbe + languageName: node + linkType: hard + +"@react-stately/overlays@npm:^3.6.17": + version: 3.6.17 + resolution: "@react-stately/overlays@npm:3.6.17" + dependencies: + "@react-stately/utils": "npm:^3.10.7" + "@react-types/overlays": "npm:^3.8.16" + "@swc/helpers": "npm:^0.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/9c44f181cd8f0b99a40142aebf3d7e1d1df1e96a789b636a5ee877529e60fddece4ebcf32d9812d9848ce0298bf5cb6202df3b680552b32c89f1276bce3f8a7b + languageName: node + linkType: hard + +"@react-stately/radio@npm:^3.10.14": + version: 3.10.14 + resolution: "@react-stately/radio@npm:3.10.14" + dependencies: + "@react-stately/form": "npm:^3.1.5" + "@react-stately/utils": "npm:^3.10.7" + "@react-types/radio": "npm:^3.8.10" + "@react-types/shared": "npm:^3.30.0" + "@swc/helpers": "npm:^0.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/45ad56b50f3fcd04c1b335f8f64caceaa6f8483fd84717a461ae04ed8718dabf06f88bf8bd89fcca27d2c6bc548b4a38f0e4ef53ad51f3320aeb85c67b288846 + languageName: node + linkType: hard + +"@react-stately/searchfield@npm:^3.5.13": + version: 3.5.13 + resolution: "@react-stately/searchfield@npm:3.5.13" + dependencies: + "@react-stately/utils": "npm:^3.10.7" + "@react-types/searchfield": "npm:^3.6.3" + "@swc/helpers": "npm:^0.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/6114f1ce0c2e8ddbeedc5b5293783c4e1ecb0cc6f24e09cb6095e32be9b49bdc67619941c16f834850e31acfafd74f4241edaa3529f510ec490a2e6c8e7cdc0b + languageName: node + linkType: hard + +"@react-stately/select@npm:^3.6.14": version: 3.6.14 - resolution: "@react-stately/overlays@npm:3.6.14" + resolution: "@react-stately/select@npm:3.6.14" dependencies: - "@react-stately/utils": "npm:^3.10.5" - "@react-types/overlays": "npm:^3.8.13" + "@react-stately/form": "npm:^3.1.5" + "@react-stately/list": "npm:^3.12.3" + "@react-stately/overlays": "npm:^3.6.17" + "@react-types/select": "npm:^3.9.13" + "@react-types/shared": "npm:^3.30.0" "@swc/helpers": "npm:^0.5.0" peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - checksum: 10/84ca6cd1a528fd0c94f5c8d0c6609a915fd7de75d70b222ab6e252456f8d67b0a394787aca97e59a9737b7e3d48bf0600d12e5d9487525e37305eea599a96fcf + checksum: 10/33116af11830f0d7bf7e10cb03e52ed9c36d17d94674d96440fd73ae8d7da1b93edc4de6170a3681493c76c0ad5c8b24c2961f170b2a784447743775dce32a65 languageName: node linkType: hard -"@react-stately/utils@npm:^3.10.5": - version: 3.10.5 - resolution: "@react-stately/utils@npm:3.10.5" +"@react-stately/selection@npm:^3.20.3": + version: 3.20.3 + resolution: "@react-stately/selection@npm:3.20.3" + dependencies: + "@react-stately/collections": "npm:^3.12.5" + "@react-stately/utils": "npm:^3.10.7" + "@react-types/shared": "npm:^3.30.0" + "@swc/helpers": "npm:^0.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/9903810f5f4e2f37381aba8c81525a819de69316c3bd5d66b29fc5f22e49b3d349d26792e811f7167e16857879c8e6ce8d817d9838c69367481a42977a2022a2 + languageName: node + linkType: hard + +"@react-stately/slider@npm:^3.6.5": + version: 3.6.5 + resolution: "@react-stately/slider@npm:3.6.5" + dependencies: + "@react-stately/utils": "npm:^3.10.7" + "@react-types/shared": "npm:^3.30.0" + "@react-types/slider": "npm:^3.7.12" + "@swc/helpers": "npm:^0.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/121f2f23cad929e7087825ec1a17c51610ac0e62a0b0951d042a6e6a354fcea1751575a7bf6648ae5054a260d89a7613dc0353bf0e9f76553e25c2dce1dba095 + languageName: node + linkType: hard + +"@react-stately/table@npm:^3.14.3": + version: 3.14.3 + resolution: "@react-stately/table@npm:3.14.3" + dependencies: + "@react-stately/collections": "npm:^3.12.5" + "@react-stately/flags": "npm:^3.1.2" + "@react-stately/grid": "npm:^3.11.3" + "@react-stately/selection": "npm:^3.20.3" + "@react-stately/utils": "npm:^3.10.7" + "@react-types/grid": "npm:^3.3.3" + "@react-types/shared": "npm:^3.30.0" + "@react-types/table": "npm:^3.13.1" + "@swc/helpers": "npm:^0.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/04cd616d526b9b806808ea09ce596dc1fe5fff931deec5ccce3258d0a76ee02c787320004ccc2d3a2d67e54d39f7ab274673210254c8598bd99b767cec8eda1a + languageName: node + linkType: hard + +"@react-stately/tabs@npm:^3.8.3": + version: 3.8.3 + resolution: "@react-stately/tabs@npm:3.8.3" + dependencies: + "@react-stately/list": "npm:^3.12.3" + "@react-types/shared": "npm:^3.30.0" + "@react-types/tabs": "npm:^3.3.16" + "@swc/helpers": "npm:^0.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/5fb036bc36b5c7fde32c6e7553795fad0f5b2d999837961298341e68d211444ca2a378554c5f73ccf0909e60299cdcd4b0e8c317e57f8c1662e6384957a1ed4a + languageName: node + linkType: hard + +"@react-stately/toast@npm:^3.1.1": + version: 3.1.1 + resolution: "@react-stately/toast@npm:3.1.1" + dependencies: + "@swc/helpers": "npm:^0.5.0" + use-sync-external-store: "npm:^1.4.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/c6ff8b947920e05e3e817cbb478f31c45c64035801456c7c8052c37bea5d966a3ea2c74071c2bed6f2006dec160a6b1204b7cc98965a9c10ca3b4bb4d6765f39 + languageName: node + linkType: hard + +"@react-stately/toggle@npm:^3.8.5": + version: 3.8.5 + resolution: "@react-stately/toggle@npm:3.8.5" + dependencies: + "@react-stately/utils": "npm:^3.10.7" + "@react-types/checkbox": "npm:^3.9.5" + "@react-types/shared": "npm:^3.30.0" + "@swc/helpers": "npm:^0.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/3d8e6c4a39c64fc904355aaa3980e3a63595c24472e3f557716597ac6f9f26299dec5b0843b327b4fe1416436054a65e45ec79073a3be1fad8f093f0d2940864 + languageName: node + linkType: hard + +"@react-stately/tooltip@npm:^3.5.5": + version: 3.5.5 + resolution: "@react-stately/tooltip@npm:3.5.5" + dependencies: + "@react-stately/overlays": "npm:^3.6.17" + "@react-types/tooltip": "npm:^3.4.18" + "@swc/helpers": "npm:^0.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/0744283f1dbb811502311370495b6722a59c251fe20ac2e5373aeed8f655ec9f89d92980426a69b7191c048f7c02e3a66c78a7018452ad4638c82e5b7f99b698 + languageName: node + linkType: hard + +"@react-stately/tree@npm:^3.9.0": + version: 3.9.0 + resolution: "@react-stately/tree@npm:3.9.0" + dependencies: + "@react-stately/collections": "npm:^3.12.5" + "@react-stately/selection": "npm:^3.20.3" + "@react-stately/utils": "npm:^3.10.7" + "@react-types/shared": "npm:^3.30.0" + "@swc/helpers": "npm:^0.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/6980382c94f87a663124e9488e3cf5f8ea09b05fc2f0017cbb886aa19ce0d8525d8b6b8221f1e293a67543cc06786ea203813218c3444fe7e14b31d9eae65ca3 + languageName: node + linkType: hard + +"@react-stately/utils@npm:^3.10.7": + version: 3.10.7 + resolution: "@react-stately/utils@npm:3.10.7" dependencies: "@swc/helpers": "npm:^0.5.0" peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - checksum: 10/76133eb64fa945216e51d8a81a0ebd06eeb78aa2d9c91d79eeb80ff44c70a6b0d6d940618b31b499fee8216640b3bf6183391151dc1769e756b56ff6b5e167ec + checksum: 10/b9c1a62d4f179e252d08a2f18120a02ffc8704424f257e81e5e74da1222e3acd1e821ce84220d87d9d7b4b6d4dc2fd58d5bb380546d198bf434b700cda8ac3d8 languageName: node linkType: hard -"@react-types/button@npm:^3.11.0": - version: 3.11.0 - resolution: "@react-types/button@npm:3.11.0" +"@react-stately/virtualizer@npm:^4.4.1": + version: 4.4.1 + resolution: "@react-stately/virtualizer@npm:4.4.1" dependencies: - "@react-types/shared": "npm:^3.28.0" + "@react-aria/utils": "npm:^3.29.1" + "@react-types/shared": "npm:^3.30.0" + "@swc/helpers": "npm:^0.5.0" peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - checksum: 10/6dbcc89f576eb6736deb1d5f92eab3c4de5ee5a78a8034b1cd2748c14d92ce05b40362ff5b629842e363d9843f823b5c044dabb3d7438f897777ff60fc5e3867 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/aab5c3a647dc43dd5120a6db4cdfdf24aa47f7fcabf273e05947e33af8cba172f4f442499729d53537a2aa46ca7292dcb94c6b4b4c5b017542df42c25a97a128 languageName: node linkType: hard -"@react-types/overlays@npm:^3.8.13": - version: 3.8.13 - resolution: "@react-types/overlays@npm:3.8.13" +"@react-types/autocomplete@npm:3.0.0-alpha.32": + version: 3.0.0-alpha.32 + resolution: "@react-types/autocomplete@npm:3.0.0-alpha.32" dependencies: - "@react-types/shared": "npm:^3.28.0" + "@react-types/combobox": "npm:^3.13.6" + "@react-types/searchfield": "npm:^3.6.3" + "@react-types/shared": "npm:^3.30.0" peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - checksum: 10/a585a2bf211af8996078dee3b7c179617ca889747049f22b8306a6e48c09afa3828a682a46f7be3c36cc1e2282f6bb98b5095c263c466634f1775a1c01599ecd + checksum: 10/ad617628499db45b2acb07d2f4a4b7aa0569124ee1b7c35b2f1eb9819a2d09a755ab4d3be489243c0d579fc16485aec24950ce3b132a655f83d302eb0d140f96 languageName: node linkType: hard -"@react-types/shared@npm:^3.28.0": - version: 3.28.0 - resolution: "@react-types/shared@npm:3.28.0" +"@react-types/breadcrumbs@npm:^3.7.14": + version: 3.7.14 + resolution: "@react-types/breadcrumbs@npm:3.7.14" + dependencies: + "@react-types/link": "npm:^3.6.2" + "@react-types/shared": "npm:^3.30.0" peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - checksum: 10/b8dcc73b950c68fdf22a1173e6e4cfc17f51c579455b3b3239cefd50ebe8bcd6a71db00f643ef8c8f6cd6a2b142780bbce243bda571f5f30be94a04ce30547cb + checksum: 10/106fa21ce01b9ee16796ba46d1133b71b466bfc069e9a90d7f00280e177e1f009791db78701565d83c22506bf72b0469756238164d8ffa36c6712f4e95932eac languageName: node linkType: hard -"@redis/bloom@npm:1.2.0": - version: 1.2.0 - resolution: "@redis/bloom@npm:1.2.0" +"@react-types/button@npm:^3.12.2": + version: 3.12.2 + resolution: "@react-types/button@npm:3.12.2" + dependencies: + "@react-types/shared": "npm:^3.30.0" peerDependencies: - "@redis/client": ^1.0.0 - checksum: 10/a16408f729ddd032a52c9d998661dfa7beabc0e92760d30619c3166c7a53a98c037956d93d230b787005fd8a599a7456461ca7429c1916893c2d13d59a41e0e6 + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/d00f7e23fd6cfa863c2d9f0f91ec47fc017666b55775842af3c001fabcf949dfa55b116674bcb841de568eacaf677c3a25e079b4810dcf857547bd9cf6d60917 languageName: node linkType: hard -"@redis/client@npm:1.6.0": - version: 1.6.0 - resolution: "@redis/client@npm:1.6.0" +"@react-types/calendar@npm:^3.7.2": + version: 3.7.2 + resolution: "@react-types/calendar@npm:3.7.2" + dependencies: + "@internationalized/date": "npm:^3.8.2" + "@react-types/shared": "npm:^3.30.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/40ad15a5f937844f6626028c8a6e7d36f09e946b4cbdfcd95ff4971f6681abd86260f64aa8298cf86fdde5a0ce2de17e327b8011bb435d0f3faf10fcd9c97f38 + languageName: node + linkType: hard + +"@react-types/checkbox@npm:^3.9.5": + version: 3.9.5 + resolution: "@react-types/checkbox@npm:3.9.5" + dependencies: + "@react-types/shared": "npm:^3.30.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/25f6c155043f25f55379b613e3e7faa16191f34c04f13acfc75fc5bda5b83d76d3062b177aad2401f9dd1570215714d477ab1d1e3b92a33e24172aa44e9ff79e + languageName: node + linkType: hard + +"@react-types/color@npm:^3.0.6": + version: 3.0.6 + resolution: "@react-types/color@npm:3.0.6" + dependencies: + "@react-types/shared": "npm:^3.30.0" + "@react-types/slider": "npm:^3.7.12" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/33ddf5239ccfdada1ae276a69b020500dae557a0a43c4bb0fb55fcd6122331c7f2adb552ff3706753214964032ea459634708a02f147777dff948045877cc01b + languageName: node + linkType: hard + +"@react-types/combobox@npm:^3.13.6": + version: 3.13.6 + resolution: "@react-types/combobox@npm:3.13.6" + dependencies: + "@react-types/shared": "npm:^3.30.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/8aaf970af426d084ba4b954aeca23cc7779de221a19465c1487d7098a5f637c13bcb6446bf695619e221d78d289cf629b94faa2c86de8bb3f949ff05a5448a13 + languageName: node + linkType: hard + +"@react-types/datepicker@npm:^3.12.2": + version: 3.12.2 + resolution: "@react-types/datepicker@npm:3.12.2" + dependencies: + "@internationalized/date": "npm:^3.8.2" + "@react-types/calendar": "npm:^3.7.2" + "@react-types/overlays": "npm:^3.8.16" + "@react-types/shared": "npm:^3.30.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/21d6b72986b18b25b6380bf85a7a12319de05160a1dee5d0e7484378627dee955c6cda9fbb0b6909e9edcfc82181be1d9e744220fcf82d75357d7208ed2978a9 + languageName: node + linkType: hard + +"@react-types/dialog@npm:^3.5.19": + version: 3.5.19 + resolution: "@react-types/dialog@npm:3.5.19" + dependencies: + "@react-types/overlays": "npm:^3.8.16" + "@react-types/shared": "npm:^3.30.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/07bd55d214d8162f1a700f1ac80cd51468d0defc0d9753309d5e58a0fffbc1eb65a588b6c0709593a41fa8d72cc1f8f8dba0a65b2a336968fdc2ff92afec3596 + languageName: node + linkType: hard + +"@react-types/form@npm:^3.7.13": + version: 3.7.13 + resolution: "@react-types/form@npm:3.7.13" + dependencies: + "@react-types/shared": "npm:^3.30.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/2c55ceb9f5e52a08b60ae0ae95d1db3e57a67d3783eaee2fb37870602afd612153506c13effec98bf4c7b58728a148e9d966c8c3442db560543779b9ef8dd091 + languageName: node + linkType: hard + +"@react-types/grid@npm:^3.3.3": + version: 3.3.3 + resolution: "@react-types/grid@npm:3.3.3" + dependencies: + "@react-types/shared": "npm:^3.30.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/cac232888139186110f7095cbb45ba2525522a296254f44290ad4c87ac2b1e72485d839e2820e7265cbcd6bc4cb8e49c170c52fd57defed16d06a4eb7f7cf047 + languageName: node + linkType: hard + +"@react-types/link@npm:^3.6.2": + version: 3.6.2 + resolution: "@react-types/link@npm:3.6.2" + dependencies: + "@react-types/shared": "npm:^3.30.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/093a3011a98f36dd252d7675365effcba219b9a89e53619e176bdf322042520d5d24e7d9dca04bd63fa6785242f097301c3921d111c43ed888072b0938133435 + languageName: node + linkType: hard + +"@react-types/listbox@npm:^3.7.1": + version: 3.7.1 + resolution: "@react-types/listbox@npm:3.7.1" + dependencies: + "@react-types/shared": "npm:^3.30.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/2040a31a6eae1a0d0fe44f2d6410dfd6e9f99849eaba4fea4b4819ed162f2642d5e023d0badb4f78b2e0d60c4480cacc2d0745f9881f77b83c20b7c2012adf0b + languageName: node + linkType: hard + +"@react-types/menu@npm:^3.10.2": + version: 3.10.2 + resolution: "@react-types/menu@npm:3.10.2" + dependencies: + "@react-types/overlays": "npm:^3.8.16" + "@react-types/shared": "npm:^3.30.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/9b6cc0818f1d63225f7794ca89d0fa25cd771bad4440fa52c403d81d7027b1f83ba600603ede4ee05dee01b57d1240c9eaa7ed890150aa9dff0c8113dc0c85ab + languageName: node + linkType: hard + +"@react-types/meter@npm:^3.4.10": + version: 3.4.10 + resolution: "@react-types/meter@npm:3.4.10" + dependencies: + "@react-types/progress": "npm:^3.5.13" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/b55f4ca464fc2873662ee50d25cdc1c77995d34d39b6d2831c0b121e47c7b12051017576f51909881a3776003e03263ce899dcf572a9f083794b160320baa754 + languageName: node + linkType: hard + +"@react-types/numberfield@npm:^3.8.12": + version: 3.8.12 + resolution: "@react-types/numberfield@npm:3.8.12" + dependencies: + "@react-types/shared": "npm:^3.30.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/98989cdcd7b7bef45129c54e9bdb919d06f09109c786f0783105c617304ee3ce15c9aad01507d4d9aa0e974ee3b50b230c057ad7a48f634247e374c9668080ae + languageName: node + linkType: hard + +"@react-types/overlays@npm:^3.8.16": + version: 3.8.16 + resolution: "@react-types/overlays@npm:3.8.16" + dependencies: + "@react-types/shared": "npm:^3.30.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/12bedf8e79d31827cd9868dcb115d07b9fee7954af5e00c1a46fe87b9f2b08e971af4b1b238faa2ce7ed173600786a83c7b9cfcdee5c7464a42bc581d7dee3a6 + languageName: node + linkType: hard + +"@react-types/progress@npm:^3.5.13": + version: 3.5.13 + resolution: "@react-types/progress@npm:3.5.13" + dependencies: + "@react-types/shared": "npm:^3.30.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/f666892cff510323e90b1e72e5351eef4f38eb752e568f46cb30250a7de8b9a4435f3506fc590d748d3a0ce30a5f64d449a88a8656369137d06a584ef667d0a8 + languageName: node + linkType: hard + +"@react-types/radio@npm:^3.8.10": + version: 3.8.10 + resolution: "@react-types/radio@npm:3.8.10" + dependencies: + "@react-types/shared": "npm:^3.30.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/ba87e61b7a84547c417baa9553bdfebf2fcd03d45038f0d6a0031a5d4e6c94f9d9a81fe8a98579c6830dcffad68c71560ccac8fd842d5f2469a05ce275d92250 + languageName: node + linkType: hard + +"@react-types/searchfield@npm:^3.6.3": + version: 3.6.3 + resolution: "@react-types/searchfield@npm:3.6.3" + dependencies: + "@react-types/shared": "npm:^3.30.0" + "@react-types/textfield": "npm:^3.12.3" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/ffe5a909fb94a28c674c1ae798e511d93be5175c3fc8adcadc88e040c6e5aca4cf55565b321219311537c11c5ce70c005aa214d8dc708a4b1583a1f1a68a75f6 + languageName: node + linkType: hard + +"@react-types/select@npm:^3.9.13": + version: 3.9.13 + resolution: "@react-types/select@npm:3.9.13" + dependencies: + "@react-types/shared": "npm:^3.30.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/9fba560d2060eb852289be76f0e0b691bddd48f744f969862da10d38c8963f6931190cb53cc8c5ea01eab3f447b8a680e6da378fe6287ec80d3f48a62d312759 + languageName: node + linkType: hard + +"@react-types/shared@npm:^3.30.0": + version: 3.30.0 + resolution: "@react-types/shared@npm:3.30.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/58af4134275a347bf18ac5d15e3dcfd07dcf623e1d494f140303e06f2149b7aad86408979e163393346df613f6390a3a387f77a2937f0bf1908c6672a44f7b69 + languageName: node + linkType: hard + +"@react-types/slider@npm:^3.7.12": + version: 3.7.12 + resolution: "@react-types/slider@npm:3.7.12" + dependencies: + "@react-types/shared": "npm:^3.30.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/38b8a556f87bb64c7f47af482a1a3ce688345a3d4b7a2c71e99522bdcb9668f8ed8e3ea0797b32d5ac1a95d6557c5f9e8eadab51e8eb780f9e66efa89ba50fa0 + languageName: node + linkType: hard + +"@react-types/switch@npm:^3.5.12": + version: 3.5.12 + resolution: "@react-types/switch@npm:3.5.12" + dependencies: + "@react-types/shared": "npm:^3.30.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/6552f113b0c3abf52f590b8cedf17f5901e7fa2d0ed94b30408fd2fbda907ee17e7792af6d86985ca742a3cb5b667bcbf6cec725e66265ccdfd201b77e7f524b + languageName: node + linkType: hard + +"@react-types/table@npm:^3.13.1": + version: 3.13.1 + resolution: "@react-types/table@npm:3.13.1" + dependencies: + "@react-types/grid": "npm:^3.3.3" + "@react-types/shared": "npm:^3.30.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/be1bac716d13148b47016f2156ee0769c044d301b538df934f6b8aa5466265a750391e462f9fcdebff7dbb93cf9e373e2117f91eab528b3f5cef062174e547ee + languageName: node + linkType: hard + +"@react-types/tabs@npm:^3.3.16": + version: 3.3.16 + resolution: "@react-types/tabs@npm:3.3.16" + dependencies: + "@react-types/shared": "npm:^3.30.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/fae8d98776408b0e9776d0217a545a1ed6035ac976321e413e4f442b525375c56854a328c33e77564efe525e66bc7b79dc89e38ff02373788b996c4b46bb6c5d + languageName: node + linkType: hard + +"@react-types/textfield@npm:^3.12.3": + version: 3.12.3 + resolution: "@react-types/textfield@npm:3.12.3" + dependencies: + "@react-types/shared": "npm:^3.30.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/d8bf58fd569b30fa13f98de834a025c9ef71d6de8c669912aa7083c83f88f7261852e0b1b30953e903d377b5b63cc849b848fd549a1466c82d6a74cb6c540cf5 + languageName: node + linkType: hard + +"@react-types/tooltip@npm:^3.4.18": + version: 3.4.18 + resolution: "@react-types/tooltip@npm:3.4.18" + dependencies: + "@react-types/overlays": "npm:^3.8.16" + "@react-types/shared": "npm:^3.30.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/5eed69c83727496a6d06796617da86740ab2629b3bd6a106c6ddfb384aaa74725aed3c3eed44f329dcebe7cf87a261ce33e8aa8a5899549446321c1a86d27b87 + languageName: node + linkType: hard + +"@redis/client@npm:^1.6.0": + version: 1.6.1 + resolution: "@redis/client@npm:1.6.1" dependencies: cluster-key-slot: "npm:1.1.2" generic-pool: "npm:3.9.0" yallist: "npm:4.0.0" - checksum: 10/ad375bd685dc34163304872e611ad31dc09a20f4dc8416e5dd588e8a9d2a42a6882f5c8f83d6388ba04ada71513c461b211c3146bcd8ab4da20b3f7edf08fb63 - languageName: node - linkType: hard - -"@redis/graph@npm:1.1.1": - version: 1.1.1 - resolution: "@redis/graph@npm:1.1.1" - peerDependencies: - "@redis/client": ^1.0.0 - checksum: 10/96b8ee9bec124947465848b56a014805f9639e09704e03c75a92072a319599ac9dcd4f9ace22970a7f72131a241166ad31db4dc6931b34808d22a5ca94649ba5 - languageName: node - linkType: hard - -"@redis/json@npm:1.0.7": - version: 1.0.7 - resolution: "@redis/json@npm:1.0.7" - peerDependencies: - "@redis/client": ^1.0.0 - checksum: 10/df0ac5035608d2e82289237d1adbf541af3743a86692df9958a2c89281bce024eeecfc031db51774d8a46639c5ec34ce9f8b71ebec7bce21865920e36ca3db57 - languageName: node - linkType: hard - -"@redis/search@npm:1.2.0": - version: 1.2.0 - resolution: "@redis/search@npm:1.2.0" - peerDependencies: - "@redis/client": ^1.0.0 - checksum: 10/25bba222c0fb1ec1f2db08fe157d30d56a8ffe234214c72d3a7a991daefe77f18c5e6440ab3aa297aef88bafd5448b04ac9fcd84671f2dadc8989712c06b63b4 - languageName: node - linkType: hard - -"@redis/time-series@npm:1.1.0": - version: 1.1.0 - resolution: "@redis/time-series@npm:1.1.0" - peerDependencies: - "@redis/client": ^1.0.0 - checksum: 10/e1d000eef7f37645f7f4ff94f32dd998384360b12fed1e4d614d828c065b72d7627e27444fab781fac4fdfe301c45f893417550fb1011d3b75237566ff0954e0 + checksum: 10/3ef20235b9b0ecba728bbc7208eabbdfc2eebb50c6fb95b20486a0c14e9d6f3ce620ac0d3d14d7f682ea7cb953b13bf89bd94932b7ab3babeb12ba77136b4291 languageName: node linkType: hard @@ -16320,82 +17612,82 @@ __metadata: languageName: node linkType: hard -"@rspack/binding-darwin-arm64@npm:1.3.10": - version: 1.3.10 - resolution: "@rspack/binding-darwin-arm64@npm:1.3.10" +"@rspack/binding-darwin-arm64@npm:1.3.15": + version: 1.3.15 + resolution: "@rspack/binding-darwin-arm64@npm:1.3.15" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@rspack/binding-darwin-x64@npm:1.3.10": - version: 1.3.10 - resolution: "@rspack/binding-darwin-x64@npm:1.3.10" +"@rspack/binding-darwin-x64@npm:1.3.15": + version: 1.3.15 + resolution: "@rspack/binding-darwin-x64@npm:1.3.15" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@rspack/binding-linux-arm64-gnu@npm:1.3.10": - version: 1.3.10 - resolution: "@rspack/binding-linux-arm64-gnu@npm:1.3.10" +"@rspack/binding-linux-arm64-gnu@npm:1.3.15": + version: 1.3.15 + resolution: "@rspack/binding-linux-arm64-gnu@npm:1.3.15" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"@rspack/binding-linux-arm64-musl@npm:1.3.10": - version: 1.3.10 - resolution: "@rspack/binding-linux-arm64-musl@npm:1.3.10" +"@rspack/binding-linux-arm64-musl@npm:1.3.15": + version: 1.3.15 + resolution: "@rspack/binding-linux-arm64-musl@npm:1.3.15" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"@rspack/binding-linux-x64-gnu@npm:1.3.10": - version: 1.3.10 - resolution: "@rspack/binding-linux-x64-gnu@npm:1.3.10" +"@rspack/binding-linux-x64-gnu@npm:1.3.15": + version: 1.3.15 + resolution: "@rspack/binding-linux-x64-gnu@npm:1.3.15" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"@rspack/binding-linux-x64-musl@npm:1.3.10": - version: 1.3.10 - resolution: "@rspack/binding-linux-x64-musl@npm:1.3.10" +"@rspack/binding-linux-x64-musl@npm:1.3.15": + version: 1.3.15 + resolution: "@rspack/binding-linux-x64-musl@npm:1.3.15" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"@rspack/binding-win32-arm64-msvc@npm:1.3.10": - version: 1.3.10 - resolution: "@rspack/binding-win32-arm64-msvc@npm:1.3.10" +"@rspack/binding-win32-arm64-msvc@npm:1.3.15": + version: 1.3.15 + resolution: "@rspack/binding-win32-arm64-msvc@npm:1.3.15" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@rspack/binding-win32-ia32-msvc@npm:1.3.10": - version: 1.3.10 - resolution: "@rspack/binding-win32-ia32-msvc@npm:1.3.10" +"@rspack/binding-win32-ia32-msvc@npm:1.3.15": + version: 1.3.15 + resolution: "@rspack/binding-win32-ia32-msvc@npm:1.3.15" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@rspack/binding-win32-x64-msvc@npm:1.3.10": - version: 1.3.10 - resolution: "@rspack/binding-win32-x64-msvc@npm:1.3.10" +"@rspack/binding-win32-x64-msvc@npm:1.3.15": + version: 1.3.15 + resolution: "@rspack/binding-win32-x64-msvc@npm:1.3.15" conditions: os=win32 & cpu=x64 languageName: node linkType: hard -"@rspack/binding@npm:1.3.10": - version: 1.3.10 - resolution: "@rspack/binding@npm:1.3.10" +"@rspack/binding@npm:1.3.15": + version: 1.3.15 + resolution: "@rspack/binding@npm:1.3.15" dependencies: - "@rspack/binding-darwin-arm64": "npm:1.3.10" - "@rspack/binding-darwin-x64": "npm:1.3.10" - "@rspack/binding-linux-arm64-gnu": "npm:1.3.10" - "@rspack/binding-linux-arm64-musl": "npm:1.3.10" - "@rspack/binding-linux-x64-gnu": "npm:1.3.10" - "@rspack/binding-linux-x64-musl": "npm:1.3.10" - "@rspack/binding-win32-arm64-msvc": "npm:1.3.10" - "@rspack/binding-win32-ia32-msvc": "npm:1.3.10" - "@rspack/binding-win32-x64-msvc": "npm:1.3.10" + "@rspack/binding-darwin-arm64": "npm:1.3.15" + "@rspack/binding-darwin-x64": "npm:1.3.15" + "@rspack/binding-linux-arm64-gnu": "npm:1.3.15" + "@rspack/binding-linux-arm64-musl": "npm:1.3.15" + "@rspack/binding-linux-x64-gnu": "npm:1.3.15" + "@rspack/binding-linux-x64-musl": "npm:1.3.15" + "@rspack/binding-win32-arm64-msvc": "npm:1.3.15" + "@rspack/binding-win32-ia32-msvc": "npm:1.3.15" + "@rspack/binding-win32-x64-msvc": "npm:1.3.15" dependenciesMeta: "@rspack/binding-darwin-arm64": optional: true @@ -16415,42 +17707,38 @@ __metadata: optional: true "@rspack/binding-win32-x64-msvc": optional: true - checksum: 10/10328e405c6708f7d1eea7e8f83d7f4453bcc3e4ca77b99eb29819d9f66c51e85b8cf46daab797bea59fdafc266dab6091deb9b5e2ec3007482da11ab10dc62c + checksum: 10/d4918ee41eecbc6d27739d21b674fe64ea7d45433e0f038618475a7cfd91a68d470d6e05d68e109ae917b88c541059c368b7734b2dca3791d7be001a5804030e languageName: node linkType: hard "@rspack/core@npm:^1.3.9": - version: 1.3.10 - resolution: "@rspack/core@npm:1.3.10" + version: 1.3.15 + resolution: "@rspack/core@npm:1.3.15" dependencies: - "@module-federation/runtime-tools": "npm:0.13.1" - "@rspack/binding": "npm:1.3.10" + "@module-federation/runtime-tools": "npm:0.14.3" + "@rspack/binding": "npm:1.3.15" "@rspack/lite-tapable": "npm:1.0.1" - caniuse-lite: "npm:^1.0.30001717" peerDependencies: "@swc/helpers": ">=0.5.1" peerDependenciesMeta: "@swc/helpers": optional: true - checksum: 10/5471ced4f461936c723199006182ce9fc54a5840aa7ba46f56f137d46b1839b994a9f6e4539e1376eaaf2956cbbbe5a7846d06ab61246e38711a805f7dd56df4 + checksum: 10/9708d4b5112f9a1c23f691e544e9b690cdc7275145772932e6ea0683b6c71d3f304c0f21513b23a01f00cebe8607adc54c23e3ed4ac9dd566e8d9d02b35f5f4e languageName: node linkType: hard "@rspack/dev-server@npm:^1.1.1": - version: 1.1.1 - resolution: "@rspack/dev-server@npm:1.1.1" + version: 1.1.3 + resolution: "@rspack/dev-server@npm:1.1.3" dependencies: chokidar: "npm:^3.6.0" - express: "npm:^4.21.2" - http-proxy-middleware: "npm:^2.0.7" - mime-types: "npm:^2.1.35" + http-proxy-middleware: "npm:^2.0.9" p-retry: "npm:^6.2.0" - webpack-dev-middleware: "npm:^7.4.2" - webpack-dev-server: "npm:5.2.0" + webpack-dev-server: "npm:5.2.2" ws: "npm:^8.18.0" peerDependencies: "@rspack/core": "*" - checksum: 10/a712c1ed6819da26984d106e7fdede3ed720ef177bf8fa976e91eb95988b862b306c354829486dce8eabde420cb5a96cb25ecf397c9532f87f3b913e9a9da40c + checksum: 10/31cef80a602acf9468a94c31b1f09239cae9c47cf0ed25c6bcddd057bbaff5a220a1dead068a255d35d0addfea21d81a574069d63ea258c2807d84a02d4fe966 languageName: node linkType: hard @@ -19893,18 +21181,18 @@ __metadata: linkType: hard "@types/content-type@npm:^1.1.8": - version: 1.1.8 - resolution: "@types/content-type@npm:1.1.8" - checksum: 10/2dd15e51925db7208b0d989c3a93d805a0e5e0942aa9edd70a1c3520896b772526d8280e344a674ae68a96a24aa8fce290843a07512460176f36a3020d99c792 + version: 1.1.9 + resolution: "@types/content-type@npm:1.1.9" + checksum: 10/ac2d419877661f25c6b2c174f42e142ee542cae7778af0a519d4787545ea190d2ff91a40acf68e5e8c52d22919be9ff0345e38a393866546ae9d45b8a79e94f6 languageName: node linkType: hard "@types/cookie-parser@npm:^1.4.2": - version: 1.4.8 - resolution: "@types/cookie-parser@npm:1.4.8" + version: 1.4.9 + resolution: "@types/cookie-parser@npm:1.4.9" peerDependencies: "@types/express": "*" - checksum: 10/b26ace5560adce1a746c059a75f18227ee3e3614a49c70dd29b8af204696079ced22eaa9d6cb084e3433ec433bff845cb47ffb890ae9af96a4aab2ff85e40da7 + checksum: 10/6192a4899b5412a4c3be0f47158321aef73a4cd7e7a4f7b2a37e2e1045f11a21209681cb1bc5335f250ee2a6ce64d8a3fefb851181a98e6415d3716ef9ed1f62 languageName: node linkType: hard @@ -19937,11 +21225,11 @@ __metadata: linkType: hard "@types/cors@npm:^2.8.6": - version: 2.8.18 - resolution: "@types/cors@npm:2.8.18" + version: 2.8.19 + resolution: "@types/cors@npm:2.8.19" dependencies: "@types/node": "npm:*" - checksum: 10/6e49b741345e67834cd19d766228509e4b37d6d5c272355bb059502b4787f5adf58776d9114ac5f0f407966e0347ae8d1f995d7ea41e6a24f716d36b3010401b + checksum: 10/9545cc532c9218754443f48a0c98c1a9ba4af1fe54a3425c95de75ff3158147bb39e666cb7c6bf98cc56a9c6dc7b4ce5b2cbdae6b55d5942e50c81b76ed6b825 languageName: node linkType: hard @@ -20093,9 +21381,9 @@ __metadata: linkType: hard "@types/estree@npm:*, @types/estree@npm:^1.0.0, @types/estree@npm:^1.0.5, @types/estree@npm:^1.0.6": - version: 1.0.7 - resolution: "@types/estree@npm:1.0.7" - checksum: 10/419c845ece767ad4b21171e6e5b63dabb2eb46b9c0d97361edcd9cabbf6a95fcadb91d89b5fa098d1336fa0b8fceaea82fca97a2ef3971f5c86e53031e157b21 + version: 1.0.8 + resolution: "@types/estree@npm:1.0.8" + checksum: 10/25a4c16a6752538ffde2826c2cc0c6491d90e69cd6187bef4a006dd2c3c45469f049e643d7e516c515f21484dc3d48fd5c870be158a5beb72f5baf3dc43e4099 languageName: node linkType: hard @@ -20145,11 +21433,11 @@ __metadata: linkType: hard "@types/express-session@npm:^1.17.2": - version: 1.18.1 - resolution: "@types/express-session@npm:1.18.1" + version: 1.18.2 + resolution: "@types/express-session@npm:1.18.2" dependencies: "@types/express": "npm:*" - checksum: 10/54316f13e789b758f9ca8209c54aff0bbcf50c9ea50a208d4ba6c3f95d21a60ddaa98bcf459bef02641b38e7244bfbc43aa724a8b607bb13c1c1bab4a139351a + checksum: 10/c1711976d089fd6da58c0262e2b21b71ee64d508ee0f9f1b90e7658b712fc59874e03f799757843d2300c1dd127813cd16ce806c208bc4975f0f7ed700f2db94 languageName: node linkType: hard @@ -20267,9 +21555,9 @@ __metadata: linkType: hard "@types/http-errors@npm:*, @types/http-errors@npm:^2.0.0": - version: 2.0.4 - resolution: "@types/http-errors@npm:2.0.4" - checksum: 10/1f3d7c3b32c7524811a45690881736b3ef741bf9849ae03d32ad1ab7062608454b150a4e7f1351f83d26a418b2d65af9bdc06198f1c079d75578282884c4e8e3 + version: 2.0.5 + resolution: "@types/http-errors@npm:2.0.5" + checksum: 10/a88da669366bc483e8f3b3eb3d34ada5f8d13eeeef851b1204d77e2ba6fc42aba4566d877cca5c095204a3f4349b87fe397e3e21288837bdd945dd514120755b languageName: node linkType: hard @@ -20495,9 +21783,9 @@ __metadata: linkType: hard "@types/lodash@npm:^4.14.151": - version: 4.17.16 - resolution: "@types/lodash@npm:4.17.16" - checksum: 10/9a8bb7471a7521bd65d528e1bd14f79819a3eeb6f8a35a8a44649a7d773775c0813e93fd93bd32ccf350bb076c0bf02c6d47877c4625f526f6dd4d283c746aec + version: 4.17.17 + resolution: "@types/lodash@npm:4.17.17" + checksum: 10/496459a3cb1a0733bb60532de3899ad6297717af0b9b26ad6821154b2005fec86f29ccd47a2e6f4da4a8c7c818bb8ae73901144e8057ea86b7b02a3d7bb9d13f languageName: node linkType: hard @@ -20881,9 +22169,9 @@ __metadata: linkType: hard "@types/prop-types@npm:*, @types/prop-types@npm:^15.0.0, @types/prop-types@npm:^15.7.12, @types/prop-types@npm:^15.7.3": - version: 15.7.14 - resolution: "@types/prop-types@npm:15.7.14" - checksum: 10/d0c5407b9ccc3dd5fae0ccf9b1007e7622ba5e6f1c18399b4f24dff33619d469da4b9fa918a374f19dc0d9fe6a013362aab0b844b606cfc10676efba3f5f736d + version: 15.7.15 + resolution: "@types/prop-types@npm:15.7.15" + checksum: 10/31aa2f59b28f24da6fb4f1d70807dae2aedfce090ec63eaf9ea01727a9533ef6eaf017de5bff99fbccad7d1c9e644f52c6c2ba30869465dd22b1a7221c29f356 languageName: node linkType: hard @@ -21022,12 +22310,12 @@ __metadata: linkType: hard "@types/react@npm:^18.0.0": - version: 18.3.21 - resolution: "@types/react@npm:18.3.21" + version: 18.3.23 + resolution: "@types/react@npm:18.3.23" dependencies: "@types/prop-types": "npm:*" csstype: "npm:^3.0.2" - checksum: 10/89adc2fe391fd63b620db0aaa10b2be89fad338039415fd748e60c962e47bf2b0f1897cb5226f181eda963f37a1c8ac1bf0b3b29a0e35313bacd0355e5d6c736 + checksum: 10/4b965dffe34a1f8aac8e2d7e976f113373f38134f9e37239f7e75d7ac6b3c2e1333a8df21febf1fe7749640f8de5708f7668cdfc70bffebda1cc4d3346724fd5 languageName: node linkType: hard @@ -22338,6 +23626,31 @@ __metadata: languageName: node linkType: hard +"@xterm/addon-attach@npm:^0.11.0": + version: 0.11.0 + resolution: "@xterm/addon-attach@npm:0.11.0" + peerDependencies: + "@xterm/xterm": ^5.0.0 + checksum: 10/f11e7ba68b8b1064ce545ecbf2beeaf3ebc94622fa3ca77e0ca0b8e8834964f634ee3897c031376abc7242ddfd305a40b10aa7b3e8056bfa59055967251523b5 + languageName: node + linkType: hard + +"@xterm/addon-fit@npm:^0.10.0": + version: 0.10.0 + resolution: "@xterm/addon-fit@npm:0.10.0" + peerDependencies: + "@xterm/xterm": ^5.0.0 + checksum: 10/8edfad561c0d0316c5883cbe2ce56109f105a2b2bf53b71d5f8c788e656a3205c1093a659dddcf4025a459e4b7ff8e07b6c6a19815c8711deeded560de5f1893 + languageName: node + linkType: hard + +"@xterm/xterm@npm:^5.5.0": + version: 5.5.0 + resolution: "@xterm/xterm@npm:5.5.0" + checksum: 10/d4cdc402de81a83a3e0ef93f38072cb8f54abe4d65865f2e29b92cbc2593f86d052f6b993895c9e5dec97f47548f504e90bcea0aad6845917c09b03f2f3a4629 + languageName: node + linkType: hard + "@xtuc/ieee754@npm:^1.2.0": version: 1.2.0 resolution: "@xtuc/ieee754@npm:1.2.0" @@ -22453,7 +23766,7 @@ __metadata: languageName: node linkType: hard -"@yarnpkg/core@npm:^4.2.1, @yarnpkg/core@npm:^4.4.0": +"@yarnpkg/core@npm:^4.2.1, @yarnpkg/core@npm:^4.4.0, @yarnpkg/core@npm:^4.4.1": version: 4.4.1 resolution: "@yarnpkg/core@npm:4.4.1" dependencies: @@ -23137,6 +24450,16 @@ __metadata: languageName: node linkType: hard +"accepts@npm:^2.0.0": + version: 2.0.0 + resolution: "accepts@npm:2.0.0" + dependencies: + mime-types: "npm:^3.0.0" + negotiator: "npm:^1.0.0" + checksum: 10/ea1343992b40b2bfb3a3113fa9c3c2f918ba0f9197ae565c48d3f84d44b174f6b1d5cd9989decd7655963eb03a272abc36968cc439c2907f999bd5ef8653d5a7 + languageName: node + linkType: hard + "acorn-globals@npm:^6.0.0": version: 6.0.0 resolution: "acorn-globals@npm:6.0.0" @@ -23352,7 +24675,7 @@ __metadata: languageName: node linkType: hard -"ajv@npm:^6.12.2, ajv@npm:^6.12.4, ajv@npm:^6.12.5, ajv@npm:^6.5.5": +"ajv@npm:^6.12.2, ajv@npm:^6.12.4, ajv@npm:^6.12.5, ajv@npm:^6.12.6, ajv@npm:^6.5.5": version: 6.12.6 resolution: "ajv@npm:6.12.6" dependencies: @@ -24165,18 +25488,7 @@ __metadata: languageName: node linkType: hard -"axios@npm:1.8.4": - version: 1.8.4 - resolution: "axios@npm:1.8.4" - dependencies: - follow-redirects: "npm:^1.15.6" - form-data: "npm:^4.0.0" - proxy-from-env: "npm:^1.1.0" - checksum: 10/a10f0dd836613924e48cf03dc2eff3fd21b14f764807aedaee4880a70c0f142aaebdb21da7ce27104d4c16ca00d0e452a20a20851f60e385a8d5bad1ae909d46 - languageName: node - linkType: hard - -"axios@npm:^1.0.0, axios@npm:^1.6.0, axios@npm:^1.7.4, axios@npm:^1.7.7, axios@npm:^1.7.8": +"axios@npm:1.9.0": version: 1.9.0 resolution: "axios@npm:1.9.0" dependencies: @@ -24187,6 +25499,17 @@ __metadata: languageName: node linkType: hard +"axios@npm:^1.0.0, axios@npm:^1.6.0, axios@npm:^1.7.4, axios@npm:^1.7.7, axios@npm:^1.7.8": + version: 1.10.0 + resolution: "axios@npm:1.10.0" + dependencies: + follow-redirects: "npm:^1.15.6" + form-data: "npm:^4.0.0" + proxy-from-env: "npm:^1.1.0" + checksum: 10/d43c80316a45611fd395743e15d16ea69a95f2b7f7095f2bb12cb78f9ca0a905194a02e52a3bf4e0db9f85fd1186d6c690410644c10ecd8bb0a468e57c2040e4 + languageName: node + linkType: hard + "axobject-query@npm:^4.1.0": version: 4.1.0 resolution: "axobject-query@npm:4.1.0" @@ -24695,6 +26018,23 @@ __metadata: languageName: node linkType: hard +"body-parser@npm:^2.2.0": + version: 2.2.0 + resolution: "body-parser@npm:2.2.0" + dependencies: + bytes: "npm:^3.1.2" + content-type: "npm:^1.0.5" + debug: "npm:^4.4.0" + http-errors: "npm:^2.0.0" + iconv-lite: "npm:^0.6.3" + on-finished: "npm:^2.4.1" + qs: "npm:^6.14.0" + raw-body: "npm:^3.0.0" + type-is: "npm:^2.0.0" + checksum: 10/e9d844b036bd15970df00a16f373c7ed28e1ef870974a0a1d4d6ef60d70e01087cc20a0dbb2081c49a88e3c08ce1d87caf1e2898c615dffa193f63e8faa8a84e + languageName: node + linkType: hard + "bonjour-service@npm:^1.2.1": version: 1.2.1 resolution: "bonjour-service@npm:1.2.1" @@ -24750,12 +26090,12 @@ __metadata: linkType: hard "brace-expansion@npm:^1.1.7": - version: 1.1.11 - resolution: "brace-expansion@npm:1.1.11" + version: 1.1.12 + resolution: "brace-expansion@npm:1.1.12" dependencies: balanced-match: "npm:^1.0.0" concat-map: "npm:0.0.1" - checksum: 10/faf34a7bb0c3fcf4b59c7808bc5d2a96a40988addf2e7e09dfbb67a2251800e0d14cd2bfc1aa79174f2f5095c54ff27f46fb1289fe2d77dac755b5eb3434cc07 + checksum: 10/12cb6d6310629e3048cadb003e1aca4d8c9bb5c67c3c321bafdd7e7a50155de081f78ea3e0ed92ecc75a9015e784f301efc8132383132f4f7904ad1ac529c562 languageName: node linkType: hard @@ -25059,7 +26399,7 @@ __metadata: languageName: node linkType: hard -"bytes@npm:3.1.2": +"bytes@npm:3.1.2, bytes@npm:^3.1.2": version: 3.1.2 resolution: "bytes@npm:3.1.2" checksum: 10/a10abf2ba70c784471d6b4f58778c0beeb2b5d405148e66affa91f23a9f13d07603d0a0354667310ae1d6dc141474ffd44e2a074be0f6e2254edb8fc21445388 @@ -25323,7 +26663,7 @@ __metadata: languageName: node linkType: hard -"caniuse-lite@npm:^1.0.0, caniuse-lite@npm:^1.0.30001669, caniuse-lite@npm:^1.0.30001717": +"caniuse-lite@npm:^1.0.0, caniuse-lite@npm:^1.0.30001669": version: 1.0.30001717 resolution: "caniuse-lite@npm:1.0.30001717" checksum: 10/e47dfd8707ea305baa177f3d3d531df614f5a9ac6335363fc8f86f0be4caf79f5734f3f68b601fee4edd9d79f1e5ffc0931466bb894bf955ed6b1dd5a1c34b1d @@ -26413,6 +27753,15 @@ __metadata: languageName: node linkType: hard +"content-disposition@npm:^1.0.0": + version: 1.0.0 + resolution: "content-disposition@npm:1.0.0" + dependencies: + safe-buffer: "npm:5.2.1" + checksum: 10/0dcc1a2d7874526b0072df3011b134857b49d97a3bc135bb464a299525d4972de6f5f464fd64da6c4d8406d26a1ffb976f62afaffef7723b1021a44498d10e08 + languageName: node + linkType: hard + "content-type@npm:^1.0.4, content-type@npm:^1.0.5, content-type@npm:~1.0.4, content-type@npm:~1.0.5": version: 1.0.5 resolution: "content-type@npm:1.0.5" @@ -26465,6 +27814,13 @@ __metadata: languageName: node linkType: hard +"cookie-signature@npm:^1.2.1": + version: 1.2.2 + resolution: "cookie-signature@npm:1.2.2" + checksum: 10/be44a3c9a56f3771aea3a8bd8ad8f0a8e2679bcb967478267f41a510b4eb5ec55085386ba79c706c4ac21605ca76f4251973444b90283e0eb3eeafe8a92c7708 + languageName: node + linkType: hard + "cookie@npm:0.7.1": version: 0.7.1 resolution: "cookie@npm:0.7.1" @@ -26472,7 +27828,7 @@ __metadata: languageName: node linkType: hard -"cookie@npm:0.7.2, cookie@npm:^0.7.0, cookie@npm:^0.7.2": +"cookie@npm:0.7.2, cookie@npm:^0.7.0, cookie@npm:^0.7.1, cookie@npm:^0.7.2": version: 0.7.2 resolution: "cookie@npm:0.7.2" checksum: 10/24b286c556420d4ba4e9bc09120c9d3db7d28ace2bd0f8ccee82422ce42322f73c8312441271e5eefafbead725980e5996cc02766dbb89a90ac7f5636ede608f @@ -26712,10 +28068,10 @@ __metadata: languageName: node linkType: hard -"crelt@npm:^1.0.5": - version: 1.0.5 - resolution: "crelt@npm:1.0.5" - checksum: 10/f692219f8550570b35d26f64a34945a016ec10c2714491d1306b95253e4b6bca609b3c73aee68e1c2035eab6cf38b6c853c4c16f80b26a808e688d25c6821b25 +"crelt@npm:^1.0.5, crelt@npm:^1.0.6": + version: 1.0.6 + resolution: "crelt@npm:1.0.6" + checksum: 10/5ed326ca6bd243b1dba6b943f665b21c2c04be03271824bc48f20dba324b0f8233e221f8c67312526d24af2b1243c023dc05a41bd8bd05d1a479fd2c72fb39c3 languageName: node linkType: hard @@ -26810,7 +28166,7 @@ __metadata: languageName: node linkType: hard -"cross-spawn@npm:^7.0.0, cross-spawn@npm:^7.0.1, cross-spawn@npm:^7.0.2, cross-spawn@npm:^7.0.3, cross-spawn@npm:^7.0.5": +"cross-spawn@npm:^7.0.1, cross-spawn@npm:^7.0.2, cross-spawn@npm:^7.0.3, cross-spawn@npm:^7.0.5, cross-spawn@npm:^7.0.6": version: 7.0.6 resolution: "cross-spawn@npm:7.0.6" dependencies: @@ -27896,8 +29252,8 @@ __metadata: linkType: hard "dockerode@npm:^4.0.0": - version: 4.0.6 - resolution: "dockerode@npm:4.0.6" + version: 4.0.7 + resolution: "dockerode@npm:4.0.7" dependencies: "@balena/dockerignore": "npm:^1.0.2" "@grpc/grpc-js": "npm:^1.11.1" @@ -27906,7 +29262,7 @@ __metadata: protobufjs: "npm:^7.3.2" tar-fs: "npm:~2.1.2" uuid: "npm:^10.0.0" - checksum: 10/75bd706f20f01742d22913b72e2a5215a4d9f79772c29079772f84fc41a2b1890a704a1aa3d1d764405367090e93c33197d6add19fde3546bac919d98eebc8e3 + checksum: 10/d7cd174cf4489f41335ec8aaaa7c98c164a624f9a793544aa5280d85254ce276e7797de896042ce47d87aca6f8d2653acc37a0d18807d4ce8ea31892faef40a8 languageName: node linkType: hard @@ -28366,7 +29722,7 @@ __metadata: languageName: node linkType: hard -"encodeurl@npm:~2.0.0": +"encodeurl@npm:^2.0.0, encodeurl@npm:~2.0.0": version: 2.0.0 resolution: "encodeurl@npm:2.0.0" checksum: 10/abf5cd51b78082cf8af7be6785813c33b6df2068ce5191a40ca8b1afe6a86f9230af9a9ce694a5ce4665955e5c1120871826df9c128a642e09c58d592e2807fe @@ -28755,34 +30111,34 @@ __metadata: linkType: hard "esbuild@npm:^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0 || ^0.24.0 || ^0.25.0, esbuild@npm:^0.25.0": - version: 0.25.4 - resolution: "esbuild@npm:0.25.4" + version: 0.25.5 + resolution: "esbuild@npm:0.25.5" dependencies: - "@esbuild/aix-ppc64": "npm:0.25.4" - "@esbuild/android-arm": "npm:0.25.4" - "@esbuild/android-arm64": "npm:0.25.4" - "@esbuild/android-x64": "npm:0.25.4" - "@esbuild/darwin-arm64": "npm:0.25.4" - "@esbuild/darwin-x64": "npm:0.25.4" - "@esbuild/freebsd-arm64": "npm:0.25.4" - "@esbuild/freebsd-x64": "npm:0.25.4" - "@esbuild/linux-arm": "npm:0.25.4" - "@esbuild/linux-arm64": "npm:0.25.4" - "@esbuild/linux-ia32": "npm:0.25.4" - "@esbuild/linux-loong64": "npm:0.25.4" - "@esbuild/linux-mips64el": "npm:0.25.4" - "@esbuild/linux-ppc64": "npm:0.25.4" - "@esbuild/linux-riscv64": "npm:0.25.4" - "@esbuild/linux-s390x": "npm:0.25.4" - "@esbuild/linux-x64": "npm:0.25.4" - "@esbuild/netbsd-arm64": "npm:0.25.4" - "@esbuild/netbsd-x64": "npm:0.25.4" - "@esbuild/openbsd-arm64": "npm:0.25.4" - "@esbuild/openbsd-x64": "npm:0.25.4" - "@esbuild/sunos-x64": "npm:0.25.4" - "@esbuild/win32-arm64": "npm:0.25.4" - "@esbuild/win32-ia32": "npm:0.25.4" - "@esbuild/win32-x64": "npm:0.25.4" + "@esbuild/aix-ppc64": "npm:0.25.5" + "@esbuild/android-arm": "npm:0.25.5" + "@esbuild/android-arm64": "npm:0.25.5" + "@esbuild/android-x64": "npm:0.25.5" + "@esbuild/darwin-arm64": "npm:0.25.5" + "@esbuild/darwin-x64": "npm:0.25.5" + "@esbuild/freebsd-arm64": "npm:0.25.5" + "@esbuild/freebsd-x64": "npm:0.25.5" + "@esbuild/linux-arm": "npm:0.25.5" + "@esbuild/linux-arm64": "npm:0.25.5" + "@esbuild/linux-ia32": "npm:0.25.5" + "@esbuild/linux-loong64": "npm:0.25.5" + "@esbuild/linux-mips64el": "npm:0.25.5" + "@esbuild/linux-ppc64": "npm:0.25.5" + "@esbuild/linux-riscv64": "npm:0.25.5" + "@esbuild/linux-s390x": "npm:0.25.5" + "@esbuild/linux-x64": "npm:0.25.5" + "@esbuild/netbsd-arm64": "npm:0.25.5" + "@esbuild/netbsd-x64": "npm:0.25.5" + "@esbuild/openbsd-arm64": "npm:0.25.5" + "@esbuild/openbsd-x64": "npm:0.25.5" + "@esbuild/sunos-x64": "npm:0.25.5" + "@esbuild/win32-arm64": "npm:0.25.5" + "@esbuild/win32-ia32": "npm:0.25.5" + "@esbuild/win32-x64": "npm:0.25.5" dependenciesMeta: "@esbuild/aix-ppc64": optional: true @@ -28836,7 +30192,7 @@ __metadata: optional: true bin: esbuild: bin/esbuild - checksum: 10/227ffe9b31f0b184a0b0a0210bb9d32b2b115b8c5c9b09f08db2c3928cb470fc55a22dbba3c2894365d3abcc62c2089b85638be96a20691d1234d31990ea01b2 + checksum: 10/0fa4c3b42c6ddf1a008e75a4bb3dcab08ce22ac0b31dd59dc01f7fe8e21380bfaec07a2fe3730a7cf430da5a30142d016714b358666325a4733547afa42be405 languageName: node linkType: hard @@ -29445,7 +30801,7 @@ __metadata: languageName: node linkType: hard -"etag@npm:~1.8.1": +"etag@npm:^1.8.1, etag@npm:~1.8.1": version: 1.8.1 resolution: "etag@npm:1.8.1" checksum: 10/571aeb3dbe0f2bbd4e4fadbdb44f325fc75335cd5f6f6b6a091e6a06a9f25ed5392f0863c5442acb0646787446e816f13cbfc6edce5b07658541dff573cab1ff @@ -29513,7 +30869,7 @@ __metadata: languageName: node linkType: hard -"eventsource@npm:^3.0.6": +"eventsource@npm:^3.0.2, eventsource@npm:^3.0.6": version: 3.0.7 resolution: "eventsource@npm:3.0.7" dependencies: @@ -29696,6 +31052,7 @@ __metadata: "@backstage/plugin-events-backend": "workspace:^" "@backstage/plugin-events-backend-module-google-pubsub": "workspace:^" "@backstage/plugin-kubernetes-backend": "workspace:^" + "@backstage/plugin-mcp-actions-backend": "workspace:^" "@backstage/plugin-notifications-backend": "workspace:^" "@backstage/plugin-permission-backend": "workspace:^" "@backstage/plugin-permission-backend-module-allow-all-policy": "workspace:^" @@ -29865,6 +31222,15 @@ __metadata: languageName: node linkType: hard +"express-rate-limit@npm:^7.5.0": + version: 7.5.0 + resolution: "express-rate-limit@npm:7.5.0" + peerDependencies: + express: ^4.11 || 5 || ^5.0.0-beta.1 + checksum: 10/eff34c83bf586789933a332a339b66649e2cca95c8e977d193aa8bead577d3182ac9f0e9c26f39389287539b8038890ff023f910b54ebb506a26a2ce135b92ca + languageName: node + linkType: hard + "express-session@npm:^1.17.1, express-session@npm:^1.17.3": version: 1.18.1 resolution: "express-session@npm:1.18.1" @@ -29920,6 +31286,41 @@ __metadata: languageName: node linkType: hard +"express@npm:^5.0.1": + version: 5.1.0 + resolution: "express@npm:5.1.0" + dependencies: + accepts: "npm:^2.0.0" + body-parser: "npm:^2.2.0" + content-disposition: "npm:^1.0.0" + content-type: "npm:^1.0.5" + cookie: "npm:^0.7.1" + cookie-signature: "npm:^1.2.1" + debug: "npm:^4.4.0" + encodeurl: "npm:^2.0.0" + escape-html: "npm:^1.0.3" + etag: "npm:^1.8.1" + finalhandler: "npm:^2.1.0" + fresh: "npm:^2.0.0" + http-errors: "npm:^2.0.0" + merge-descriptors: "npm:^2.0.0" + mime-types: "npm:^3.0.0" + on-finished: "npm:^2.4.1" + once: "npm:^1.4.0" + parseurl: "npm:^1.3.3" + proxy-addr: "npm:^2.0.7" + qs: "npm:^6.14.0" + range-parser: "npm:^1.2.1" + router: "npm:^2.2.0" + send: "npm:^1.1.0" + serve-static: "npm:^2.2.0" + statuses: "npm:^2.0.1" + type-is: "npm:^2.0.1" + vary: "npm:^1.1.2" + checksum: 10/6dba00bbdf308f43a84ed3f07a7e9870d5208f2a0b8f60f39459dda089750379747819863fad250849d3c9163833f33f94ce69d73938df31e0c5a430800d7e56 + languageName: node + linkType: hard + "ext@npm:^1.1.2": version: 1.7.0 resolution: "ext@npm:1.7.0" @@ -30233,15 +31634,15 @@ __metadata: languageName: node linkType: hard -"file-type@npm:20.4.1": - version: 20.4.1 - resolution: "file-type@npm:20.4.1" +"file-type@npm:20.5.0": + version: 20.5.0 + resolution: "file-type@npm:20.5.0" dependencies: "@tokenizer/inflate": "npm:^0.2.6" strtok3: "npm:^10.2.0" token-types: "npm:^6.0.0" uint8array-extras: "npm:^1.4.0" - checksum: 10/efbb81c69c84ea4d83ea86dc1c95a45bc6830d5455deb7666e0dbefde2dbfe2bcee4e5398bfc5a8fc1ac55a80a27a3ec4f2bff4b53d4af20be799db4fae324b6 + checksum: 10/1cc1ccd7cf76086e10b65cba88c708e0653676fbae900107deeb91c46de011acd1492200bf47e75cddf395de27dbe8584ca042f4cfa4a1efdf933644b7143f1d languageName: node linkType: hard @@ -30325,6 +31726,20 @@ __metadata: languageName: node linkType: hard +"finalhandler@npm:^2.1.0": + version: 2.1.0 + resolution: "finalhandler@npm:2.1.0" + dependencies: + debug: "npm:^4.4.0" + encodeurl: "npm:^2.0.0" + escape-html: "npm:^1.0.3" + on-finished: "npm:^2.4.1" + parseurl: "npm:^1.3.3" + statuses: "npm:^2.0.1" + checksum: 10/b2bd68c310e2c463df0ab747ab05f8defbc540b8c3f2442f86e7d084ac8acbc31f8cae079931b7f5a406521501941e3395e963de848a0aaf45dd414adeb5ff4e + languageName: node + linkType: hard + "find-cache-dir@npm:^2.0.0": version: 2.1.0 resolution: "find-cache-dir@npm:2.1.0" @@ -30539,13 +31954,13 @@ __metadata: languageName: node linkType: hard -"foreground-child@npm:^3.1.0": - version: 3.1.1 - resolution: "foreground-child@npm:3.1.1" +"foreground-child@npm:^3.1.0, foreground-child@npm:^3.3.1": + version: 3.3.1 + resolution: "foreground-child@npm:3.3.1" dependencies: - cross-spawn: "npm:^7.0.0" + cross-spawn: "npm:^7.0.6" signal-exit: "npm:^4.0.1" - checksum: 10/087edd44857d258c4f73ad84cb8df980826569656f2550c341b27adf5335354393eec24ea2fabd43a253233fb27cee177ebe46bd0b7ea129c77e87cb1e9936fb + checksum: 10/427b33f997a98073c0424e5c07169264a62cda806d8d2ded159b5b903fdfc8f0a1457e06b5fc35506497acb3f1e353f025edee796300209ac6231e80edece835 languageName: node linkType: hard @@ -30752,6 +32167,13 @@ __metadata: languageName: node linkType: hard +"fresh@npm:^2.0.0": + version: 2.0.0 + resolution: "fresh@npm:2.0.0" + checksum: 10/44e1468488363074641991c1340d2a10c5a6f6d7c353d89fd161c49d120c58ebf9890720f7584f509058385836e3ce50ddb60e9f017315a4ba8c6c3461813bfc + languageName: node + linkType: hard + "from2@npm:^2.3.0": version: 2.3.0 resolution: "from2@npm:2.3.0" @@ -31291,18 +32713,18 @@ __metadata: linkType: hard "glob@npm:^11.0.1": - version: 11.0.2 - resolution: "glob@npm:11.0.2" + version: 11.0.3 + resolution: "glob@npm:11.0.3" dependencies: - foreground-child: "npm:^3.1.0" - jackspeak: "npm:^4.0.1" - minimatch: "npm:^10.0.0" + foreground-child: "npm:^3.3.1" + jackspeak: "npm:^4.1.1" + minimatch: "npm:^10.0.3" minipass: "npm:^7.1.2" package-json-from-dist: "npm:^1.0.0" path-scurry: "npm:^2.0.0" bin: glob: dist/esm/bin.mjs - checksum: 10/53501530240150fdceb9ace47ab856acd1e0d598f8101b0760b665fc11dae2160d366563b89232ae4f5df7ddba8f7c92294719268fe932bd3a32d16cc58c3d02 + checksum: 10/2ae536c1360c0266b523b2bfa6aadc10144a8b7e08869b088e37ac3c27cd30774f82e4bfb291cde796776e878f9e13200c7ff44010eb7054e00f46f649397893 languageName: node linkType: hard @@ -32305,7 +33727,7 @@ __metadata: languageName: node linkType: hard -"http-proxy-middleware@npm:^2.0.0, http-proxy-middleware@npm:^2.0.6, http-proxy-middleware@npm:^2.0.7": +"http-proxy-middleware@npm:^2.0.0, http-proxy-middleware@npm:^2.0.6, http-proxy-middleware@npm:^2.0.9": version: 2.0.9 resolution: "http-proxy-middleware@npm:2.0.9" dependencies: @@ -33928,12 +35350,12 @@ __metadata: languageName: node linkType: hard -"jackspeak@npm:^4.0.1": - version: 4.0.2 - resolution: "jackspeak@npm:4.0.2" +"jackspeak@npm:^4.1.1": + version: 4.1.1 + resolution: "jackspeak@npm:4.1.1" dependencies: "@isaacs/cliui": "npm:^8.0.2" - checksum: 10/d9722f0e55f6c322c57aedf094c405f4201b834204629817187953988075521cfddb23df83e2a7b845723ca7eb0555068c5ce1556732e9c275d32a531881efa8 + checksum: 10/ffceb270ec286841f48413bfb4a50b188662dfd599378ce142b6540f3f0a66821dc9dcb1e9ebc55c6c3b24dc2226c96e5819ba9bd7a241bd29031b61911718c7 languageName: node linkType: hard @@ -35266,6 +36688,13 @@ __metadata: languageName: node linkType: hard +"kafkajs@npm:^2.2.4": + version: 2.2.4 + resolution: "kafkajs@npm:2.2.4" + checksum: 10/75eb0d221397085f90e51f8a2d752495c9fa9c1b3a1a6db610cd7074fa8c52777f295832fd0a7c49cded5e574337a09fafa8c3f7cf1caa38f4dc9aa20fcfb7df + languageName: node + linkType: hard + "keygrip@npm:~1.1.0": version: 1.1.0 resolution: "keygrip@npm:1.1.0" @@ -35276,11 +36705,11 @@ __metadata: linkType: hard "keyv@npm:*, keyv@npm:^5.2.1": - version: 5.2.3 - resolution: "keyv@npm:5.2.3" + version: 5.3.4 + resolution: "keyv@npm:5.3.4" dependencies: - "@keyv/serialize": "npm:^1.0.2" - checksum: 10/47b4e9deb33e6a80e5ea79f3022ed3a14bc9fe553b7527ffff0a70b10c7a6c1a5d7e49b9bcfdbd8e8b9fb4632d68baa19d09e82628bcf853103e750e56d49a9e + "@keyv/serialize": "npm:^1.0.3" + checksum: 10/3e294eb1168af78ad3430d0cc47b6839fd3e70593238d35226a0a1e4094abe397ea378b7bce35cfcb314e55b5d1b4fcdae3c19bee5610e78d283b3cb5b279c8b languageName: node linkType: hard @@ -36998,7 +38427,7 @@ __metadata: languageName: node linkType: hard -"memjs@npm:^1.3.1, memjs@npm:^1.3.2": +"memjs@npm:^1.3.2": version: 1.3.2 resolution: "memjs@npm:1.3.2" checksum: 10/705bb9be88180685fa3bc71375dc8b3a188356ab8f5c6c5ea1761e5e0912a78520cb964d2afc24e65686d53b45d3a7d8b5e770b2f3cf071a6eaea7f8d0d6bbfd @@ -37044,6 +38473,13 @@ __metadata: languageName: node linkType: hard +"merge-descriptors@npm:^2.0.0": + version: 2.0.0 + resolution: "merge-descriptors@npm:2.0.0" + checksum: 10/e383332e700a94682d0125a36c8be761142a1320fc9feeb18e6e36647c9edf064271645f5669b2c21cf352116e561914fd8aa831b651f34db15ef4038c86696a + languageName: node + linkType: hard + "merge-stream@npm:^2.0.0": version: 2.0.0 resolution: "merge-stream@npm:2.0.0" @@ -37427,13 +38863,20 @@ __metadata: languageName: node linkType: hard -"mime-db@npm:1.52.0, mime-db@npm:>= 1.43.0 < 2": +"mime-db@npm:1.52.0": version: 1.52.0 resolution: "mime-db@npm:1.52.0" checksum: 10/54bb60bf39e6f8689f6622784e668a3d7f8bed6b0d886f5c3c446cb3284be28b30bf707ed05d0fe44a036f8469976b2629bbea182684977b084de9da274694d7 languageName: node linkType: hard +"mime-db@npm:>= 1.43.0 < 2, mime-db@npm:^1.54.0": + version: 1.54.0 + resolution: "mime-db@npm:1.54.0" + checksum: 10/9e7834be3d66ae7f10eaa69215732c6d389692b194f876198dca79b2b90cbf96688d9d5d05ef7987b20f749b769b11c01766564264ea5f919c88b32a29011311 + languageName: node + linkType: hard + "mime-db@npm:~1.33.0": version: 1.33.0 resolution: "mime-db@npm:1.33.0" @@ -37459,7 +38902,7 @@ __metadata: languageName: node linkType: hard -"mime-types@npm:2.1.35, mime-types@npm:^2.1.12, mime-types@npm:^2.1.18, mime-types@npm:^2.1.27, mime-types@npm:^2.1.31, mime-types@npm:^2.1.35, mime-types@npm:~2.1.17, mime-types@npm:~2.1.19, mime-types@npm:~2.1.24, mime-types@npm:~2.1.34": +"mime-types@npm:2.1.35, mime-types@npm:^2.1.12, mime-types@npm:^2.1.18, mime-types@npm:^2.1.27, mime-types@npm:^2.1.31, mime-types@npm:~2.1.17, mime-types@npm:~2.1.19, mime-types@npm:~2.1.24, mime-types@npm:~2.1.34": version: 2.1.35 resolution: "mime-types@npm:2.1.35" dependencies: @@ -37468,6 +38911,15 @@ __metadata: languageName: node linkType: hard +"mime-types@npm:^3.0.0, mime-types@npm:^3.0.1": + version: 3.0.1 + resolution: "mime-types@npm:3.0.1" + dependencies: + mime-db: "npm:^1.54.0" + checksum: 10/fa1d3a928363723a8046c346d87bf85d35014dae4285ad70a3ff92bd35957992b3094f8417973cfe677330916c6ef30885109624f1fb3b1e61a78af509dba120 + languageName: node + linkType: hard + "mime@npm:1.6.0, mime@npm:^1.3.4": version: 1.6.0 resolution: "mime@npm:1.6.0" @@ -37604,12 +39056,12 @@ __metadata: languageName: node linkType: hard -"minimatch@npm:^10.0.0": - version: 10.0.1 - resolution: "minimatch@npm:10.0.1" +"minimatch@npm:^10.0.3": + version: 10.0.3 + resolution: "minimatch@npm:10.0.3" dependencies: - brace-expansion: "npm:^2.0.1" - checksum: 10/082e7ccbc090d5f8c4e4e029255d5a1d1e3af37bda837da2b8b0085b1503a1210c91ac90d9ebfe741d8a5f286ece820a1abb4f61dc1f82ce602a055d461d93f3 + "@isaacs/brace-expansion": "npm:^5.0.0" + checksum: 10/d5b8b2538b367f2cfd4aeef27539fddeee58d1efb692102b848e4a968a09780a302c530eb5aacfa8c57f7299155fb4b4e85219ad82664dcef5c66f657111d9b8 languageName: node linkType: hard @@ -38091,14 +39543,14 @@ __metadata: linkType: hard "msw@npm:^2.0.0, msw@npm:^2.0.8": - version: 2.8.2 - resolution: "msw@npm:2.8.2" + version: 2.10.2 + resolution: "msw@npm:2.10.2" dependencies: "@bundled-es-modules/cookie": "npm:^2.0.1" "@bundled-es-modules/statuses": "npm:^1.0.1" "@bundled-es-modules/tough-cookie": "npm:^0.1.6" "@inquirer/confirm": "npm:^5.0.0" - "@mswjs/interceptors": "npm:^0.37.0" + "@mswjs/interceptors": "npm:^0.39.1" "@open-draft/deferred-promise": "npm:^2.2.0" "@open-draft/until": "npm:^2.1.0" "@types/cookie": "npm:^0.6.0" @@ -38119,7 +39571,7 @@ __metadata: optional: true bin: msw: cli/index.js - checksum: 10/7579a8dccb8cc8eb0f13d0bf3a232a3d50a478511d95bc2a4b70778e78ffa28fd0949a855fbceb6ec381bbf76f6331a6d36fcb4a3197ff5bf55d0f14a7f3b35c + checksum: 10/bc90bc34a0b9e978e662f33fa630a0de66c4b6eff3a92b41efa08bf67d79b43e4a961a17b0d274580393c912f4ac6226c76a8bc33148799b1ee43477df712c26 languageName: node linkType: hard @@ -39184,20 +40636,21 @@ __metadata: linkType: hard "octokit@npm:^3.0.0": - version: 3.2.1 - resolution: "octokit@npm:3.2.1" + version: 3.2.2 + resolution: "octokit@npm:3.2.2" dependencies: "@octokit/app": "npm:^14.0.2" "@octokit/core": "npm:^5.0.0" "@octokit/oauth-app": "npm:^6.0.0" "@octokit/plugin-paginate-graphql": "npm:^4.0.0" - "@octokit/plugin-paginate-rest": "npm:11.3.1" - "@octokit/plugin-rest-endpoint-methods": "npm:13.2.2" + "@octokit/plugin-paginate-rest": "npm:11.4.4-cjs.2" + "@octokit/plugin-rest-endpoint-methods": "npm:13.3.2-cjs.1" "@octokit/plugin-retry": "npm:^6.0.0" "@octokit/plugin-throttling": "npm:^8.0.0" "@octokit/request-error": "npm:^5.0.0" "@octokit/types": "npm:^13.0.0" - checksum: 10/a3539831c9c0828b1e37dc94a3668f5fb9aa873fc396c0464275d152e4065b6b20300cfba766871cb52ed2e6d537febda7d4be872894c4c62024393a3578fde0 + "@octokit/webhooks": "npm:^12.3.1" + checksum: 10/a258cc62767552fcf9d9a2dfb2aac44b326a2a235fb6444c1f37bc018bda4ac4bf0203704d8b7b3955d3caee6f9256c200287f7e99843c8be01febe4d9fe86d8 languageName: node linkType: hard @@ -40523,6 +41976,13 @@ __metadata: languageName: node linkType: hard +"pkce-challenge@npm:^5.0.0": + version: 5.0.0 + resolution: "pkce-challenge@npm:5.0.0" + checksum: 10/e60c06a0e0481cb82f80072053d5c479a7490758541c4226460450285dd5d72a995c44b3c553731ca7c2f64cc34b35f1d2e5f9de08d276b59899298f9efe1ddf + languageName: node + linkType: hard + "pkg-dir@npm:^3.0.0": version: 3.0.0 resolution: "pkg-dir@npm:3.0.0" @@ -40573,27 +42033,27 @@ __metadata: languageName: node linkType: hard -"playwright-core@npm:1.52.0": - version: 1.52.0 - resolution: "playwright-core@npm:1.52.0" +"playwright-core@npm:1.53.0": + version: 1.53.0 + resolution: "playwright-core@npm:1.53.0" bin: playwright-core: cli.js - checksum: 10/42e13f5f98dc25ebc95525fb338a215b9097b2ba39d41e99972a190bf75d79979f163f5bc07b1ca06847ee07acb2c9b487d070fab67e9cd55e33310fc05aca3c + checksum: 10/881f27a9b7edd9954700489a5a4212cb91bcada226fd1d79a239b2eab0f333df1e2e41e275e6fa846d7f57c6a92afe14dca33ca7a2ce303dfb687d02511b7c69 languageName: node linkType: hard -"playwright@npm:1.52.0": - version: 1.52.0 - resolution: "playwright@npm:1.52.0" +"playwright@npm:1.53.0": + version: 1.53.0 + resolution: "playwright@npm:1.53.0" dependencies: fsevents: "npm:2.3.2" - playwright-core: "npm:1.52.0" + playwright-core: "npm:1.53.0" dependenciesMeta: fsevents: optional: true bin: playwright: cli.js - checksum: 10/214175446089000c2ac997b925063b95f7d86d129c5d7c74caa5ddcb05bcad598dfd569d2133a10dc82d288bf67e7858877dcd099274b0b928b9c63db7d6ecec + checksum: 10/0b0258630f39b4d6ff1555d008ee4d591fe45cbe1e0f643a612397e3e6b1f7a99a2037a957eaa7351edd907ba10966ba105b2d244eafd1b247378910b660f086 languageName: node linkType: hard @@ -41543,7 +43003,7 @@ __metadata: languageName: node linkType: hard -"proxy-addr@npm:~2.0.7": +"proxy-addr@npm:^2.0.7, proxy-addr@npm:~2.0.7": version: 2.0.7 resolution: "proxy-addr@npm:2.0.7" dependencies: @@ -41667,7 +43127,7 @@ __metadata: languageName: node linkType: hard -"qs@npm:^6.10.1, qs@npm:^6.10.3, qs@npm:^6.11.0, qs@npm:^6.12.2, qs@npm:^6.12.3, qs@npm:^6.7.0, qs@npm:^6.9.4": +"qs@npm:^6.10.1, qs@npm:^6.10.3, qs@npm:^6.11.0, qs@npm:^6.12.2, qs@npm:^6.12.3, qs@npm:^6.14.0, qs@npm:^6.7.0, qs@npm:^6.9.4": version: 6.14.0 resolution: "qs@npm:6.14.0" dependencies: @@ -41835,6 +43295,15 @@ __metadata: languageName: node linkType: hard +"rate-limit-redis@npm:^4.2.0": + version: 4.2.1 + resolution: "rate-limit-redis@npm:4.2.1" + peerDependencies: + express-rate-limit: ">= 6" + checksum: 10/c36c50cfca992cbd14c97c08bb01c7d1d340d27b5fa1a2c1154275fec0b59c187eb6fb207da3d035c7c87e7629c92324cd53074f854dbb16548faf94f5a41351 + languageName: node + linkType: hard + "rate-limiter-flexible@npm:^4.0.1": version: 4.0.1 resolution: "rate-limiter-flexible@npm:4.0.1" @@ -41854,6 +43323,18 @@ __metadata: languageName: node linkType: hard +"raw-body@npm:^3.0.0": + version: 3.0.0 + resolution: "raw-body@npm:3.0.0" + dependencies: + bytes: "npm:3.1.2" + http-errors: "npm:2.0.0" + iconv-lite: "npm:0.6.3" + unpipe: "npm:1.0.0" + checksum: 10/2443429bbb2f9ae5c50d3d2a6c342533dfbde6b3173740b70fa0302b30914ff400c6d31a46b3ceacbe7d0925dc07d4413928278b494b04a65736fc17ca33e30c + languageName: node + linkType: hard + "raw-loader@npm:^4.0.2": version: 4.0.2 resolution: "raw-loader@npm:4.0.2" @@ -41915,6 +43396,98 @@ __metadata: languageName: node linkType: hard +"react-aria-components@npm:^1.10.1": + version: 1.10.1 + resolution: "react-aria-components@npm:1.10.1" + dependencies: + "@internationalized/date": "npm:^3.8.2" + "@internationalized/string": "npm:^3.2.7" + "@react-aria/autocomplete": "npm:3.0.0-beta.5" + "@react-aria/collections": "npm:3.0.0-rc.3" + "@react-aria/dnd": "npm:^3.10.1" + "@react-aria/focus": "npm:^3.20.5" + "@react-aria/interactions": "npm:^3.25.3" + "@react-aria/live-announcer": "npm:^3.4.3" + "@react-aria/overlays": "npm:^3.27.3" + "@react-aria/ssr": "npm:^3.9.9" + "@react-aria/toolbar": "npm:3.0.0-beta.18" + "@react-aria/utils": "npm:^3.29.1" + "@react-aria/virtualizer": "npm:^4.1.7" + "@react-stately/autocomplete": "npm:3.0.0-beta.2" + "@react-stately/layout": "npm:^4.3.1" + "@react-stately/selection": "npm:^3.20.3" + "@react-stately/table": "npm:^3.14.3" + "@react-stately/utils": "npm:^3.10.7" + "@react-stately/virtualizer": "npm:^4.4.1" + "@react-types/form": "npm:^3.7.13" + "@react-types/grid": "npm:^3.3.3" + "@react-types/shared": "npm:^3.30.0" + "@react-types/table": "npm:^3.13.1" + "@swc/helpers": "npm:^0.5.0" + client-only: "npm:^0.0.1" + react-aria: "npm:^3.41.1" + react-stately: "npm:^3.39.0" + use-sync-external-store: "npm:^1.4.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/6fcc35404bdd8718bbfb05263bd0c67157d2ba665e0446c47f42f78262ef92231bb0512fc7734c2114bb20c28fff8eb13694c9719c741d2c7a59181fd8fdf115 + languageName: node + linkType: hard + +"react-aria@npm:^3.41.1": + version: 3.41.1 + resolution: "react-aria@npm:3.41.1" + dependencies: + "@internationalized/string": "npm:^3.2.7" + "@react-aria/breadcrumbs": "npm:^3.5.26" + "@react-aria/button": "npm:^3.13.3" + "@react-aria/calendar": "npm:^3.8.3" + "@react-aria/checkbox": "npm:^3.15.7" + "@react-aria/color": "npm:^3.0.9" + "@react-aria/combobox": "npm:^3.12.5" + "@react-aria/datepicker": "npm:^3.14.5" + "@react-aria/dialog": "npm:^3.5.27" + "@react-aria/disclosure": "npm:^3.0.6" + "@react-aria/dnd": "npm:^3.10.1" + "@react-aria/focus": "npm:^3.20.5" + "@react-aria/gridlist": "npm:^3.13.2" + "@react-aria/i18n": "npm:^3.12.10" + "@react-aria/interactions": "npm:^3.25.3" + "@react-aria/label": "npm:^3.7.19" + "@react-aria/landmark": "npm:^3.0.4" + "@react-aria/link": "npm:^3.8.3" + "@react-aria/listbox": "npm:^3.14.6" + "@react-aria/menu": "npm:^3.18.5" + "@react-aria/meter": "npm:^3.4.24" + "@react-aria/numberfield": "npm:^3.11.16" + "@react-aria/overlays": "npm:^3.27.3" + "@react-aria/progress": "npm:^3.4.24" + "@react-aria/radio": "npm:^3.11.5" + "@react-aria/searchfield": "npm:^3.8.6" + "@react-aria/select": "npm:^3.15.7" + "@react-aria/selection": "npm:^3.24.3" + "@react-aria/separator": "npm:^3.4.10" + "@react-aria/slider": "npm:^3.7.21" + "@react-aria/ssr": "npm:^3.9.9" + "@react-aria/switch": "npm:^3.7.5" + "@react-aria/table": "npm:^3.17.5" + "@react-aria/tabs": "npm:^3.10.5" + "@react-aria/tag": "npm:^3.6.2" + "@react-aria/textfield": "npm:^3.17.5" + "@react-aria/toast": "npm:^3.0.5" + "@react-aria/tooltip": "npm:^3.8.5" + "@react-aria/tree": "npm:^3.1.1" + "@react-aria/utils": "npm:^3.29.1" + "@react-aria/visually-hidden": "npm:^3.8.25" + "@react-types/shared": "npm:^3.30.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/6ec619bc9b26800516e22054a428ea29ebc7bcfabf762918893a5a1a73d1576dd4b1c99d85aae02ae69eb16a49d1a765ab34cb840a500134a76e145a4e995f42 + languageName: node + linkType: hard + "react-base16-styling@npm:^0.6.0": version: 0.6.0 resolution: "react-base16-styling@npm:0.6.0" @@ -42510,6 +44083,42 @@ __metadata: languageName: node linkType: hard +"react-stately@npm:^3.39.0": + version: 3.39.0 + resolution: "react-stately@npm:3.39.0" + dependencies: + "@react-stately/calendar": "npm:^3.8.2" + "@react-stately/checkbox": "npm:^3.6.15" + "@react-stately/collections": "npm:^3.12.5" + "@react-stately/color": "npm:^3.8.6" + "@react-stately/combobox": "npm:^3.10.6" + "@react-stately/data": "npm:^3.13.1" + "@react-stately/datepicker": "npm:^3.14.2" + "@react-stately/disclosure": "npm:^3.0.5" + "@react-stately/dnd": "npm:^3.6.0" + "@react-stately/form": "npm:^3.1.5" + "@react-stately/list": "npm:^3.12.3" + "@react-stately/menu": "npm:^3.9.5" + "@react-stately/numberfield": "npm:^3.9.13" + "@react-stately/overlays": "npm:^3.6.17" + "@react-stately/radio": "npm:^3.10.14" + "@react-stately/searchfield": "npm:^3.5.13" + "@react-stately/select": "npm:^3.6.14" + "@react-stately/selection": "npm:^3.20.3" + "@react-stately/slider": "npm:^3.6.5" + "@react-stately/table": "npm:^3.14.3" + "@react-stately/tabs": "npm:^3.8.3" + "@react-stately/toast": "npm:^3.1.1" + "@react-stately/toggle": "npm:^3.8.5" + "@react-stately/tooltip": "npm:^3.5.5" + "@react-stately/tree": "npm:^3.9.0" + "@react-types/shared": "npm:^3.30.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/f59f86aca0797e389698fc20a7e88a26748e00e56e011dd6d9f7a4fa1ba7fda32083bc8e5f2af000957d20ad9f4c74dd151cb667b958dcac8f3959d860905fd4 + languageName: node + linkType: hard + "react-style-singleton@npm:^2.2.1": version: 2.2.1 resolution: "react-style-singleton@npm:2.2.1" @@ -42882,20 +44491,6 @@ __metadata: languageName: node linkType: hard -"redis@npm:^4.7.0": - version: 4.7.0 - resolution: "redis@npm:4.7.0" - dependencies: - "@redis/bloom": "npm:1.2.0" - "@redis/client": "npm:1.6.0" - "@redis/graph": "npm:1.1.1" - "@redis/json": "npm:1.0.7" - "@redis/search": "npm:1.2.0" - "@redis/time-series": "npm:1.1.0" - checksum: 10/d927a0b1516e2845b7eab67b1466b6f2d0d0695be7a3d4a0a1ffa2f2c60dace98fb9ad01ec0db07519fb9d4d078b99d95b6809508c2a72afe6f814fc8f693188 - languageName: node - linkType: hard - "redux-immutable@npm:^4.0.0": version: 4.0.0 resolution: "redux-immutable@npm:4.0.0" @@ -43726,6 +45321,7 @@ __metadata: "@backstage/create-app": "workspace:*" "@backstage/e2e-test-utils": "workspace:*" "@backstage/errors": "workspace:^" + "@backstage/eslint-plugin": "workspace:*" "@backstage/repo-tools": "workspace:*" "@changesets/cli": "npm:^2.14.0" "@manypkg/get-packages": "npm:^1.1.3" @@ -43763,6 +45359,19 @@ __metadata: languageName: unknown linkType: soft +"router@npm:^2.2.0": + version: 2.2.0 + resolution: "router@npm:2.2.0" + dependencies: + debug: "npm:^4.4.0" + depd: "npm:^2.0.0" + is-promise: "npm:^4.0.0" + parseurl: "npm:^1.3.3" + path-to-regexp: "npm:^8.0.0" + checksum: 10/8949bd1d3da5403cc024e2989fee58d7fda0f3ffe9f2dc5b8a192f295f400b3cde307b0b554f7d44851077640f36962ca469a766b3d57410d7d96245a7ba6c91 + languageName: node + linkType: hard + "rrweb-cssom@npm:^0.7.1": version: 0.7.1 resolution: "rrweb-cssom@npm:0.7.1" @@ -44146,6 +45755,25 @@ __metadata: languageName: node linkType: hard +"send@npm:^1.1.0, send@npm:^1.2.0": + version: 1.2.0 + resolution: "send@npm:1.2.0" + dependencies: + debug: "npm:^4.3.5" + encodeurl: "npm:^2.0.0" + escape-html: "npm:^1.0.3" + etag: "npm:^1.8.1" + fresh: "npm:^2.0.0" + http-errors: "npm:^2.0.0" + mime-types: "npm:^3.0.1" + ms: "npm:^2.1.3" + on-finished: "npm:^2.4.1" + range-parser: "npm:^1.2.1" + statuses: "npm:^2.0.1" + checksum: 10/9fa3b1a3b9a06b7b4ab00c25e8228326d9665a9745753a34d1ffab8ac63c7c206727331d1dc5be73647f1b658d259a1aa8e275b0e0eee51349370af02e9da506 + languageName: node + linkType: hard + "seq-queue@npm:^0.0.5": version: 0.0.5 resolution: "seq-queue@npm:0.0.5" @@ -44222,6 +45850,18 @@ __metadata: languageName: node linkType: hard +"serve-static@npm:^2.2.0": + version: 2.2.0 + resolution: "serve-static@npm:2.2.0" + dependencies: + encodeurl: "npm:^2.0.0" + escape-html: "npm:^1.0.3" + parseurl: "npm:^1.3.3" + send: "npm:^1.2.0" + checksum: 10/9f1a900738c5bb02258275ce3bd1273379c4c3072b622e15d44e8f47d89a1ba2d639ec2d63b11c263ca936096b40758acb7a0d989cd6989018a65a12f9433ada + languageName: node + linkType: hard + "set-blocking@npm:^2.0.0": version: 2.0.0 resolution: "set-blocking@npm:2.0.0" @@ -46965,6 +48605,17 @@ __metadata: languageName: node linkType: hard +"type-is@npm:^2.0.0, type-is@npm:^2.0.1": + version: 2.0.1 + resolution: "type-is@npm:2.0.1" + dependencies: + content-type: "npm:^1.0.5" + media-typer: "npm:^1.1.0" + mime-types: "npm:^3.0.0" + checksum: 10/bacdb23c872dacb7bd40fbd9095e6b2fca2895eedbb689160c05534d7d4810a7f4b3fd1ae87e96133c505958f6d602967a68db5ff577b85dd6be76eaa75d58af + languageName: node + linkType: hard + "type@npm:^1.0.1": version: 1.2.0 resolution: "type@npm:1.2.0" @@ -48274,53 +49925,9 @@ __metadata: languageName: node linkType: hard -"webpack-dev-server@npm:5.2.0": - version: 5.2.0 - resolution: "webpack-dev-server@npm:5.2.0" - dependencies: - "@types/bonjour": "npm:^3.5.13" - "@types/connect-history-api-fallback": "npm:^1.5.4" - "@types/express": "npm:^4.17.21" - "@types/serve-index": "npm:^1.9.4" - "@types/serve-static": "npm:^1.15.5" - "@types/sockjs": "npm:^0.3.36" - "@types/ws": "npm:^8.5.10" - ansi-html-community: "npm:^0.0.8" - bonjour-service: "npm:^1.2.1" - chokidar: "npm:^3.6.0" - colorette: "npm:^2.0.10" - compression: "npm:^1.7.4" - connect-history-api-fallback: "npm:^2.0.0" - express: "npm:^4.21.2" - graceful-fs: "npm:^4.2.6" - http-proxy-middleware: "npm:^2.0.7" - ipaddr.js: "npm:^2.1.0" - launch-editor: "npm:^2.6.1" - open: "npm:^10.0.3" - p-retry: "npm:^6.2.0" - schema-utils: "npm:^4.2.0" - selfsigned: "npm:^2.4.1" - serve-index: "npm:^1.9.1" - sockjs: "npm:^0.3.24" - spdy: "npm:^4.0.2" - webpack-dev-middleware: "npm:^7.4.2" - ws: "npm:^8.18.0" - peerDependencies: - webpack: ^5.0.0 - peerDependenciesMeta: - webpack: - optional: true - webpack-cli: - optional: true - bin: - webpack-dev-server: bin/webpack-dev-server.js - checksum: 10/f93ca46b037e547a9db157db72ef98ab177659ad13a6e63302d87bd77b32e524dd7133f1ad18f5a51ec68712911c59be8d4e06aa7bcbe6f56a9e9ce3774cf7f6 - languageName: node - linkType: hard - -"webpack-dev-server@npm:^5.0.0": - version: 5.2.1 - resolution: "webpack-dev-server@npm:5.2.1" +"webpack-dev-server@npm:5.2.2, webpack-dev-server@npm:^5.0.0": + version: 5.2.2 + resolution: "webpack-dev-server@npm:5.2.2" dependencies: "@types/bonjour": "npm:^3.5.13" "@types/connect-history-api-fallback": "npm:^1.5.4" @@ -48338,7 +49945,7 @@ __metadata: connect-history-api-fallback: "npm:^2.0.0" express: "npm:^4.21.2" graceful-fs: "npm:^4.2.6" - http-proxy-middleware: "npm:^2.0.7" + http-proxy-middleware: "npm:^2.0.9" ipaddr.js: "npm:^2.1.0" launch-editor: "npm:^2.6.1" open: "npm:^10.0.3" @@ -48359,7 +49966,7 @@ __metadata: optional: true bin: webpack-dev-server: bin/webpack-dev-server.js - checksum: 10/424edfe22b7bbe2301a38b8b519dfeb7643e0ca643be01af3fa48ec18512955c1952246741d7577bdb911ee09dcd6c521ade7d65e0059448ee69ab02bfac4624 + checksum: 10/59517409cd38c01a875a03b9658f3d20d492b5b8bead9ded4a0f3d33e6857daf2d352fe89f0181dcaea6d0fbe84b0494cb4750a87120fe81cdbb3c32b499451c languageName: node linkType: hard @@ -48876,31 +50483,6 @@ __metadata: languageName: node linkType: hard -"xterm-addon-attach@npm:^0.9.0": - version: 0.9.0 - resolution: "xterm-addon-attach@npm:0.9.0" - peerDependencies: - xterm: ^5.0.0 - checksum: 10/70e5d3ecf139c04fae13c644b79c33858ef1a6e28dfe78f91dad3e34f5a155579029b87e91d1d016575acaf17f74e6c59402bde4bcff03461595bea0870f1ec1 - languageName: node - linkType: hard - -"xterm-addon-fit@npm:^0.8.0": - version: 0.8.0 - resolution: "xterm-addon-fit@npm:0.8.0" - peerDependencies: - xterm: ^5.0.0 - checksum: 10/5af2041b442f7c804eda2e6f62e3b68b5159b0ae6bd96e2aa8d85b26441df57291cbfed653d1196d4af5d9b94bfc39993df8b409a25c35e0d36bdaf6f5cdfe5f - languageName: node - linkType: hard - -"xterm@npm:^5.2.1, xterm@npm:^5.3.0": - version: 5.3.0 - resolution: "xterm@npm:5.3.0" - checksum: 10/3690b6a6d744f1d2932279975bb8e6c786e70c675531045016ecfe0f9b7957e2fc6811b815335f3e0e84b40ffae654f6ee4afe55a5768534744497e62252dd50 - languageName: node - linkType: hard - "y18n@npm:^5.0.5": version: 5.0.8 resolution: "y18n@npm:5.0.8" @@ -49020,8 +50602,9 @@ __metadata: "@backstage/cli-common": "workspace:^" "@backstage/release-manifests": "workspace:^" "@yarnpkg/builder": "npm:^4.2.1" - "@yarnpkg/core": "npm:^4.4.0" + "@yarnpkg/core": "npm:^4.4.1" "@yarnpkg/fslib": "npm:^3.1.2" + "@yarnpkg/plugin-essentials": "npm:^4.4.0" "@yarnpkg/plugin-npm": "patch:@yarnpkg/plugin-npm@npm%3A3.1.0#~/.yarn/patches/@yarnpkg-plugin-npm-npm-3.1.0-6533d0f5a1.patch" "@yarnpkg/plugin-pack": "npm:^4.0.1" fs-extra: "npm:^11.2.0" @@ -49168,12 +50751,12 @@ __metadata: languageName: node linkType: hard -"zod-to-json-schema@npm:^3.20.4, zod-to-json-schema@npm:^3.21.4": - version: 3.23.5 - resolution: "zod-to-json-schema@npm:3.23.5" +"zod-to-json-schema@npm:^3.20.4, zod-to-json-schema@npm:^3.21.4, zod-to-json-schema@npm:^3.24.1": + version: 3.24.5 + resolution: "zod-to-json-schema@npm:3.24.5" peerDependencies: - zod: ^3.23.3 - checksum: 10/53d07a419f0f194e0b96711dc11e7e6fa52a366b0ed5fceb405dc55f13252a1bf433712e4fb496c2a5fdc851018ee1acba7b39c2265c43d6fbb180e12c110c3b + zod: ^3.24.1 + checksum: 10/1af291b4c429945c9568c2e924bdb7c66ab8d139cbeb9a99b6e9fc9e1b02863f85d07759b9303714f07ceda3993dcaf0ebcb80d2c18bb2aaf5502b2c1016affd languageName: node linkType: hard @@ -49186,10 +50769,10 @@ __metadata: languageName: node linkType: hard -"zod@npm:^3.22.4": - version: 3.24.4 - resolution: "zod@npm:3.24.4" - checksum: 10/3d545792fa54bb27ee5dbc34a5709e81f603185fcc94c8204b5d95c20dc4c81d870ff9c51f3884a30ef05cdc601449f4c4df254ac4783f0827b1faed7c1cdb48 +"zod@npm:^3.22.4, zod@npm:^3.23.8": + version: 3.25.67 + resolution: "zod@npm:3.25.67" + checksum: 10/0e35432dcca7f053e63f5dd491a87c78abe0d981817547252c3b6d05f0f58788695d1a69724759c6501dff3fd62929be24c9f314a3625179bee889150f7a61fa languageName: node linkType: hard